1 from __future__ import absolute_import
2 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
8 numpy.seterr(all='ignore')
10 class printableObject(object):
11 def __init__(self, name):
14 self._name = self._name[0:self._name.rfind('.')]
16 self._position = numpy.array([0.0, 0.0])
17 self._matrix = numpy.matrix([[1,0,0],[0,1,0],[0,0,1]], numpy.float64)
18 self._transformedMin = None
19 self._transformedMax = None
20 self._transformedSize = None
21 self._boundaryCircleSize = None
22 self._drawOffset = None
26 ret = printableObject(self._name)
27 ret._matrix = self._matrix.copy()
28 ret._transformedMin = self._transformedMin.copy()
29 ret._transformedMax = self._transformedMin.copy()
30 ret._transformedSize = self._transformedSize.copy()
31 ret._boundaryCircleSize = self._boundaryCircleSize
32 ret._drawOffset = self._drawOffset.copy()
33 for m in self._meshList[:]:
35 m2.vertexes = m.vertexes
36 m2.vertexCount = m.vertexCount
43 self._meshList.append(m)
46 def _postProcessAfterLoad(self):
47 for m in self._meshList:
51 def applyMatrix(self, m):
55 def processMatrix(self):
56 self._transformedMin = numpy.array([999999999999,999999999999,999999999999], numpy.float64)
57 self._transformedMax = numpy.array([-999999999999,-999999999999,-999999999999], numpy.float64)
58 self._boundaryCircleSize = 0
60 for m in self._meshList:
61 transformedVertexes = m.getTransformedVertexes()
62 transformedMin = transformedVertexes.min(0)
63 transformedMax = transformedVertexes.max(0)
64 for n in xrange(0, 3):
65 self._transformedMin[n] = min(transformedMin[n], self._transformedMin[n])
66 self._transformedMax[n] = max(transformedMax[n], self._transformedMax[n])
68 #Calculate the boundary circle
69 transformedSize = transformedMax - transformedMin
70 center = transformedMin + transformedSize / 2.0
71 boundaryCircleSize = round(math.sqrt(numpy.max(((transformedVertexes[::,0] - center[0]) * (transformedVertexes[::,0] - center[0])) + ((transformedVertexes[::,1] - center[1]) * (transformedVertexes[::,1] - center[1])) + ((transformedVertexes[::,2] - center[2]) * (transformedVertexes[::,2] - center[2])))), 3)
72 self._boundaryCircleSize = max(self._boundaryCircleSize, boundaryCircleSize)
73 self._transformedSize = self._transformedMax - self._transformedMin
74 self._drawOffset = (self._transformedMax + self._transformedMin) / 2
75 self._drawOffset[2] = self._transformedMin[2]
76 self._transformedMax -= self._drawOffset
77 self._transformedMin -= self._drawOffset
81 def getPosition(self):
83 def setPosition(self, newPos):
84 self._position = newPos
89 return self._transformedMax
91 return self._transformedMin
93 return self._transformedSize
94 def getDrawOffset(self):
95 return self._drawOffset
96 def getBoundaryCircle(self):
97 return self._boundaryCircleSize
99 def mirror(self, axis):
100 matrix = [[1,0,0], [0, 1, 0], [0, 0, 1]]
101 matrix[axis][axis] = -1
102 self.applyMatrix(numpy.matrix(matrix, numpy.float64))
106 numpy.linalg.norm(self._matrix[::,0].getA().flatten()),
107 numpy.linalg.norm(self._matrix[::,1].getA().flatten()),
108 numpy.linalg.norm(self._matrix[::,2].getA().flatten())], numpy.float64);
110 def setScale(self, scale, axis, uniform):
111 currentScale = numpy.linalg.norm(self._matrix[::,axis].getA().flatten())
112 scale /= currentScale
116 matrix = [[scale,0,0], [0, scale, 0], [0, 0, scale]]
118 matrix = [[1.0,0,0], [0, 1.0, 0], [0, 0, 1.0]]
119 matrix[axis][axis] = scale
120 self.applyMatrix(numpy.matrix(matrix, numpy.float64))
122 def setSize(self, size, axis, uniform):
123 scale = self.getSize()[axis]
128 matrix = [[scale,0,0], [0, scale, 0], [0, 0, scale]]
130 matrix = [[1,0,0], [0, 1, 0], [0, 0, 1]]
131 matrix[axis][axis] = scale
132 self.applyMatrix(numpy.matrix(matrix, numpy.float64))
134 def resetScale(self):
135 x = 1/numpy.linalg.norm(self._matrix[::,0].getA().flatten())
136 y = 1/numpy.linalg.norm(self._matrix[::,1].getA().flatten())
137 z = 1/numpy.linalg.norm(self._matrix[::,2].getA().flatten())
138 self.applyMatrix(numpy.matrix([[x,0,0],[0,y,0],[0,0,z]], numpy.float64))
140 def resetRotation(self):
141 x = numpy.linalg.norm(self._matrix[::,0].getA().flatten())
142 y = numpy.linalg.norm(self._matrix[::,1].getA().flatten())
143 z = numpy.linalg.norm(self._matrix[::,2].getA().flatten())
144 self._matrix = numpy.matrix([[x,0,0],[0,y,0],[0,0,z]], numpy.float64)
148 transformedVertexes = self._meshList[0].getTransformedVertexes()
149 minZvertex = transformedVertexes[transformedVertexes.argmin(0)[2]]
152 for v in transformedVertexes:
153 diff = v - minZvertex
154 len = math.sqrt(diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2])
157 dot = (diff[2] / len)
163 rad = -math.atan2(dotV[1], dotV[0])
164 self._matrix *= numpy.matrix([[math.cos(rad), math.sin(rad), 0], [-math.sin(rad), math.cos(rad), 0], [0,0,1]], numpy.float64)
165 rad = -math.asin(dotMin)
166 self._matrix *= numpy.matrix([[math.cos(rad), 0, math.sin(rad)], [0,1,0], [-math.sin(rad), 0, math.cos(rad)]], numpy.float64)
169 transformedVertexes = self._meshList[0].getTransformedVertexes()
170 minZvertex = transformedVertexes[transformedVertexes.argmin(0)[2]]
173 for v in transformedVertexes:
174 diff = v - minZvertex
175 len = math.sqrt(diff[1] * diff[1] + diff[2] * diff[2])
178 dot = (diff[2] / len)
185 rad = math.asin(dotMin)
187 rad = -math.asin(dotMin)
188 self.applyMatrix(numpy.matrix([[1,0,0], [0, math.cos(rad), math.sin(rad)], [0, -math.sin(rad), math.cos(rad)]], numpy.float64))
190 def scaleUpTo(self, size):
191 vMin = self._transformedMin
192 vMax = self._transformedMax
194 scaleX1 = (size[0] / 2 - self._position[0]) / ((vMax[0] - vMin[0]) / 2)
195 scaleY1 = (size[1] / 2 - self._position[1]) / ((vMax[1] - vMin[1]) / 2)
196 scaleX2 = (self._position[0] + size[0] / 2) / ((vMax[0] - vMin[0]) / 2)
197 scaleY2 = (self._position[1] + size[1] / 2) / ((vMax[1] - vMin[1]) / 2)
198 scaleZ = size[2] / (vMax[2] - vMin[2])
199 scale = min(scaleX1, scaleY1, scaleX2, scaleY2, scaleZ)
201 self.applyMatrix(numpy.matrix([[scale,0,0],[0,scale,0],[0,0,scale]], numpy.float64))
203 def split(self, callback):
205 for oriMesh in self._meshList:
206 ret += oriMesh.split(callback)
210 def __init__(self, obj):
216 def _addFace(self, x0, y0, z0, x1, y1, z1, x2, y2, z2):
218 self.vertexes[n][0] = x0
219 self.vertexes[n][1] = y0
220 self.vertexes[n][2] = z0
222 self.vertexes[n][0] = x1
223 self.vertexes[n][1] = y1
224 self.vertexes[n][2] = z1
226 self.vertexes[n][0] = x2
227 self.vertexes[n][1] = y2
228 self.vertexes[n][2] = z2
229 self.vertexCount += 3
231 def _prepareFaceCount(self, faceNumber):
232 #Set the amount of faces before loading data in them. This way we can create the numpy arrays before we fill them.
233 self.vertexes = numpy.zeros((faceNumber*3, 3), numpy.float32)
234 self.normal = numpy.zeros((faceNumber*3, 3), numpy.float32)
237 def _calculateNormals(self):
238 #Calculate the normals
239 tris = self.vertexes.reshape(self.vertexCount / 3, 3, 3)
240 normals = numpy.cross( tris[::,1 ] - tris[::,0] , tris[::,2 ] - tris[::,0] )
241 lens = numpy.sqrt( normals[:,0]**2 + normals[:,1]**2 + normals[:,2]**2 )
246 n = numpy.zeros((self.vertexCount / 3, 9), numpy.float32)
250 self.normal = n.reshape(self.vertexCount, 3)
251 self.invNormal = -self.normal
253 def _vertexHash(self, idx):
254 v = self.vertexes[idx]
255 return int(v[0] * 100) | int(v[1] * 100) << 10 | int(v[2] * 100) << 20
257 def _idxFromHash(self, map, idx):
258 vHash = self._vertexHash(idx)
260 if numpy.linalg.norm(self.vertexes[i] - self.vertexes[idx]) < 0.001:
263 def getTransformedVertexes(self, applyOffsets = False):
265 pos = self._obj._position.copy()
267 pos[2] = self._obj.getSize()[2] / 2
268 offset = self._obj._drawOffset.copy()
269 offset[2] += self._obj.getSize()[2] / 2
270 return (numpy.matrix(self.vertexes, copy = False) * numpy.matrix(self._obj._matrix, numpy.float32)).getA() - offset + pos
271 return (numpy.matrix(self.vertexes, copy = False) * numpy.matrix(self._obj._matrix, numpy.float32)).getA()
273 def split(self, callback):
277 for idx in xrange(0, self.vertexCount):
279 callback(idx * 100 / self.vertexCount)
280 vHash = self._vertexHash(idx)
281 if vHash not in vertexMap:
282 vertexMap[vHash] = []
283 vertexMap[vHash].append(idx)
284 vertexToFace.append([])
287 for idx in xrange(0, self.vertexCount, 3):
289 callback(idx * 100 / self.vertexCount)
290 f = [self._idxFromHash(vertexMap, idx), self._idxFromHash(vertexMap, idx+1), self._idxFromHash(vertexMap, idx+2)]
291 vertexToFace[f[0]].append(idx / 3)
292 vertexToFace[f[1]].append(idx / 3)
293 vertexToFace[f[2]].append(idx / 3)
298 for idx in xrange(0, len(faceList)):
304 while len(todoList) > 0:
306 meshFaceList.append(idx)
307 for n in xrange(0, 3):
308 for i in vertexToFace[faceList[idx][n]]:
313 obj = printableObject(self._obj._name)
314 obj._matrix = self._obj._matrix.copy()
316 m._prepareFaceCount(len(meshFaceList))
317 for idx in meshFaceList:
318 m.vertexes[m.vertexCount] = self.vertexes[faceList[idx][0]]
320 m.vertexes[m.vertexCount] = self.vertexes[faceList[idx][1]]
322 m.vertexes[m.vertexCount] = self.vertexes[faceList[idx][2]]
324 obj._postProcessAfterLoad()