Coverage Report

Created: 2026-05-16 08:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/dxf/ogrdxf_hatch.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  DXF Translator
4
 * Purpose:  Implements translation support for HATCH elements as part
5
 *           of the OGRDXFLayer class.
6
 * Author:   Frank Warmerdam, warmerdam@pobox.com
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 2010, Frank Warmerdam <warmerdam@pobox.com>
10
 * Copyright (c) 2011-2013, Even Rouault <even dot rouault at spatialys.com>
11
 * Copyright (c) 2017, Alan Thomas <alant@outlook.com.au>
12
 *
13
 * SPDX-License-Identifier: MIT
14
 ****************************************************************************/
15
16
#include "ogr_dxf.h"
17
#include "cpl_conv.h"
18
#include "ogr_api.h"
19
20
#include <algorithm>
21
#include <cmath>
22
#include "ogrdxf_polyline_smooth.h"
23
24
/************************************************************************/
25
/*                           TranslateHATCH()                           */
26
/*                                                                      */
27
/*      We mostly just try to convert hatch objects as polygons or      */
28
/*      multipolygons representing the hatched area.  It is hard to     */
29
/*      preserve the actual details of the hatching.                    */
30
/************************************************************************/
31
32
OGRDXFFeature *OGRDXFLayer::TranslateHATCH()
33
34
101k
{
35
101k
    char szLineBuf[257];
36
101k
    int nCode = 0;
37
101k
    OGRDXFFeature *poFeature = new OGRDXFFeature(poFeatureDefn);
38
39
101k
    double dfElevation = 0.0;  // Z value to be used for EVERY point
40
101k
    OGRGeometryCollection oGC;
41
101k
    std::string osExtendedData;
42
43
3.50M
    while ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) > 0)
44
3.39M
    {
45
3.39M
        switch (nCode)
46
3.39M
        {
47
100k
            case 30:
48
                // Constant elevation.
49
100k
                dfElevation = CPLAtof(szLineBuf);
50
100k
                break;
51
52
40.7k
            case 70:
53
40.7k
            {
54
40.7k
                const int nFillFlag = atoi(szLineBuf);
55
40.7k
                poFeature->oStyleProperties["FillFlag"] =
56
40.7k
                    nFillFlag ? "Filled" : "Pattern";
57
40.7k
                break;
58
0
            }
59
60
168k
            case 2:  // Hatch pattern name
61
168k
                poFeature->SetField("Text", szLineBuf);
62
168k
                break;
63
64
375k
            case 91:
65
375k
            {
66
375k
                int nBoundaryPathCount = atoi(szLineBuf);
67
68
519k
                for (int iBoundary = 0; iBoundary < nBoundaryPathCount;
69
375k
                     iBoundary++)
70
389k
                {
71
389k
                    if (CollectBoundaryPath(&oGC, dfElevation) != OGRERR_NONE)
72
245k
                        break;
73
389k
                }
74
375k
            }
75
375k
            break;
76
77
4.68k
            case 52:
78
4.68k
            {
79
4.68k
                poFeature->oStyleProperties["HatchPatternRotation"] = szLineBuf;
80
4.68k
                break;
81
0
            }
82
83
5.48k
            case 41:
84
5.48k
            {
85
5.48k
                poFeature->oStyleProperties["HatchPatternScale"] = szLineBuf;
86
5.48k
                break;
87
0
            }
88
89
3.43k
            case 1001:
90
3.43k
            {
91
3.43k
                osExtendedData = szLineBuf;
92
3.43k
                break;
93
0
            }
94
95
4.95k
            case 1071:
96
4.95k
            {
97
4.95k
                if (osExtendedData == "HATCHBACKGROUNDCOLOR")
98
1.87k
                    poFeature->oStyleProperties["HatchBackgroundColor"] =
99
1.87k
                        szLineBuf;
100
4.95k
                break;
101
0
            }
102
103
2.69M
            default:
104
2.69M
                TranslateGenericProperty(poFeature, nCode, szLineBuf);
105
2.69M
                break;
106
3.39M
        }
107
3.39M
    }
108
101k
    if (nCode < 0)
109
4.70k
    {
110
4.70k
        DXF_LAYER_READER_ERROR();
111
4.70k
        delete poFeature;
112
4.70k
        return nullptr;
113
4.70k
    }
114
115
97.0k
    if (nCode == 0)
116
97.0k
        poDS->UnreadValue();
117
118
    /* -------------------------------------------------------------------- */
119
    /*      Obtain a tolerance value used when building the polygon.        */
120
    /* -------------------------------------------------------------------- */
121
97.0k
    double dfTolerance = poDS->HatchTolerance();
122
97.0k
    if (dfTolerance < 0)
123
97.0k
    {
124
        // If the configuration variable isn't set, compute the bounding box
125
        // and work out a tolerance from that
126
97.0k
        OGREnvelope oEnvelope;
127
97.0k
        oGC.getEnvelope(&oEnvelope);
128
97.0k
        dfTolerance = std::max(oEnvelope.MaxX - oEnvelope.MinX,
129
97.0k
                               oEnvelope.MaxY - oEnvelope.MinY) *
130
97.0k
                      1e-7;
131
97.0k
    }
132
133
    /* -------------------------------------------------------------------- */
134
    /*      Try to turn the set of lines into something useful.             */
135
    /* -------------------------------------------------------------------- */
136
97.0k
    OGRErr eErr;
137
138
97.0k
    auto poFinalGeom = std::unique_ptr<OGRGeometry>(
139
97.0k
        OGRGeometry::FromHandle(OGRBuildPolygonFromEdges(
140
97.0k
            OGRGeometry::ToHandle(&oGC), TRUE, TRUE, dfTolerance, &eErr)));
141
97.0k
    if (eErr != OGRERR_NONE)
142
23.6k
    {
143
23.6k
        auto poMLS = std::make_unique<OGRMultiLineString>();
144
101k
        for (int i = 0; i < oGC.getNumGeometries(); i++)
145
77.6k
            poMLS->addGeometry(oGC.getGeometryRef(i));
146
23.6k
        poFinalGeom = std::move(poMLS);
147
23.6k
    }
148
149
97.0k
    poFeature->ApplyOCSTransformer(poFinalGeom.get());
150
97.0k
    poFeature->SetGeometry(std::move(poFinalGeom));
151
152
97.0k
    PrepareBrushStyle(poFeature);
153
154
97.0k
    return poFeature;
155
101k
}
156
157
/************************************************************************/
158
/*                        CollectBoundaryPath()                         */
159
/************************************************************************/
160
161
OGRErr OGRDXFLayer::CollectBoundaryPath(OGRGeometryCollection *poGC,
162
                                        const double dfElevation)
163
164
389k
{
165
389k
    char szLineBuf[257];
166
167
    /* -------------------------------------------------------------------- */
168
    /*      Read the boundary path type.                                    */
169
    /* -------------------------------------------------------------------- */
170
389k
    int nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
171
389k
    if (nCode != 92)
172
166k
    {
173
166k
        DXF_LAYER_READER_ERROR();
174
166k
        return OGRERR_FAILURE;
175
166k
    }
176
177
223k
    const int nBoundaryPathType = atoi(szLineBuf);
178
179
    /* ==================================================================== */
180
    /*      Handle polyline loops.                                          */
181
    /* ==================================================================== */
182
223k
    if (nBoundaryPathType & 0x02)
183
155k
        return CollectPolylinePath(poGC, dfElevation);
184
185
    /* ==================================================================== */
186
    /*      Handle non-polyline loops.                                      */
187
    /* ==================================================================== */
188
189
    /* -------------------------------------------------------------------- */
190
    /*      Read number of edges.                                           */
191
    /* -------------------------------------------------------------------- */
192
68.1k
    nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
193
68.1k
    if (nCode != 93)
194
21.4k
    {
195
21.4k
        DXF_LAYER_READER_ERROR();
196
21.4k
        return OGRERR_FAILURE;
197
21.4k
    }
198
199
46.6k
    const int nEdgeCount = atoi(szLineBuf);
200
201
    /* -------------------------------------------------------------------- */
202
    /*      Loop reading edges.                                             */
203
    /* -------------------------------------------------------------------- */
204
85.2k
    for (int iEdge = 0; iEdge < nEdgeCount; iEdge++)
205
80.5k
    {
206
        /* --------------------------------------------------------------------
207
         */
208
        /*      Read the edge type. */
209
        /* --------------------------------------------------------------------
210
         */
211
80.5k
        const int ET_LINE = 1;
212
80.5k
        const int ET_CIRCULAR_ARC = 2;
213
80.5k
        const int ET_ELLIPTIC_ARC = 3;
214
80.5k
        const int ET_SPLINE = 4;
215
216
80.5k
        nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
217
80.5k
        if (nCode != 72)
218
15.6k
        {
219
15.6k
            DXF_LAYER_READER_ERROR();
220
15.6k
            return OGRERR_FAILURE;
221
15.6k
        }
222
223
64.8k
        int nEdgeType = atoi(szLineBuf);
224
225
        /* --------------------------------------------------------------------
226
         */
227
        /*      Process a line edge. */
228
        /* --------------------------------------------------------------------
229
         */
230
64.8k
        if (nEdgeType == ET_LINE)
231
25.2k
        {
232
25.2k
            double dfStartX = 0.0;
233
234
25.2k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 10)
235
23.1k
                dfStartX = CPLAtof(szLineBuf);
236
2.12k
            else
237
2.12k
                break;
238
239
23.1k
            double dfStartY = 0.0;
240
241
23.1k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 20)
242
21.6k
                dfStartY = CPLAtof(szLineBuf);
243
1.53k
            else
244
1.53k
                break;
245
246
21.6k
            double dfEndX = 0.0;
247
248
21.6k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 11)
249
19.4k
                dfEndX = CPLAtof(szLineBuf);
250
2.15k
            else
251
2.15k
                break;
252
253
19.4k
            double dfEndY = 0.0;
254
255
19.4k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 21)
256
18.3k
                dfEndY = CPLAtof(szLineBuf);
257
1.14k
            else
258
1.14k
                break;
259
260
18.3k
            OGRLineString *poLS = new OGRLineString();
261
262
18.3k
            poLS->addPoint(dfStartX, dfStartY, dfElevation);
263
18.3k
            poLS->addPoint(dfEndX, dfEndY, dfElevation);
264
265
18.3k
            poGC->addGeometryDirectly(poLS);
266
18.3k
        }
267
        /* --------------------------------------------------------------------
268
         */
269
        /*      Process a circular arc. */
270
        /* --------------------------------------------------------------------
271
         */
272
39.5k
        else if (nEdgeType == ET_CIRCULAR_ARC)
273
20.8k
        {
274
20.8k
            double dfCenterX = 0.0;
275
276
20.8k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 10)
277
19.9k
                dfCenterX = CPLAtof(szLineBuf);
278
908
            else
279
908
                break;
280
281
19.9k
            double dfCenterY = 0.0;
282
283
19.9k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 20)
284
18.9k
                dfCenterY = CPLAtof(szLineBuf);
285
1.05k
            else
286
1.05k
                break;
287
288
18.9k
            double dfRadius = 0.0;
289
290
18.9k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 40)
291
18.0k
                dfRadius = CPLAtof(szLineBuf);
292
898
            else
293
898
                break;
294
295
18.0k
            double dfStartAngle = 0.0;
296
297
18.0k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 50)
298
17.3k
                dfStartAngle = CPLAtof(szLineBuf);
299
673
            else
300
673
                break;
301
302
17.3k
            double dfEndAngle = 0.0;
303
304
17.3k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 51)
305
16.6k
                dfEndAngle = CPLAtof(szLineBuf);
306
676
            else
307
676
                break;
308
309
16.6k
            bool bCounterClockwise = false;
310
311
16.6k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 73)
312
1.26k
                bCounterClockwise = atoi(szLineBuf) != 0;
313
15.4k
            else if (nCode >= 0)
314
15.1k
                poDS->UnreadValue();
315
213
            else
316
213
                break;
317
318
16.4k
            if (dfStartAngle > dfEndAngle)
319
8.77k
                dfEndAngle += 360.0;
320
16.4k
            if (bCounterClockwise)
321
1.25k
            {
322
1.25k
                dfStartAngle *= -1;
323
1.25k
                dfEndAngle *= -1;
324
1.25k
            }
325
326
16.4k
            if (fabs(dfEndAngle - dfStartAngle) <= 361.0)
327
15.7k
            {
328
15.7k
                OGRGeometry *poArc = OGRGeometryFactory::approximateArcAngles(
329
15.7k
                    dfCenterX, dfCenterY, dfElevation, dfRadius, dfRadius, 0.0,
330
15.7k
                    dfStartAngle, dfEndAngle, 0.0, poDS->InlineBlocks());
331
332
                // If the input was 2D, we assume we want to keep it that way
333
15.7k
                if (dfElevation == 0.0)
334
13.0k
                    poArc->flattenTo2D();
335
336
15.7k
                poGC->addGeometryDirectly(poArc);
337
15.7k
            }
338
724
            else
339
724
            {
340
                // TODO: emit error ?
341
724
            }
342
16.4k
        }
343
344
        /* --------------------------------------------------------------------
345
         */
346
        /*      Process an elliptical arc. */
347
        /* --------------------------------------------------------------------
348
         */
349
18.6k
        else if (nEdgeType == ET_ELLIPTIC_ARC)
350
9.09k
        {
351
9.09k
            double dfCenterX = 0.0;
352
353
9.09k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 10)
354
7.53k
                dfCenterX = CPLAtof(szLineBuf);
355
1.55k
            else
356
1.55k
                break;
357
358
7.53k
            double dfCenterY = 0.0;
359
360
7.53k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 20)
361
6.70k
                dfCenterY = CPLAtof(szLineBuf);
362
839
            else
363
839
                break;
364
365
6.70k
            double dfMajorX = 0.0;
366
367
6.70k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 11)
368
5.66k
                dfMajorX = CPLAtof(szLineBuf);
369
1.03k
            else
370
1.03k
                break;
371
372
5.66k
            double dfMajorY = 0.0;
373
374
5.66k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 21)
375
4.79k
                dfMajorY = CPLAtof(szLineBuf);
376
869
            else
377
869
                break;
378
379
4.79k
            double dfRatio = 0.0;
380
381
4.79k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 40)
382
4.05k
                dfRatio = CPLAtof(szLineBuf);
383
4.79k
            if (dfRatio == 0.0)
384
863
                break;
385
386
3.93k
            double dfStartAngle = 0.0;
387
388
3.93k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 50)
389
3.83k
                dfStartAngle = CPLAtof(szLineBuf);
390
100
            else
391
100
                break;
392
393
3.83k
            double dfEndAngle = 0.0;
394
395
3.83k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 51)
396
3.48k
                dfEndAngle = CPLAtof(szLineBuf);
397
346
            else
398
346
                break;
399
400
3.48k
            bool bCounterClockwise = false;
401
402
3.48k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 73)
403
663
                bCounterClockwise = atoi(szLineBuf) != 0;
404
2.82k
            else if (nCode >= 0)
405
2.67k
                poDS->UnreadValue();
406
153
            else
407
153
                break;
408
409
3.33k
            if (dfStartAngle > dfEndAngle)
410
2.13k
                dfEndAngle += 360.0;
411
3.33k
            if (bCounterClockwise)
412
662
            {
413
662
                dfStartAngle *= -1;
414
662
                dfEndAngle *= -1;
415
662
            }
416
417
3.33k
            const double dfMajorRadius =
418
3.33k
                sqrt(dfMajorX * dfMajorX + dfMajorY * dfMajorY);
419
3.33k
            const double dfMinorRadius = dfMajorRadius * dfRatio;
420
421
3.33k
            const double dfRotation =
422
3.33k
                -1 * atan2(dfMajorY, dfMajorX) * 180 / M_PI;
423
424
            // The start and end angles are stored as circular angles. However,
425
            // approximateArcAngles is expecting elliptical angles (what AutoCAD
426
            // calls "parameters"), so let's transform them.
427
3.33k
            dfStartAngle =
428
3.33k
                180.0 * round(dfStartAngle / 180) +
429
3.33k
                (fabs(fmod(dfStartAngle, 180)) == 90
430
3.33k
                     ? (std::signbit(dfStartAngle) ? 180 : -180)
431
3.33k
                     : 0) +
432
3.33k
                atan((1.0 / dfRatio) * tan(dfStartAngle * M_PI / 180)) * 180 /
433
3.33k
                    M_PI;
434
3.33k
            dfEndAngle = 180.0 * round(dfEndAngle / 180) +
435
3.33k
                         (fabs(fmod(dfEndAngle, 180)) == 90
436
3.33k
                              ? (std::signbit(dfEndAngle) ? 180 : -180)
437
3.33k
                              : 0) +
438
3.33k
                         atan((1.0 / dfRatio) * tan(dfEndAngle * M_PI / 180)) *
439
3.33k
                             180 / M_PI;
440
441
3.33k
            if (fabs(dfEndAngle - dfStartAngle) <= 361.0)
442
2.58k
            {
443
2.58k
                OGRGeometry *poArc = OGRGeometryFactory::approximateArcAngles(
444
2.58k
                    dfCenterX, dfCenterY, dfElevation, dfMajorRadius,
445
2.58k
                    dfMinorRadius, dfRotation, dfStartAngle, dfEndAngle, 0.0,
446
2.58k
                    poDS->InlineBlocks());
447
448
                // If the input was 2D, we assume we want to keep it that way
449
2.58k
                if (dfElevation == 0.0)
450
1.32k
                    poArc->flattenTo2D();
451
452
2.58k
                poGC->addGeometryDirectly(poArc);
453
2.58k
            }
454
751
            else
455
751
            {
456
                // TODO: emit error ?
457
751
            }
458
3.33k
        }
459
460
        /* --------------------------------------------------------------------
461
         */
462
        /*      Process an elliptical arc. */
463
        /* --------------------------------------------------------------------
464
         */
465
9.59k
        else if (nEdgeType == ET_SPLINE)
466
7.31k
        {
467
7.31k
            int nDegree = 3;
468
469
7.31k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 94)
470
6.55k
                nDegree = atoi(szLineBuf);
471
762
            else
472
762
                break;
473
474
            // Skip a few things we don't care about
475
6.55k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) != 73)
476
381
                break;
477
6.17k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) != 74)
478
428
                break;
479
480
5.74k
            int nKnots = 0;
481
482
5.74k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 95)
483
4.19k
                nKnots = atoi(szLineBuf);
484
1.54k
            else
485
1.54k
                break;
486
487
4.19k
            int nControlPoints = 0;
488
489
4.19k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 96)
490
3.25k
                nControlPoints = atoi(szLineBuf);
491
946
            else
492
946
                break;
493
494
3.25k
            std::vector<double> adfKnots(FORTRAN_INDEXING, 0.0);
495
496
3.25k
            nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
497
3.25k
            if (nCode != 40)
498
277
                break;
499
500
12.2k
            while (nCode == 40)
501
9.29k
            {
502
9.29k
                adfKnots.push_back(CPLAtof(szLineBuf));
503
9.29k
                nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
504
9.29k
            }
505
506
2.97k
            std::vector<double> adfControlPoints(FORTRAN_INDEXING, 0.0);
507
2.97k
            std::vector<double> adfWeights(FORTRAN_INDEXING, 0.0);
508
509
2.97k
            if (nCode != 10)
510
338
                break;
511
512
7.65k
            while (nCode == 10)
513
6.48k
            {
514
6.48k
                adfControlPoints.push_back(CPLAtof(szLineBuf));
515
516
6.48k
                if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) ==
517
6.48k
                    20)
518
5.01k
                {
519
5.01k
                    adfControlPoints.push_back(CPLAtof(szLineBuf));
520
5.01k
                }
521
1.46k
                else
522
1.46k
                    break;
523
524
5.01k
                adfControlPoints.push_back(0.0);  // Z coordinate
525
526
                // 42 (weights) are optional
527
5.01k
                if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) ==
528
5.01k
                    42)
529
69
                {
530
69
                    adfWeights.push_back(CPLAtof(szLineBuf));
531
69
                    nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
532
69
                }
533
5.01k
            }
534
535
            // Skip past the number of fit points
536
2.63k
            if (nCode != 97)
537
1.35k
                break;
538
539
            // Eat the rest of this section, if present, until the next
540
            // boundary segment (72) or the conclusion of the boundary data (97)
541
1.28k
            nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
542
11.3k
            while (nCode > 0 && nCode != 72 && nCode != 97)
543
10.0k
                nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
544
1.28k
            if (nCode > 0)
545
604
                poDS->UnreadValue();
546
547
1.28k
            auto poLS =
548
1.28k
                InsertSplineWithChecks(nDegree, adfControlPoints,
549
1.28k
                                       /* bHaZ = */ false, nControlPoints,
550
1.28k
                                       adfKnots, nKnots, adfWeights);
551
552
1.28k
            if (!poLS)
553
862
            {
554
862
                DXF_LAYER_READER_ERROR();
555
862
                return OGRERR_FAILURE;
556
862
            }
557
558
419
            poGC->addGeometryDirectly(poLS.release());
559
419
        }
560
561
2.28k
        else
562
2.28k
        {
563
2.28k
            CPLDebug("DXF", "Unsupported HATCH boundary line type:%d",
564
2.28k
                     nEdgeType);
565
2.28k
            return OGRERR_UNSUPPORTED_OPERATION;
566
2.28k
        }
567
64.8k
    }
568
569
27.8k
    if (nCode < 0)
570
3.00k
    {
571
3.00k
        DXF_LAYER_READER_ERROR();
572
3.00k
        return OGRERR_FAILURE;
573
3.00k
    }
574
575
    /* -------------------------------------------------------------------- */
576
    /*      Skip through source boundary objects if present.                */
577
    /* -------------------------------------------------------------------- */
578
24.8k
    nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
579
24.8k
    if (nCode != 97)
580
21.7k
    {
581
21.7k
        if (nCode < 0)
582
940
            return OGRERR_FAILURE;
583
20.8k
        poDS->UnreadValue();
584
20.8k
    }
585
3.11k
    else
586
3.11k
    {
587
3.11k
        int iObj, nObjCount = atoi(szLineBuf);
588
589
28.0k
        for (iObj = 0; iObj < nObjCount; iObj++)
590
25.3k
        {
591
25.3k
            if (poDS->ReadValue(szLineBuf, sizeof(szLineBuf)) < 0)
592
402
                return OGRERR_FAILURE;
593
25.3k
        }
594
3.11k
    }
595
596
23.5k
    return OGRERR_NONE;
597
24.8k
}
598
599
/************************************************************************/
600
/*                        CollectPolylinePath()                         */
601
/************************************************************************/
602
603
OGRErr OGRDXFLayer::CollectPolylinePath(OGRGeometryCollection *poGC,
604
                                        const double dfElevation)
605
606
155k
{
607
155k
    int nCode = 0;
608
155k
    char szLineBuf[257];
609
155k
    DXFSmoothPolyline oSmoothPolyline;
610
155k
    double dfBulge = 0.0;
611
155k
    double dfX = 0.0;
612
155k
    double dfY = 0.0;
613
155k
    bool bHaveX = false;
614
155k
    bool bHaveY = false;
615
155k
    bool bIsClosed = false;
616
155k
    int nVertexCount = -1;
617
155k
    bool bHaveBulges = false;
618
619
155k
    if (dfElevation != 0)
620
24.6k
        oSmoothPolyline.setCoordinateDimension(3);
621
622
    /* -------------------------------------------------------------------- */
623
    /*      Read the boundary path type.                                    */
624
    /* -------------------------------------------------------------------- */
625
6.92M
    while ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) > 0)
626
6.83M
    {
627
6.83M
        if (nVertexCount > 0 && (int)oSmoothPolyline.size() == nVertexCount)
628
66.6k
            break;
629
630
6.76M
        switch (nCode)
631
6.76M
        {
632
293k
            case 93:
633
293k
                nVertexCount = atoi(szLineBuf);
634
293k
                break;
635
636
35.4k
            case 72:
637
35.4k
                bHaveBulges = CPL_TO_BOOL(atoi(szLineBuf));
638
35.4k
                break;
639
640
19.0k
            case 73:
641
19.0k
                bIsClosed = CPL_TO_BOOL(atoi(szLineBuf));
642
19.0k
                break;
643
644
1.26M
            case 10:
645
1.26M
                if (bHaveX && bHaveY)
646
74.1k
                {
647
74.1k
                    oSmoothPolyline.AddPoint(dfX, dfY, dfElevation, dfBulge);
648
74.1k
                    dfBulge = 0.0;
649
74.1k
                    bHaveY = false;
650
74.1k
                }
651
1.26M
                dfX = CPLAtof(szLineBuf);
652
1.26M
                bHaveX = true;
653
1.26M
                break;
654
655
1.05M
            case 20:
656
1.05M
                if (bHaveX && bHaveY)
657
110k
                {
658
110k
                    oSmoothPolyline.AddPoint(dfX, dfY, dfElevation, dfBulge);
659
110k
                    dfBulge = 0.0;
660
110k
                    bHaveX = false;
661
110k
                }
662
1.05M
                dfY = CPLAtof(szLineBuf);
663
1.05M
                bHaveY = true;
664
1.05M
                if (bHaveX /* && bHaveY */ && !bHaveBulges)
665
598k
                {
666
598k
                    oSmoothPolyline.AddPoint(dfX, dfY, dfElevation, dfBulge);
667
598k
                    dfBulge = 0.0;
668
598k
                    bHaveX = false;
669
598k
                    bHaveY = false;
670
598k
                }
671
1.05M
                break;
672
673
238k
            case 42:
674
238k
                dfBulge = CPLAtof(szLineBuf);
675
238k
                if (bHaveX && bHaveY)
676
80.3k
                {
677
80.3k
                    oSmoothPolyline.AddPoint(dfX, dfY, dfElevation, dfBulge);
678
80.3k
                    dfBulge = 0.0;
679
80.3k
                    bHaveX = false;
680
80.3k
                    bHaveY = false;
681
80.3k
                }
682
238k
                break;
683
684
3.85M
            default:
685
3.85M
                break;
686
6.76M
        }
687
6.76M
    }
688
155k
    if (nCode < 0)
689
23.4k
    {
690
23.4k
        DXF_LAYER_READER_ERROR();
691
23.4k
        return OGRERR_FAILURE;
692
23.4k
    }
693
694
131k
    if (nCode != 10 && nCode != 20 && nCode != 42)
695
125k
        poDS->UnreadValue();
696
697
131k
    if (bHaveX && bHaveY)
698
7.30k
        oSmoothPolyline.AddPoint(dfX, dfY, dfElevation, dfBulge);
699
700
131k
    if (bIsClosed)
701
4.76k
        oSmoothPolyline.Close();
702
703
131k
    if (oSmoothPolyline.IsEmpty())
704
10.9k
    {
705
10.9k
        return OGRERR_FAILURE;
706
10.9k
    }
707
708
    // Only process polylines with at least 2 vertices
709
120k
    if (nVertexCount >= 2)
710
96.0k
    {
711
96.0k
        oSmoothPolyline.SetUseMaxGapWhenTessellatingArcs(poDS->InlineBlocks());
712
96.0k
        poGC->addGeometryDirectly(oSmoothPolyline.Tessellate(false));
713
96.0k
    }
714
715
    /* -------------------------------------------------------------------- */
716
    /*      Skip through source boundary objects if present.                */
717
    /* -------------------------------------------------------------------- */
718
120k
    nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
719
120k
    if (nCode != 97)
720
119k
    {
721
119k
        if (nCode < 0)
722
126
            return OGRERR_FAILURE;
723
119k
        poDS->UnreadValue();
724
119k
    }
725
1.07k
    else
726
1.07k
    {
727
1.07k
        int iObj, nObjCount = atoi(szLineBuf);
728
729
2.51k
        for (iObj = 0; iObj < nObjCount; iObj++)
730
1.53k
        {
731
1.53k
            if (poDS->ReadValue(szLineBuf, sizeof(szLineBuf)) < 0)
732
95
                return OGRERR_FAILURE;
733
1.53k
        }
734
1.07k
    }
735
120k
    return OGRERR_NONE;
736
120k
}