1 """
2 Boolean geometry four by four matrix.
3
4 """
5
6 from fabmetheus_utilities.geometry.geometry_utilities import evaluate
7 from fabmetheus_utilities.vector3 import Vector3
8 from fabmetheus_utilities import archive
9 from fabmetheus_utilities import euclidean
10 from fabmetheus_utilities import xml_simple_writer
11 import StringIO
12 import math
13
14
15 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
16 __credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
17 __date__ = '$Date: 2008/02/05 $'
18 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
19
20
21 globalExecutionOrder = 300
22
23
25 'Add the vertexes.'
26 if geometryOutput.__class__ == list:
27 for element in geometryOutput:
28 addVertexes(element, vertexes)
29 return
30 if geometryOutput.__class__ != dict:
31 return
32 for geometryOutputKey in geometryOutput.keys():
33 geometryOutputValue = geometryOutput[geometryOutputKey]
34 if geometryOutputKey == 'vertex':
35 for vertex in geometryOutputValue:
36 vertexes.append(vertex)
37 else:
38 addVertexes(geometryOutputValue, vertexes)
39
41 'Get matrix starting from the object if it exists, otherwise get a matrix starting from stratch.'
42 branchMatrix = Matrix()
43 matrixChildElement = xmlElement.getFirstChildByLocalName('matrix')
44 if matrixChildElement != None:
45 branchMatrix = branchMatrix.getFromXMLElement('', matrixChildElement)
46 branchMatrix = branchMatrix.getFromXMLElement('matrix.', xmlElement)
47 if xmlElement.xmlObject == None:
48 return branchMatrix
49 xmlElementMatrix = xmlElement.xmlObject.getMatrix4X4()
50 if xmlElementMatrix == None:
51 return branchMatrix
52 return xmlElementMatrix.getOtherTimesSelf(branchMatrix.tetragrid)
53
55 'Get matrix starting from the object if it exists, otherwise get a matrix starting from stratch.'
56 branchMatrix = getBranchMatrix(xmlElement)
57 setXMLElementDictionaryMatrix(branchMatrix, xmlElement)
58 return branchMatrix
59
61 'Get cumulative vector3 and delete the prefixed attributes.'
62 if prefix == '':
63 defaultVector3.x = evaluate.getEvaluatedFloat(defaultVector3.x, 'x', xmlElement)
64 defaultVector3.y = evaluate.getEvaluatedFloat(defaultVector3.y, 'y', xmlElement)
65 defaultVector3.z = evaluate.getEvaluatedFloat(defaultVector3.z, 'z', xmlElement)
66 euclidean.removeElementsFromDictionary(xmlElement.attributeDictionary, ['x', 'y', 'z'])
67 prefix = 'cartesian'
68 defaultVector3 = evaluate.getVector3ByPrefix(defaultVector3, prefix, xmlElement)
69 euclidean.removePrefixFromDictionary(xmlElement.attributeDictionary, prefix)
70 return defaultVector3
71
75
79
81 'Get the diagonals and switched matrix by unitPolar.'
82 diagonalSwitchedTetragrid = getIdentityTetragrid()
83 for diagonal in diagonals:
84 diagonalSwitchedTetragrid[diagonal][diagonal] = unitPolar.real
85 diagonalSwitchedTetragrid[diagonals[0]][diagonals[1]] = -unitPolar.imag
86 diagonalSwitchedTetragrid[diagonals[1]][diagonals[0]] = unitPolar.imag
87 return diagonalSwitchedTetragrid
88
90 'Get four by four matrix with diagonal elements set to one.'
91 if tetragrid == None:
92 return [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]]
93 return tetragrid
94
95 -def getKeyA(row, column, prefix=''):
96 'Get the a format key string from row & column, counting from zero.'
97 return '%sa%s%s' % (prefix, row, column)
98
99 -def getKeyM(row, column, prefix=''):
100 'Get the m format key string from row & column, counting from one.'
101 return '%sm%s%s' % (prefix, row + 1, column + 1)
102
104 'Get the matrix keys, counting from zero.'
105 keysA = []
106 for row in xrange(4):
107 for column in xrange(4):
108 key = getKeyA(row, column, prefix)
109 keysA.append(key)
110 return keysA
111
113 'Get the matrix keys, counting from one.'
114 keysM = []
115 for row in xrange(4):
116 for column in xrange(4):
117 key = getKeyM(row, column, prefix)
118 keysM.append(key)
119 return keysM
120
122 'Get the float by the key and the prefix.'
123 prefixKey = prefix + key
124 if prefixKey in xmlElement.attributeDictionary:
125 floatValue = evaluate.getEvaluatedFloat(None, prefixKey, xmlElement)
126 if floatValue == None:
127 print('Warning, evaluated value in getRemovedFloatByKeys in matrix is None for key:')
128 print(prefixKey)
129 print('for xmlElement dictionary value:')
130 print(xmlElement.attributeDictionary[prefixKey])
131 print('for xmlElement dictionary:')
132 print(xmlElement.attributeDictionary)
133 else:
134 defaultFloat = floatValue
135 del xmlElement.attributeDictionary[prefixKey]
136 return defaultFloat
137
139 'Get the float by the keys and the prefix.'
140 for key in keys:
141 defaultFloat = getRemovedFloat(defaultFloat, key, prefix, xmlElement)
142 return defaultFloat
143
145 'Get rotate around axis tetragrid and delete the axis and angle attributes.'
146 angle = getRemovedFloatByKeys(0.0, ['angle', 'counterclockwise'], prefix, xmlElement)
147 angle -= getRemovedFloat(0.0, 'clockwise', prefix, xmlElement)
148 if angle == 0.0:
149 return None
150 angleRadians = math.radians(angle)
151 axis = getCumulativeVector3Remove(Vector3(), prefix + 'axis', xmlElement)
152 axisLength = abs(axis)
153 if axisLength <= 0.0:
154 print('Warning, axisLength was zero in getRotateAroundAxisTetragrid in matrix so nothing will be done for:')
155 print(xmlElement)
156 return None
157 axis /= axisLength
158 tetragrid = getIdentityTetragrid()
159 cosAngle = math.cos(angleRadians)
160 sinAngle = math.sin(angleRadians)
161 oneMinusCos = 1.0 - math.cos(angleRadians)
162 xx = axis.x * axis.x
163 xy = axis.x * axis.y
164 xz = axis.x * axis.z
165 yy = axis.y * axis.y
166 yz = axis.y * axis.z
167 zz = axis.z * axis.z
168 tetragrid[0] = [cosAngle + xx * oneMinusCos, xy * oneMinusCos - axis.z * sinAngle, xz * oneMinusCos + axis.y * sinAngle, 0.0]
169 tetragrid[1] = [xy * oneMinusCos + axis.z * sinAngle, cosAngle + yy * oneMinusCos, yz * oneMinusCos - axis.x * sinAngle, 0.0]
170 tetragrid[2] = [xz * oneMinusCos - axis.y * sinAngle, yz * oneMinusCos + axis.x * sinAngle, cosAngle + zz * oneMinusCos, 0.0]
171 return tetragrid
172
174 'Get rotate tetragrid and delete the rotate attributes.'
175
176 rotateMatrix = Matrix()
177 rotateMatrix.tetragrid = getRotateAroundAxisTetragrid(prefix, xmlElement)
178 zAngle = getRemovedFloatByKeys(0.0, ['axisclockwisez', 'observerclockwisez', 'z'], prefix, xmlElement)
179 zAngle -= getRemovedFloatByKeys(0.0, ['axiscounterclockwisez', 'observercounterclockwisez'], prefix, xmlElement)
180 if zAngle != 0.0:
181 rotateMatrix.tetragrid = getTetragridTimesOther(getDiagonalSwitchedTetragrid(-zAngle, [0, 1]), rotateMatrix.tetragrid)
182 xAngle = getRemovedFloatByKeys(0.0, ['axisclockwisex', 'observerclockwisex', 'x'], prefix, xmlElement)
183 xAngle -= getRemovedFloatByKeys(0.0, ['axiscounterclockwisex', 'observercounterclockwisex'], prefix, xmlElement)
184 if xAngle != 0.0:
185 rotateMatrix.tetragrid = getTetragridTimesOther(getDiagonalSwitchedTetragrid(-xAngle, [1, 2]), rotateMatrix.tetragrid)
186 yAngle = getRemovedFloatByKeys(0.0, ['axiscounterclockwisey', 'observerclockwisey', 'y'], prefix, xmlElement)
187 yAngle -= getRemovedFloatByKeys(0.0, ['axisclockwisey', 'observercounterclockwisey'], prefix, xmlElement)
188 if yAngle != 0.0:
189 rotateMatrix.tetragrid = getTetragridTimesOther(getDiagonalSwitchedTetragrid(yAngle, [0, 2]), rotateMatrix.tetragrid)
190 return rotateMatrix.tetragrid
191
193 'Get scale matrix and delete the scale attributes.'
194 scaleDefaultVector3 = Vector3(1.0, 1.0, 1.0)
195 scale = getCumulativeVector3Remove(scaleDefaultVector3.copy(), prefix, xmlElement)
196 if scale == scaleDefaultVector3:
197 return None
198 return [[scale.x, 0.0, 0.0, 0.0], [0.0, scale.y, 0.0, 0.0], [0.0, 0.0, scale.z, 0.0], [0.0, 0.0, 0.0, 1.0]]
199
201 'Get the tetragrid from the xmlElement letter a values.'
202 keysA = getKeysA(prefix)
203 evaluatedDictionary = evaluate.getEvaluatedDictionaryByEvaluationKeys(keysA, xmlElement)
204 if len(evaluatedDictionary.keys()) < 1:
205 return tetragrid
206 for row in xrange(4):
207 for column in xrange(4):
208 key = getKeyA(row, column, prefix)
209 if key in evaluatedDictionary:
210 value = evaluatedDictionary[key]
211 if value == None or value == 'None':
212 print('Warning, value in getTetragridA in matrix is None for key for dictionary:')
213 print(key)
214 print(evaluatedDictionary)
215 else:
216 tetragrid = getIdentityTetragrid(tetragrid)
217 tetragrid[row][column] = float(value)
218 euclidean.removeElementsFromDictionary(xmlElement.attributeDictionary, keysA)
219 return tetragrid
220
222 'Get the matrix Tetragrid from the xmlElement letter c values.'
223 columnKeys = 'Pc1 Pc2 Pc3 Pc4'.replace('P', prefix).split()
224 evaluatedDictionary = evaluate.getEvaluatedDictionaryByEvaluationKeys(columnKeys, xmlElement)
225 if len(evaluatedDictionary.keys()) < 1:
226 return tetragrid
227 for columnKeyIndex, columnKey in enumerate(columnKeys):
228 if columnKey in evaluatedDictionary:
229 value = evaluatedDictionary[columnKey]
230 if value == None or value == 'None':
231 print('Warning, value in getTetragridC in matrix is None for columnKey for dictionary:')
232 print(columnKey)
233 print(evaluatedDictionary)
234 else:
235 tetragrid = getIdentityTetragrid(tetragrid)
236 for elementIndex, element in enumerate(value):
237 tetragrid[elementIndex][columnKeyIndex] = element
238 euclidean.removeElementsFromDictionary(xmlElement.attributeDictionary, columnKeys)
239 return tetragrid
240
242 'Get tetragrid copy.'
243 tetragridCopy = []
244 for tetragridRow in tetragrid:
245 tetragridCopy.append(tetragridRow[:])
246 return tetragridCopy
247
249 'Get the tetragrid from the xmlElement letter m values.'
250 keysM = getKeysM(prefix)
251 evaluatedDictionary = evaluate.getEvaluatedDictionaryByEvaluationKeys(keysM, xmlElement)
252 if len(evaluatedDictionary.keys()) < 1:
253 return tetragrid
254 for row in xrange(4):
255 for column in xrange(4):
256 key = getKeyM(row, column, prefix)
257 if key in evaluatedDictionary:
258 value = evaluatedDictionary[key]
259 if value == None or value == 'None':
260 print('Warning, value in getTetragridM in matrix is None for key for dictionary:')
261 print(key)
262 print(evaluatedDictionary)
263 else:
264 tetragrid = getIdentityTetragrid(tetragrid)
265 tetragrid[row][column] = float(value)
266 euclidean.removeElementsFromDictionary(xmlElement.attributeDictionary, keysM)
267 return tetragrid
268
270 'Get the tetragrid from the xmlElement matrix value.'
271 matrixKey = prefix + 'matrix'
272 evaluatedDictionary = evaluate.getEvaluatedDictionaryByEvaluationKeys([matrixKey], xmlElement)
273 if len(evaluatedDictionary.keys()) < 1:
274 return tetragrid
275 value = evaluatedDictionary[matrixKey]
276 if value == None or value == 'None':
277 print('Warning, value in getTetragridMatrix in matrix is None for matrixKey for dictionary:')
278 print(matrixKey)
279 print(evaluatedDictionary)
280 else:
281 tetragrid = getIdentityTetragrid(tetragrid)
282 for rowIndex, row in enumerate(value):
283 for elementIndex, element in enumerate(row):
284 tetragrid[rowIndex][elementIndex] = element
285 euclidean.removeElementsFromDictionary(xmlElement.attributeDictionary, [matrixKey])
286 return tetragrid
287
289 'Get the tetragrid from the xmlElement letter r values.'
290 rowKeys = 'Pr1 Pr2 Pr3 Pr4'.replace('P', prefix).split()
291 evaluatedDictionary = evaluate.getEvaluatedDictionaryByEvaluationKeys(rowKeys, xmlElement)
292 if len(evaluatedDictionary.keys()) < 1:
293 return tetragrid
294 for rowKeyIndex, rowKey in enumerate(rowKeys):
295 if rowKey in evaluatedDictionary:
296 value = evaluatedDictionary[rowKey]
297 if value == None or value == 'None':
298 print('Warning, value in getTetragridR in matrix is None for rowKey for dictionary:')
299 print(rowKey)
300 print(evaluatedDictionary)
301 else:
302 tetragrid = getIdentityTetragrid(tetragrid)
303 for elementIndex, element in enumerate(value):
304 tetragrid[rowKeyIndex][elementIndex] = element
305 euclidean.removeElementsFromDictionary(xmlElement.attributeDictionary, rowKeys)
306 return tetragrid
307
309 'Get this matrix multiplied by the other matrix.'
310
311 if firstTetragrid == None:
312 return otherTetragrid
313 if otherTetragrid == None:
314 return firstTetragrid
315 tetragridTimesOther = []
316 for row in xrange(4):
317 matrixRow = firstTetragrid[row]
318 tetragridTimesOtherRow = []
319 tetragridTimesOther.append(tetragridTimesOtherRow)
320 for column in xrange(4):
321 dotProduct = 0
322 for elementIndex in xrange(4):
323 dotProduct += matrixRow[elementIndex] * otherTetragrid[elementIndex][column]
324 tetragridTimesOtherRow.append(dotProduct)
325 return tetragridTimesOther
326
330
339
346
355
362
364 'Get translate tetragrid by translation.'
365 return [[1.0, 0.0, 0.0, translation.x], [0.0, 1.0, 0.0, translation.y], [0.0, 0.0, 1.0, translation.z], [0.0, 0.0, 0.0, 1.0]]
366
368 'Get the vertexes.'
369 vertexes = []
370 addVertexes(geometryOutput, vertexes)
371 return vertexes
372
376
378 'Set the element attribute dictionary or element matrix to the matrix.'
379 if xmlElement.xmlObject == None:
380 xmlElement.attributeDictionary.update(matrix4X4.getAttributeDictionary('matrix.'))
381 else:
382 xmlElement.xmlObject.matrix4X4 = matrix4X4
383
387
388
390 'A four by four matrix.'
392 'Add empty lists.'
393 if tetragrid == None:
394 self.tetragrid = None
395 return
396 self.tetragrid = getTetragridCopy(tetragrid)
397
399 'Determine whether this matrix is identical to other one.'
400 if other == None:
401 return False
402 if other.__class__ != self.__class__:
403 return False
404 return other.tetragrid == self.tetragrid
405
407 'Determine whether this vector is not identical to other one.'
408 return not self.__eq__(other)
409
411 'Get the string representation of this four by four matrix.'
412 output = StringIO.StringIO()
413 self.addXML(0, output)
414 return output.getvalue()
415
416 - def addXML(self, depth, output):
421
423 'Get the attributeDictionary from row column attribute strings, counting from one.'
424 attributeDictionary = {}
425 if self.tetragrid == None:
426 return attributeDictionary
427 for row in xrange(4):
428 for column in xrange(4):
429 default = float(column == row)
430 value = self.tetragrid[row][column]
431 if abs( value - default ) > 0.00000000000001:
432 if abs(value) < 0.00000000000001:
433 value = 0.0
434 attributeDictionary[prefix + getKeyM(row, column)] = value
435 return attributeDictionary
436
447
451
455