2 Add material to support overhang or remove material at the overhang angle.
6 from __future__ import absolute_import
8 from fabmetheus_utilities.geometry.creation import lineation
9 from fabmetheus_utilities.geometry.geometry_utilities import evaluate
10 from fabmetheus_utilities.vector3 import Vector3
11 from fabmetheus_utilities import euclidean
13 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
14 __credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
15 __date__ = '$Date: 2008/02/05 $'
16 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
19 globalExecutionOrder = 60
22 def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
26 derivation = SegmentDerivation(elementNode, prefix)
27 if derivation.path == getSegmentPathDefault():
29 path = getXNormalizedVector3Path(derivation.path)
30 if euclidean.getIsWiddershinsByVector3(loop):
33 point.x = 1.0 - point.x
34 if derivation.center == None:
37 startEnd = StartEnd(elementNode, len(loop), prefix)
38 for pointIndex in xrange(len(loop)):
39 if startEnd.start <= pointIndex < startEnd.end:
40 segmentLoop += getSegmentPath(derivation.center, loop, path, pointIndex)
42 segmentLoop.append(loop[pointIndex])
43 return [euclidean.getLoopWithoutCloseSequentialPoints( close, segmentLoop)]
45 def getNewDerivation(elementNode, prefix, sideLength):
47 return SegmentDerivation(elementNode, prefix)
49 def getRadialPath(begin, center, end, path):
51 beginComplex = begin.dropAxis()
52 endComplex = end.dropAxis()
53 centerComplex = center.dropAxis()
54 beginMinusCenterComplex = beginComplex - centerComplex
55 endMinusCenterComplex = endComplex - centerComplex
56 beginMinusCenterComplexRadius = abs( beginMinusCenterComplex )
57 endMinusCenterComplexRadius = abs( endMinusCenterComplex )
58 if beginMinusCenterComplexRadius == 0.0 or endMinusCenterComplexRadius == 0.0:
60 beginMinusCenterComplex /= beginMinusCenterComplexRadius
61 endMinusCenterComplex /= endMinusCenterComplexRadius
62 angleDifference = euclidean.getAngleDifferenceByComplex( endMinusCenterComplex, beginMinusCenterComplex )
66 weightBegin = 1.0 - weightEnd
67 weightedRadius = beginMinusCenterComplexRadius * weightBegin + endMinusCenterComplexRadius * weightEnd * ( 1.0 + point.y )
68 radialComplex = weightedRadius * euclidean.getWiddershinsUnitPolar( angleDifference * point.x ) * beginMinusCenterComplex
69 polygonPoint = center + Vector3( radialComplex.real, radialComplex.imag, point.z )
70 radialPath.append( polygonPoint )
73 def getSegmentPath(center, loop, path, pointIndex):
75 centerBegin = loop[pointIndex]
76 centerEnd = loop[(pointIndex + 1) % len(loop)]
77 centerEndMinusBegin = centerEnd - centerBegin
78 if abs( centerEndMinusBegin ) <= 0.0:
79 return [ centerBegin ]
81 return getRadialPath(centerBegin, center, centerEnd, path)
82 begin = loop[(pointIndex + len(loop) - 1) % len(loop)]
83 end = loop[(pointIndex + 2) % len(loop)]
84 return getWedgePath(begin, centerBegin, centerEnd, centerEndMinusBegin, end, path)
86 def getSegmentPathDefault():
87 "Get segment path default."
88 return [Vector3(), Vector3(0.0, 1.0)]
90 def getWedgePath( begin, centerBegin, centerEnd, centerEndMinusBegin, end, path ):
92 beginComplex = begin.dropAxis()
93 centerBeginComplex = centerBegin.dropAxis()
94 centerEndComplex = centerEnd.dropAxis()
95 endComplex = end.dropAxis()
97 centerBeginMinusBeginComplex = euclidean.getNormalized( centerBeginComplex - beginComplex )
98 centerEndMinusCenterBeginComplexOriginal = centerEndComplex - centerBeginComplex
99 centerEndMinusCenterBeginComplexLength = abs( centerEndMinusCenterBeginComplexOriginal )
100 if centerEndMinusCenterBeginComplexLength <= 0.0:
101 return [ centerBegin ]
102 centerEndMinusCenterBeginComplex = centerEndMinusCenterBeginComplexOriginal / centerEndMinusCenterBeginComplexLength
103 endMinusCenterEndComplex = euclidean.getNormalized( endComplex - centerEndComplex )
104 widdershinsBegin = getWiddershinsAverageByVector3( centerBeginMinusBeginComplex, centerEndMinusCenterBeginComplex )
105 widdershinsEnd = getWiddershinsAverageByVector3( centerEndMinusCenterBeginComplex, endMinusCenterEndComplex )
108 weightBegin = 1.0 - weightEnd
109 polygonPoint = centerBegin + centerEndMinusBegin * point.x
110 weightedWiddershins = widdershinsBegin * weightBegin + widdershinsEnd * weightEnd
111 polygonPoint += weightedWiddershins * point.y * centerEndMinusCenterBeginComplexLength
112 polygonPoint.z += point.z
113 wedgePath.append( polygonPoint )
116 def getWiddershinsAverageByVector3( centerMinusBeginComplex, endMinusCenterComplex ):
117 "Get the normalized average of the widdershins vectors."
118 centerMinusBeginWiddershins = Vector3( - centerMinusBeginComplex.imag, centerMinusBeginComplex.real )
119 endMinusCenterWiddershins = Vector3( - endMinusCenterComplex.imag, endMinusCenterComplex.real )
120 return ( centerMinusBeginWiddershins + endMinusCenterWiddershins ).getNormalized()
122 def getXNormalizedVector3Path(path):
123 "Get path where the x ranges from 0 to 1."
127 for point in path[1 :]:
128 minimumX = min( minimumX, point.x )
132 for point in path[1 :]:
133 maximumX = max( maximumX, point.x )
138 def processElementNode(elementNode):
139 "Process the xml element."
140 lineation.processElementNodeByFunction(elementNode, getManipulatedPaths)
143 class SegmentDerivation(object):
144 "Class to hold segment variables."
145 def __init__(self, elementNode, prefix):
147 self.center = evaluate.getVector3ByPrefix(None, elementNode, prefix + 'center')
148 self.path = evaluate.getPathByPrefix(elementNode, getSegmentPathDefault(), prefix)
151 class StartEnd(object):
152 'Class to get a start through end range.'
153 def __init__(self, elementNode, modulo, prefix):
155 self.start = evaluate.getEvaluatedInt(0, elementNode, prefix + 'start')
156 self.extent = evaluate.getEvaluatedInt(modulo - self.start, elementNode, prefix + 'extent')
157 self.end = evaluate.getEvaluatedInt(self.start + self.extent, elementNode, prefix + 'end')
158 self.revolutions = evaluate.getEvaluatedInt(1, elementNode, prefix + 'revolutions')
159 if self.revolutions > 1:
160 self.end += modulo * (self.revolutions - 1)
163 "Get the string representation of this StartEnd."
164 return '%s, %s, %s' % (self.start, self.end, self.revolutions)