1# Copyright (c) 2019-2020 Manfred Moitzi
2# License: MIT License
3import pytest
4
5from ezdxf.entities.solid import Solid, Trace, Face3d
6from ezdxf.lldxf.const import DXF12, DXF2000
7from ezdxf.lldxf.tagwriter import TagCollector, basic_tags_from_text
8
9TEST_CLASS = Solid
10TEST_TYPE = 'SOLID'
11
12ENTITY_R12 = """0
13SOLID
145
150
168
170
1810
190.0
2020
210.0
2230
230.0
2411
250.0
2621
270.0
2831
290.0
3012
310.0
3222
330.0
3432
350.0
3613
370.0
3823
390.0
4033
410.0
42"""
43
44ENTITY_R2000 = """0
45SOLID
465
470
48330
490
50100
51AcDbEntity
528
530
54100
55AcDbTrace
5610
570.0
5820
590.0
6030
610.0
6211
630.0
6421
650.0
6631
670.0
6812
690.0
7022
710.0
7232
730.0
7413
750.0
7623
770.0
7833
790.0
80"""
81
82ELEVATION = """0
83SOLID
845
850
868
870
8838
892.0
9010
910.0
9220
930.0
9411
950.0
9621
970.0
9812
990.0
10022
1010.0
10213
1030.0
10423
1050.0
106"""
107
108
109@pytest.fixture(params=[ENTITY_R12, ENTITY_R2000])
110def entity(request):
111    return TEST_CLASS.from_text(request.param)
112
113
114def test_registered():
115    from ezdxf.entities.factory import ENTITY_CLASSES
116    assert TEST_TYPE in ENTITY_CLASSES
117
118
119def test_default_init():
120    entity = TEST_CLASS()
121    assert entity.dxftype() == TEST_TYPE
122
123
124def test_default_new():
125    entity = TEST_CLASS.new(handle='ABBA', owner='0', dxfattribs={
126        'color': '7',
127        'vtx3': (1, 2, 3),
128    })
129    assert entity.dxf.layer == '0'
130    assert entity.dxf.color == 7
131    assert entity.dxf.linetype == 'BYLAYER'
132    assert entity.dxf.vtx3 == (1, 2, 3)
133    assert entity.dxf.vtx3.x == 1, 'is not Vec3 compatible'
134    assert entity.dxf.vtx3.y == 2, 'is not Vec3 compatible'
135    assert entity.dxf.vtx3.z == 3, 'is not Vec3 compatible'
136    # can set DXF R2007 value
137    entity.dxf.shadow_mode = 1
138    assert entity.dxf.shadow_mode == 1
139    assert entity.dxf.extrusion == (0.0, 0.0, 1.0)
140    assert entity.dxf.hasattr('extrusion') is False, 'just the default value'
141
142
143def test_load_from_text(entity):
144    assert entity.dxf.layer == '0'
145    assert entity.dxf.color == 256, 'default color is 256 (by layer)'
146    assert entity.dxf.vtx3 == (0, 0, 0)
147
148
149@pytest.mark.parametrize("txt,ver",
150                         [(ENTITY_R2000, DXF2000), (ENTITY_R12, DXF12)])
151def test_write_dxf(txt, ver):
152    expected = basic_tags_from_text(txt)
153    solid = TEST_CLASS.from_text(txt)
154    collector = TagCollector(dxfversion=ver, optional=True)
155    solid.export_dxf(collector)
156    assert collector.tags == expected
157
158    collector2 = TagCollector(dxfversion=ver, optional=False)
159    solid.export_dxf(collector2)
160    assert collector.has_all_tags(collector2)
161
162
163def test_trace():
164    trace = Trace()
165    trace[0] = (1, 2, 3)
166    trace[1] = (4, 5, 6)
167    trace[2] = (7, 8, 9)
168    trace[3] = (5, 1, 0)
169    assert trace[0] == (1, 2, 3)
170    assert trace[1] == (4, 5, 6)
171    assert trace[2] == (7, 8, 9)
172    assert trace[3] == (5, 1, 0)
173    assert trace.dxf.vtx0 == (1, 2, 3)
174    assert trace.dxf.vtx1 == (4, 5, 6)
175    assert trace.dxf.vtx2 == (7, 8, 9)
176    assert trace.dxf.vtx3 == (5, 1, 0)
177
178    collector = TagCollector(dxfversion=DXF2000)
179    trace.export_dxf(collector)
180    assert collector.tags[0] == (0, 'TRACE')
181    assert collector.tags[5] == (100, 'AcDbTrace')
182
183    # Elevation tag should not be written by default
184    assert any(tag[0] == 38 for tag in collector.tags) is False
185
186
187def test_3dface():
188    face = Face3d()
189    face.dxf.invisible = 2 + 8
190    assert face.is_invisible_edge(0) is False
191    assert face.is_invisible_edge(1) is True
192    assert face.is_invisible_edge(2) is False
193    assert face.is_invisible_edge(3) is True
194
195    face.dxf.invisible = 0
196    face.set_edge_visibility(3, False)
197    assert face.dxf.invisible == 8
198    face.set_edge_visibility(1, False)
199    assert face.dxf.invisible == 10
200    face.set_edge_visibility(3, True)
201    assert face.dxf.invisible == 2
202
203    collector = TagCollector(dxfversion=DXF2000)
204    face.export_dxf(collector)
205    assert collector.tags[0] == (0, '3DFACE')
206    assert collector.tags[5] == (100, 'AcDbFace')
207
208
209def test_solid_translate():
210    solid = Solid()
211    solid.dxf.vtx1 = (3, 3, 0)
212    solid.translate(1, 1, 0)
213    assert solid.dxf.vtx1 == (4, 4, 0)
214
215
216def test_trace_translate():
217    face = Face3d()
218    face.dxf.vtx1 = (3, 3, 0)
219    face.translate(1, 1, 0)
220    assert face.dxf.vtx1 == (4, 4, 0)
221
222
223def test_solid_reorder_quad_ocs_vertices():
224    solid = Solid()
225    for index, vertex in enumerate([(0, 0), (1, 0), (0, 1), (1, 1)]):
226        solid[index] = vertex
227
228    # reorder weird vertex order:
229    assert solid.vertices() == [(0, 0), (1, 0), (1, 1), (0, 1)]
230
231
232def test_solid_triangle_ocs_vertices():
233    solid = Solid()
234    for index, vertex in enumerate([(0, 0), (1, 0), (0, 1), (0, 1)]):
235        solid[index] = vertex
236    assert solid.vertices() == [(0, 0), (1, 0), (0, 1)]
237
238
239def test_solid_close_triangle_ocs_vertices():
240    solid = Solid()
241    for index, vertex in enumerate([(0, 0), (1, 0), (0, 1), (0, 1)]):
242        solid[index] = vertex
243    assert solid.vertices(close=True) == [(0, 0), (1, 0), (0, 1), (0, 0)]
244
245
246def test_solid_close_quad_ocs_vertices():
247    solid = Solid()
248    for index, vertex in enumerate([(0, 0), (1, 0), (1, 1), (0, 1)]):
249        solid[index] = vertex
250    assert solid.vertices(close=True) == [
251        (0, 0), (1, 0), (0, 1), (1, 1), (0, 0)]
252
253
254def test_solid_wcs_vertices():
255    solid = Solid()
256    for index, vertex in enumerate([(0, 0), (1, 0), (0, 1), (1, 1)]):
257        solid[index] = vertex
258    # reorder weird vertex order:
259    assert solid.wcs_vertices() == [(0, 0), (1, 0), (1, 1), (0, 1)]
260
261
262def test_3dface_quad_vertices():
263    face = Face3d()
264    for index, vertex in enumerate([(0, 0), (1, 0), (1, 1), (0, 1)]):
265        face[index] = vertex
266    # no weird vertex order:
267    assert face.wcs_vertices() == [(0, 0), (1, 0), (1, 1), (0, 1)]
268    assert face.wcs_vertices(close=True) == [(0, 0), (1, 0), (1, 1), (0, 1),
269                                             (0, 0)]
270
271
272def test_3dface_triangle_vertices():
273    face = Face3d()
274    for index, vertex in enumerate([(0, 0), (1, 0), (1, 1), (1, 1)]):
275        face[index] = vertex
276    assert face.wcs_vertices() == [(0, 0), (1, 0), (1, 1)]
277    assert face.wcs_vertices(close=True) == [(0, 0), (1, 0), (1, 1), (0, 0)]
278
279
280def test_elevation_group_code_support():
281    solid = Solid.from_text(ELEVATION)
282    # elevation data is copied to z-axis of vertices:
283    assert solid.dxf.hasattr('elevation') is False
284    vertices = solid.vertices()
285    assert vertices[0] == (0, 0, 2)
286
287
288def test_do_not_write_elevation_group_code():
289    solid = Solid.from_text(ELEVATION)
290    collector = TagCollector(dxfversion=DXF12)
291    solid.export_dxf(collector)
292    # Elevation tag should be written:
293    assert any(tag[0] == 38 for tag in collector.tags) is False
294