Coverage Report

Created: 2025-12-03 08:24

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