1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
4 from Cura.util import profile
6 class _objectOrder(object):
7 def __init__(self, order, todo):
11 class _objectOrderFinder(object):
12 def __init__(self, scene, offset, leftToRight, frontToBack, gantryHeight):
14 self._offset = offset - numpy.array([0.1,0.1])
15 self._objs = scene.objects()
16 self._leftToRight = leftToRight
17 self._frontToBack = frontToBack
19 for n in xrange(0, len(self._objs)):
20 if scene.checkPlatform(self._objs[n]):
23 if self._objs[n].getSize()[2] > gantryHeight and len(initialList) > 1:
26 if len(initialList) == 0:
31 self._hitMap = [None] * (max(initialList)+1)
33 self._hitMap[a] = [False] * (max(initialList)+1)
35 self._hitMap[a][b] = self._checkHit(a, b)
37 initialList.sort(self._objIdxCmp)
40 self._todo = [_objectOrder([], initialList)]
41 while len(self._todo) > 0:
43 current = self._todo.pop()
44 #print len(self._todo), len(current.order), len(initialList), current.order
45 for addIdx in current.todo:
46 if not self._checkHitFor(addIdx, current.order) and not self._checkBlocks(addIdx, current.todo):
47 todoList = current.todo[:]
48 todoList.remove(addIdx)
49 order = current.order[:] + [addIdx]
50 if len(todoList) == 0:
54 self._todo.append(_objectOrder(order, todoList))
57 def _objIdxCmp(self, a, b):
58 scoreA = sum(self._hitMap[a])
59 scoreB = sum(self._hitMap[b])
60 return scoreA - scoreB
62 def _checkHitFor(self, addIdx, others):
64 if self._hitMap[addIdx][idx]:
68 def _checkBlocks(self, addIdx, others):
70 if addIdx != idx and self._hitMap[idx][addIdx]:
74 #Check if printing one object will cause printhead colission with other object.
75 def _checkHit(self, addIdx, idx):
76 addPos = self._scene._objectList[addIdx].getPosition()
77 addSize = self._scene._objectList[addIdx].getSize()
78 pos = self._scene._objectList[idx].getPosition()
79 size = self._scene._objectList[idx].getSize()
82 if addPos[0] - addSize[0] / 2 - self._offset[0] >= pos[0] + size[0] / 2:
85 if addPos[0] + addSize[0] / 2 + self._offset[0] <= pos[0] - size[0] / 2:
89 if addPos[1] - addSize[1] / 2 - self._offset[1] >= pos[1] + size[1] / 2:
92 if addPos[1] + addSize[1] / 2 + self._offset[1] <= pos[1] - size[1] / 2:
100 self._sizeOffsets = numpy.array([0.0,0.0], numpy.float32)
101 self._machineSize = numpy.array([100,100,100], numpy.float32)
102 self._headOffsets = numpy.array([18.0,18.0], numpy.float32)
103 #Print order variables
104 self._leftToRight = False
105 self._frontToBack = True
106 self._gantryHeight = 60
107 # Physical (square) machine size.
108 def setMachineSize(self, machineSize):
109 self._machineSize = machineSize
111 # Size offsets are offsets caused by brim, skirt, etc.
112 def setSizeOffsets(self, sizeOffsets):
113 self._sizeOffsets = sizeOffsets
115 #size of the printing head.
116 def setHeadSize(self, xMin, xMax, yMin, yMax, gantryHeight):
117 self._leftToRight = xMin < xMax
118 self._frontToBack = yMin < yMax
119 self._headOffsets[0] = min(xMin, xMax)
120 self._headOffsets[1] = min(yMin, yMax)
121 self._gantryHeight = gantryHeight
123 def getObjectExtend(self):
124 return self._sizeOffsets + self._headOffsets
127 return self._objectList
129 #Add new object to print area
131 self._findFreePositionFor(obj)
132 self._objectList.append(obj)
134 if numpy.max(obj.getSize()[0:2]) > numpy.max(self._machineSize[0:2]) * 2.5:
135 scale = numpy.max(self._machineSize[0:2]) * 2.5 / numpy.max(obj.getSize()[0:2])
136 matrix = [[scale,0,0], [0, scale, 0], [0, 0, scale]]
137 obj.applyMatrix(numpy.matrix(matrix, numpy.float64))
139 def remove(self, obj):
140 self._objectList.remove(obj)
142 #Dual(multiple) extrusion merge
143 def merge(self, obj1, obj2):
145 obj1._meshList += obj2._meshList
146 for m in obj2._meshList:
149 obj1.setPosition((obj1.getPosition() + obj2.getPosition()) / 2)
154 while self._pushFree():
159 def arrangeAll(self):
160 oldList = self._objectList
161 self._objectList = []
163 obj.setPosition(numpy.array([0,0], numpy.float32))
167 minPos = numpy.array([9999999,9999999], numpy.float32)
168 maxPos = numpy.array([-9999999,-9999999], numpy.float32)
169 for obj in self._objectList:
170 pos = obj.getPosition()
172 minPos[0] = min(minPos[0], pos[0] - size[0] / 2)
173 minPos[1] = min(minPos[1], pos[1] - size[1] / 2)
174 maxPos[0] = max(maxPos[0], pos[0] + size[0] / 2)
175 maxPos[1] = max(maxPos[1], pos[1] + size[1] / 2)
176 offset = -(maxPos + minPos) / 2
177 for obj in self._objectList:
178 obj.setPosition(obj.getPosition() + offset)
180 def printOrder(self):
181 order = _objectOrderFinder(self, self._headOffsets + self._sizeOffsets, self._leftToRight, self._frontToBack, self._gantryHeight).order
185 for a in self._objectList:
186 for b in self._objectList:
187 if not self._checkHit(a, b):
189 posDiff = a.getPosition() - b.getPosition()
190 if posDiff[0] == 0.0 and posDiff[1] == 0.0:
192 if abs(posDiff[0]) > abs(posDiff[1]):
196 aPos = a.getPosition()
197 bPos = b.getPosition()
198 center = (aPos[axis] + bPos[axis]) / 2
199 distance = (a.getSize()[axis] + b.getSize()[axis]) / 2 + 0.1 + self._sizeOffsets[axis] + self._headOffsets[axis]
200 if posDiff[axis] < 0:
202 aPos[axis] = center + distance / 2
203 bPos[axis] = center - distance / 2
209 #Check if two objects are hitting each-other (+ head space).
210 def _checkHit(self, a, b):
213 posDiff = a.getPosition() - b.getPosition()
214 if abs(posDiff[0]) < (a.getSize()[0] + b.getSize()[0]) / 2 + self._sizeOffsets[0] + self._headOffsets[0]:
215 if abs(posDiff[1]) < (a.getSize()[1] + b.getSize()[1]) / 2 + self._sizeOffsets[1] + self._headOffsets[1]:
219 def checkPlatform(self, obj):
220 p = obj.getPosition()
221 s = obj.getSize()[0:2] / 2 + self._sizeOffsets
222 if p[0] - s[0] < -self._machineSize[0] / 2:
224 if p[0] + s[0] > self._machineSize[0] / 2:
226 if p[1] - s[1] < -self._machineSize[1] / 2:
228 if p[1] + s[1] > self._machineSize[1] / 2:
231 #Do clip Check for UM2.
232 machine = profile.getMachineSetting('machine_type')
233 if(machine == "ultimaker2"):
234 #lowerRight clip check
235 if p[0] - s[0] < -self._machineSize[0] / 2 + 50 and p[1] - s[1] < -self._machineSize[1]/2 + 5:
238 if p[0] - s[0] < -self._machineSize[0] / 2 + 50 and p[1] + s[1] > self._machineSize[1]/2 - 35:
241 if p[0] + s[0] > self._machineSize[0] / 2 - 55 and p[1] - s[1] < -self._machineSize[1]/2 + 5:
244 if p[0] + s[0] > self._machineSize[0] / 2 - 55 and p[1] + s[1] > self._machineSize[1]/2 - 35:
248 def _findFreePositionFor(self, obj):
250 for a in self._objectList:
252 s = (a.getSize()[0:2] + obj.getSize()[0:2]) / 2 + self._sizeOffsets + self._headOffsets
253 posList.append(p + s * ( 1.0, 1.0))
254 posList.append(p + s * ( 0.0, 1.0))
255 posList.append(p + s * (-1.0, 1.0))
256 posList.append(p + s * ( 1.0, 0.0))
257 posList.append(p + s * (-1.0, 0.0))
258 posList.append(p + s * ( 1.0,-1.0))
259 posList.append(p + s * ( 0.0,-1.0))
260 posList.append(p + s * (-1.0,-1.0))
267 for a in self._objectList:
268 if self._checkHit(a, obj):
273 dist = numpy.linalg.norm(p)
274 if not self.checkPlatform(obj):
276 if best is None or dist < bestDist:
280 obj.setPosition(best)