-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
/
Copy pathogr_dxf.py
4149 lines (3251 loc) · 427 KB
/
ogr_dxf.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
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
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env pytest
# -*- coding: utf-8 -*-
###############################################################################
#
# Project: GDAL/OGR Test Suite
# Purpose: Test OGR DXF driver functionality.
# Author: Frank Warmerdam <warmerdam@pobox.com>
#
###############################################################################
# Copyright (c) 2009, Frank Warmerdam <warmerdam@pobox.com>
# Copyright (c) 2009-2013, Even Rouault <even dot rouault at spatialys.com>
#
# SPDX-License-Identifier: MIT
###############################################################################
import gdaltest
import ogrtest
import pytest
from osgeo import gdal, ogr, osr
###############################################################################
@pytest.fixture(autouse=True, scope="module")
def module_disable_exceptions():
with gdaltest.disable_exceptions():
yield
pytestmark = pytest.mark.require_driver("DXF")
###############################################################################
# Setup the utf-8 string.
sample_text = 'Text Sample1\u00BF\u03BB\n"abc"'
sample_style = 'Text Sample1\u00BF\u03BB\n\\"abc\\"'
###############################################################################
# Check some general things to see if they meet expectations.
def test_ogr_dxf_1():
ds = ogr.Open("data/dxf/assorted.dxf")
assert ds is not None
assert ds.GetLayerCount() == 1, "expected exactly one layer!"
layer = ds.GetLayer(0)
assert layer.GetName() == "entities", "did not get expected layer name."
assert layer.GetDataset().GetDescription() == ds.GetDescription()
defn = layer.GetLayerDefn()
assert defn.GetFieldCount() == 6, "did not get expected number of fields."
fc = layer.GetFeatureCount()
assert fc == 22, "did not get expected feature count, got %d" % fc
###############################################################################
# Read the first feature, an ellipse and see if it generally meets expectations.
def test_ogr_dxf_2():
ds = ogr.Open("data/dxf/assorted.dxf")
layer = ds.GetLayer(0)
feat = layer.GetNextFeature()
assert feat.Layer == "0", "did not get expected layer for feature 0"
assert feat.PaperSpace == None, "did not get expected PaperSpace for feature 0"
assert feat.GetFID() == 0, "did not get expected fid for feature 0"
assert (
feat.SubClasses == "AcDbEntity:AcDbEllipse"
), "did not get expected SubClasses on feature 0."
assert feat.LineType == "ByLayer", "Did not get expected LineType"
assert feat.EntityHandle == "43", "did not get expected EntityHandle"
if feat.GetStyleString() != "PEN(c:#000000)":
print("%s" % feat.GetStyleString())
pytest.fail("did not get expected style string on feat 0.")
geom = feat.GetGeometryRef()
assert (
geom.GetGeometryType() == ogr.wkbLineString25D
), "did not get expected geometry type."
envelope = geom.GetEnvelope()
area = (envelope[1] - envelope[0]) * (envelope[3] - envelope[2])
exp_area = 1596.12
assert area >= exp_area - 0.5 and area <= exp_area + 0.5, (
"envelope area not as expected, got %g." % area
)
assert geom.GetX(0) == pytest.approx(73.25, abs=0.001) and geom.GetY(
0
) == pytest.approx(
139.75, abs=0.001
), "first point (%g,%g) not expected location." % (
geom.GetX(0),
geom.GetY(0),
)
###############################################################################
# Second feature should be a partial ellipse.
def test_ogr_dxf_3():
ds = ogr.Open("data/dxf/assorted.dxf")
layer = ds.GetLayer(0)
for _ in range(1):
layer.GetNextFeature()
feat = layer.GetNextFeature()
geom = feat.GetGeometryRef()
envelope = geom.GetEnvelope()
area = (envelope[1] - envelope[0]) * (envelope[3] - envelope[2])
exp_area = 311.864
assert area >= exp_area - 0.5 and area <= exp_area + 0.5, (
"envelope area not as expected, got %g." % area
)
assert geom.GetX(0) == pytest.approx(61.133, abs=0.01) and geom.GetY(
0
) == pytest.approx(
103.592, abs=0.01
), "first point (%g,%g) not expected location." % (
geom.GetX(0),
geom.GetY(0),
)
###############################################################################
# Third feature: POINT with RGB true color
def test_ogr_dxf_4():
ds = ogr.Open("data/dxf/assorted.dxf")
layer = ds.GetLayer(0)
for _ in range(2):
layer.GetNextFeature()
feat = layer.GetNextFeature()
ogrtest.check_feature_geometry(feat, "POINT (83.5 160.0 0)")
assert feat.GetStyleString() == "PEN(c:#ffbeb8)", "got wrong color on POINT"
###############################################################################
# Fourth feature: LINE
def test_ogr_dxf_5():
ds = ogr.Open("data/dxf/assorted.dxf")
layer = ds.GetLayer(0)
for _ in range(3):
layer.GetNextFeature()
feat = layer.GetNextFeature()
ogrtest.check_feature_geometry(feat, "LINESTRING (97.0 159.5 0,108.5 132.25 0)")
assert (
feat.GetGeometryRef().GetGeometryType() != ogr.wkbLineString
), "not keeping 3D linestring as 3D"
###############################################################################
# Fourth feature: MTEXT
def test_ogr_dxf_6():
ds = ogr.Open("data/dxf/assorted.dxf")
layer = ds.GetLayer(0)
for _ in range(4):
layer.GetNextFeature()
feat = layer.GetNextFeature()
ogrtest.check_feature_geometry(feat, "POINT (84 126)")
assert (
feat.GetGeometryRef().GetGeometryType() != ogr.wkbPoint25D
), "not keeping 2D text as 2D"
assert (
feat.GetStyleString() == 'LABEL(f:"Arial",t:"Test",a:30,s:5g,p:7,c:#000000)'
), "got wrong style string"
###############################################################################
# Partial CIRCLE
def test_ogr_dxf_7():
ds = ogr.Open("data/dxf/assorted.dxf")
layer = ds.GetLayer(0)
for _ in range(5):
layer.GetNextFeature()
feat = layer.GetNextFeature()
geom = feat.GetGeometryRef()
envelope = geom.GetEnvelope()
area = (envelope[1] - envelope[0]) * (envelope[3] - envelope[2])
exp_area = 445.748
if area < exp_area - 0.5 or area > exp_area + 0.5:
print(envelope)
pytest.fail("envelope area not as expected, got %g." % area)
assert geom.GetX(0) == pytest.approx(115.258, abs=0.01) and geom.GetY(
0
) == pytest.approx(
107.791, abs=0.01
), "first point (%g,%g) not expected location." % (
geom.GetX(0),
geom.GetY(0),
)
###############################################################################
# PaperSpace and dimension
def test_ogr_dxf_8():
ds = ogr.Open("data/dxf/assorted.dxf")
layer = ds.GetLayer(0)
for _ in range(6):
layer.GetNextFeature()
# Check that this line is in PaperSpace
feat = layer.GetNextFeature()
assert feat.GetField("PaperSpace") == 1, "did not get expected PaperSpace"
# Dimension lines
feat = layer.GetNextFeature()
geom = feat.GetGeometryRef()
assert (
geom.GetGeometryType() == ogr.wkbMultiLineString
), "did not get expected geometry type."
ogrtest.check_feature_geometry(
feat,
"MULTILINESTRING ((63.8628719444825 149.209935992088,24.3419606685507 111.934531038653),(72.3255686642474 140.237438265109,63.0051995752285 150.119275371538),(32.8046573883157 102.962033311673,23.4842882992968 112.843870418103))",
)
# Dimension arrowheads
feat = layer.GetNextFeature()
geom = feat.GetGeometryRef()
assert (
geom.GetGeometryType() == ogr.wkbPolygon25D
), "did not get expected geometry type."
ogrtest.check_feature_geometry(
feat,
"POLYGON Z ((61.7583023958313 147.797704380064 0,63.8628719444825 149.209935992088 0,62.3300839753339 147.191478127097 0,61.7583023958313 147.797704380064 0))",
)
feat = layer.GetNextFeature()
geom = feat.GetGeometryRef()
assert (
geom.GetGeometryType() == ogr.wkbPolygon25D
), "did not get expected geometry type."
ogrtest.check_feature_geometry(
feat,
"POLYGON Z ((26.4465302172018 113.346762650677 0,24.3419606685507 111.934531038653 0,25.8747486376992 113.952988903644 0,26.4465302172018 113.346762650677 0))",
)
# Dimension text
feat = layer.GetNextFeature()
geom = feat.GetGeometryRef()
ogrtest.check_feature_geometry(
feat, "POINT (42.815907752635709 131.936242584545397)"
)
expected_style = 'LABEL(f:"Arial",t:"54.33",p:5,a:43.3,s:2.5g,c:#000000)'
assert (
feat.GetStyleString() == expected_style
), "Got unexpected style string:\n%s\ninstead of:\n%s" % (
feat.GetStyleString(),
expected_style,
)
###############################################################################
# BLOCK (inlined)
def test_ogr_dxf_9():
ds = ogr.Open("data/dxf/assorted.dxf")
layer = ds.GetLayer(0)
for _ in range(11):
layer.GetNextFeature()
# Skip two dimensions each with a line, two arrowheads and text.
for _ in range(8):
layer.GetNextFeature()
# block (merged geometries)
feat = layer.GetNextFeature()
geom = feat.GetGeometryRef()
assert (
geom.GetGeometryType() == ogr.wkbMultiLineString25D
), "did not get expected geometry type."
ogrtest.check_feature_geometry(
feat,
"MULTILINESTRING ((79.069506278985116 121.003652476272777 0,79.716898725419625 118.892590150942851 0),(79.716898725419625 118.892590150942851 0,78.140638855839953 120.440702522851453 0),(78.140638855839953 120.440702522851453 0,80.139111190485622 120.328112532167196 0),(80.139111190485622 120.328112532167196 0,78.619146316248077 118.920737648613908 0),(78.619146316248077 118.920737648613908 0,79.041358781314059 120.975504978601705 0))",
)
# First of two MTEXTs
feat = layer.GetNextFeature()
assert feat.GetField("Text") == sample_text, "Did not get expected first mtext."
expected_style = f'LABEL(f:"Arial",t:"{sample_style}",a:45,s:0.5g,p:5,c:#000000)'
assert (
feat.GetStyleString() == expected_style
), "Got unexpected style string:\n%s\ninstead of:\n%s." % (
feat.GetStyleString(),
expected_style,
)
ogrtest.check_feature_geometry(
feat, "POINT (77.602201427662891 120.775897075866169 0)"
)
# Second of two MTEXTs
feat = layer.GetNextFeature()
assert feat.GetField("Text") == "Second", "Did not get expected second mtext."
assert (
feat.GetField("SubClasses") == "AcDbEntity:AcDbMText"
), "Did not get expected subclasses."
ogrtest.check_feature_geometry(
feat, "POINT (79.977331629005178 119.698291706738644 0)"
)
###############################################################################
# LWPOLYLINE in an Object Coordinate System.
def test_ogr_dxf_10():
ocs_ds = ogr.Open("data/dxf/LWPOLYLINE-OCS.dxf")
ocs_lyr = ocs_ds.GetLayer(0)
# Skip boring line.
feat = ocs_lyr.GetNextFeature()
# LWPOLYLINE in OCS
feat = ocs_lyr.GetNextFeature()
geom = feat.GetGeometryRef()
assert (
geom.GetGeometryType() == ogr.wkbLineString25D
), "did not get expected geometry type."
ogrtest.check_feature_geometry(
feat,
"LINESTRING (600325.567999998573214 3153021.253000000491738 562.760000000052969,600255.215999998385087 3151973.98600000096485 536.950000000069849,597873.927999997511506 3152247.628000000491738 602.705000000089058)",
)
# LWPOLYLINE in OCS with bulge
feat = ocs_lyr.GetFeature(12)
ogrtest.check_feature_geometry(
feat,
"LINESTRING Z (611415.459819656 3139300.00002682 1807.37309215522,611245.079665823 3139720.59876424 1807.37309215522,611245.079665823 3139720.59876424 1807.37309215522,611244.054791235 3139723.12875936 1807.27984293229,611243.034695086 3139725.64695847 1807.00053001486,611242.024133533 3139728.14162057 1806.53645568869,611241.027818282 3139730.6011144 1805.88978368251,611240.050394615 3139733.01397265 1805.06352907972,611239.096419732 3139735.36894547 1804.06154426071,611238.170341503 3139737.65505289 1802.88850094122,611237.276477734 3139739.86163602 1801.54986839073,611236.418996029 3139741.97840675 1800.0518879321,611235.601894365 3139743.99549572 1798.40154384175,611234.828982446 3139745.90349832 1796.60653078564,611234.103863944 3139747.69351857 1794.67521794327,611233.429919697 3139749.35721058 1792.61660998662,611232.810291944 3139750.88681743 1790.44030509629,611232.247869676 3139752.27520739 1788.15645021029,611231.745275164 3139753.51590716 1785.77569371438,611231.304851737 3139754.60313201 1783.30913579435,611230.928652852 3139755.5318128 1780.76827668182,611230.618432521 3139756.29761959 1778.16496303489,611230.375637135 3139756.89698184 1775.51133270351,611230.201398719 3139757.32710505 1772.81975813727,611230.096529651 3139757.58598378 1770.10278869926,611230.06151888 3139757.67241101 1767.37309215522,611230.06151892 3139757.67241089 1661.18408370228,611230.06151892 3139757.67241089 1661.18408370228,611230.026508154 3139757.75883812 1658.45438717061,611229.921639091 3139758.01771683 1655.73741774404,611229.74740068 3139758.44784002 1653.04584318824,611229.5046053 3139759.04720226 1650.39221286628,611229.194384975 3139759.81300904 1647.78889922769,611228.818186096 3139760.74168982 1645.24804012238,611228.377762675 3139761.82891465 1642.78148220841,611227.87516817 3139763.0696144 1640.40072571739,611227.312745909 3139764.45800435 1638.11687083509,611226.693118163 3139765.98761118 1635.94056594722,611226.019173923 3139767.65130317 1633.88195799181,611225.294055428 3139769.4413234 1631.95064514943,611224.521143516 3139771.34932599 1630.15563209209,611223.704041858 3139773.36641494 1628.50528799927,611222.84656016 3139775.48318565 1627.00730753696,611221.952696397 3139777.68976876 1625.66867498157,611221.026618175 3139779.97587617 1624.49563165602,611220.072643298 3139782.33084897 1623.49364682979,611219.095219637 3139784.74370721 1622.66739221866,611218.098904392 3139787.20320102 1622.02072020306,611217.088342845 3139789.69786311 1621.55664586644,"
+ "611216.0682467 3139792.21606221 1621.27733293758,611215.043372117 3139794.74605732 1621.18408370228,610905.973331759 3140557.71325641 1621.18408370228,610905.973331759 3140557.71325641 1621.18408370228,610904.948457176 3140560.24325151 1621.2773329396,610903.928361033 3140562.76145061 1621.55664587034,610902.917799487 3140565.2561127 1622.02072020868,610901.921484243 3140567.71560651 1622.66739222582,610900.944060583 3140570.12846474 1623.49364683831,610899.990085707 3140572.48343755 1624.49563166573,610899.064007486 3140574.76954495 1625.66867499227,610898.170143725 3140576.97612806 1627.00730754846,610897.312662028 3140579.09289877 1628.50528801138,610896.495560372 3140581.10998771 1630.1556321046,610895.722648461 3140583.0179903 1631.95064516215,610894.997529967 3140584.80801053 1633.88195800453,610894.323585729 3140586.47170251 1635.94056595974,610893.703957984 3140588.00130935 1638.1168708472,610893.141535724 3140589.38969929 1640.4007257289,610892.63894122 3140590.63039904 1642.78148221912,610892.198517801 3140591.71762387 1645.2480401321,610891.822318923 3140592.64630464 1647.78889923622,610891.5120986 3140593.41211142 1650.39221287345,610891.269303221 3140594.01147366 1653.04584319386,610891.095064811 3140594.44159685 1655.73741774794,610890.99019575 3140594.70047556 1658.45438717264,610890.955184986 3140594.78690278 1661.18408370228,610890.955185021 3140594.78690272 1752.31638281001,610890.955185021 3140594.78690271 1752.31638281001,610890.920174252 3140594.87332995 1755.04607934987,610890.815305187 3140595.13220867 1757.76304878401,610890.641066773 3140595.56233187 1760.45462334672,610890.398271389 3140596.16169412 1763.10825367492,610890.088051061 3140596.92750091 1765.71156731903,610889.711852178 3140597.85618169 1768.25242642912,610889.271428753 3140598.94340654 1770.71898434711,610888.768834244 3140600.1841063 1773.09974084137,610888.206411978 3140601.57249626 1775.38359572612,610887.586784228 3140603.1021031 1777.55990061562,610886.912839984 3140604.7657951 1779.61850857185,610886.187721485 3140606.55581535 1781.54982141423,610885.414809569 3140608.46381795 1783.34483447076,610884.597707907 3140610.48090691 1784.99517856195,610883.740226205 3140612.59767763 1786.49315902182,610882.846362438 3140614.80426075 1787.83179157397,610881.920284211 3140617.09036817 1789.0048348955,610880.96630933 3140619.44534098 1790.00681971696,610879.988885665 3140621.85819923 1790.83307432256,610878.992570417 3140624.31769305 1791.47974633192,610877.982008866 3140626.81235515 1791.94382066162,610876.961912718 3140629.33055426 1792.22313358291,610875.937038132 3140631.86054938 1792.31638281001,610699.99993399 3141066.17711854 1792.31638281001)",
)
ocs_lyr = None
ocs_ds = None
###############################################################################
# Test reading from an entities-only dxf file (#3412)
def test_ogr_dxf_11():
eo_ds = ogr.Open("data/dxf/entities_only.dxf")
eo_lyr = eo_ds.GetLayer(0)
# Check first point.
feat = eo_lyr.GetNextFeature()
ogrtest.check_feature_geometry(feat, "POINT (672500.0 242000.0 539.986)")
# Check second point.
feat = eo_lyr.GetNextFeature()
ogrtest.check_feature_geometry(feat, "POINT (672750.0 242000.0 558.974)")
eo_lyr = None
eo_ds = None
###############################################################################
# Write a simple file with a few geometries of different types, and read back.
def test_ogr_dxf_12(tmp_path):
ds = ogr.GetDriverByName("DXF").CreateDataSource(tmp_path / "dxf_11.dxf")
lyr = ds.CreateLayer("entities")
assert lyr.GetDataset().GetDescription() == ds.GetDescription()
dst_feat = ogr.Feature(feature_def=lyr.GetLayerDefn())
dst_feat.SetGeometryDirectly(ogr.CreateGeometryFromWkt("LINESTRING(10 12, 60 65)"))
dst_feat.SetFID(0)
lyr.CreateFeature(dst_feat)
# 80 is the minimum handle value we set in case of inapproriate or unset
# initial FID value
assert dst_feat.GetFID() >= 80
dst_feat = None
dst_feat = ogr.Feature(feature_def=lyr.GetLayerDefn())
dst_feat.SetGeometryDirectly(
ogr.CreateGeometryFromWkt("POLYGON((0 0,100 0,100 100,0 0))")
)
dst_feat.SetFID(79)
lyr.CreateFeature(dst_feat)
assert dst_feat.GetFID() == 79
dst_feat = None
# Test 25D linestring with constant Z (#5210)
dst_feat = ogr.Feature(feature_def=lyr.GetLayerDefn())
dst_feat.SetGeometryDirectly(ogr.CreateGeometryFromWkt("LINESTRING(1 2 10,3 4 10)"))
dst_feat.SetFID(79)
lyr.CreateFeature(dst_feat)
assert dst_feat.GetFID() > 79
dst_feat = None
# Test 25D linestring with different Z (#5210)
dst_feat = ogr.Feature(feature_def=lyr.GetLayerDefn())
dst_feat.SetGeometryDirectly(
ogr.CreateGeometryFromWkt("LINESTRING(1 2 -10,3 4 10)")
)
lyr.CreateFeature(dst_feat)
dst_feat = None
# Test multipoint
dst_feat = ogr.Feature(feature_def=lyr.GetLayerDefn())
dst_feat.SetGeometryDirectly(
ogr.CreateGeometryFromWkt("MULTIPOINT((10 40),(40 30))")
)
lyr.CreateFeature(dst_feat)
dst_feat = None
lyr = None
ds = None
# Read back.
ds = ogr.Open(tmp_path / "dxf_11.dxf")
lyr = ds.GetLayer(0)
# Check first feature
feat = lyr.GetNextFeature()
ogrtest.check_feature_geometry(
feat, "LINESTRING(10 12, 60 65)"
), feat.GetGeometryRef().ExportToWkt()
assert (
feat.GetGeometryRef().GetGeometryType() == ogr.wkbLineString
), "not linestring 2D"
feat = None
# Check second feature
feat = lyr.GetNextFeature()
ogrtest.check_feature_geometry(
feat, "POLYGON((0 0,100 0,100 100,0 0))"
), feat.GetGeometryRef().ExportToWkt()
assert (
feat.GetGeometryRef().GetGeometryType() == ogr.wkbPolygon
), "not keeping polygon 2D"
feat = None
# Check third feature
feat = lyr.GetNextFeature()
ogrtest.check_feature_geometry(
feat, "LINESTRING(1 2 10,3 4 10)"
), feat.GetGeometryRef().ExportToWkt()
feat = None
# Check fourth feature
feat = lyr.GetNextFeature()
ogrtest.check_feature_geometry(
feat, "LINESTRING(1 2 -10,3 4 10)"
), feat.GetGeometryRef().ExportToWkt()
feat = None
# Check 5th feature (1st multipoint part)
feat = lyr.GetNextFeature()
ogrtest.check_feature_geometry(
feat, "POINT(10 40)"
), feat.GetGeometryRef().ExportToWkt()
feat = None
# Check 6th feature (2nd multipoint part)
feat = lyr.GetNextFeature()
ogrtest.check_feature_geometry(
feat, "POINT(40 30)"
), feat.GetGeometryRef().ExportToWkt()
feat = None
lyr = None
ds = None
###############################################################################
# Check smoothed polyline.
def test_ogr_dxf_13():
ds = ogr.Open("data/dxf/polyline_smooth.dxf")
layer = ds.GetLayer(0)
feat = layer.GetNextFeature()
assert feat.Layer == "1", "did not get expected layer for feature 0"
geom = feat.GetGeometryRef()
assert (
geom.GetGeometryType() == ogr.wkbLineString25D
), "did not get expected geometry type."
envelope = geom.GetEnvelope()
area = (envelope[1] - envelope[0]) * (envelope[3] - envelope[2])
exp_area = 1350.43
assert area >= exp_area - 0.5 and area <= exp_area + 0.5, (
"envelope area not as expected, got %g." % area
)
# Check for specific number of points from tessellated arc(s).
# Note that this number depends on the tessellation algorithm and
# possibly the default global arc_stepsize variable; therefore it is
# not guaranteed to remain constant even if the input DXF file is constant.
# If you retain this test, you may need to update the point count if
# changes are made to the aforementioned items. Ideally, one would test
# only that more points are returned than in the original polyline, and
# that the points lie along (or reasonably close to) said path.
assert geom.GetPointCount() == 146, (
"did not get expected number of points, got %d" % geom.GetPointCount()
)
assert geom.GetX(0) == pytest.approx(251297.8179, abs=0.001) and geom.GetY(
0
) == pytest.approx(
412226.8286, abs=0.001
), "first point (%g,%g) not expected location." % (
geom.GetX(0),
geom.GetY(0),
)
# Other possible tests:
# Polylines with no explicit Z coordinates (e.g., no attribute 38 for
# LWPOLYLINE and no attribute 30 for POLYLINE) should always return
# geometry type ogr.wkbPolygon. Otherwise, ogr.wkbPolygon25D should be
# returned even if the Z coordinate values are zero.
# If the arc_stepsize global is used, one could test that returned adjacent
# points do not slope-diverge greater than that value.
ds = None
###############################################################################
# Check smooth LWPOLYLINE entity.
def test_ogr_dxf_14():
# This test is identical to the previous one except the
# newer lwpolyline entity is used. See the comments in the
# previous test regarding caveats, etc.
ds = ogr.Open("data/dxf/lwpolyline_smooth.dxf")
layer = ds.GetLayer(0)
feat = layer.GetNextFeature()
assert feat.Layer == "1", "did not get expected layer for feature 0"
geom = feat.GetGeometryRef()
assert (
geom.GetGeometryType() == ogr.wkbLineString
), "did not get expected geometry type."
envelope = geom.GetEnvelope()
area = (envelope[1] - envelope[0]) * (envelope[3] - envelope[2])
exp_area = 1350.43
assert area >= exp_area - 0.5 and area <= exp_area + 0.5, (
"envelope area not as expected, got %g." % area
)
assert geom.GetPointCount() == 146, (
"did not get expected number of points, got %d" % geom.GetPointCount()
)
assert geom.GetX(0) == pytest.approx(251297.8179, abs=0.001) and geom.GetY(
0
) == pytest.approx(
412226.8286, abs=0.001
), "first point (%g,%g) not expected location." % (
geom.GetX(0),
geom.GetY(0),
)
ds = None
###############################################################################
# Write a file with dynamic layer creation and confirm that the
# dynamically created layer 'abc' matches the definition of the default
# layer '0'.
def test_ogr_dxf_15(tmp_path):
ds = ogr.GetDriverByName("DXF").CreateDataSource(
tmp_path / "dxf_14.dxf", ["FIRST_ENTITY=80"]
)
lyr = ds.CreateLayer("entities")
dst_feat = ogr.Feature(feature_def=lyr.GetLayerDefn())
dst_feat.SetGeometryDirectly(ogr.CreateGeometryFromWkt("LINESTRING(10 12, 60 65)"))
dst_feat.SetField("Layer", "abc")
lyr.CreateFeature(dst_feat)
dst_feat = ogr.Feature(feature_def=lyr.GetLayerDefn())
dst_feat.SetGeometryDirectly(
ogr.CreateGeometryFromWkt("POLYGON((0 0,100 0,100 100,0 0))")
)
lyr.CreateFeature(dst_feat)
lyr = None
ds = None
# Read back.
ds = ogr.Open(tmp_path / "dxf_14.dxf")
lyr = ds.GetLayer(0)
# Check first feature
feat = lyr.GetNextFeature()
ogrtest.check_feature_geometry(
feat, "LINESTRING(10 12, 60 65)"
), feat.GetGeometryRef().ExportToWkt()
assert (
feat.GetGeometryRef().GetGeometryType() != ogr.wkbLineString25D
), "not linestring 2D"
assert feat.GetField("Layer") == "abc", "Did not get expected layer, abc."
# Check second point.
feat = lyr.GetNextFeature()
ogrtest.check_feature_geometry(
feat, "POLYGON((0 0,100 0,100 100,0 0))"
), feat.GetGeometryRef().ExportToWkt()
assert (
feat.GetGeometryRef().GetGeometryType() != ogr.wkbPolygon25D
), "not keeping polygon 2D"
assert feat.GetField("Layer") == "0", "Did not get expected layer, 0."
lyr = None
ds = None
# Check the DXF file itself to try and ensure that the layer
# is defined essentially as we expect. We assume the only thing
# that will be different is the layer name is 'abc' instead of '0'
# and the entity id.
outdxf = open(tmp_path / "dxf_14.dxf").read()
start_1 = outdxf.find(" 0\nLAYER")
start_2 = outdxf.find(" 0\nLAYER", start_1 + 10)
txt_1 = outdxf[start_1:start_2]
txt_2 = outdxf[start_2 : start_2 + len(txt_1) + 2]
abc_off = txt_2.find("abc\n")
assert (
txt_2[16:abc_off] + "0" + txt_2[abc_off + 3 :] == txt_1[16:]
), "Layer abc does not seem to match layer 0."
# Check that $HANDSEED was set as expected.
start_seed = outdxf.find("$HANDSEED")
handseed = outdxf[start_seed + 10 + 4 : start_seed + 10 + 4 + 8]
assert handseed == "00000053", "Did not get expected HANDSEED, got %s." % handseed
###############################################################################
# Test reading without DXF blocks inlined.
def test_ogr_dxf_16():
with gdal.config_option("DXF_INLINE_BLOCKS", "FALSE"):
dxf_ds = ogr.Open("data/dxf/assorted.dxf")
assert dxf_ds is not None
assert dxf_ds.GetLayerCount() == 2, "expected exactly two layers!"
dxf_layer = dxf_ds.GetLayer(1)
assert dxf_layer.GetName() == "entities", "did not get expected layer name."
# read through till we encounter the block reference.
feat = dxf_layer.GetNextFeature()
while feat.GetField("EntityHandle") != "55":
feat = dxf_layer.GetNextFeature()
# check contents.
assert feat.GetField("BlockName") == "STAR", "Did not get blockname!"
assert feat.GetField("BlockAngle") == 0.0, "Did not get expected angle."
assert feat.GetField("BlockScale") == [
1.0,
1.0,
1.0,
], "Did not get expected BlockScale"
ogrtest.check_feature_geometry(
feat, "POINT (79.097653776656188 119.962195062443342 0)"
)
feat = None
# Now we need to check the blocks layer and ensure it is as expected.
dxf_layer = dxf_ds.GetLayer(0)
assert dxf_layer.GetName() == "blocks", "did not get expected layer name."
# STAR geometry
feat = dxf_layer.GetNextFeature()
assert feat.GetField("Block") == "STAR", "Did not get expected block name."
ogrtest.check_feature_geometry(
feat,
"MULTILINESTRING ((-0.028147497671066 1.041457413829428 0,0.619244948763444 -1.069604911500494 0),(0.619244948763444 -1.069604911500494 0,-0.957014920816232 0.478507460408116 0),(-0.957014920816232 0.478507460408116 0,1.041457413829428 0.365917469723853 0),(1.041457413829428 0.365917469723853 0,-0.478507460408116 -1.041457413829428 0),(-0.478507460408116 -1.041457413829428 0,-0.056294995342131 1.013309916158363 0))",
)
# First MTEXT
feat = dxf_layer.GetNextFeature()
assert feat.GetField("Text") == sample_text, "Did not get expected first mtext."
expected_style = (
f'LABEL(f:"Arial",t:"{sample_style}",a:45,s:0.5g,p:5,c:#000000)'
)
assert (
feat.GetStyleString() == expected_style
), "Got unexpected style string:\n%s\ninstead of:\n%s." % (
feat.GetStyleString(),
expected_style,
)
ogrtest.check_feature_geometry(
feat, "POINT (-1.495452348993292 0.813702013422821 0)"
)
# Second MTEXT
feat = dxf_layer.GetNextFeature()
assert feat.GetField("Text") == "Second", "Did not get expected second mtext."
assert (
feat.GetField("SubClasses") == "AcDbEntity:AcDbMText"
), "Did not get expected subclasses."
ogrtest.check_feature_geometry(
feat, "POINT (0.879677852348995 -0.263903355704699 0)"
)
feat = None
###############################################################################
# Write a file with blocks defined from a source blocks layer.
def test_ogr_dxf_17(tmp_path):
ds = ogr.GetDriverByName("DXF").CreateDataSource(
tmp_path / "dxf_17.dxf", ["HEADER=data/dxf/header_extended.dxf"]
)
blyr = ds.CreateLayer("blocks")
lyr = ds.CreateLayer("entities")
dst_feat = ogr.Feature(feature_def=blyr.GetLayerDefn())
dst_feat.SetGeometryDirectly(
ogr.CreateGeometryFromWkt(
"GEOMETRYCOLLECTION( LINESTRING(0 0,1 1),LINESTRING(1 0,0 1))"
)
)
dst_feat.SetField("Block", "XMark")
blyr.CreateFeature(dst_feat)
# Block with 2 polygons
dst_feat = ogr.Feature(feature_def=blyr.GetLayerDefn())
dst_feat.SetGeometryDirectly(
ogr.CreateGeometryFromWkt(
"GEOMETRYCOLLECTION( POLYGON((10 10,10 20,20 20,20 10,10 10)),POLYGON((10 -10,10 -20,20 -20,20 -10,10 -10)))"
)
)
dst_feat.SetField("Block", "Block2")
blyr.CreateFeature(dst_feat)
# Block with point and line
dst_feat = ogr.Feature(feature_def=blyr.GetLayerDefn())
dst_feat.SetGeometryDirectly(
ogr.CreateGeometryFromWkt("GEOMETRYCOLLECTION( POINT(1 2),LINESTRING(0 0,1 1))")
)
dst_feat.SetField("Block", "Block3")
blyr.CreateFeature(dst_feat)
# Write a block reference feature.
dst_feat = ogr.Feature(feature_def=lyr.GetLayerDefn())
dst_feat.SetGeometryDirectly(ogr.CreateGeometryFromWkt("POINT(200 100)"))
dst_feat.SetField("Layer", "abc")
dst_feat.SetField("BlockName", "XMark")
lyr.CreateFeature(dst_feat)
# Write a block reference feature for a non-existent block.
dst_feat = ogr.Feature(feature_def=lyr.GetLayerDefn())
dst_feat.SetGeometryDirectly(ogr.CreateGeometryFromWkt("POINT(300 50)"))
dst_feat.SetField("Layer", "abc")
dst_feat.SetField("BlockName", "DoesNotExist")
lyr.CreateFeature(dst_feat)
# Write a block reference feature for a template defined block
dst_feat = ogr.Feature(feature_def=lyr.GetLayerDefn())
dst_feat.SetGeometryDirectly(ogr.CreateGeometryFromWkt("POINT(250 200)"))
dst_feat.SetField("Layer", "abc")
dst_feat.SetField("BlockName", "STAR")
lyr.CreateFeature(dst_feat)
# Write a block reference feature with scaling and rotation
dst_feat = ogr.Feature(feature_def=lyr.GetLayerDefn())
dst_feat.SetGeometryDirectly(ogr.CreateGeometryFromWkt("POINT(300 100)"))
dst_feat.SetField("BlockName", "XMark")
dst_feat.SetField("BlockAngle", "30")
dst_feat.SetFieldDoubleList(
lyr.GetLayerDefn().GetFieldIndex("BlockScale"), [4.0, 5.0, 6.0]
)
lyr.CreateFeature(dst_feat)
# Write a Block2 reference feature.
dst_feat = ogr.Feature(feature_def=lyr.GetLayerDefn())
dst_feat.SetGeometryDirectly(ogr.CreateGeometryFromWkt("POINT(350 100)"))
dst_feat.SetField("Layer", "abc")
dst_feat.SetField("BlockName", "Block2")
lyr.CreateFeature(dst_feat)
# Write a Block3 reference feature.
dst_feat = ogr.Feature(feature_def=lyr.GetLayerDefn())
dst_feat.SetGeometryDirectly(ogr.CreateGeometryFromWkt("POINT(400 100)"))
dst_feat.SetField("Layer", "abc")
dst_feat.SetField("BlockName", "Block3")
lyr.CreateFeature(dst_feat)
ds = None
# Reopen and check contents.
ds = ogr.Open(tmp_path / "dxf_17.dxf")
lyr = ds.GetLayer(0)
# Check first feature.
feat = lyr.GetNextFeature()
assert (
feat.GetField("SubClasses") == "AcDbEntity:AcDbBlockReference"
), "Got wrong subclasses for feature 1."
ogrtest.check_feature_geometry(
feat, "MULTILINESTRING ((200 100,201 101),(201 100,200 101))"
), "Feature 1"
# Check 2nd feature.
feat = lyr.GetNextFeature()
assert (
feat.GetField("SubClasses") == "AcDbEntity:AcDbPoint"
), "Got wrong subclasses for feature 2."
ogrtest.check_feature_geometry(feat, "POINT (300 50)"), "Feature 2"
# Check 3rd feature.
feat = lyr.GetNextFeature()
assert (
feat.GetField("SubClasses") == "AcDbEntity:AcDbBlockReference"
), "Got wrong subclasses for feature 3."
ogrtest.check_feature_geometry(
feat,
"MULTILINESTRING ((249.971852502328943 201.04145741382942 0,250.619244948763452 198.930395088499495 0),(250.619244948763452 198.930395088499495 0,249.042985079183779 200.47850746040811 0),(249.042985079183779 200.47850746040811 0,251.04145741382942 200.365917469723854 0),(251.04145741382942 200.365917469723854 0,249.52149253959189 198.95854258617058 0),(249.52149253959189 198.95854258617058 0,249.943705004657858 201.013309916158363 0))",
), "Feature 3"
# Check 4th feature (scaled and rotated)
feat = lyr.GetNextFeature()
assert (
feat.GetField("SubClasses") == "AcDbEntity:AcDbBlockReference"
), "Got wrong subclasses for feature 4."
ogrtest.check_feature_geometry(
feat,
"MULTILINESTRING ((300 100,300.964101615137736 106.330127018922198), (303.464101615137736 102.0,297.5 104.330127018922198))",
), "Feature 4"
# Check 5th feature
feat = lyr.GetNextFeature()
ogrtest.check_feature_geometry(
feat,
"MULTIPOLYGON (((360 110,360 120,370 120,370 110,360 110)),((360 90,360 80,370 80,370 90,360 90)))",
), "Feature 5"
# Check 6th feature
feat = lyr.GetNextFeature()
ogrtest.check_feature_geometry(
feat, "GEOMETRYCOLLECTION (POINT (401 102),LINESTRING (400 100,401 101))"
), "Feature 5"
# Cleanup
lyr = None
ds = None
###############################################################################
# Write a file with line patterns, and make sure corresponding Linetypes are
# created.
def test_ogr_dxf_18(tmp_path):
ds = ogr.GetDriverByName("DXF").CreateDataSource(
tmp_path / "dxf_18.dxf", ["HEADER=data/dxf/header_extended.dxf"]
)
lyr = ds.CreateLayer("entities")
# Write a feature with a predefined LTYPE in the header.
dst_feat = ogr.Feature(feature_def=lyr.GetLayerDefn())
dst_feat.SetGeometryDirectly(ogr.CreateGeometryFromWkt("LINESTRING(0 0,25 25)"))
dst_feat.SetField("Linetype", "DASHED")
dst_feat.SetStyleString('PEN(c:#ffff00,w:2g,p:"12.0g 6.0g")')
lyr.CreateFeature(dst_feat)
# Write a feature with a named linetype but that isn't predefined in the header.
dst_feat = ogr.Feature(feature_def=lyr.GetLayerDefn())
dst_feat.SetGeometryDirectly(ogr.CreateGeometryFromWkt("LINESTRING(5 5,30 30)"))