-
Notifications
You must be signed in to change notification settings - Fork 55
/
nesting.py
85 lines (73 loc) · 2.87 KB
/
nesting.py
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
from mathutils.geometry import box_pack_2d
from time import time
def get_nester(method):
return rect_pack_custom if method == 'CCOR' else rect_pack_bpy
class Page:
"""Container for several Islands"""
__slots__ = ('islands', 'name', 'image_path')
def __init__(self, num=1, islands=None):
self.islands = islands or list()
self.name = "page{}".format(num) # note: this is only used in svg files naming
self.image_path = None
def can_pack_ccor(islands, cage_size):
if len(islands) <= 1:
islands[0].pos.xy = 0, 0
return True
for isle in islands[1:]:
...
boxes = [[0, 0, isle.bounding_box.x, isle.bounding_box.y / aspect] for isle in islands]
width, height = box_pack_2d(boxes)
if width < cage_size.x > height:
for (x, y, *_), isle in zip(boxes, islands):
isle.pos.xy = x, y * aspect
return True
return False
def can_pack_bpy(islands, cage_size):
if len(islands) <= 1:
islands[0].pos.xy = 0, 0
return True
aspect = cage_size.y / cage_size.x
boxes = [[0, 0, isle.bounding_box.x, isle.bounding_box.y / aspect] for isle in islands]
width, height = box_pack_2d(boxes)
if width < cage_size.x > height:
for (x, y, *_), isle in zip(boxes, islands):
isle.pos.xy = x, y * aspect
return True
return False
def branch_and_bound(can_pack_fn, timeout_seconds=15):
# exhaustive search for minimal number of pages
def result(islands, cage_size):
time_limit = time() + timeout_seconds
# default solution: each island goes to i-th page on position [0, 0]
best = [(i, [0, 0]) for i, _ in enumerate(islands)]
# current solution: first island will definitely go to page 0
path = [0]
while True:
if path[-1] > max(path[:-1], default=0) + 1 or max(path) >= max(i for i, _ in best):
# invalid step
path.pop()
if len(path) <= 1:
break
path[-1] += 1
continue
page = [isle for i, isle in zip(path, islands) if i == path[-1]]
if can_pack_fn(page, cage_size):
# good step
if len(path) == len(islands):
best = [(i, isle.pos.xy) for i, isle in zip(path, islands)]
path.pop()
path[-1] += 1
else:
path.append(0)
else:
# bad step
if time() > time_limit:
break
path[-1] += 1
pages = [list() for _ in range(max(i for i, _ in best) + 1)]
for (i, pos), isle in zip(best, islands):
isle.pos.xy = pos
pages[i].append(isle)
return [Page(i, page) for i, page in enumerate(pages)]
return result
rect_pack_bpy = branch_and_bound(can_pack_bpy)