chiark / gitweb /
Add back the ultimaker platform, and made the platform mesh simpler.
[cura.git] / Cura / slice / cura_sf / fabmetheus_utilities / geometry / creation / mechaslab.py
1 """
2 Mechaslab.
3
4 """
5
6 from __future__ import absolute_import
7
8 from fabmetheus_utilities.geometry.creation import extrude
9 from fabmetheus_utilities.geometry.creation import lineation
10 from fabmetheus_utilities.geometry.creation import peg
11 from fabmetheus_utilities.geometry.creation import solid
12 from fabmetheus_utilities.geometry.geometry_utilities.evaluate_elements import setting
13 from fabmetheus_utilities.geometry.geometry_utilities import evaluate
14 from fabmetheus_utilities.geometry.solids import cylinder
15 from fabmetheus_utilities.geometry.solids import triangle_mesh
16 from fabmetheus_utilities.vector3 import Vector3
17 from fabmetheus_utilities import euclidean
18 import math
19
20
21 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
22 __credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
23 __date__ = '$Date: 2008/02/05 $'
24 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
25
26
27 def addAlongWay(begin, distance, end, loop):
28         'Get the beveled rectangle.'
29         endMinusBegin = end - begin
30         endMinusBeginLength = abs(endMinusBegin)
31         if endMinusBeginLength <= 0.0:
32                 return
33         alongWayMultiplier = distance / endMinusBeginLength
34         loop.append(begin + alongWayMultiplier * endMinusBegin)
35
36 def addGroove(derivation, negatives):
37         'Add groove on each side of cage.'
38         copyShallow = derivation.elementNode.getCopyShallow()
39         extrude.setElementNodeToEndStart(copyShallow, Vector3(-derivation.demilength), Vector3(derivation.demilength))
40         extrudeDerivation = extrude.ExtrudeDerivation(copyShallow)
41         bottom = derivation.demiheight - 0.5 * derivation.grooveWidth
42         outside = derivation.demiwidth
43         top = derivation.demiheight
44         leftGroove = [
45                 complex(-outside, bottom),
46                 complex(-derivation.innerDemiwidth, derivation.demiheight),
47                 complex(-outside, top)]
48         rightGroove = [
49                 complex(outside, top),
50                 complex(derivation.innerDemiwidth, derivation.demiheight),
51                 complex(outside, bottom)]
52         groovesComplex = [leftGroove, rightGroove]
53         groovesVector3 = euclidean.getVector3Paths(groovesComplex)
54         extrude.addPositives(extrudeDerivation, groovesVector3, negatives)
55
56 def addHollowPegSocket(derivation, hollowPegSocket, negatives, positives):
57         'Add the socket and hollow peg.'
58         pegHeight = derivation.pegHeight
59         pegRadians = derivation.pegRadians
60         pegRadiusComplex = complex(derivation.pegRadiusArealized, derivation.pegRadiusArealized)
61         pegTip = 0.8 * derivation.pegRadiusArealized
62         sides = derivation.pegSides
63         start = Vector3(hollowPegSocket.center.real, hollowPegSocket.center.imag, derivation.height)
64         tinyHeight = 0.0001 * pegHeight
65         topRadians = 0.25 * math.pi
66         boltTop = derivation.height
67         if hollowPegSocket.shouldAddPeg:
68                 boltTop = peg.getTopAddBiconicOutput(
69                         pegRadians, pegHeight, positives, pegRadiusComplex, sides, start, pegTip, topRadians)
70         sides = derivation.socketSides
71         socketHeight = 1.05 * derivation.pegHeight
72         socketRadiusComplex = complex(derivation.socketRadiusArealized, derivation.socketRadiusArealized)
73         socketTip = 0.5 * derivation.overhangSpan
74         start = Vector3(hollowPegSocket.center.real, hollowPegSocket.center.imag, -tinyHeight)
75         topRadians = derivation.interiorOverhangRadians
76         if hollowPegSocket.shouldAddSocket:
77                 peg.getTopAddBiconicOutput(pegRadians, socketHeight, negatives, socketRadiusComplex, sides, start, socketTip, topRadians)
78         if derivation.boltRadius <= 0.0:
79                 return
80         if (not hollowPegSocket.shouldAddPeg) and (not hollowPegSocket.shouldAddSocket):
81                 return
82         boltRadiusComplex = complex(derivation.boltRadius, derivation.boltRadius)
83         cylinder.addCylinderOutputByEndStart(boltTop + tinyHeight, boltRadiusComplex, negatives, derivation.boltSides, start)
84
85 def addSlab(derivation, positives):
86         'Add slab.'
87         copyShallow = derivation.elementNode.getCopyShallow()
88         copyShallow.attributes['path'] = [Vector3(), Vector3(0.0, 0.0, derivation.height)]
89         extrudeDerivation = extrude.ExtrudeDerivation(copyShallow)
90         beveledRectangle = getBeveledRectangle(derivation.bevel, -derivation.topRight)
91         outsidePath = euclidean.getVector3Path(beveledRectangle)
92         extrude.addPositives(extrudeDerivation, [outsidePath], positives)
93
94 def addXGroove(derivation, negatives, y):
95         'Add x groove.'
96         if derivation.topBevel <= 0.0:
97                 return
98         bottom = derivation.height - derivation.topBevel
99         top = derivation.height
100         groove = [complex(y, bottom), complex(y - derivation.topBevel, top), complex(y + derivation.topBevel, top)]
101         triangle_mesh.addSymmetricXPath(negatives, groove, 1.0001 * derivation.topRight.real)
102
103 def addYGroove(derivation, negatives, x):
104         'Add y groove'
105         if derivation.topBevel <= 0.0:
106                 return
107         bottom = derivation.height - derivation.topBevel
108         top = derivation.height
109         groove = [complex(x, bottom), complex(x - derivation.topBevel, top), complex(x + derivation.topBevel, top)]
110         triangle_mesh.addSymmetricYPath(negatives, groove, 1.0001 * derivation.topRight.imag)
111
112 def getBeveledRectangle(bevel, bottomLeft):
113         'Get the beveled rectangle.'
114         bottomRight = complex(-bottomLeft.real, bottomLeft.imag)
115         rectangle = [bottomLeft, bottomRight, -bottomLeft, -bottomRight]
116         if bevel <= 0.0:
117                 return rectangle
118         beveledRectangle = []
119         for pointIndex, point in enumerate(rectangle):
120                 begin = rectangle[(pointIndex + len(rectangle) - 1) % len(rectangle)]
121                 end = rectangle[(pointIndex + 1) % len(rectangle)]
122                 addAlongWay(point, bevel, begin, beveledRectangle)
123                 addAlongWay(point, bevel, end, beveledRectangle)
124         return beveledRectangle
125
126 def getGeometryOutput(elementNode):
127         'Get vector3 vertexes from attribute dictionary.'
128         derivation = MechaslabDerivation(elementNode)
129         negatives = []
130         positives = []
131         addSlab(derivation, positives)
132         for hollowPegSocket in derivation.hollowPegSockets:
133                 addHollowPegSocket(derivation, hollowPegSocket, negatives, positives)
134         if 's' in derivation.topBevelPositions:
135                 addXGroove(derivation, negatives, -derivation.topRight.imag)
136         if 'n' in derivation.topBevelPositions:
137                 addXGroove(derivation, negatives, derivation.topRight.imag)
138         if 'w' in derivation.topBevelPositions:
139                 addYGroove(derivation, negatives, -derivation.topRight.real)
140         if 'e' in derivation.topBevelPositions:
141                 addYGroove(derivation, negatives, derivation.topRight.real)
142         return extrude.getGeometryOutputByNegativesPositives(elementNode, negatives, positives)
143
144 def getGeometryOutputByArguments(arguments, elementNode):
145         'Get vector3 vertexes from attribute dictionary by arguments.'
146         evaluate.setAttributesByArguments(['length', 'radius'], arguments, elementNode)
147         return getGeometryOutput(elementNode)
148
149 def getNewDerivation(elementNode):
150         'Get new derivation.'
151         return MechaslabDerivation(elementNode)
152
153 def processElementNode(elementNode):
154         'Process the xml element.'
155         solid.processElementNodeByGeometry(elementNode, getGeometryOutput(elementNode))
156
157
158 class CellExistence(object):
159         'Class to determine if a cell exists.'
160         def __init__(self, columns, rows, value):
161                 'Initialize.'
162                 self.existenceSet = None
163                 if value == None:
164                         return
165                 self.existenceSet = set()
166                 for element in value:
167                         if element.__class__ == int:
168                                 columnIndex = (element + columns) % columns
169                                 for rowIndex in xrange(rows):
170                                         keyTuple = (columnIndex, rowIndex)
171                                         self.existenceSet.add(keyTuple)
172                         else:
173                                 keyTuple = (element[0], element[1])
174                                 self.existenceSet.add(keyTuple)
175
176         def __repr__(self):
177                 'Get the string representation of this CellExistence.'
178                 return euclidean.getDictionaryString(self.__dict__)
179
180         def getIsInExistence(self, columnIndex, rowIndex):
181                 'Detremine if the cell at the column and row exists.'
182                 if self.existenceSet == None:
183                         return True
184                 return (columnIndex, rowIndex) in self.existenceSet
185
186
187 class HollowPegSocket(object):
188         'Class to hold hollow peg socket variables.'
189         def __init__(self, center):
190                 'Initialize.'
191                 self.center = center
192                 self.shouldAddPeg = True
193                 self.shouldAddSocket = True
194
195         def __repr__(self):
196                 'Get the string representation of this HollowPegSocket.'
197                 return euclidean.getDictionaryString(self.__dict__)
198
199
200 class MechaslabDerivation(object):
201         'Class to hold mechaslab variables.'
202         def __init__(self, elementNode):
203                 'Set defaults.'
204                 self.bevelOverRadius = evaluate.getEvaluatedFloat(0.2, elementNode, 'bevelOverRadius')
205                 self.boltRadiusOverRadius = evaluate.getEvaluatedFloat(0.0, elementNode, 'boltRadiusOverRadius')
206                 self.columns = evaluate.getEvaluatedInt(2, elementNode, 'columns')
207                 self.elementNode = elementNode
208                 self.heightOverRadius = evaluate.getEvaluatedFloat(2.0, elementNode, 'heightOverRadius')
209                 self.interiorOverhangRadians = setting.getInteriorOverhangRadians(elementNode)
210                 self.overhangSpan = setting.getOverhangSpan(elementNode)
211                 self.pegClearanceOverRadius = evaluate.getEvaluatedFloat(0.0, elementNode, 'pegClearanceOverRadius')
212                 self.pegRadians = math.radians(evaluate.getEvaluatedFloat(2.0, elementNode, 'pegAngle'))
213                 self.pegHeightOverHeight = evaluate.getEvaluatedFloat(0.4, elementNode, 'pegHeightOverHeight')
214                 self.pegRadiusOverRadius = evaluate.getEvaluatedFloat(0.7, elementNode, 'pegRadiusOverRadius')
215                 self.radius = lineation.getFloatByPrefixBeginEnd(elementNode, 'radius', 'width', 5.0)
216                 self.rows = evaluate.getEvaluatedInt(1, elementNode, 'rows')
217                 self.topBevelOverRadius = evaluate.getEvaluatedFloat(0.2, elementNode, 'topBevelOverRadius')
218                 # Set derived values.
219                 self.bevel = evaluate.getEvaluatedFloat(self.bevelOverRadius * self.radius, elementNode, 'bevel')
220                 self.boltRadius = evaluate.getEvaluatedFloat(self.boltRadiusOverRadius * self.radius, elementNode, 'boltRadius')
221                 self.boltSides = evaluate.getSidesMinimumThreeBasedOnPrecision(elementNode, self.boltRadius)
222                 self.bottomLeftCenter = complex(-float(self.columns - 1), -float(self.rows - 1)) * self.radius
223                 self.height = evaluate.getEvaluatedFloat(self.heightOverRadius * self.radius, elementNode, 'height')
224                 self.hollowPegSockets = []
225                 centerY = self.bottomLeftCenter.imag
226                 diameter = self.radius + self.radius
227                 self.pegExistence = CellExistence(self.columns, self.rows, evaluate.getEvaluatedValue(None, elementNode, 'pegs'))
228                 self.socketExistence = CellExistence(self.columns, self.rows, evaluate.getEvaluatedValue(None, elementNode, 'sockets'))
229                 for rowIndex in xrange(self.rows):
230                         centerX = self.bottomLeftCenter.real
231                         for columnIndex in xrange(self.columns):
232                                 hollowPegSocket = HollowPegSocket(complex(centerX, centerY))
233                                 hollowPegSocket.shouldAddPeg = self.pegExistence.getIsInExistence(columnIndex, rowIndex)
234                                 hollowPegSocket.shouldAddSocket = self.socketExistence.getIsInExistence(columnIndex, rowIndex)
235                                 self.hollowPegSockets.append(hollowPegSocket)
236                                 centerX += diameter
237                         centerY += diameter
238                 self.pegClearance = evaluate.getEvaluatedFloat(self.pegClearanceOverRadius * self.radius, elementNode, 'pegClearance')
239                 halfPegClearance = 0.5 * self.pegClearance
240                 self.pegHeight = evaluate.getEvaluatedFloat(self.pegHeightOverHeight * self.height, elementNode, 'pegHeight')
241                 self.pegRadius = evaluate.getEvaluatedFloat(self.pegRadiusOverRadius * self.radius, elementNode, 'pegRadius')
242                 sides = 24 * max(1, math.floor(evaluate.getSidesBasedOnPrecision(elementNode, self.pegRadius) / 24))
243                 self.socketRadius = self.pegRadius + halfPegClearance
244                 self.pegSides = evaluate.getEvaluatedInt(sides, elementNode, 'pegSides')
245                 self.pegRadius -= halfPegClearance
246                 self.pegRadiusArealized = evaluate.getRadiusArealizedBasedOnAreaRadius(elementNode, self.pegRadius, self.pegSides)
247                 self.socketSides = evaluate.getEvaluatedInt(sides, elementNode, 'socketSides')
248                 self.socketRadiusArealized = evaluate.getRadiusArealizedBasedOnAreaRadius(elementNode, self.socketRadius, self.socketSides)
249                 self.topBevel = evaluate.getEvaluatedFloat(self.topBevelOverRadius * self.radius, elementNode, 'topBevel')
250                 self.topBevelPositions = evaluate.getEvaluatedString('nwse', elementNode, 'topBevelPositions').lower()
251                 self.topRight = complex(float(self.columns), float(self.rows)) * self.radius
252
253         def __repr__(self):
254                 'Get the string representation of this MechaslabDerivation.'
255                 return euclidean.getDictionaryString(self.__dict__)