chiark / gitweb /
Should use "is None" instead of "== None"
[cura.git] / Cura / util / mesh.py
1 from __future__ import absolute_import
2
3 import time
4 import math
5
6 import numpy
7 numpy.seterr(all='ignore')
8
9 from Cura.util import util3d
10
11 class mesh(object):
12         def __init__(self):
13                 self.vertexes = None
14                 self.origonalVertexes = None
15                 self.vertexCount = 0
16
17         def addVertex(self, x, y, z):
18                 n = self.vertexCount
19                 self.origonalVertexes[n][0] = x
20                 self.origonalVertexes[n][1] = y
21                 self.origonalVertexes[n][2] = z
22                 self.vertexCount += 1
23         
24         def _prepareVertexCount(self, vertexNumber):
25                 #Set the amount of faces before loading data in them. This way we can create the numpy arrays before we fill them.
26                 self.origonalVertexes = numpy.zeros((vertexNumber, 3), numpy.float32)
27                 self.normal = numpy.zeros((vertexNumber, 3), numpy.float32)
28                 self.vertexCount = 0
29
30         def _postProcessAfterLoad(self):
31                 self.vertexes = self.origonalVertexes.copy()
32                 self.getMinimumZ()
33
34         def getMinimumZ(self):
35                 self.min = self.vertexes.min(0)
36                 self.max = self.vertexes.max(0)
37                 self.size = self.max - self.min
38                 return self.min[2]
39         
40         def getMaximum(self):
41                 return self.max
42         def getMinimum(self):
43                 return self.min
44         def getSize(self):
45                 return self.size
46
47         def setRotateMirror(self, rotate, mirrorX, mirrorY, mirrorZ, swapXZ, swapYZ):
48                 #Modify the vertexes with the rotation/mirror
49                 rotate = rotate / 180.0 * math.pi
50                 scaleX = 1.0
51                 scaleY = 1.0
52                 scaleZ = 1.0
53                 if mirrorX:
54                         scaleX = -scaleX
55                 if mirrorY:
56                         scaleY = -scaleY
57                 if mirrorZ:
58                         scaleZ = -scaleZ
59                 mat00 = math.cos(rotate) * scaleX
60                 mat01 =-math.sin(rotate) * scaleY
61                 mat10 = math.sin(rotate) * scaleX
62                 mat11 = math.cos(rotate) * scaleY
63                 
64                 mat = numpy.array([[mat00,mat10,0],[mat01,mat11,0],[0,0,scaleZ]], numpy.float32)
65                 if swapXZ:
66                         mat = numpy.array([mat[2],mat[1],mat[0]], numpy.float32)
67                 if swapYZ:
68                         mat = numpy.array([mat[0],mat[2],mat[1]], numpy.float32)
69                 self.matrix = mat
70                 self.vertexes = (numpy.matrix(self.origonalVertexes, copy = False) * numpy.matrix(mat)).getA()
71                 
72                 #Calculate the boundery box of the object
73                 self.getMinimumZ()
74                 #Calculate the boundery circle
75                 center = (self.max + self.min) / 2.0
76                 self.bounderyCircleSize = round(math.sqrt(numpy.max(((self.vertexes[::,0] - center[0]) * (self.vertexes[::,0] - center[0])) + ((self.vertexes[::,1] - center[1]) * (self.vertexes[::,1] - center[1])))), 3)
77                 
78                 #Calculate the normals
79                 tris = self.vertexes.reshape(self.vertexCount / 3, 3, 3)
80                 normals = numpy.cross( tris[::,1 ] - tris[::,0]  , tris[::,2 ] - tris[::,0] )
81                 lens = numpy.sqrt( normals[:,0]**2 + normals[:,1]**2 + normals[:,2]**2 )
82                 normals[:,0] /= lens
83                 normals[:,1] /= lens
84                 normals[:,2] /= lens
85                 
86                 n = numpy.zeros((self.vertexCount / 3, 9), numpy.float32)
87                 n[:,0:3] = normals
88                 n[:,3:6] = normals
89                 n[:,6:9] = normals
90                 self.normal = n.reshape(self.vertexCount, 3)
91                 self.invNormal = -self.normal
92
93         def splitToParts(self, callback = None):
94                 t0 = time.time()
95
96                 #print "%f: " % (time.time() - t0), "Splitting a model with %d vertexes." % (len(self.vertexes))
97                 removeDict = {}
98                 tree = util3d.AABBTree()
99                 off = numpy.array([0.0001,0.0001,0.0001])
100                 for idx in xrange(0, self.vertexCount):
101                         v = self.vertexes[idx]
102                         e = util3d.AABB(v-off, v+off)
103                         q = tree.query(e)
104                         if len(q) < 1:
105                                 e.idx = idx
106                                 tree.insert(e)
107                         else:
108                                 removeDict[idx] = q[0].idx
109                         if callback is not None and (idx % 100) == 0:
110                                 callback(idx)
111                 #print "%f: " % (time.time() - t0), "Marked %d duplicate vertexes for removal." % (len(removeDict))
112
113                 faceList = []
114                 for idx in xrange(0, self.vertexCount, 3):
115                         f = [idx, idx + 1, idx + 2]
116                         if removeDict.has_key(f[0]):
117                                 f[0] = removeDict[f[0]]
118                         if removeDict.has_key(f[1]):
119                                 f[1] = removeDict[f[1]]
120                         if removeDict.has_key(f[2]):
121                                 f[2] = removeDict[f[2]]
122                         faceList.append(f)
123                 
124                 #print "%f: " % (time.time() - t0), "Building face lists after vertex removal."
125                 vertexFaceList = []
126                 for idx in xrange(0, self.vertexCount):
127                         vertexFaceList.append([])
128                 for idx in xrange(0, len(faceList)):
129                         f = faceList[idx]
130                         vertexFaceList[f[0]].append(idx)
131                         vertexFaceList[f[1]].append(idx)
132                         vertexFaceList[f[2]].append(idx)
133                 
134                 #print "%f: " % (time.time() - t0), "Building parts."
135                 self._vertexFaceList = vertexFaceList
136                 self._faceList = faceList
137                 partList = []
138                 doneSet = set()
139                 for idx in xrange(0, len(faceList)):
140                         if not idx in doneSet:
141                                 partList.append(self._createPartFromFacewalk(idx, doneSet))
142                 #print "%f: " % (time.time() - t0), "Split into %d parts" % (len(partList))
143                 self._vertexFaceList = None
144                 self._faceList = None
145                 return partList
146
147         def _createPartFromFacewalk(self, startFaceIdx, doneSet):
148                 m = mesh()
149                 m._prepareVertexCount(self.vertexCount)
150                 todoList = [startFaceIdx]
151                 doneSet.add(startFaceIdx)
152                 while len(todoList) > 0:
153                         faceIdx = todoList.pop()
154                         self._partAddFacewalk(m, faceIdx, doneSet, todoList)
155                 return m
156
157         def _partAddFacewalk(self, part, faceIdx, doneSet, todoList):
158                 f = self._faceList[faceIdx]
159                 v0 = self.vertexes[f[0]]
160                 v1 = self.vertexes[f[1]]
161                 v2 = self.vertexes[f[2]]
162                 part.addVertex(v0[0], v0[1], v0[2])
163                 part.addVertex(v1[0], v1[1], v1[2])
164                 part.addVertex(v2[0], v2[1], v2[2])
165                 for f1 in self._vertexFaceList[f[0]]:
166                         if f1 not in doneSet:
167                                 todoList.append(f1)
168                                 doneSet.add(f1)
169                 for f1 in self._vertexFaceList[f[1]]:
170                         if f1 not in doneSet:
171                                 todoList.append(f1)
172                                 doneSet.add(f1)
173                 for f1 in self._vertexFaceList[f[2]]:
174                         if f1 not in doneSet:
175                                 todoList.append(f1)
176                                 doneSet.add(f1)
177