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
15 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
16 __credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
17 __date__ = '$Date: 2008/02/05 $'
18 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
21 globalExecutionOrder = 60
24 def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
28 derivation = SegmentDerivation(elementNode, prefix)
29 if derivation.path == getSegmentPathDefault():
31 path = getXNormalizedVector3Path(derivation.path)
32 if euclidean.getIsWiddershinsByVector3(loop):
35 point.x = 1.0 - point.x
36 if derivation.center == None:
39 startEnd = StartEnd(elementNode, len(loop), prefix)
40 for pointIndex in xrange(len(loop)):
41 if pointIndex >= startEnd.start and pointIndex < startEnd.end:
42 segmentLoop += getSegmentPath(derivation.center, loop, path, pointIndex)
44 segmentLoop.append(loop[pointIndex])
45 return [euclidean.getLoopWithoutCloseSequentialPoints( close, segmentLoop)]
47 def getNewDerivation(elementNode, prefix, sideLength):
49 return SegmentDerivation(elementNode, prefix)
51 def getRadialPath(begin, center, end, path):
53 beginComplex = begin.dropAxis()
54 endComplex = end.dropAxis()
55 centerComplex = center.dropAxis()
56 beginMinusCenterComplex = beginComplex - centerComplex
57 endMinusCenterComplex = endComplex - centerComplex
58 beginMinusCenterComplexRadius = abs( beginMinusCenterComplex )
59 endMinusCenterComplexRadius = abs( endMinusCenterComplex )
60 if beginMinusCenterComplexRadius == 0.0 or endMinusCenterComplexRadius == 0.0:
62 beginMinusCenterComplex /= beginMinusCenterComplexRadius
63 endMinusCenterComplex /= endMinusCenterComplexRadius
64 angleDifference = euclidean.getAngleDifferenceByComplex( endMinusCenterComplex, beginMinusCenterComplex )
68 weightBegin = 1.0 - weightEnd
69 weightedRadius = beginMinusCenterComplexRadius * weightBegin + endMinusCenterComplexRadius * weightEnd * ( 1.0 + point.y )
70 radialComplex = weightedRadius * euclidean.getWiddershinsUnitPolar( angleDifference * point.x ) * beginMinusCenterComplex
71 polygonPoint = center + Vector3( radialComplex.real, radialComplex.imag, point.z )
72 radialPath.append( polygonPoint )
75 def getSegmentPath(center, loop, path, pointIndex):
77 centerBegin = loop[pointIndex]
78 centerEnd = loop[(pointIndex + 1) % len(loop)]
79 centerEndMinusBegin = centerEnd - centerBegin
80 if abs( centerEndMinusBegin ) <= 0.0:
81 return [ centerBegin ]
83 return getRadialPath(centerBegin, center, centerEnd, path)
84 begin = loop[(pointIndex + len(loop) - 1) % len(loop)]
85 end = loop[(pointIndex + 2) % len(loop)]
86 return getWedgePath(begin, centerBegin, centerEnd, centerEndMinusBegin, end, path)
88 def getSegmentPathDefault():
89 "Get segment path default."
90 return [Vector3(), Vector3(0.0, 1.0)]
92 def getWedgePath( begin, centerBegin, centerEnd, centerEndMinusBegin, end, path ):
94 beginComplex = begin.dropAxis()
95 centerBeginComplex = centerBegin.dropAxis()
96 centerEndComplex = centerEnd.dropAxis()
97 endComplex = end.dropAxis()
99 centerBeginMinusBeginComplex = euclidean.getNormalized( centerBeginComplex - beginComplex )
100 centerEndMinusCenterBeginComplexOriginal = centerEndComplex - centerBeginComplex
101 centerEndMinusCenterBeginComplexLength = abs( centerEndMinusCenterBeginComplexOriginal )
102 if centerEndMinusCenterBeginComplexLength <= 0.0:
103 return [ centerBegin ]
104 centerEndMinusCenterBeginComplex = centerEndMinusCenterBeginComplexOriginal / centerEndMinusCenterBeginComplexLength
105 endMinusCenterEndComplex = euclidean.getNormalized( endComplex - centerEndComplex )
106 widdershinsBegin = getWiddershinsAverageByVector3( centerBeginMinusBeginComplex, centerEndMinusCenterBeginComplex )
107 widdershinsEnd = getWiddershinsAverageByVector3( centerEndMinusCenterBeginComplex, endMinusCenterEndComplex )
110 weightBegin = 1.0 - weightEnd
111 polygonPoint = centerBegin + centerEndMinusBegin * point.x
112 weightedWiddershins = widdershinsBegin * weightBegin + widdershinsEnd * weightEnd
113 polygonPoint += weightedWiddershins * point.y * centerEndMinusCenterBeginComplexLength
114 polygonPoint.z += point.z
115 wedgePath.append( polygonPoint )
118 def getWiddershinsAverageByVector3( centerMinusBeginComplex, endMinusCenterComplex ):
119 "Get the normalized average of the widdershins vectors."
120 centerMinusBeginWiddershins = Vector3( - centerMinusBeginComplex.imag, centerMinusBeginComplex.real )
121 endMinusCenterWiddershins = Vector3( - endMinusCenterComplex.imag, endMinusCenterComplex.real )
122 return ( centerMinusBeginWiddershins + endMinusCenterWiddershins ).getNormalized()
124 def getXNormalizedVector3Path(path):
125 "Get path where the x ranges from 0 to 1."
129 for point in path[1 :]:
130 minimumX = min( minimumX, point.x )
134 for point in path[1 :]:
135 maximumX = max( maximumX, point.x )
140 def processElementNode(elementNode):
141 "Process the xml element."
142 lineation.processElementNodeByFunction(elementNode, getManipulatedPaths)
145 class SegmentDerivation:
146 "Class to hold segment variables."
147 def __init__(self, elementNode, prefix):
149 self.center = evaluate.getVector3ByPrefix(None, elementNode, prefix + 'center')
150 self.path = evaluate.getPathByPrefix(elementNode, getSegmentPathDefault(), prefix)
154 'Class to get a start through end range.'
155 def __init__(self, elementNode, modulo, prefix):
157 self.start = evaluate.getEvaluatedInt(0, elementNode, prefix + 'start')
158 self.extent = evaluate.getEvaluatedInt(modulo - self.start, elementNode, prefix + 'extent')
159 self.end = evaluate.getEvaluatedInt(self.start + self.extent, elementNode, prefix + 'end')
160 self.revolutions = evaluate.getEvaluatedInt(1, elementNode, prefix + 'revolutions')
161 if self.revolutions > 1:
162 self.end += modulo * (self.revolutions - 1)
165 "Get the string representation of this StartEnd."
166 return '%s, %s, %s' % (self.start, self.end, self.revolutions)