Coverage Report

Created: 2025-11-15 08:43

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
87.5k
{
35
87.5k
    char szLineBuf[257];
36
87.5k
    int nCode = 0;
37
87.5k
    OGRDXFFeature *poFeature = new OGRDXFFeature(poFeatureDefn);
38
39
87.5k
    double dfElevation = 0.0;  // Z value to be used for EVERY point
40
87.5k
    OGRGeometryCollection oGC;
41
87.5k
    std::string osExtendedData;
42
43
1.27M
    while ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) > 0)
44
1.18M
    {
45
1.18M
        switch (nCode)
46
1.18M
        {
47
43.9k
            case 30:
48
                // Constant elevation.
49
43.9k
                dfElevation = CPLAtof(szLineBuf);
50
43.9k
                break;
51
52
26.5k
            case 70:
53
26.5k
            {
54
26.5k
                const int nFillFlag = atoi(szLineBuf);
55
26.5k
                poFeature->oStyleProperties["FillFlag"] =
56
26.5k
                    nFillFlag ? "Filled" : "Pattern";
57
26.5k
                break;
58
0
            }
59
60
90.7k
            case 2:  // Hatch pattern name
61
90.7k
                poFeature->SetField("Text", szLineBuf);
62
90.7k
                break;
63
64
152k
            case 91:
65
152k
            {
66
152k
                int nBoundaryPathCount = atoi(szLineBuf);
67
68
224k
                for (int iBoundary = 0; iBoundary < nBoundaryPathCount;
69
152k
                     iBoundary++)
70
185k
                {
71
185k
                    if (CollectBoundaryPath(&oGC, dfElevation) != OGRERR_NONE)
72
113k
                        break;
73
185k
                }
74
152k
            }
75
152k
            break;
76
77
2.72k
            case 52:
78
2.72k
            {
79
2.72k
                poFeature->oStyleProperties["HatchPatternRotation"] = szLineBuf;
80
2.72k
                break;
81
0
            }
82
83
5.03k
            case 41:
84
5.03k
            {
85
5.03k
                poFeature->oStyleProperties["HatchPatternScale"] = szLineBuf;
86
5.03k
                break;
87
0
            }
88
89
2.15k
            case 1001:
90
2.15k
            {
91
2.15k
                osExtendedData = szLineBuf;
92
2.15k
                break;
93
0
            }
94
95
2.44k
            case 1071:
96
2.44k
            {
97
2.44k
                if (osExtendedData == "HATCHBACKGROUNDCOLOR")
98
748
                    poFeature->oStyleProperties["HatchBackgroundColor"] =
99
748
                        szLineBuf;
100
2.44k
                break;
101
0
            }
102
103
856k
            default:
104
856k
                TranslateGenericProperty(poFeature, nCode, szLineBuf);
105
856k
                break;
106
1.18M
        }
107
1.18M
    }
108
87.5k
    if (nCode < 0)
109
3.98k
    {
110
3.98k
        DXF_LAYER_READER_ERROR();
111
3.98k
        delete poFeature;
112
3.98k
        return nullptr;
113
3.98k
    }
114
115
83.5k
    if (nCode == 0)
116
83.5k
        poDS->UnreadValue();
117
118
    /* -------------------------------------------------------------------- */
119
    /*      Obtain a tolerance value used when building the polygon.        */
120
    /* -------------------------------------------------------------------- */
121
83.5k
    double dfTolerance = poDS->HatchTolerance();
122
83.5k
    if (dfTolerance < 0)
123
83.5k
    {
124
        // If the configuration variable isn't set, compute the bounding box
125
        // and work out a tolerance from that
126
83.5k
        OGREnvelope oEnvelope;
127
83.5k
        oGC.getEnvelope(&oEnvelope);
128
83.5k
        dfTolerance = std::max(oEnvelope.MaxX - oEnvelope.MinX,
129
83.5k
                               oEnvelope.MaxY - oEnvelope.MinY) *
130
83.5k
                      1e-7;
131
83.5k
    }
132
133
    /* -------------------------------------------------------------------- */
134
    /*      Try to turn the set of lines into something useful.             */
135
    /* -------------------------------------------------------------------- */
136
83.5k
    OGRErr eErr;
137
138
83.5k
    auto poFinalGeom = std::unique_ptr<OGRGeometry>(
139
83.5k
        OGRGeometry::FromHandle(OGRBuildPolygonFromEdges(
140
83.5k
            OGRGeometry::ToHandle(&oGC), TRUE, TRUE, dfTolerance, &eErr)));
141
83.5k
    if (eErr != OGRERR_NONE)
142
23.0k
    {
143
23.0k
        auto poMLS = std::make_unique<OGRMultiLineString>();
144
70.1k
        for (int i = 0; i < oGC.getNumGeometries(); i++)
145
47.1k
            poMLS->addGeometry(oGC.getGeometryRef(i));
146
23.0k
        poFinalGeom = std::move(poMLS);
147
23.0k
    }
148
149
83.5k
    poFeature->ApplyOCSTransformer(poFinalGeom.get());
150
83.5k
    poFeature->SetGeometry(std::move(poFinalGeom));
151
152
83.5k
    PrepareBrushStyle(poFeature);
153
154
83.5k
    return poFeature;
155
87.5k
}
156
157
/************************************************************************/
158
/*                        CollectBoundaryPath()                         */
159
/************************************************************************/
160
161
OGRErr OGRDXFLayer::CollectBoundaryPath(OGRGeometryCollection *poGC,
162
                                        const double dfElevation)
163
164
185k
{
165
185k
    char szLineBuf[257];
166
167
    /* -------------------------------------------------------------------- */
168
    /*      Read the boundary path type.                                    */
169
    /* -------------------------------------------------------------------- */
170
185k
    int nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
171
185k
    if (nCode != 92)
172
77.7k
    {
173
77.7k
        DXF_LAYER_READER_ERROR();
174
77.7k
        return OGRERR_FAILURE;
175
77.7k
    }
176
177
107k
    const int nBoundaryPathType = atoi(szLineBuf);
178
179
    /* ==================================================================== */
180
    /*      Handle polyline loops.                                          */
181
    /* ==================================================================== */
182
107k
    if (nBoundaryPathType & 0x02)
183
65.3k
        return CollectPolylinePath(poGC, dfElevation);
184
185
    /* ==================================================================== */
186
    /*      Handle non-polyline loops.                                      */
187
    /* ==================================================================== */
188
189
    /* -------------------------------------------------------------------- */
190
    /*      Read number of edges.                                           */
191
    /* -------------------------------------------------------------------- */
192
42.2k
    nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
193
42.2k
    if (nCode != 93)
194
6.41k
    {
195
6.41k
        DXF_LAYER_READER_ERROR();
196
6.41k
        return OGRERR_FAILURE;
197
6.41k
    }
198
199
35.8k
    const int nEdgeCount = atoi(szLineBuf);
200
201
    /* -------------------------------------------------------------------- */
202
    /*      Loop reading edges.                                             */
203
    /* -------------------------------------------------------------------- */
204
64.6k
    for (int iEdge = 0; iEdge < nEdgeCount; iEdge++)
205
60.7k
    {
206
        /* --------------------------------------------------------------------
207
         */
208
        /*      Read the edge type. */
209
        /* --------------------------------------------------------------------
210
         */
211
60.7k
        const int ET_LINE = 1;
212
60.7k
        const int ET_CIRCULAR_ARC = 2;
213
60.7k
        const int ET_ELLIPTIC_ARC = 3;
214
60.7k
        const int ET_SPLINE = 4;
215
216
60.7k
        nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
217
60.7k
        if (nCode != 72)
218
8.66k
        {
219
8.66k
            DXF_LAYER_READER_ERROR();
220
8.66k
            return OGRERR_FAILURE;
221
8.66k
        }
222
223
52.0k
        int nEdgeType = atoi(szLineBuf);
224
225
        /* --------------------------------------------------------------------
226
         */
227
        /*      Process a line edge. */
228
        /* --------------------------------------------------------------------
229
         */
230
52.0k
        if (nEdgeType == ET_LINE)
231
23.5k
        {
232
23.5k
            double dfStartX = 0.0;
233
234
23.5k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 10)
235
22.1k
                dfStartX = CPLAtof(szLineBuf);
236
1.42k
            else
237
1.42k
                break;
238
239
22.1k
            double dfStartY = 0.0;
240
241
22.1k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 20)
242
21.0k
                dfStartY = CPLAtof(szLineBuf);
243
1.13k
            else
244
1.13k
                break;
245
246
21.0k
            double dfEndX = 0.0;
247
248
21.0k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 11)
249
18.6k
                dfEndX = CPLAtof(szLineBuf);
250
2.39k
            else
251
2.39k
                break;
252
253
18.6k
            double dfEndY = 0.0;
254
255
18.6k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 21)
256
17.4k
                dfEndY = CPLAtof(szLineBuf);
257
1.14k
            else
258
1.14k
                break;
259
260
17.4k
            OGRLineString *poLS = new OGRLineString();
261
262
17.4k
            poLS->addPoint(dfStartX, dfStartY, dfElevation);
263
17.4k
            poLS->addPoint(dfEndX, dfEndY, dfElevation);
264
265
17.4k
            poGC->addGeometryDirectly(poLS);
266
17.4k
        }
267
        /* --------------------------------------------------------------------
268
         */
269
        /*      Process a circular arc. */
270
        /* --------------------------------------------------------------------
271
         */
272
28.5k
        else if (nEdgeType == ET_CIRCULAR_ARC)
273
12.5k
        {
274
12.5k
            double dfCenterX = 0.0;
275
276
12.5k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 10)
277
11.9k
                dfCenterX = CPLAtof(szLineBuf);
278
608
            else
279
608
                break;
280
281
11.9k
            double dfCenterY = 0.0;
282
283
11.9k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 20)
284
10.7k
                dfCenterY = CPLAtof(szLineBuf);
285
1.19k
            else
286
1.19k
                break;
287
288
10.7k
            double dfRadius = 0.0;
289
290
10.7k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 40)
291
10.1k
                dfRadius = CPLAtof(szLineBuf);
292
576
            else
293
576
                break;
294
295
10.1k
            double dfStartAngle = 0.0;
296
297
10.1k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 50)
298
9.63k
                dfStartAngle = CPLAtof(szLineBuf);
299
563
            else
300
563
                break;
301
302
9.63k
            double dfEndAngle = 0.0;
303
304
9.63k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 51)
305
9.19k
                dfEndAngle = CPLAtof(szLineBuf);
306
439
            else
307
439
                break;
308
309
9.19k
            bool bCounterClockwise = false;
310
311
9.19k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 73)
312
426
                bCounterClockwise = atoi(szLineBuf) != 0;
313
8.76k
            else if (nCode >= 0)
314
8.68k
                poDS->UnreadValue();
315
85
            else
316
85
                break;
317
318
9.11k
            if (dfStartAngle > dfEndAngle)
319
4.07k
                dfEndAngle += 360.0;
320
9.11k
            if (bCounterClockwise)
321
418
            {
322
418
                dfStartAngle *= -1;
323
418
                dfEndAngle *= -1;
324
418
            }
325
326
9.11k
            if (fabs(dfEndAngle - dfStartAngle) <= 361.0)
327
8.93k
            {
328
8.93k
                OGRGeometry *poArc = OGRGeometryFactory::approximateArcAngles(
329
8.93k
                    dfCenterX, dfCenterY, dfElevation, dfRadius, dfRadius, 0.0,
330
8.93k
                    dfStartAngle, dfEndAngle, 0.0, poDS->InlineBlocks());
331
332
                // If the input was 2D, we assume we want to keep it that way
333
8.93k
                if (dfElevation == 0.0)
334
6.03k
                    poArc->flattenTo2D();
335
336
8.93k
                poGC->addGeometryDirectly(poArc);
337
8.93k
            }
338
175
            else
339
175
            {
340
                // TODO: emit error ?
341
175
            }
342
9.11k
        }
343
344
        /* --------------------------------------------------------------------
345
         */
346
        /*      Process an elliptical arc. */
347
        /* --------------------------------------------------------------------
348
         */
349
15.9k
        else if (nEdgeType == ET_ELLIPTIC_ARC)
350
7.93k
        {
351
7.93k
            double dfCenterX = 0.0;
352
353
7.93k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 10)
354
5.59k
                dfCenterX = CPLAtof(szLineBuf);
355
2.34k
            else
356
2.34k
                break;
357
358
5.59k
            double dfCenterY = 0.0;
359
360
5.59k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 20)
361
4.70k
                dfCenterY = CPLAtof(szLineBuf);
362
895
            else
363
895
                break;
364
365
4.70k
            double dfMajorX = 0.0;
366
367
4.70k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 11)
368
3.91k
                dfMajorX = CPLAtof(szLineBuf);
369
790
            else
370
790
                break;
371
372
3.91k
            double dfMajorY = 0.0;
373
374
3.91k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 21)
375
3.39k
                dfMajorY = CPLAtof(szLineBuf);
376
516
            else
377
516
                break;
378
379
3.39k
            double dfRatio = 0.0;
380
381
3.39k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 40)
382
2.73k
                dfRatio = CPLAtof(szLineBuf);
383
3.39k
            if (dfRatio == 0.0)
384
678
                break;
385
386
2.71k
            double dfStartAngle = 0.0;
387
388
2.71k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 50)
389
2.48k
                dfStartAngle = CPLAtof(szLineBuf);
390
231
            else
391
231
                break;
392
393
2.48k
            double dfEndAngle = 0.0;
394
395
2.48k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 51)
396
2.17k
                dfEndAngle = CPLAtof(szLineBuf);
397
313
            else
398
313
                break;
399
400
2.17k
            bool bCounterClockwise = false;
401
402
2.17k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 73)
403
632
                bCounterClockwise = atoi(szLineBuf) != 0;
404
1.54k
            else if (nCode >= 0)
405
1.40k
                poDS->UnreadValue();
406
136
            else
407
136
                break;
408
409
2.03k
            if (dfStartAngle > dfEndAngle)
410
1.30k
                dfEndAngle += 360.0;
411
2.03k
            if (bCounterClockwise)
412
632
            {
413
632
                dfStartAngle *= -1;
414
632
                dfEndAngle *= -1;
415
632
            }
416
417
2.03k
            const double dfMajorRadius =
418
2.03k
                sqrt(dfMajorX * dfMajorX + dfMajorY * dfMajorY);
419
2.03k
            const double dfMinorRadius = dfMajorRadius * dfRatio;
420
421
2.03k
            const double dfRotation =
422
2.03k
                -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
2.03k
            dfStartAngle =
428
2.03k
                180.0 * round(dfStartAngle / 180) +
429
2.03k
                (fabs(fmod(dfStartAngle, 180)) == 90
430
2.03k
                     ? (std::signbit(dfStartAngle) ? 180 : -180)
431
2.03k
                     : 0) +
432
2.03k
                atan((1.0 / dfRatio) * tan(dfStartAngle * M_PI / 180)) * 180 /
433
2.03k
                    M_PI;
434
2.03k
            dfEndAngle = 180.0 * round(dfEndAngle / 180) +
435
2.03k
                         (fabs(fmod(dfEndAngle, 180)) == 90
436
2.03k
                              ? (std::signbit(dfEndAngle) ? 180 : -180)
437
2.03k
                              : 0) +
438
2.03k
                         atan((1.0 / dfRatio) * tan(dfEndAngle * M_PI / 180)) *
439
2.03k
                             180 / M_PI;
440
441
2.03k
            if (fabs(dfEndAngle - dfStartAngle) <= 361.0)
442
1.36k
            {
443
1.36k
                OGRGeometry *poArc = OGRGeometryFactory::approximateArcAngles(
444
1.36k
                    dfCenterX, dfCenterY, dfElevation, dfMajorRadius,
445
1.36k
                    dfMinorRadius, dfRotation, dfStartAngle, dfEndAngle, 0.0,
446
1.36k
                    poDS->InlineBlocks());
447
448
                // If the input was 2D, we assume we want to keep it that way
449
1.36k
                if (dfElevation == 0.0)
450
982
                    poArc->flattenTo2D();
451
452
1.36k
                poGC->addGeometryDirectly(poArc);
453
1.36k
            }
454
675
            else
455
675
            {
456
                // TODO: emit error ?
457
675
            }
458
2.03k
        }
459
460
        /* --------------------------------------------------------------------
461
         */
462
        /*      Process an elliptical arc. */
463
        /* --------------------------------------------------------------------
464
         */
465
8.01k
        else if (nEdgeType == ET_SPLINE)
466
5.96k
        {
467
5.96k
            int nDegree = 3;
468
469
5.96k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 94)
470
5.25k
                nDegree = atoi(szLineBuf);
471
702
            else
472
702
                break;
473
474
            // Skip a few things we don't care about
475
5.25k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) != 73)
476
363
                break;
477
4.89k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) != 74)
478
461
                break;
479
480
4.43k
            int nKnots = 0;
481
482
4.43k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 95)
483
3.62k
                nKnots = atoi(szLineBuf);
484
807
            else
485
807
                break;
486
487
3.62k
            int nControlPoints = 0;
488
489
3.62k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 96)
490
3.17k
                nControlPoints = atoi(szLineBuf);
491
452
            else
492
452
                break;
493
494
3.17k
            std::vector<double> adfKnots(FORTRAN_INDEXING, 0.0);
495
496
3.17k
            nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
497
3.17k
            if (nCode != 40)
498
329
                break;
499
500
9.20k
            while (nCode == 40)
501
6.35k
            {
502
6.35k
                adfKnots.push_back(CPLAtof(szLineBuf));
503
6.35k
                nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
504
6.35k
            }
505
506
2.84k
            std::vector<double> adfControlPoints(FORTRAN_INDEXING, 0.0);
507
2.84k
            std::vector<double> adfWeights(FORTRAN_INDEXING, 0.0);
508
509
2.84k
            if (nCode != 10)
510
674
                break;
511
512
5.56k
            while (nCode == 10)
513
4.83k
            {
514
4.83k
                adfControlPoints.push_back(CPLAtof(szLineBuf));
515
516
4.83k
                if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) ==
517
4.83k
                    20)
518
3.38k
                {
519
3.38k
                    adfControlPoints.push_back(CPLAtof(szLineBuf));
520
3.38k
                }
521
1.44k
                else
522
1.44k
                    break;
523
524
3.38k
                adfControlPoints.push_back(0.0);  // Z coordinate
525
526
                // 42 (weights) are optional
527
3.38k
                if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) ==
528
3.38k
                    42)
529
35
                {
530
35
                    adfWeights.push_back(CPLAtof(szLineBuf));
531
35
                    nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
532
35
                }
533
3.38k
            }
534
535
            // Skip past the number of fit points
536
2.17k
            if (nCode != 97)
537
1.12k
                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.04k
            nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
542
10.4k
            while (nCode > 0 && nCode != 72 && nCode != 97)
543
9.38k
                nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
544
1.04k
            if (nCode > 0)
545
562
                poDS->UnreadValue();
546
547
1.04k
            auto poLS =
548
1.04k
                InsertSplineWithChecks(nDegree, adfControlPoints,
549
1.04k
                                       /* bHaZ = */ false, nControlPoints,
550
1.04k
                                       adfKnots, nKnots, adfWeights);
551
552
1.04k
            if (!poLS)
553
836
            {
554
836
                DXF_LAYER_READER_ERROR();
555
836
                return OGRERR_FAILURE;
556
836
            }
557
558
211
            poGC->addGeometryDirectly(poLS.release());
559
211
        }
560
561
2.05k
        else
562
2.05k
        {
563
2.05k
            CPLDebug("DXF", "Unsupported HATCH boundary line type:%d",
564
2.05k
                     nEdgeType);
565
2.05k
            return OGRERR_UNSUPPORTED_OPERATION;
566
2.05k
        }
567
52.0k
    }
568
569
24.2k
    if (nCode < 0)
570
2.41k
    {
571
2.41k
        DXF_LAYER_READER_ERROR();
572
2.41k
        return OGRERR_FAILURE;
573
2.41k
    }
574
575
    /* -------------------------------------------------------------------- */
576
    /*      Skip through source boundary objects if present.                */
577
    /* -------------------------------------------------------------------- */
578
21.8k
    nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
579
21.8k
    if (nCode != 97)
580
19.5k
    {
581
19.5k
        if (nCode < 0)
582
1.07k
            return OGRERR_FAILURE;
583
18.4k
        poDS->UnreadValue();
584
18.4k
    }
585
2.28k
    else
586
2.28k
    {
587
2.28k
        int iObj, nObjCount = atoi(szLineBuf);
588
589
17.4k
        for (iObj = 0; iObj < nObjCount; iObj++)
590
15.6k
        {
591
15.6k
            if (poDS->ReadValue(szLineBuf, sizeof(szLineBuf)) < 0)
592
404
                return OGRERR_FAILURE;
593
15.6k
        }
594
2.28k
    }
595
596
20.3k
    return OGRERR_NONE;
597
21.8k
}
598
599
/************************************************************************/
600
/*                        CollectPolylinePath()                         */
601
/************************************************************************/
602
603
OGRErr OGRDXFLayer::CollectPolylinePath(OGRGeometryCollection *poGC,
604
                                        const double dfElevation)
605
606
65.3k
{
607
65.3k
    int nCode = 0;
608
65.3k
    char szLineBuf[257];
609
65.3k
    DXFSmoothPolyline oSmoothPolyline;
610
65.3k
    double dfBulge = 0.0;
611
65.3k
    double dfX = 0.0;
612
65.3k
    double dfY = 0.0;
613
65.3k
    bool bHaveX = false;
614
65.3k
    bool bHaveY = false;
615
65.3k
    bool bIsClosed = false;
616
65.3k
    int nVertexCount = -1;
617
65.3k
    bool bHaveBulges = false;
618
619
65.3k
    if (dfElevation != 0)
620
10.5k
        oSmoothPolyline.setCoordinateDimension(3);
621
622
    /* -------------------------------------------------------------------- */
623
    /*      Read the boundary path type.                                    */
624
    /* -------------------------------------------------------------------- */
625
1.92M
    while ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) > 0)
626
1.87M
    {
627
1.87M
        if (nVertexCount > 0 && (int)oSmoothPolyline.size() == nVertexCount)
628
14.5k
            break;
629
630
1.86M
        switch (nCode)
631
1.86M
        {
632
98.2k
            case 93:
633
98.2k
                nVertexCount = atoi(szLineBuf);
634
98.2k
                break;
635
636
27.5k
            case 72:
637
27.5k
                bHaveBulges = CPL_TO_BOOL(atoi(szLineBuf));
638
27.5k
                break;
639
640
13.3k
            case 73:
641
13.3k
                bIsClosed = CPL_TO_BOOL(atoi(szLineBuf));
642
13.3k
                break;
643
644
369k
            case 10:
645
369k
                if (bHaveX && bHaveY)
646
36.8k
                {
647
36.8k
                    oSmoothPolyline.AddPoint(dfX, dfY, dfElevation, dfBulge);
648
36.8k
                    dfBulge = 0.0;
649
36.8k
                    bHaveY = false;
650
36.8k
                }
651
369k
                dfX = CPLAtof(szLineBuf);
652
369k
                bHaveX = true;
653
369k
                break;
654
655
311k
            case 20:
656
311k
                if (bHaveX && bHaveY)
657
34.1k
                {
658
34.1k
                    oSmoothPolyline.AddPoint(dfX, dfY, dfElevation, dfBulge);
659
34.1k
                    dfBulge = 0.0;
660
34.1k
                    bHaveX = false;
661
34.1k
                }
662
311k
                dfY = CPLAtof(szLineBuf);
663
311k
                bHaveY = true;
664
311k
                if (bHaveX /* && bHaveY */ && !bHaveBulges)
665
155k
                {
666
155k
                    oSmoothPolyline.AddPoint(dfX, dfY, dfElevation, dfBulge);
667
155k
                    dfBulge = 0.0;
668
155k
                    bHaveX = false;
669
155k
                    bHaveY = false;
670
155k
                }
671
311k
                break;
672
673
99.1k
            case 42:
674
99.1k
                dfBulge = CPLAtof(szLineBuf);
675
99.1k
                if (bHaveX && bHaveY)
676
26.0k
                {
677
26.0k
                    oSmoothPolyline.AddPoint(dfX, dfY, dfElevation, dfBulge);
678
26.0k
                    dfBulge = 0.0;
679
26.0k
                    bHaveX = false;
680
26.0k
                    bHaveY = false;
681
26.0k
                }
682
99.1k
                break;
683
684
944k
            default:
685
944k
                break;
686
1.86M
        }
687
1.86M
    }
688
65.3k
    if (nCode < 0)
689
3.77k
    {
690
3.77k
        DXF_LAYER_READER_ERROR();
691
3.77k
        return OGRERR_FAILURE;
692
3.77k
    }
693
694
61.5k
    if (nCode != 10 && nCode != 20 && nCode != 42)
695
57.6k
        poDS->UnreadValue();
696
697
61.5k
    if (bHaveX && bHaveY)
698
6.07k
        oSmoothPolyline.AddPoint(dfX, dfY, dfElevation, dfBulge);
699
700
61.5k
    if (bIsClosed)
701
4.09k
        oSmoothPolyline.Close();
702
703
61.5k
    if (oSmoothPolyline.IsEmpty())
704
9.33k
    {
705
9.33k
        return OGRERR_FAILURE;
706
9.33k
    }
707
708
    // Only process polylines with at least 2 vertices
709
52.2k
    if (nVertexCount >= 2)
710
43.1k
    {
711
43.1k
        oSmoothPolyline.SetUseMaxGapWhenTessellatingArcs(poDS->InlineBlocks());
712
43.1k
        poGC->addGeometryDirectly(oSmoothPolyline.Tessellate(false));
713
43.1k
    }
714
715
    /* -------------------------------------------------------------------- */
716
    /*      Skip through source boundary objects if present.                */
717
    /* -------------------------------------------------------------------- */
718
52.2k
    nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
719
52.2k
    if (nCode != 97)
720
51.2k
    {
721
51.2k
        if (nCode < 0)
722
191
            return OGRERR_FAILURE;
723
51.1k
        poDS->UnreadValue();
724
51.1k
    }
725
921
    else
726
921
    {
727
921
        int iObj, nObjCount = atoi(szLineBuf);
728
729
2.13k
        for (iObj = 0; iObj < nObjCount; iObj++)
730
1.29k
        {
731
1.29k
            if (poDS->ReadValue(szLineBuf, sizeof(szLineBuf)) < 0)
732
80
                return OGRERR_FAILURE;
733
1.29k
        }
734
921
    }
735
51.9k
    return OGRERR_NONE;
736
52.2k
}