chiark / gitweb /
Add back the ultimaker platform, and made the platform mesh simpler.
[cura.git] / Cura / slice / cura_sf / fabmetheus_utilities / geometry / creation / lathe.py
1 """
2 Boolean geometry extrusion.
3
4 """
5
6 from __future__ import absolute_import
7
8 from fabmetheus_utilities.geometry.creation import solid
9 from fabmetheus_utilities.geometry.geometry_utilities import evaluate
10 from fabmetheus_utilities.geometry.solids import triangle_mesh
11 from fabmetheus_utilities.vector3 import Vector3
12 from fabmetheus_utilities import euclidean
13 import math
14
15
16 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
17 __credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
18 __date__ = '$Date: 2008/02/05 $'
19 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
20
21 def addLoopByComplex(derivation, endMultiplier, loopLists, path, pointComplex, vertexes):
22         "Add an indexed loop to the vertexes."
23         loops = loopLists[-1]
24         loop = []
25         loops.append(loop)
26         for point in path:
27                 pointMinusBegin = point - derivation.axisStart
28                 dotVector3 = derivation.axisProjectiveSpace.getDotVector3(pointMinusBegin)
29                 dotVector3Complex = dotVector3.dropAxis()
30                 dotPointComplex = pointComplex * dotVector3Complex
31                 dotPoint = Vector3(dotPointComplex.real, dotPointComplex.imag, dotVector3.z)
32                 projectedVector3 = derivation.axisProjectiveSpace.getVector3ByPoint(dotPoint) + derivation.axisStart
33                 loop.append(projectedVector3)
34
35 def addNegatives(derivation, negatives, paths):
36         "Add pillars output to negatives."
37         for path in paths:
38                 loopListsByPath = getLoopListsByPath(derivation, 1.000001, path)
39                 geometryOutput = triangle_mesh.getPillarsOutput(loopListsByPath)
40                 negatives.append(geometryOutput)
41
42 def addNegativesPositives(derivation, negatives, paths, positives):
43         "Add pillars output to negatives and positives."
44         for path in paths:
45                 endMultiplier = None
46                 normal = euclidean.getNormalByPath(path)
47                 if normal.dot(derivation.normal) < 0.0:
48                         endMultiplier = 1.000001
49                 loopListsByPath = getLoopListsByPath(derivation, endMultiplier, path)
50                 geometryOutput = triangle_mesh.getPillarsOutput(loopListsByPath)
51                 if endMultiplier == None:
52                         positives.append(geometryOutput)
53                 else:
54                         negatives.append(geometryOutput)
55
56 def addOffsetAddToLists( loop, offset, vector3Index, vertexes ):
57         "Add an indexed loop to the vertexes."
58         vector3Index += offset
59         loop.append( vector3Index )
60         vertexes.append( vector3Index )
61
62 def addPositives(derivation, paths, positives):
63         "Add pillars output to positives."
64         for path in paths:
65                 loopListsByPath = getLoopListsByPath(derivation, None, path)
66                 geometryOutput = triangle_mesh.getPillarsOutput(loopListsByPath)
67                 positives.append(geometryOutput)
68
69 def getGeometryOutput(derivation, elementNode):
70         "Get triangle mesh from attribute dictionary."
71         if derivation == None:
72                 derivation = LatheDerivation(elementNode)
73         if len(euclidean.getConcatenatedList(derivation.target)) == 0:
74                 print('Warning, in lathe there are no paths.')
75                 print(elementNode.attributes)
76                 return None
77         negatives = []
78         positives = []
79         addNegativesPositives(derivation, negatives, derivation.target, positives)
80         return getGeometryOutputByNegativesPositives(derivation, elementNode, negatives, positives)
81
82 def getGeometryOutputByArguments(arguments, elementNode):
83         "Get triangle mesh from attribute dictionary by arguments."
84         return getGeometryOutput(None, elementNode)
85
86 def getGeometryOutputByNegativesPositives(derivation, elementNode, negatives, positives):
87         "Get triangle mesh from derivation, elementNode, negatives and positives."
88         positiveOutput = triangle_mesh.getUnifiedOutput(positives)
89         if len(negatives) < 1:
90                 return solid.getGeometryOutputByManipulation(elementNode, positiveOutput)
91         return solid.getGeometryOutputByManipulation(elementNode, {'difference' : {'shapes' : [positiveOutput] + negatives}})
92
93 def getLoopListsByPath(derivation, endMultiplier, path):
94         "Get loop lists from path."
95         vertexes = []
96         loopLists = [[]]
97         if len(derivation.loop) < 2:
98                 return loopLists
99         for pointIndex, pointComplex in enumerate(derivation.loop):
100                 if endMultiplier != None and not derivation.isEndCloseToStart:
101                         if pointIndex == 0:
102                                 nextPoint = derivation.loop[1]
103                                 pointComplex = endMultiplier * (pointComplex - nextPoint) + nextPoint
104                         elif pointIndex == len(derivation.loop) - 1:
105                                 previousPoint = derivation.loop[pointIndex - 1]
106                                 pointComplex = endMultiplier * (pointComplex - previousPoint) + previousPoint
107                 addLoopByComplex(derivation, endMultiplier, loopLists, path, pointComplex, vertexes)
108         if derivation.isEndCloseToStart:
109                 loopLists[-1].append([])
110         return loopLists
111
112 def getNewDerivation(elementNode):
113         'Get new derivation.'
114         return LatheDerivation(elementNode)
115
116 def processElementNode(elementNode):
117         "Process the xml element."
118         solid.processElementNodeByGeometry(elementNode, getGeometryOutput(None, elementNode))
119
120
121 class LatheDerivation(object):
122         "Class to hold lathe variables."
123         def __init__(self, elementNode):
124                 'Set defaults.'
125                 self.axisEnd = evaluate.getVector3ByPrefix(None, elementNode, 'axisEnd')
126                 self.axisStart = evaluate.getVector3ByPrefix(None, elementNode, 'axisStart')
127                 self.end = evaluate.getEvaluatedFloat(360.0, elementNode, 'end')
128                 self.loop = evaluate.getTransformedPathByKey([], elementNode, 'loop')
129                 self.sides = evaluate.getEvaluatedInt(None, elementNode, 'sides')
130                 self.start = evaluate.getEvaluatedFloat(0.0, elementNode, 'start')
131                 self.target = evaluate.getTransformedPathsByKey([], elementNode, 'target')
132                 if len(self.target) < 1:
133                         print('Warning, no target in derive in lathe for:')
134                         print(elementNode)
135                         return
136                 firstPath = self.target[0]
137                 if len(firstPath) < 3:
138                         print('Warning, firstPath length is less than three in derive in lathe for:')
139                         print(elementNode)
140                         self.target = []
141                         return
142                 if self.axisStart == None:
143                         if self.axisEnd == None:
144                                 self.axisStart = firstPath[0]
145                                 self.axisEnd = firstPath[-1]
146                         else:
147                                 self.axisStart = Vector3()
148                 self.axis = self.axisEnd - self.axisStart
149                 axisLength = abs(self.axis)
150                 if axisLength <= 0.0:
151                         print('Warning, axisLength is zero in derive in lathe for:')
152                         print(elementNode)
153                         self.target = []
154                         return
155                 self.axis /= axisLength
156                 firstVector3 = firstPath[1] - self.axisStart
157                 firstVector3Length = abs(firstVector3)
158                 if firstVector3Length <= 0.0:
159                         print('Warning, firstVector3Length is zero in derive in lathe for:')
160                         print(elementNode)
161                         self.target = []
162                         return
163                 firstVector3 /= firstVector3Length
164                 self.axisProjectiveSpace = euclidean.ProjectiveSpace().getByBasisZFirst(self.axis, firstVector3)
165                 if self.sides == None:
166                         distanceToLine = euclidean.getDistanceToLineByPaths(self.axisStart, self.axisEnd, self.target)
167                         self.sides = evaluate.getSidesMinimumThreeBasedOnPrecisionSides(elementNode, distanceToLine)
168                 endRadian = math.radians(self.end)
169                 startRadian = math.radians(self.start)
170                 self.isEndCloseToStart = euclidean.getIsRadianClose(endRadian, startRadian)
171                 if len(self.loop) < 1:
172                         self.loop = euclidean.getComplexPolygonByStartEnd(endRadian, 1.0, self.sides, startRadian)
173                 self.normal = euclidean.getNormalByPath(firstPath)