1#  Copyright (c) 2021, Manfred Moitzi
2#  License: MIT License
3
4import pytest
5from ezdxf.entities.mtext import (
6    load_columns_from_embedded_object, MText, ColumnType, MTextColumns,
7)
8from ezdxf.lldxf import const
9from ezdxf.lldxf.types import EMBEDDED_OBJ_STR, EMBEDDED_OBJ_MARKER
10from ezdxf.lldxf.tags import Tags
11from ezdxf.lldxf.tagwriter import TagCollector
12
13DYNAMIC_MANUAL_HEIGHT = """101
14Embedded Object
1570
161
1710
181.0
1920
200.0
2130
220.0
2311
2469.8
2521
26276.1
2731
280.0
2940
3062.6
3141
320.0
3342
34175.0
3543
36164.8
3771
382
3972
403
4144
4250.0
4345
4412.5
4573
460
4774
480
4946
50164.8
5146
52154.3
5346
540.0
55"""
56
57DYNAMIC_AUTO_HEIGHT = """101
58Embedded Object
5970
601
6110
621.0
6320
640.0
6530
660.0
6711
6869.8
6921
70276.1
7131
720.0
7340
7462.6
7541
76158.1
7742
78175.0
7943
80158.1
8171
822
8372
840
8544
8650.0
8745
8812.5
8973
901
9174
920
93"""
94
95STATIC = """101
96Embedded Object
9770
981
9910
1001.0
10120
1020.0
10330
1040.0
10511
10669.8
10721
108276.1
10931
1100.0
11140
11262.6
11341
114150.0
11542
116175.0
11743
118150.0
11971
1201
12172
1223
12344
12450.0
12545
12612.5
12773
1280
12974
1300
131"""
132
133
134# The dynamic auto height and static types are very similar, the difference is
135# important for CAD applications, but not for the DXF format itself.
136
137
138@pytest.mark.parametrize('obj', [
139    DYNAMIC_MANUAL_HEIGHT,
140    DYNAMIC_AUTO_HEIGHT,
141    STATIC
142], ids=['DYN_MANUAL', 'DYN_AUTO', 'STATIC'])
143def test_load_mtext_attribs_from_embedded_object(obj):
144    embedded_obj = Tags.from_text(obj)
145    dxf = MText().dxf
146    dxf.rotation = 45
147
148    load_columns_from_embedded_object(dxf, embedded_obj)
149    assert dxf.width == 62.6
150    assert dxf.text_direction == (1, 0, 0)
151    assert dxf.hasattr('rotation') is False, "remove rotation attribute"
152    assert dxf.insert == (69.8, 276.1, 0)
153
154
155def test_load_dynamic_cols_manual_height():
156    """ Every column can have a different height. """
157    embedded_obj = Tags.from_text(DYNAMIC_MANUAL_HEIGHT)
158    cols = load_columns_from_embedded_object(MText().dxf, embedded_obj)
159    assert cols.count == 3
160    assert cols.column_type == ColumnType.DYNAMIC
161    assert cols.auto_height is False
162    assert cols.reversed_column_flow is False
163    assert cols.defined_height == 0.0, "not defined if auto_height is False"
164    assert cols.width == 50.0
165    assert cols.gutter_width == 12.5
166    assert cols.total_width == 175.0  # 3 * 50 + 2 * 12.5
167    # total_height = max(heights) even if the last column is the tallest
168    assert cols.total_height == 164.8
169    assert cols.total_height == max(cols.heights)
170    assert len(cols.linked_columns) == 0, "MTEXT is a single entity in R2018"
171    assert len(cols.heights) == 3
172    assert cols.heights[-1] == 0.0, "last column height has to be 0.0"
173    assert cols.heights == [164.8, 154.3, 0.0]
174
175
176def test_load_dynamic_cols_with_auto_height():
177    """ All columns have the same column height. """
178    embedded_obj = Tags.from_text(DYNAMIC_AUTO_HEIGHT)
179    cols = load_columns_from_embedded_object(MText().dxf, embedded_obj)
180    # Count is a calculated value, group code 72 (column height count) is 0!
181    assert cols.count == 3
182    assert cols.column_type == ColumnType.DYNAMIC
183    assert cols.auto_height is True
184    assert cols.reversed_column_flow is False
185    assert cols.defined_height == 158.1, "required if auto_height is True"
186    assert cols.width == 50.0
187    assert cols.gutter_width == 12.5
188    assert cols.total_width == 175.0  # 3 * 50 + 2 * 12.5
189    assert cols.total_height == 158.1
190    assert len(cols.linked_columns) == 0, "MTEXT is a single entity in R2018"
191    assert len(cols.heights) == 0
192
193
194def test_load_static_cols():
195    """ All columns have the same column height. """
196    embedded_obj = Tags.from_text(STATIC)
197    cols = load_columns_from_embedded_object(MText().dxf, embedded_obj)
198    assert cols.count == 3
199    assert cols.column_type == ColumnType.STATIC
200    assert cols.auto_height is False
201    assert cols.reversed_column_flow is False
202    assert cols.defined_height == 150.0, "required for static columns"
203    assert cols.width == 50.0
204    assert cols.gutter_width == 12.5
205    assert cols.total_width == 175.0  # 3 * 50 + 2 * 12.5
206    assert cols.total_height == 150.0
207    assert len(cols.linked_columns) == 0, "MTEXT is a single entity in R2018"
208    assert len(cols.heights) == 0
209
210
211def make_mtext(txt: str):
212    mtext = MText()
213    embedded_obj = Tags.from_text(txt)
214    mtext._columns = load_columns_from_embedded_object(mtext.dxf, embedded_obj)
215    return mtext
216
217
218def test_export_static_columns_as_embedded_object():
219    mtext = make_mtext(STATIC)
220    collector = TagCollector(dxfversion=const.DXF2018)
221    mtext.export_embedded_object(collector)
222    tags = collector.tags
223    assert len(tags) == 18
224    assert tags[0] == (EMBEDDED_OBJ_MARKER, EMBEDDED_OBJ_STR)
225    assert tags[1] == (70, 1)
226    assert tags[2] == (10, 1)
227    assert tags[3] == (20, 0)
228    assert tags[4] == (30, 0)
229    assert tags[5] == (11, 69.8)
230    assert tags[6] == (21, 276.1)
231    assert tags[7] == (31, 0)
232    assert tags[8] == (40, 62.6)
233    assert tags[9] == (41, 150.0)
234    assert tags[10] == (42, 175.0)
235    assert tags[11] == (43, 150.0)
236    assert tags[12] == (71, 1)
237    assert tags[13] == (72, 3)
238    assert tags[14] == (44, 50.0)
239    assert tags[15] == (45, 12.5)
240    assert tags[16] == (73, 0)
241    assert tags[17] == (74, 0)
242
243
244def test_export_dynamic_columns_auto_height_as_embedded_object():
245    mtext = make_mtext(DYNAMIC_AUTO_HEIGHT)
246    collector = TagCollector(dxfversion=const.DXF2018)
247    mtext.export_embedded_object(collector)
248    tags = collector.tags
249    assert len(tags) == 18
250    assert tags[0] == (EMBEDDED_OBJ_MARKER, EMBEDDED_OBJ_STR)
251    assert tags[1] == (70, 1)
252    assert tags[2] == (10, 1)
253    assert tags[3] == (20, 0)
254    assert tags[4] == (30, 0)
255    assert tags[5] == (11, 69.8)
256    assert tags[6] == (21, 276.1)
257    assert tags[7] == (31, 0)
258    assert tags[8] == (40, 62.6)
259    assert tags[9] == (41, 158.1)
260    assert tags[10] == (42, 175.0)
261    assert tags[11] == (43, 158.1)
262    assert tags[12] == (71, 2)
263    assert tags[13] == (72, 0)
264    assert tags[14] == (44, 50.0)
265    assert tags[15] == (45, 12.5)
266    assert tags[16] == (73, 1)
267    assert tags[17] == (74, 0)
268
269
270def test_export_dynamic_columns_manual_height_as_embedded_object():
271    mtext = make_mtext(DYNAMIC_MANUAL_HEIGHT)
272    collector = TagCollector(dxfversion=const.DXF2018)
273    mtext.export_embedded_object(collector)
274    tags = collector.tags
275    assert len(tags) == 21
276    assert tags[0] == (EMBEDDED_OBJ_MARKER, EMBEDDED_OBJ_STR)
277    assert tags[1] == (70, 1)
278    assert tags[2] == (10, 1)
279    assert tags[3] == (20, 0)
280    assert tags[4] == (30, 0)
281    assert tags[5] == (11, 69.8)
282    assert tags[6] == (21, 276.1)
283    assert tags[7] == (31, 0)
284    assert tags[8] == (40, 62.6)
285    assert tags[9] == (41, 0.0)
286    assert tags[10] == (42, 175.0)
287    assert tags[11] == (43, 164.8)
288    assert tags[12] == (71, 2)
289    assert tags[13] == (72, 3)
290    assert tags[14] == (44, 50.0)
291    assert tags[15] == (45, 12.5)
292    assert tags[16] == (73, 0)
293    assert tags[17] == (74, 0)
294    assert tags[18] == (46, 164.8)
295    assert tags[19] == (46, 154.3)
296    assert tags[20] == (46, 0)
297
298
299def new_mtext_with_columns(count=3):
300    columns = MTextColumns()
301    columns.count = count
302    columns.width = 10
303    columns.gutter_width = 0.5
304    columns.defined_height = 50
305    mtext = MText.new()
306    mtext.setup_columns(columns, linked=False)
307    return mtext
308
309
310def test_create_new_mtext_with_columns():
311    mtext = new_mtext_with_columns(3)
312    columns = mtext.columns
313    assert columns.column_type == ColumnType.STATIC
314    assert len(columns.linked_columns) == 0
315    assert len(columns.heights) == 0, "all columns have the same defined height"
316    assert mtext.dxf.width == columns.width
317    assert columns.total_height == columns.defined_height
318    assert columns.total_width == 31
319
320    # default location and text direction:
321    assert mtext.dxf.insert == (0, 0, 0)
322    assert mtext.dxf.text_direction == (1, 0, 0)
323
324
325if __name__ == '__main__':
326    pytest.main([__file__])
327