chiark / gitweb /
Add back the ultimaker platform, and made the platform mesh simpler.
[cura.git] / Cura / slice / 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
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
12
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'
17
18
19 globalExecutionOrder = 60
20
21
22 def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
23         "Get segment loop."
24         if len(loop) < 3:
25                 return [loop]
26         derivation = SegmentDerivation(elementNode, prefix)
27         if derivation.path == getSegmentPathDefault():
28                 return [loop]
29         path = getXNormalizedVector3Path(derivation.path)
30         if euclidean.getIsWiddershinsByVector3(loop):
31                 path = path[: : -1]
32                 for point in path:
33                         point.x = 1.0 - point.x
34                         if derivation.center == None:
35                                 point.y = - point.y
36         segmentLoop = []
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)
41                 else:
42                         segmentLoop.append(loop[pointIndex])
43         return [euclidean.getLoopWithoutCloseSequentialPoints( close, segmentLoop)]
44
45 def getNewDerivation(elementNode, prefix, sideLength):
46         'Get new derivation.'
47         return SegmentDerivation(elementNode, prefix)
48
49 def getRadialPath(begin, center, end, path):
50         "Get radial 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:
59                 return [ begin ]
60         beginMinusCenterComplex /= beginMinusCenterComplexRadius
61         endMinusCenterComplex /= endMinusCenterComplexRadius
62         angleDifference = euclidean.getAngleDifferenceByComplex( endMinusCenterComplex, beginMinusCenterComplex )
63         radialPath = []
64         for point in path:
65                 weightEnd = point.x
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 )
71         return radialPath
72
73 def getSegmentPath(center, loop, path, pointIndex):
74         "Get segment path."
75         centerBegin = loop[pointIndex]
76         centerEnd = loop[(pointIndex + 1) % len(loop)]
77         centerEndMinusBegin = centerEnd - centerBegin
78         if abs( centerEndMinusBegin ) <= 0.0:
79                 return [ centerBegin ]
80         if center != None:
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)
85
86 def getSegmentPathDefault():
87         "Get segment path default."
88         return [Vector3(), Vector3(0.0, 1.0)]
89
90 def getWedgePath( begin, centerBegin, centerEnd, centerEndMinusBegin, end, path ):
91         "Get segment path."
92         beginComplex = begin.dropAxis()
93         centerBeginComplex = centerBegin.dropAxis()
94         centerEndComplex = centerEnd.dropAxis()
95         endComplex = end.dropAxis()
96         wedgePath = []
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 )
106         for point in path:
107                 weightEnd = point.x
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 )
114         return wedgePath
115
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()
121
122 def getXNormalizedVector3Path(path):
123         "Get path where the x ranges from 0 to 1."
124         if len(path) < 1:
125                 return path
126         minimumX = path[0].x
127         for point in path[1 :]:
128                 minimumX = min( minimumX, point.x )
129         for point in path:
130                 point.x -= minimumX
131         maximumX = path[0].x
132         for point in path[1 :]:
133                 maximumX = max( maximumX, point.x )
134         for point in path:
135                 point.x /= maximumX
136         return path
137
138 def processElementNode(elementNode):
139         "Process the xml element."
140         lineation.processElementNodeByFunction(elementNode, getManipulatedPaths)
141
142
143 class SegmentDerivation(object):
144         "Class to hold segment variables."
145         def __init__(self, elementNode, prefix):
146                 'Set defaults.'
147                 self.center = evaluate.getVector3ByPrefix(None, elementNode, prefix + 'center')
148                 self.path = evaluate.getPathByPrefix(elementNode, getSegmentPathDefault(), prefix)
149
150
151 class StartEnd(object):
152         'Class to get a start through end range.'
153         def __init__(self, elementNode, modulo, prefix):
154                 "Initialize."
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)
161
162         def __repr__(self):
163                 "Get the string representation of this StartEnd."
164                 return '%s, %s, %s' % (self.start, self.end, self.revolutions)