1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
|
# Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import numpy
import pytest
from cura.Arranging.Arrange import Arrange
from cura.Arranging.ShapeArray import ShapeArray
pytestmark = pytest.mark.skip()
def gimmeTriangle():
"""Triangle of area 12"""
return numpy.array([[-3, 1], [3, 1], [0, -3]], dtype=numpy.int32)
def gimmeSquare():
"""Boring square"""
return numpy.array([[-2, -2], [2, -2], [2, 2], [-2, 2]], dtype=numpy.int32)
def gimmeShapeArray(scale = 1.0):
"""Triangle of area 12"""
vertices = gimmeTriangle()
shape_arr = ShapeArray.fromPolygon(vertices, scale = scale)
return shape_arr
def gimmeShapeArraySquare(scale = 1.0):
"""Boring square"""
vertices = gimmeSquare()
shape_arr = ShapeArray.fromPolygon(vertices, scale = scale)
return shape_arr
def test_smoke_arrange():
"""Smoke test for Arrange"""
Arrange.create(fixed_nodes = [])
def test_smoke_ShapeArray():
"""Smoke test for ShapeArray"""
gimmeShapeArray()
def test_ShapeArray():
"""Test ShapeArray"""
scale = 1
ar = Arrange(16, 16, 8, 8, scale = scale)
ar.centerFirst()
shape_arr = gimmeShapeArray(scale)
count = len(numpy.where(shape_arr.arr == 1)[0])
assert count >= 10 # should approach 12
def test_ShapeArray_scaling():
"""Test ShapeArray with scaling"""
scale = 2
ar = Arrange(16, 16, 8, 8, scale = scale)
ar.centerFirst()
shape_arr = gimmeShapeArray(scale)
count = len(numpy.where(shape_arr.arr == 1)[0])
assert count >= 40 # should approach 2*2*12 = 48
def test_ShapeArray_scaling2():
"""Test ShapeArray with scaling"""
scale = 0.5
ar = Arrange(16, 16, 8, 8, scale = scale)
ar.centerFirst()
shape_arr = gimmeShapeArray(scale)
count = len(numpy.where(shape_arr.arr == 1)[0])
assert count >= 1 # should approach 3, but it can be inaccurate due to pixel rounding
def test_centerFirst():
"""Test centerFirst"""
ar = Arrange(300, 300, 150, 150, scale = 1)
ar.centerFirst()
assert ar._priority[150][150] < ar._priority[170][150]
assert ar._priority[150][150] < ar._priority[150][170]
assert ar._priority[150][150] < ar._priority[170][170]
assert ar._priority[150][150] < ar._priority[130][150]
assert ar._priority[150][150] < ar._priority[150][130]
assert ar._priority[150][150] < ar._priority[130][130]
def test_centerFirst_rectangular():
"""Test centerFirst"""
ar = Arrange(400, 300, 200, 150, scale = 1)
ar.centerFirst()
assert ar._priority[150][200] < ar._priority[150][220]
assert ar._priority[150][200] < ar._priority[170][200]
assert ar._priority[150][200] < ar._priority[170][220]
assert ar._priority[150][200] < ar._priority[180][150]
assert ar._priority[150][200] < ar._priority[130][200]
assert ar._priority[150][200] < ar._priority[130][180]
def test_centerFirst_rectangular2():
"""Test centerFirst"""
ar = Arrange(10, 20, 5, 10, scale = 1)
ar.centerFirst()
assert ar._priority[10][5] < ar._priority[10][7]
def test_backFirst():
"""Test backFirst"""
ar = Arrange(300, 300, 150, 150, scale = 1)
ar.backFirst()
assert ar._priority[150][150] < ar._priority[170][150]
assert ar._priority[150][150] < ar._priority[170][170]
assert ar._priority[150][150] > ar._priority[130][150]
assert ar._priority[150][150] > ar._priority[130][130]
def test_smoke_bestSpot():
"""See if the result of bestSpot has the correct form"""
ar = Arrange(30, 30, 15, 15, scale = 1)
ar.centerFirst()
shape_arr = gimmeShapeArray()
best_spot = ar.bestSpot(shape_arr)
assert hasattr(best_spot, "x")
assert hasattr(best_spot, "y")
assert hasattr(best_spot, "penalty_points")
assert hasattr(best_spot, "priority")
def test_bestSpot():
"""Real life test"""
ar = Arrange(16, 16, 8, 8, scale = 1)
ar.centerFirst()
shape_arr = gimmeShapeArray()
best_spot = ar.bestSpot(shape_arr)
assert best_spot.x == 0
assert best_spot.y == 0
ar.place(best_spot.x, best_spot.y, shape_arr)
# Place object a second time
best_spot = ar.bestSpot(shape_arr)
assert best_spot.x is not None # we found a location
assert best_spot.x != 0 or best_spot.y != 0 # it can't be on the same location
ar.place(best_spot.x, best_spot.y, shape_arr)
def test_bestSpot_rectangular_build_plate():
"""Real life test rectangular build plate"""
ar = Arrange(16, 40, 8, 20, scale = 1)
ar.centerFirst()
shape_arr = gimmeShapeArray()
best_spot = ar.bestSpot(shape_arr)
ar.place(best_spot.x, best_spot.y, shape_arr)
assert best_spot.x == 0
assert best_spot.y == 0
# Place object a second time
best_spot2 = ar.bestSpot(shape_arr)
assert best_spot2.x is not None # we found a location
assert best_spot2.x != 0 or best_spot2.y != 0 # it can't be on the same location
ar.place(best_spot2.x, best_spot2.y, shape_arr)
# Place object a 3rd time
best_spot3 = ar.bestSpot(shape_arr)
assert best_spot3.x is not None # we found a location
assert best_spot3.x != best_spot.x or best_spot3.y != best_spot.y # it can't be on the same location
assert best_spot3.x != best_spot2.x or best_spot3.y != best_spot2.y # it can't be on the same location
ar.place(best_spot3.x, best_spot3.y, shape_arr)
best_spot_x = ar.bestSpot(shape_arr)
ar.place(best_spot_x.x, best_spot_x.y, shape_arr)
best_spot_x = ar.bestSpot(shape_arr)
ar.place(best_spot_x.x, best_spot_x.y, shape_arr)
best_spot_x = ar.bestSpot(shape_arr)
ar.place(best_spot_x.x, best_spot_x.y, shape_arr)
def test_bestSpot_scale():
"""Real life test"""
scale = 0.5
ar = Arrange(16, 16, 8, 8, scale = scale)
ar.centerFirst()
shape_arr = gimmeShapeArray(scale)
best_spot = ar.bestSpot(shape_arr)
assert best_spot.x == 0
assert best_spot.y == 0
ar.place(best_spot.x, best_spot.y, shape_arr)
# Place object a second time
best_spot = ar.bestSpot(shape_arr)
assert best_spot.x is not None # we found a location
assert best_spot.x != 0 or best_spot.y != 0 # it can't be on the same location
ar.place(best_spot.x, best_spot.y, shape_arr)
def test_bestSpot_scale_rectangular():
"""Real life test"""
scale = 0.5
ar = Arrange(16, 40, 8, 20, scale = scale)
ar.centerFirst()
shape_arr = gimmeShapeArray(scale)
shape_arr_square = gimmeShapeArraySquare(scale)
best_spot = ar.bestSpot(shape_arr_square)
assert best_spot.x == 0
assert best_spot.y == 0
ar.place(best_spot.x, best_spot.y, shape_arr_square)
# Place object a second time
best_spot = ar.bestSpot(shape_arr)
assert best_spot.x is not None # we found a location
assert best_spot.x != 0 or best_spot.y != 0 # it can't be on the same location
ar.place(best_spot.x, best_spot.y, shape_arr)
best_spot = ar.bestSpot(shape_arr_square)
ar.place(best_spot.x, best_spot.y, shape_arr_square)
def test_smoke_place():
"""Try to place an object and see if something explodes"""
ar = Arrange(30, 30, 15, 15)
ar.centerFirst()
shape_arr = gimmeShapeArray()
assert not numpy.any(ar._occupied)
ar.place(0, 0, shape_arr)
assert numpy.any(ar._occupied)
def test_checkShape():
"""See of our center has less penalty points than out of the center"""
ar = Arrange(30, 30, 15, 15)
ar.centerFirst()
shape_arr = gimmeShapeArray()
points = ar.checkShape(0, 0, shape_arr)
points2 = ar.checkShape(5, 0, shape_arr)
points3 = ar.checkShape(0, 5, shape_arr)
assert points2 > points
assert points3 > points
def test_checkShape_rectangular():
"""See of our center has less penalty points than out of the center"""
ar = Arrange(20, 30, 10, 15)
ar.centerFirst()
shape_arr = gimmeShapeArray()
points = ar.checkShape(0, 0, shape_arr)
points2 = ar.checkShape(5, 0, shape_arr)
points3 = ar.checkShape(0, 5, shape_arr)
assert points2 > points
assert points3 > points
def test_checkShape_place():
"""Check that placing an object on occupied place returns None."""
ar = Arrange(30, 30, 15, 15)
ar.centerFirst()
shape_arr = gimmeShapeArray()
ar.checkShape(3, 6, shape_arr)
ar.place(3, 6, shape_arr)
points2 = ar.checkShape(3, 6, shape_arr)
assert points2 is None
def test_smoke_place_objects():
"""Test the whole sequence"""
ar = Arrange(20, 20, 10, 10, scale = 1)
ar.centerFirst()
shape_arr = gimmeShapeArray()
for i in range(5):
best_spot_x, best_spot_y, score, prio = ar.bestSpot(shape_arr)
ar.place(best_spot_x, best_spot_y, shape_arr)
# Test some internals
def test_compare_occupied_and_priority_tables():
ar = Arrange(10, 15, 5, 7)
ar.centerFirst()
assert ar._priority.shape == ar._occupied.shape
def test_arrayFromPolygon():
"""Polygon -> array"""
vertices = numpy.array([[-3, 1], [3, 1], [0, -3]])
array = ShapeArray.arrayFromPolygon([5, 5], vertices)
assert numpy.any(array)
def test_arrayFromPolygon2():
"""Polygon -> array"""
vertices = numpy.array([[-3, 1], [3, 1], [2, -3]])
array = ShapeArray.arrayFromPolygon([5, 5], vertices)
assert numpy.any(array)
def test_fromPolygon():
"""Polygon -> array"""
vertices = numpy.array([[0, 0.5], [0, 0], [0.5, 0]])
array = ShapeArray.fromPolygon(vertices, scale=0.5)
assert numpy.any(array.arr)
def test_check():
"""Line definition -> array with true/false"""
base_array = numpy.zeros([5, 5], dtype=float)
p1 = numpy.array([0, 0])
p2 = numpy.array([4, 4])
check_array = ShapeArray._check(p1, p2, base_array)
assert numpy.any(check_array)
assert check_array[3][0]
assert not check_array[0][3]
def test_check2():
"""Line definition -> array with true/false"""
base_array = numpy.zeros([5, 5], dtype=float)
p1 = numpy.array([0, 3])
p2 = numpy.array([4, 3])
check_array = ShapeArray._check(p1, p2, base_array)
assert numpy.any(check_array)
assert not check_array[3][0]
assert check_array[3][4]
def test_parts_of_fromNode():
"""Just adding some stuff to ensure fromNode works as expected. Some parts should actually be in UM"""
from UM.Math.Polygon import Polygon
p = Polygon(numpy.array([[-2, -2], [2, -2], [2, 2], [-2, 2]], dtype=numpy.int32))
offset = 1
p_offset = p.getMinkowskiHull(Polygon.approximatedCircle(offset))
assert len(numpy.where(p_offset._points[:, 0] >= 2.9)) > 0
assert len(numpy.where(p_offset._points[:, 0] <= -2.9)) > 0
assert len(numpy.where(p_offset._points[:, 1] >= 2.9)) > 0
assert len(numpy.where(p_offset._points[:, 1] <= -2.9)) > 0
def test_parts_of_fromNode2():
from UM.Math.Polygon import Polygon
p = Polygon(numpy.array([[-2, -2], [2, -2], [2, 2], [-2, 2]], dtype=numpy.int32) * 2) # 4x4
offset = 13.3
scale = 0.5
p_offset = p.getMinkowskiHull(Polygon.approximatedCircle(offset))
shape_arr1 = ShapeArray.fromPolygon(p._points, scale = scale)
shape_arr2 = ShapeArray.fromPolygon(p_offset._points, scale = scale)
assert shape_arr1.arr.shape[0] >= (4 * scale) - 1 # -1 is to account for rounding errors
assert shape_arr2.arr.shape[0] >= (2 * offset + 4) * scale - 1
|