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