6 from __future__ import absolute_import
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
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'
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:
33 alongWayMultiplier = distance / endMinusBeginLength
34 loop.append(begin + alongWayMultiplier * endMinusBegin)
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
45 complex(-outside, bottom),
46 complex(-derivation.innerDemiwidth, derivation.demiheight),
47 complex(-outside, top)]
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)
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:
80 if (not hollowPegSocket.shouldAddPeg) and (not hollowPegSocket.shouldAddSocket):
82 boltRadiusComplex = complex(derivation.boltRadius, derivation.boltRadius)
83 cylinder.addCylinderOutputByEndStart(boltTop + tinyHeight, boltRadiusComplex, negatives, derivation.boltSides, start)
85 def addSlab(derivation, positives):
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)
94 def addXGroove(derivation, negatives, y):
96 if derivation.topBevel <= 0.0:
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)
103 def addYGroove(derivation, negatives, x):
105 if derivation.topBevel <= 0.0:
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)
112 def getBeveledRectangle(bevel, bottomLeft):
113 'Get the beveled rectangle.'
114 bottomRight = complex(-bottomLeft.real, bottomLeft.imag)
115 rectangle = [bottomLeft, bottomRight, -bottomLeft, -bottomRight]
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
126 def getGeometryOutput(elementNode):
127 'Get vector3 vertexes from attribute dictionary.'
128 derivation = MechaslabDerivation(elementNode)
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)
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)
149 def getNewDerivation(elementNode):
150 'Get new derivation.'
151 return MechaslabDerivation(elementNode)
153 def processElementNode(elementNode):
154 'Process the xml element.'
155 solid.processElementNodeByGeometry(elementNode, getGeometryOutput(elementNode))
158 class CellExistence(object):
159 'Class to determine if a cell exists.'
160 def __init__(self, columns, rows, value):
162 self.existenceSet = None
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)
173 keyTuple = (element[0], element[1])
174 self.existenceSet.add(keyTuple)
177 'Get the string representation of this CellExistence.'
178 return euclidean.getDictionaryString(self.__dict__)
180 def getIsInExistence(self, columnIndex, rowIndex):
181 'Detremine if the cell at the column and row exists.'
182 if self.existenceSet == None:
184 return (columnIndex, rowIndex) in self.existenceSet
187 class HollowPegSocket(object):
188 'Class to hold hollow peg socket variables.'
189 def __init__(self, center):
192 self.shouldAddPeg = True
193 self.shouldAddSocket = True
196 'Get the string representation of this HollowPegSocket.'
197 return euclidean.getDictionaryString(self.__dict__)
200 class MechaslabDerivation(object):
201 'Class to hold mechaslab variables.'
202 def __init__(self, elementNode):
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)
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
254 'Get the string representation of this MechaslabDerivation.'
255 return euclidean.getDictionaryString(self.__dict__)