Package fabmetheus_utilities :: Package geometry :: Package geometry_utilities :: Module matrix
[hide private]
[frames] | no frames]

Source Code for Module fabmetheus_utilities.geometry.geometry_utilities.matrix

  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   
24 -def addVertexes(geometryOutput, vertexes):
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
40 -def getBranchMatrix(xmlElement):
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
54 -def getBranchMatrixSetXMLElement(xmlElement):
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
60 -def getCumulativeVector3Remove(defaultVector3, prefix, xmlElement):
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
72 -def getDiagonalSwitchedTetragrid(angleDegrees, diagonals):
73 'Get the diagonals and switched matrix by degrees.' 74 return getDiagonalSwitchedTetragridByRadians(math.radians(angleDegrees), diagonals)
75
76 -def getDiagonalSwitchedTetragridByRadians(angleRadians, diagonals):
77 'Get the diagonals and switched matrix by radians.' 78 return getDiagonalSwitchedTetragridByPolar(diagonals, euclidean.getWiddershinsUnitPolar(angleRadians))
79
80 -def getDiagonalSwitchedTetragridByPolar(diagonals, unitPolar):
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
89 -def getIdentityTetragrid(tetragrid=None):
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
103 -def getKeysA(prefix=''):
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
112 -def getKeysM(prefix=''):
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
121 -def getRemovedFloat(defaultFloat, key, prefix, xmlElement):
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
138 -def getRemovedFloatByKeys(defaultFloat, keys, prefix, xmlElement):
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
144 -def getRotateAroundAxisTetragrid(prefix, xmlElement):
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
173 -def getRotateTetragrid(prefix, xmlElement):
174 'Get rotate tetragrid and delete the rotate attributes.' 175 # http://en.wikipedia.org/wiki/Rotation_matrix 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
192 -def getScaleTetragrid(prefix, xmlElement):
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
200 -def getTetragridA(prefix, tetragrid, xmlElement):
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
221 -def getTetragridC(prefix, tetragrid, xmlElement):
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
241 -def getTetragridCopy(tetragrid):
242 'Get tetragrid copy.' 243 tetragridCopy = [] 244 for tetragridRow in tetragrid: 245 tetragridCopy.append(tetragridRow[:]) 246 return tetragridCopy
247
248 -def getTetragridM(prefix, tetragrid, xmlElement):
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
269 -def getTetragridMatrix(prefix, tetragrid, xmlElement):
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
288 -def getTetragridR(prefix, tetragrid, xmlElement):
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
308 -def getTetragridTimesOther(firstTetragrid, otherTetragrid ):
309 'Get this matrix multiplied by the other matrix.' 310 #A down, B right from http://en.wikipedia.org/wiki/Matrix_multiplication 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
327 -def getTransformedByList(floatList, point):
328 'Get the point transformed by the array.' 329 return floatList[0] * point.x + floatList[1] * point.y + floatList[2] * point.z + floatList[3]
330
331 -def getTransformedVector3(tetragrid, vector3):
332 'Get the vector3 multiplied by a matrix.' 333 if tetragrid == None: 334 return vector3.copy() 335 return Vector3( 336 getTransformedByList(tetragrid[0], vector3), 337 getTransformedByList(tetragrid[1], vector3), 338 getTransformedByList(tetragrid[2], vector3))
339
340 -def getTransformedVector3s(tetragrid, vector3s):
341 'Get the vector3s multiplied by a matrix.' 342 transformedVector3s = [] 343 for vector3 in vector3s: 344 transformedVector3s.append(getTransformedVector3(tetragrid, vector3)) 345 return transformedVector3s
346
347 -def getTransformTetragrid(prefix, xmlElement):
348 'Get the tetragrid from the xmlElement.' 349 tetragrid = getTetragridA(prefix, None, xmlElement) 350 tetragrid = getTetragridC(prefix, tetragrid, xmlElement) 351 tetragrid = getTetragridM(prefix, tetragrid, xmlElement) 352 tetragrid = getTetragridMatrix(prefix, tetragrid, xmlElement) 353 tetragrid = getTetragridR(prefix, tetragrid, xmlElement) 354 return tetragrid
355
356 -def getTranslateTetragrid(prefix, xmlElement):
357 'Get translate matrix and delete the translate attributes.' 358 translation = getCumulativeVector3Remove(Vector3(), prefix, xmlElement) 359 if translation.getIsDefault(): 360 return None 361 return getTranslateTetragridByTranslation(translation)
362
363 -def getTranslateTetragridByTranslation(translation):
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
367 -def getVertexes(geometryOutput):
368 'Get the vertexes.' 369 vertexes = [] 370 addVertexes(geometryOutput, vertexes) 371 return vertexes
372
373 -def setAttributeDictionaryToMultipliedTetragrid(tetragrid, xmlElement):
374 'Set the element attribute dictionary and element matrix to the matrix times the tetragrid.' 375 setXMLElementDictionaryMatrix(getBranchMatrix(xmlElement).getOtherTimesSelf(tetragrid), xmlElement)
376
377 -def setXMLElementDictionaryMatrix(matrix4X4, xmlElement):
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
384 -def transformVector3ByMatrix( tetragrid, vector3 ):
385 'Transform the vector3 by a matrix.' 386 vector3.setToVector3(getTransformedVector3(tetragrid, vector3))
387 388
389 -class Matrix:
390 'A four by four matrix.'
391 - def __init__(self, tetragrid=None):
392 'Add empty lists.' 393 if tetragrid == None: 394 self.tetragrid = None 395 return 396 self.tetragrid = getTetragridCopy(tetragrid)
397
398 - def __eq__(self, other):
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
406 - def __ne__(self, other):
407 'Determine whether this vector is not identical to other one.' 408 return not self.__eq__(other)
409
410 - def __repr__(self):
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):
417 'Add xml for this object.' 418 attributeDictionary = self.getAttributeDictionary() 419 if len(attributeDictionary) > 0: 420 xml_simple_writer.addClosedXMLTag(attributeDictionary, depth, self.__class__.__name__.lower(), output)
421
422 - def getAttributeDictionary(self, prefix=''):
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
437 - def getFromXMLElement(self, prefix, xmlElement):
438 'Get the values from row column attribute strings, counting from one.' 439 attributeDictionary = xmlElement.attributeDictionary 440 if attributeDictionary == None: 441 return self 442 self.tetragrid = getTetragridTimesOther(getTransformTetragrid(prefix, xmlElement), self.tetragrid) 443 self.tetragrid = getTetragridTimesOther(getScaleTetragrid('scale.', xmlElement), self.tetragrid) 444 self.tetragrid = getTetragridTimesOther(getRotateTetragrid('rotate.', xmlElement), self.tetragrid) 445 self.tetragrid = getTetragridTimesOther(getTranslateTetragrid('translate.', xmlElement), self.tetragrid) 446 return self
447
448 - def getOtherTimesSelf(self, otherTetragrid):
449 'Get this matrix reverse multiplied by the other matrix.' 450 return Matrix(getTetragridTimesOther(otherTetragrid, self.tetragrid))
451
452 - def getSelfTimesOther(self, otherTetragrid):
453 'Get this matrix multiplied by the other matrix.' 454 return Matrix(getTetragridTimesOther(self.tetragrid, otherTetragrid))
455