File: test_429_xclip.py

package info (click to toggle)
ezdxf 1.4.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 104,528 kB
  • sloc: python: 182,341; makefile: 116; lisp: 20; ansic: 4
file content (220 lines) | stat: -rw-r--r-- 7,593 bytes parent folder | download
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
# Copyright (c) 2023, Manfred Moitzi
# License: MIT License
import pytest
import ezdxf
from ezdxf.document import Drawing
from ezdxf.entities import factory, Dictionary, XRecord
from ezdxf import xclip
from ezdxf.math import BoundingBox2d
from ezdxf.entities.acad_xrec_roundtrip import RoundtripXRecord

TEST_BLK = "TEST_BLK"


@pytest.fixture(scope="module")
def doc() -> Drawing:
    _doc = ezdxf.new()
    blk = _doc.blocks.new(TEST_BLK)
    blk.add_line((0, 0), (10, 10))
    return _doc


@pytest.fixture
def clipper(doc: Drawing) -> xclip.XClip:
    msp = doc.modelspace()
    insert = msp.add_blockref(TEST_BLK, (10, 10))
    return xclip.XClip(insert)


def test_new_clipping_path_dxf_structure(doc: Drawing):
    msp = doc.modelspace()
    insert = msp.add_blockref(TEST_BLK, (10, 10))
    clipper = xclip.XClip(insert)
    clipper.set_block_clipping_path([(-1, -1), (2, 2)])

    spatial_filter = clipper.get_spatial_filter()
    assert spatial_filter is not None
    assert factory.is_bound(spatial_filter, doc) is True

    acad_filter_dict = doc.entitydb.get(spatial_filter.dxf.owner)
    assert isinstance(acad_filter_dict, Dictionary)
    assert acad_filter_dict.get("SPATIAL") is spatial_filter

    assert spatial_filter.reactors is not None
    assert acad_filter_dict.dxf.handle in spatial_filter.reactors

    xdict = insert.get_extension_dict()
    assert xdict["ACAD_FILTER"] is acad_filter_dict

    assert spatial_filter in doc.objects


def test_new_clipping_path_geometry(clipper: xclip.XClip):
    clipper.set_block_clipping_path([(-2, -1), (2, -1), (0, 2)])
    clipping_path = clipper.get_block_clipping_path()

    assert len(clipping_path.vertices) == 3
    assert len(clipping_path.inverted_clip) == 0
    assert clipping_path.is_inverted_clip is False


@pytest.mark.parametrize("vertices", [[], [(0, 0)]])
def test_invalid_clipping_path_raises_exception(clipper: xclip.XClip, vertices):
    with pytest.raises(ValueError):
        clipper.set_block_clipping_path(vertices)


def test_rectangular_clipping_path_geometry(clipper: xclip.XClip):
    clipper.set_block_clipping_path([(-1, 2), (2, -1)])
    clipping_path = clipper.get_block_clipping_path()
    # counter-clockwise rectangular boundary path
    p0, p1, p2, p3 = clipping_path.vertices
    assert p0.isclose((-1, -1)) is True
    assert p1.isclose((2, -1)) is True
    assert p2.isclose((2, 2)) is True
    assert p3.isclose((-1, 2)) is True


def test_new_spatial_filter_parmeters(clipper: xclip.XClip):
    clipper.set_block_clipping_path([(-1, -1), (2, 2)])
    assert clipper.is_clipping_enabled is True
    assert clipper.has_clipping_path is True

    spatial_filter = clipper.get_spatial_filter()
    assert spatial_filter.dxf.has_front_clipping_plane == 0
    assert spatial_filter.dxf.front_clipping_plane_distance == 0.0
    assert spatial_filter.dxf.has_back_clipping_plane == 0
    assert spatial_filter.dxf.back_clipping_plane_distance == 0.0
    assert spatial_filter.dxf.origin == (0, 0, 0)
    assert spatial_filter.dxf.extrusion == (0, 0, 1)


def test_enable_clipping_without_path_set(clipper: xclip.XClip):
    clipper.enable_clipping()
    assert clipper.is_clipping_enabled is False
    clipper.disable_clipping()
    assert clipper.is_clipping_enabled is False


def test_toggle_clipping_state(clipper: xclip.XClip):
    clipper.set_block_clipping_path([(0, 0), (1, 1)])
    assert clipper.is_clipping_enabled is True, "clipping path is enabled by default"

    clipper.disable_clipping()
    assert clipper.is_clipping_enabled is False

    clipper.enable_clipping()
    assert clipper.is_clipping_enabled is True


def test_discard_clipping_path(doc: Drawing):
    msp = doc.modelspace()
    insert = msp.add_blockref(TEST_BLK, (10, 10))
    clipper = xclip.XClip(insert)

    clipper.set_block_clipping_path([(0, 0), (1, 1)])
    spatial_filter = clipper.get_spatial_filter()

    clipper.discard_clipping_path()
    assert clipper.has_clipping_path is False
    assert spatial_filter.is_alive is False, "destroy SPATIAL_FILTER entity"
    assert insert.has_extension_dict is True, "do not discard empty extension dict"
    assert spatial_filter not in doc.objects, "removed from objects section"


def test_cleanup_base_entity(clipper: xclip.XClip):
    insert = clipper._insert
    clipper.set_block_clipping_path([(0, 0), (1, 1)])

    clipper.cleanup()
    assert insert.has_extension_dict is True, "do not discard non-empty extension dict"

    clipper.discard_clipping_path()
    assert (
        insert.has_extension_dict is True
    ), "do not discard empty extension dict automatically"

    clipper.cleanup()
    assert insert.has_extension_dict is False, "discard empty extension dict"


def test_get_wcs_clipping_path(doc: Drawing):
    """The clipping path defined in BLOCK coordinates should be transformed to the
    location of the INSERT entity.
    """
    msp = doc.modelspace()
    insert = msp.add_blockref(TEST_BLK, (10, 10))
    clipper = xclip.XClip(insert)

    clipper.set_block_clipping_path([(0, 0), (1, 1)])
    clipping_path = clipper.get_wcs_clipping_path()
    bbox = BoundingBox2d(clipping_path.vertices)
    assert bbox.extmin.isclose((10, 10))
    assert bbox.extmax.isclose((11, 11))


def test_set_wcs_clipping_path(doc: Drawing):
    """The clipping path defined in WCS coordinates should be stored as BLOCK
    coordinates.
    """
    msp = doc.modelspace()
    insert = msp.add_blockref(TEST_BLK, (10, 10))
    clipper = xclip.XClip(insert)

    clipper.set_wcs_clipping_path([(10, 10), (11, 11)])
    clipping_path = clipper.get_block_clipping_path()
    bbox = BoundingBox2d(clipping_path.vertices)
    assert bbox.extmin.isclose((0, 0))
    assert bbox.extmax.isclose((1, 1))


def test_invert_clip_without_clipping_path(clipper: xclip.XClip):
    with pytest.raises(ValueError):
        clipper.invert_clipping_path(ignore_acad_compatibility=True)


def test_cannot_invert_clipping_path_twice(clipper: xclip.XClip):
    clipper.set_block_clipping_path([(2, 2), (8, 8)])
    clipper.invert_clipping_path(ignore_acad_compatibility=True)

    with pytest.raises(ValueError):
        clipper.invert_clipping_path(ignore_acad_compatibility=True)


def test_invert_clipping_path_properties(clipper: xclip.XClip):
    clipper.set_block_clipping_path([(2, 2), (8, 8)])
    clipper.invert_clipping_path(ignore_acad_compatibility=True)

    assert clipper.is_inverted_clip is True
    clipping_path = clipper.get_block_clipping_path()

    assert clipping_path.is_inverted_clip is True
    # the inner clipping path - "The Hole"
    bbox = BoundingBox2d(clipping_path.inverted_clip)
    assert bbox.extmin.isclose((2, 2))
    assert bbox.extmax.isclose((8, 8))

    bbox = BoundingBox2d(clipping_path.vertices)
    # outer boundary is extents of block content + 10%
    # block content = Line((0, 0), (10, 10))
    assert bbox.extmin.isclose((-1, -1))
    assert bbox.extmax.isclose((11, 11))


def test_invert_clipping_path_dxf_structure(clipper: xclip.XClip):
    clipper.set_block_clipping_path([(2, 2), (8, 8)])
    clipper.invert_clipping_path(ignore_acad_compatibility=True)

    spatial_filter = clipper.get_spatial_filter()
    assert spatial_filter is not None
    xdict = spatial_filter.get_extension_dict()
    xrec = xdict["ACAD_XREC_ROUNDTRIP"]
    assert isinstance(xrec, XRecord) is True

    rtr = RoundtripXRecord(xrec)
    assert len(rtr.get_section("ACAD_INVERTEDCLIP_ROUNDTRIP")) == 4
    assert len(rtr.get_section("ACAD_INVERTEDCLIP_ROUNDTRIP_COMPARE")) == 11


if __name__ == "__main__":
    pytest.main([__file__])