2 Add material to support overhang or remove material at the overhang angle.
6 from __future__ import absolute_import
7 #Init has to be imported first because it has code to workaround the python bug where relative imports don't work if the module is imported as a main module.
10 from fabmetheus_utilities.geometry.creation import lineation
11 from fabmetheus_utilities.geometry.geometry_utilities import evaluate
12 from fabmetheus_utilities.vector3 import Vector3
13 from fabmetheus_utilities import euclidean
17 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
18 __credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
19 __date__ = '$Date: 2008/02/05 $'
20 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
23 globalExecutionOrder = 40
26 def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
30 derivation = RoundDerivation(elementNode, prefix, sideLength)
31 if derivation.radius == 0.0:
34 sidesPerRadian = 0.5 / math.pi * evaluate.getSidesMinimumThreeBasedOnPrecision(elementNode, sideLength)
35 for pointIndex in xrange(len(loop)):
36 begin = loop[(pointIndex + len(loop) - 1) % len(loop)]
37 center = loop[pointIndex]
38 end = loop[(pointIndex + 1) % len(loop)]
39 roundLoop += getRoundPath(begin, center, close, end, derivation.radius, sidesPerRadian)
40 return [euclidean.getLoopWithoutCloseSequentialPoints(close, roundLoop)]
42 def getNewDerivation(elementNode, prefix, sideLength):
44 return RoundDerivation(elementNode, prefix, sideLength)
46 def getRoundPath( begin, center, close, end, radius, sidesPerRadian ):
48 beginComplex = begin.dropAxis()
49 centerComplex = center.dropAxis()
50 endComplex = end.dropAxis()
51 beginComplexSegmentLength = abs( centerComplex - beginComplex )
52 endComplexSegmentLength = abs( centerComplex - endComplex )
53 minimumRadius = lineation.getMinimumRadius( beginComplexSegmentLength, endComplexSegmentLength, radius )
54 if minimumRadius <= close:
56 beginBevel = center + minimumRadius / beginComplexSegmentLength * ( begin - center )
57 endBevel = center + minimumRadius / endComplexSegmentLength * ( end - center )
58 beginBevelComplex = beginBevel.dropAxis()
59 endBevelComplex = endBevel.dropAxis()
60 midpointComplex = 0.5 * ( beginBevelComplex + endBevelComplex )
62 centerComplex = midpointComplex + midpointComplex - centerComplex
63 midpointMinusCenterComplex = midpointComplex - centerComplex
64 midpointCenterLength = abs( midpointMinusCenterComplex )
65 midpointEndLength = abs( midpointComplex - endBevelComplex )
66 midpointCircleCenterLength = midpointEndLength * midpointEndLength / midpointCenterLength
67 circleRadius = math.sqrt( midpointCircleCenterLength * midpointCircleCenterLength + midpointEndLength * midpointEndLength )
68 circleCenterComplex = midpointComplex + midpointMinusCenterComplex * midpointCircleCenterLength / midpointCenterLength
69 circleCenter = Vector3( circleCenterComplex.real, circleCenterComplex.imag, center.z )
70 endMinusCircleCenterComplex = endBevelComplex - circleCenterComplex
71 beginMinusCircleCenter = beginBevel - circleCenter
72 beginMinusCircleCenterComplex = beginMinusCircleCenter.dropAxis()
73 angleDifference = euclidean.getAngleDifferenceByComplex( endMinusCircleCenterComplex, beginMinusCircleCenterComplex )
74 steps = int( math.ceil( abs( angleDifference ) * sidesPerRadian ) )
75 stepPlaneAngle = euclidean.getWiddershinsUnitPolar( angleDifference / float( steps ) )
76 deltaZStep = ( end.z - begin.z ) / float( steps )
77 roundPath = [ beginBevel ]
78 for step in xrange( 1, steps ):
79 beginMinusCircleCenterComplex = beginMinusCircleCenterComplex * stepPlaneAngle
80 arcPointComplex = circleCenterComplex + beginMinusCircleCenterComplex
81 arcPoint = Vector3( arcPointComplex.real, arcPointComplex.imag, begin.z + deltaZStep * step )
82 roundPath.append( arcPoint )
83 return roundPath + [ endBevel ]
85 def processElementNode(elementNode):
86 "Process the xml element."
87 lineation.processElementNodeByFunction(elementNode, getManipulatedPaths)
90 class RoundDerivation:
91 "Class to hold round variables."
92 def __init__(self, elementNode, prefix, sideLength):
94 self.radius = lineation.getFloatByPrefixSide(0.0, elementNode, prefix + 'radius', sideLength)