chiark / gitweb /
Add uppercase STL and HEX to file dialog filters for linux/MacOS
[cura.git] / Cura / cura_sf / fabmetheus_utilities / geometry / manipulation_paths / segment.py
1 """
2 Add material to support overhang or remove material at the overhang angle.
3
4 """
5
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.
8 import __init__
9
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
14
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'
19
20
21 globalExecutionOrder = 60
22
23
24 def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
25         "Get segment loop."
26         if len(loop) < 3:
27                 return [loop]
28         derivation = SegmentDerivation(elementNode, prefix)
29         if derivation.path == getSegmentPathDefault():
30                 return [loop]
31         path = getXNormalizedVector3Path(derivation.path)
32         if euclidean.getIsWiddershinsByVector3(loop):
33                 path = path[: : -1]
34                 for point in path:
35                         point.x = 1.0 - point.x
36                         if derivation.center == None:
37                                 point.y = - point.y
38         segmentLoop = []
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)
43                 else:
44                         segmentLoop.append(loop[pointIndex])
45         return [euclidean.getLoopWithoutCloseSequentialPoints( close, segmentLoop)]
46
47 def getNewDerivation(elementNode, prefix, sideLength):
48         'Get new derivation.'
49         return SegmentDerivation(elementNode, prefix)
50
51 def getRadialPath(begin, center, end, path):
52         "Get radial 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:
61                 return [ begin ]
62         beginMinusCenterComplex /= beginMinusCenterComplexRadius
63         endMinusCenterComplex /= endMinusCenterComplexRadius
64         angleDifference = euclidean.getAngleDifferenceByComplex( endMinusCenterComplex, beginMinusCenterComplex )
65         radialPath = []
66         for point in path:
67                 weightEnd = point.x
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 )
73         return radialPath
74
75 def getSegmentPath(center, loop, path, pointIndex):
76         "Get segment path."
77         centerBegin = loop[pointIndex]
78         centerEnd = loop[(pointIndex + 1) % len(loop)]
79         centerEndMinusBegin = centerEnd - centerBegin
80         if abs( centerEndMinusBegin ) <= 0.0:
81                 return [ centerBegin ]
82         if center != None:
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)
87
88 def getSegmentPathDefault():
89         "Get segment path default."
90         return [Vector3(), Vector3(0.0, 1.0)]
91
92 def getWedgePath( begin, centerBegin, centerEnd, centerEndMinusBegin, end, path ):
93         "Get segment path."
94         beginComplex = begin.dropAxis()
95         centerBeginComplex = centerBegin.dropAxis()
96         centerEndComplex = centerEnd.dropAxis()
97         endComplex = end.dropAxis()
98         wedgePath = []
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 )
108         for point in path:
109                 weightEnd = point.x
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 )
116         return wedgePath
117
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()
123
124 def getXNormalizedVector3Path(path):
125         "Get path where the x ranges from 0 to 1."
126         if len(path) < 1:
127                 return path
128         minimumX = path[0].x
129         for point in path[1 :]:
130                 minimumX = min( minimumX, point.x )
131         for point in path:
132                 point.x -= minimumX
133         maximumX = path[0].x
134         for point in path[1 :]:
135                 maximumX = max( maximumX, point.x )
136         for point in path:
137                 point.x /= maximumX
138         return path
139
140 def processElementNode(elementNode):
141         "Process the xml element."
142         lineation.processElementNodeByFunction(elementNode, getManipulatedPaths)
143
144
145 class SegmentDerivation:
146         "Class to hold segment variables."
147         def __init__(self, elementNode, prefix):
148                 'Set defaults.'
149                 self.center = evaluate.getVector3ByPrefix(None, elementNode, prefix + 'center')
150                 self.path = evaluate.getPathByPrefix(elementNode, getSegmentPathDefault(), prefix)
151
152
153 class StartEnd:
154         'Class to get a start through end range.'
155         def __init__(self, elementNode, modulo, prefix):
156                 "Initialize."
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)
163
164         def __repr__(self):
165                 "Get the string representation of this StartEnd."
166                 return '%s, %s, %s' % (self.start, self.end, self.revolutions)