chiark / gitweb /
Merge branch 'master' into SteamEngine
[cura.git] / Cura / util / objectScene.py
1 import random
2 import numpy
3
4 class Scene():
5         def __init__(self):
6                 self._objectList = []
7                 self._sizeOffsets = numpy.array([3.0,3.0], numpy.float32)
8                 self._machineSize = numpy.array([100,100,100], numpy.float32)
9                 self._headOffsets = numpy.array([18.0,18.0], numpy.float32)
10
11         def setMachineSize(self, machineSize):
12                 self._machineSize = machineSize
13
14         def setSizeOffsets(self, sizeOffsets):
15                 self._sizeOffsets = sizeOffsets
16
17         def objects(self):
18                 return self._objectList
19
20         def add(self, obj):
21                 self._findFreePositionFor(obj)
22                 self._objectList.append(obj)
23                 self.pushFree()
24
25         def remove(self, obj):
26                 self._objectList.remove(obj)
27
28         def pushFree(self):
29                 n = 1000
30                 while self._pushFree():
31                         n -= 1
32                         if n < 0:
33                                 return
34
35         def arrangeAll(self):
36                 oldList = self._objectList
37                 self._objectList = []
38                 for obj in oldList:
39                         obj.setPosition(numpy.array([0,0], numpy.float32))
40                         self.add(obj)
41
42         def centerAll(self):
43                 minPos = numpy.array([9999999,9999999], numpy.float32)
44                 maxPos = numpy.array([-9999999,-9999999], numpy.float32)
45                 for obj in self._objectList:
46                         pos = obj.getPosition()
47                         size = obj.getSize()
48                         minPos[0] = min(minPos[0], pos[0] - size[0] / 2)
49                         minPos[1] = min(minPos[1], pos[1] - size[1] / 2)
50                         maxPos[0] = max(maxPos[0], pos[0] + size[0] / 2)
51                         maxPos[1] = max(maxPos[1], pos[1] + size[1] / 2)
52                 offset = -(maxPos + minPos) / 2
53                 for obj in self._objectList:
54                         obj.setPosition(obj.getPosition() + offset)
55
56         def _pushFree(self):
57                 for a in self._objectList:
58                         for b in self._objectList:
59                                 if not self._checkHit(a, b):
60                                         continue
61                                 posDiff = a.getPosition() - b.getPosition()
62                                 if posDiff[0] == 0.0 and posDiff[1] == 0.0:
63                                         posDiff[1] = 1.0
64                                 if abs(posDiff[0]) > abs(posDiff[1]):
65                                         axis = 0
66                                 else:
67                                         axis = 1
68                                 aPos = a.getPosition()
69                                 bPos = b.getPosition()
70                                 center = (aPos[axis] + bPos[axis]) / 2
71                                 distance = (a.getSize()[axis] + b.getSize()[axis]) / 2 + 0.1 + self._sizeOffsets[axis] + self._headOffsets[axis]
72                                 if posDiff[axis] < 0:
73                                         distance = -distance
74                                 aPos[axis] = center + distance / 2
75                                 bPos[axis] = center - distance / 2
76                                 a.setPosition(aPos)
77                                 b.setPosition(bPos)
78                                 return True
79                 return False
80
81         def _checkHit(self, a, b):
82                 if a == b:
83                         return False
84                 posDiff = a.getPosition() - b.getPosition()
85                 if abs(posDiff[0]) < (a.getSize()[0] + b.getSize()[0]) / 2 + self._sizeOffsets[0] + self._headOffsets[0]:
86                         if abs(posDiff[1]) < (a.getSize()[1] + b.getSize()[1]) / 2 + self._sizeOffsets[1] + self._headOffsets[1]:
87                                 return True
88                 return False
89
90         def checkPlatform(self, obj):
91                 p = obj.getPosition()
92                 s = obj.getSize()[0:2] / 2 + self._sizeOffsets
93                 if p[0] - s[0] < -self._machineSize[0] / 2:
94                         return False
95                 if p[0] + s[0] > self._machineSize[0] / 2:
96                         return False
97                 if p[1] - s[1] < -self._machineSize[1] / 2:
98                         return False
99                 if p[1] + s[1] > self._machineSize[1] / 2:
100                         return False
101                 return True
102
103         def _findFreePositionFor(self, obj):
104                 posList = []
105                 for a in self._objectList:
106                         p = a.getPosition()
107                         s = (a.getSize()[0:2] + obj.getSize()[0:2]) / 2 + self._sizeOffsets + self._headOffsets
108                         posList.append(p + s * ( 1, 1))
109                         posList.append(p + s * ( 0, 1))
110                         posList.append(p + s * (-1, 1))
111                         posList.append(p + s * ( 1, 0))
112                         posList.append(p + s * (-1, 0))
113                         posList.append(p + s * ( 1,-1))
114                         posList.append(p + s * ( 0,-1))
115                         posList.append(p + s * (-1,-1))
116
117                 best = None
118                 bestDist = None
119                 for p in posList:
120                         obj.setPosition(p)
121                         ok = True
122                         for a in self._objectList:
123                                 if self._checkHit(a, obj):
124                                         ok = False
125                                         break
126                         if not ok:
127                                 continue
128                         dist = numpy.linalg.norm(p)
129                         if not self.checkPlatform(obj):
130                                 dist *= 3
131                         if best is None or dist < bestDist:
132                                 best = p
133                                 bestDist = dist
134                 if best is not None:
135                         obj.setPosition(best)