1#  Copyright (c) 2020, Manfred Moitzi
2#  License: MIT License
3
4import pytest
5from ezdxf.render.forms import square, translate
6from ezdxf.path import Path, nesting, from_vertices
7
8EXTERIOR = list(translate(square(10), (-5, -5)))
9EXT1_PATH = from_vertices(EXTERIOR)
10EXT2_PATH = from_vertices(translate(EXTERIOR, (11, 0)))
11
12CENTER_HOLE1 = list(translate(square(8), (-4, -4)))
13CH1_PATH = from_vertices(CENTER_HOLE1)
14
15CENTER_HOLE2 = list(translate(square(6), (-3, -3)))
16CH2_PATH = from_vertices(CENTER_HOLE2)
17
18LEFT_HOLE = list(translate(square(2.1), (-3, -1)))
19LH_PATH = from_vertices(LEFT_HOLE)
20
21RIGHT_HOLE = list(translate(square(2.0), (3, -1)))
22RH_PATH = from_vertices(RIGHT_HOLE)
23
24DETECTION_DATA = [
25    pytest.param(
26        # Each polygon is a list of paths
27        [EXT1_PATH], [[EXT1_PATH]],
28        id='1 path'),
29    pytest.param(
30        # returns the path sorted by area, and reversed if equal sized
31        [EXT1_PATH, EXT2_PATH], [[EXT2_PATH], [EXT1_PATH]],
32        id='2 separated paths'),
33    pytest.param(
34        [CH1_PATH, EXT1_PATH], [[EXT1_PATH, [CH1_PATH]]],
35        id='1 nested sub-path'),
36    pytest.param(
37        [CH1_PATH, EXT1_PATH, CH2_PATH], [[EXT1_PATH, [CH1_PATH, [CH2_PATH]]]],
38        id='2 nested sub-path'),
39    pytest.param(
40        [RH_PATH, LH_PATH, EXT1_PATH], [[EXT1_PATH, [LH_PATH], [RH_PATH]]],
41        id='2 separated sub-paths'),
42]
43
44
45@pytest.mark.parametrize('paths,polygons', DETECTION_DATA)
46def test_fast_bbox_detection(paths, polygons):
47    assert nesting.fast_bbox_detection(paths) == polygons
48
49
50@pytest.mark.parametrize('polygons,exp_ccw,exp_cw', [
51    pytest.param(
52        [[EXT1_PATH]],
53        [EXT1_PATH],  # ccw paths
54        [],  # cw paths
55        id='1 polygon'),
56    pytest.param(
57        [[EXT1_PATH], [EXT1_PATH]],
58        [EXT1_PATH, EXT1_PATH],  # ccw paths
59        [],  # cw paths
60        id='2 polygons'),
61    pytest.param(
62        [[EXT1_PATH, [CH1_PATH]]],
63        [EXT1_PATH],  # ccw paths
64        [CH1_PATH],  # cw paths
65        id='1 polygon 1 nested sub-polygon'),
66    pytest.param(
67        [[EXT1_PATH, [CH1_PATH, [CH1_PATH]]]],
68        [EXT1_PATH, CH1_PATH],  # ccw paths
69        [CH1_PATH],  # cw paths
70        id='1 polygon 2 nested sub-polygons'
71    ),
72    pytest.param(
73        [[EXT1_PATH, [CH1_PATH], [CH1_PATH]]],
74        [EXT1_PATH],  # ccw paths
75        [CH1_PATH, CH1_PATH],  # cw paths
76        id='1 polygon 2 separated sub-polygons'
77    ),
78])
79def test_winding_deconstruction(polygons, exp_ccw, exp_cw):
80    ccw, cw = nesting.winding_deconstruction(polygons)
81    assert ccw == exp_ccw
82    assert cw == exp_cw
83
84
85@pytest.mark.parametrize('polygons,n', [
86    pytest.param(
87        [[EXT1_PATH]], 1,
88        id='1 polygon'),
89    pytest.param(
90        [[EXT1_PATH], [EXT1_PATH]], 2,
91        id='2 polygons'),
92    pytest.param(
93        [[EXT1_PATH, [CH1_PATH]]], 2,
94        id='1 polygon 1 nested sub-polygon'),
95    pytest.param(
96        [[EXT1_PATH, [CH1_PATH, [CH1_PATH]]]], 3,
97        id='1 polygon 2 nested sub-polygons'
98    ),
99    pytest.param(
100        [[EXT1_PATH, [CH1_PATH], [CH1_PATH]]], 3,
101        id='1 polygon 2 separated sub-polygons'
102    ),
103    pytest.param(
104        [[EXT1_PATH, [CH1_PATH, [CH2_PATH]], [CH1_PATH, [CH2_PATH]]]], 5,
105        id='1 polygon 2 separated nested sub-polygons'
106    ),
107])
108def test_flatten_polygons(polygons, n):
109    nlists = 0
110    npaths = 0
111    for path in list(nesting.flatten_polygons(polygons)):
112        if isinstance(path, Path):
113            npaths += 1
114        elif isinstance(path, list):
115            nlists += 1
116        else:
117            raise TypeError('?')
118
119    assert nlists == 0
120    assert npaths == n
121
122
123if __name__ == '__main__':
124    pytest.main([__file__])
125