Coverage Report

Created: 2025-08-11 09:23

/src/gdal/ogr/ogrsf_frmts/dxf/ogrdxf_hatch.cpp
Line
Count
Source (jump to first uncovered line)
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
89.4k
{
35
89.4k
    char szLineBuf[257];
36
89.4k
    int nCode = 0;
37
89.4k
    OGRDXFFeature *poFeature = new OGRDXFFeature(poFeatureDefn);
38
39
89.4k
    double dfElevation = 0.0;  // Z value to be used for EVERY point
40
89.4k
    OGRGeometryCollection oGC;
41
89.4k
    std::string osExtendedData;
42
43
1.09M
    while ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) > 0)
44
1.00M
    {
45
1.00M
        switch (nCode)
46
1.00M
        {
47
40.4k
            case 30:
48
                // Constant elevation.
49
40.4k
                dfElevation = CPLAtof(szLineBuf);
50
40.4k
                break;
51
52
27.7k
            case 70:
53
27.7k
            {
54
27.7k
                const int nFillFlag = atoi(szLineBuf);
55
27.7k
                poFeature->oStyleProperties["FillFlag"] =
56
27.7k
                    nFillFlag ? "Filled" : "Pattern";
57
27.7k
                break;
58
0
            }
59
60
81.7k
            case 2:  // Hatch pattern name
61
81.7k
                poFeature->SetField("Text", szLineBuf);
62
81.7k
                break;
63
64
149k
            case 91:
65
149k
            {
66
149k
                int nBoundaryPathCount = atoi(szLineBuf);
67
68
220k
                for (int iBoundary = 0; iBoundary < nBoundaryPathCount;
69
149k
                     iBoundary++)
70
185k
                {
71
185k
                    if (CollectBoundaryPath(&oGC, dfElevation) != OGRERR_NONE)
72
114k
                        break;
73
185k
                }
74
149k
            }
75
149k
            break;
76
77
636
            case 52:
78
636
            {
79
636
                poFeature->oStyleProperties["HatchPatternRotation"] = szLineBuf;
80
636
                break;
81
0
            }
82
83
3.33k
            case 41:
84
3.33k
            {
85
3.33k
                poFeature->oStyleProperties["HatchPatternScale"] = szLineBuf;
86
3.33k
                break;
87
0
            }
88
89
827
            case 1001:
90
827
            {
91
827
                osExtendedData = szLineBuf;
92
827
                break;
93
0
            }
94
95
897
            case 1071:
96
897
            {
97
897
                if (osExtendedData == "HATCHBACKGROUNDCOLOR")
98
0
                    poFeature->oStyleProperties["HatchBackgroundColor"] =
99
0
                        szLineBuf;
100
897
                break;
101
0
            }
102
103
700k
            default:
104
700k
                TranslateGenericProperty(poFeature, nCode, szLineBuf);
105
700k
                break;
106
1.00M
        }
107
1.00M
    }
108
89.4k
    if (nCode < 0)
109
3.83k
    {
110
3.83k
        DXF_LAYER_READER_ERROR();
111
3.83k
        delete poFeature;
112
3.83k
        return nullptr;
113
3.83k
    }
114
115
85.5k
    if (nCode == 0)
116
85.5k
        poDS->UnreadValue();
117
118
    /* -------------------------------------------------------------------- */
119
    /*      Obtain a tolerance value used when building the polygon.        */
120
    /* -------------------------------------------------------------------- */
121
85.5k
    double dfTolerance = poDS->HatchTolerance();
122
85.5k
    if (dfTolerance < 0)
123
85.5k
    {
124
        // If the configuration variable isn't set, compute the bounding box
125
        // and work out a tolerance from that
126
85.5k
        OGREnvelope oEnvelope;
127
85.5k
        oGC.getEnvelope(&oEnvelope);
128
85.5k
        dfTolerance = std::max(oEnvelope.MaxX - oEnvelope.MinX,
129
85.5k
                               oEnvelope.MaxY - oEnvelope.MinY) *
130
85.5k
                      1e-7;
131
85.5k
    }
132
133
    /* -------------------------------------------------------------------- */
134
    /*      Try to turn the set of lines into something useful.             */
135
    /* -------------------------------------------------------------------- */
136
85.5k
    OGRErr eErr;
137
138
85.5k
    OGRGeometry *poFinalGeom = (OGRGeometry *)OGRBuildPolygonFromEdges(
139
85.5k
        (OGRGeometryH)&oGC, TRUE, TRUE, dfTolerance, &eErr);
140
85.5k
    if (eErr != OGRERR_NONE)
141
22.9k
    {
142
22.9k
        delete poFinalGeom;
143
22.9k
        OGRMultiLineString *poMLS = new OGRMultiLineString();
144
68.1k
        for (int i = 0; i < oGC.getNumGeometries(); i++)
145
45.1k
            poMLS->addGeometry(oGC.getGeometryRef(i));
146
22.9k
        poFinalGeom = poMLS;
147
22.9k
    }
148
149
85.5k
    poFeature->ApplyOCSTransformer(poFinalGeom);
150
85.5k
    poFeature->SetGeometryDirectly(poFinalGeom);
151
152
85.5k
    PrepareBrushStyle(poFeature);
153
154
85.5k
    return poFeature;
155
89.4k
}
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.2k
    {
173
77.2k
        DXF_LAYER_READER_ERROR();
174
77.2k
        return OGRERR_FAILURE;
175
77.2k
    }
176
177
108k
    const int nBoundaryPathType = atoi(szLineBuf);
178
179
    /* ==================================================================== */
180
    /*      Handle polyline loops.                                          */
181
    /* ==================================================================== */
182
108k
    if (nBoundaryPathType & 0x02)
183
60.8k
        return CollectPolylinePath(poGC, dfElevation);
184
185
    /* ==================================================================== */
186
    /*      Handle non-polyline loops.                                      */
187
    /* ==================================================================== */
188
189
    /* -------------------------------------------------------------------- */
190
    /*      Read number of edges.                                           */
191
    /* -------------------------------------------------------------------- */
192
47.6k
    nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
193
47.6k
    if (nCode != 93)
194
6.05k
    {
195
6.05k
        DXF_LAYER_READER_ERROR();
196
6.05k
        return OGRERR_FAILURE;
197
6.05k
    }
198
199
41.6k
    const int nEdgeCount = atoi(szLineBuf);
200
201
    /* -------------------------------------------------------------------- */
202
    /*      Loop reading edges.                                             */
203
    /* -------------------------------------------------------------------- */
204
70.2k
    for (int iEdge = 0; iEdge < nEdgeCount; iEdge++)
205
66.5k
    {
206
        /* --------------------------------------------------------------------
207
         */
208
        /*      Read the edge type. */
209
        /* --------------------------------------------------------------------
210
         */
211
66.5k
        const int ET_LINE = 1;
212
66.5k
        const int ET_CIRCULAR_ARC = 2;
213
66.5k
        const int ET_ELLIPTIC_ARC = 3;
214
66.5k
        const int ET_SPLINE = 4;
215
216
66.5k
        nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
217
66.5k
        if (nCode != 72)
218
10.3k
        {
219
10.3k
            DXF_LAYER_READER_ERROR();
220
10.3k
            return OGRERR_FAILURE;
221
10.3k
        }
222
223
56.2k
        int nEdgeType = atoi(szLineBuf);
224
225
        /* --------------------------------------------------------------------
226
         */
227
        /*      Process a line edge. */
228
        /* --------------------------------------------------------------------
229
         */
230
56.2k
        if (nEdgeType == ET_LINE)
231
21.6k
        {
232
21.6k
            double dfStartX = 0.0;
233
234
21.6k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 10)
235
20.1k
                dfStartX = CPLAtof(szLineBuf);
236
1.53k
            else
237
1.53k
                break;
238
239
20.1k
            double dfStartY = 0.0;
240
241
20.1k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 20)
242
18.5k
                dfStartY = CPLAtof(szLineBuf);
243
1.58k
            else
244
1.58k
                break;
245
246
18.5k
            double dfEndX = 0.0;
247
248
18.5k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 11)
249
15.9k
                dfEndX = CPLAtof(szLineBuf);
250
2.62k
            else
251
2.62k
                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.18k
            else
258
1.18k
                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
34.5k
        else if (nEdgeType == ET_CIRCULAR_ARC)
273
15.3k
        {
274
15.3k
            double dfCenterX = 0.0;
275
276
15.3k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 10)
277
14.5k
                dfCenterX = CPLAtof(szLineBuf);
278
768
            else
279
768
                break;
280
281
14.5k
            double dfCenterY = 0.0;
282
283
14.5k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 20)
284
13.5k
                dfCenterY = CPLAtof(szLineBuf);
285
1.05k
            else
286
1.05k
                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
535
            else
293
535
                break;
294
295
12.9k
            double dfStartAngle = 0.0;
296
297
12.9k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 50)
298
12.3k
                dfStartAngle = CPLAtof(szLineBuf);
299
640
            else
300
640
                break;
301
302
12.3k
            double dfEndAngle = 0.0;
303
304
12.3k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 51)
305
11.7k
                dfEndAngle = CPLAtof(szLineBuf);
306
633
            else
307
633
                break;
308
309
11.7k
            bool bCounterClockwise = false;
310
311
11.7k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 73)
312
836
                bCounterClockwise = atoi(szLineBuf) != 0;
313
10.8k
            else if (nCode >= 0)
314
10.7k
                poDS->UnreadValue();
315
93
            else
316
93
                break;
317
318
11.6k
            if (dfStartAngle > dfEndAngle)
319
6.01k
                dfEndAngle += 360.0;
320
11.6k
            if (bCounterClockwise)
321
833
            {
322
833
                dfStartAngle *= -1;
323
833
                dfEndAngle *= -1;
324
833
            }
325
326
11.6k
            if (fabs(dfEndAngle - dfStartAngle) <= 361.0)
327
11.3k
            {
328
11.3k
                OGRGeometry *poArc = OGRGeometryFactory::approximateArcAngles(
329
11.3k
                    dfCenterX, dfCenterY, dfElevation, dfRadius, dfRadius, 0.0,
330
11.3k
                    dfStartAngle, dfEndAngle, 0.0, poDS->InlineBlocks());
331
332
                // If the input was 2D, we assume we want to keep it that way
333
11.3k
                if (dfElevation == 0.0)
334
8.31k
                    poArc->flattenTo2D();
335
336
11.3k
                poGC->addGeometryDirectly(poArc);
337
11.3k
            }
338
268
            else
339
268
            {
340
                // TODO: emit error ?
341
268
            }
342
11.6k
        }
343
344
        /* --------------------------------------------------------------------
345
         */
346
        /*      Process an elliptical arc. */
347
        /* --------------------------------------------------------------------
348
         */
349
19.2k
        else if (nEdgeType == ET_ELLIPTIC_ARC)
350
9.21k
        {
351
9.21k
            double dfCenterX = 0.0;
352
353
9.21k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 10)
354
6.76k
                dfCenterX = CPLAtof(szLineBuf);
355
2.44k
            else
356
2.44k
                break;
357
358
6.76k
            double dfCenterY = 0.0;
359
360
6.76k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 20)
361
5.61k
                dfCenterY = CPLAtof(szLineBuf);
362
1.14k
            else
363
1.14k
                break;
364
365
5.61k
            double dfMajorX = 0.0;
366
367
5.61k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 11)
368
4.47k
                dfMajorX = CPLAtof(szLineBuf);
369
1.14k
            else
370
1.14k
                break;
371
372
4.47k
            double dfMajorY = 0.0;
373
374
4.47k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 21)
375
3.73k
                dfMajorY = CPLAtof(szLineBuf);
376
742
            else
377
742
                break;
378
379
3.73k
            double dfRatio = 0.0;
380
381
3.73k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 40)
382
2.66k
                dfRatio = CPLAtof(szLineBuf);
383
3.73k
            if (dfRatio == 0.0)
384
1.06k
                break;
385
386
2.66k
            double dfStartAngle = 0.0;
387
388
2.66k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 50)
389
2.25k
                dfStartAngle = CPLAtof(szLineBuf);
390
412
            else
391
412
                break;
392
393
2.25k
            double dfEndAngle = 0.0;
394
395
2.25k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 51)
396
1.84k
                dfEndAngle = CPLAtof(szLineBuf);
397
412
            else
398
412
                break;
399
400
1.84k
            bool bCounterClockwise = false;
401
402
1.84k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 73)
403
970
                bCounterClockwise = atoi(szLineBuf) != 0;
404
873
            else if (nCode >= 0)
405
762
                poDS->UnreadValue();
406
111
            else
407
111
                break;
408
409
1.73k
            if (dfStartAngle > dfEndAngle)
410
1.23k
                dfEndAngle += 360.0;
411
1.73k
            if (bCounterClockwise)
412
970
            {
413
970
                dfStartAngle *= -1;
414
970
                dfEndAngle *= -1;
415
970
            }
416
417
1.73k
            const double dfMajorRadius =
418
1.73k
                sqrt(dfMajorX * dfMajorX + dfMajorY * dfMajorY);
419
1.73k
            const double dfMinorRadius = dfMajorRadius * dfRatio;
420
421
1.73k
            const double dfRotation =
422
1.73k
                -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.73k
            dfStartAngle =
428
1.73k
                180.0 * round(dfStartAngle / 180) +
429
1.73k
                (fabs(fmod(dfStartAngle, 180)) == 90
430
1.73k
                     ? (std::signbit(dfStartAngle) ? 180 : -180)
431
1.73k
                     : 0) +
432
1.73k
                atan((1.0 / dfRatio) * tan(dfStartAngle * M_PI / 180)) * 180 /
433
1.73k
                    M_PI;
434
1.73k
            dfEndAngle = 180.0 * round(dfEndAngle / 180) +
435
1.73k
                         (fabs(fmod(dfEndAngle, 180)) == 90
436
1.73k
                              ? (std::signbit(dfEndAngle) ? 180 : -180)
437
1.73k
                              : 0) +
438
1.73k
                         atan((1.0 / dfRatio) * tan(dfEndAngle * M_PI / 180)) *
439
1.73k
                             180 / M_PI;
440
441
1.73k
            if (fabs(dfEndAngle - dfStartAngle) <= 361.0)
442
723
            {
443
723
                OGRGeometry *poArc = OGRGeometryFactory::approximateArcAngles(
444
723
                    dfCenterX, dfCenterY, dfElevation, dfMajorRadius,
445
723
                    dfMinorRadius, dfRotation, dfStartAngle, dfEndAngle, 0.0,
446
723
                    poDS->InlineBlocks());
447
448
                // If the input was 2D, we assume we want to keep it that way
449
723
                if (dfElevation == 0.0)
450
570
                    poArc->flattenTo2D();
451
452
723
                poGC->addGeometryDirectly(poArc);
453
723
            }
454
1.00k
            else
455
1.00k
            {
456
                // TODO: emit error ?
457
1.00k
            }
458
1.73k
        }
459
460
        /* --------------------------------------------------------------------
461
         */
462
        /*      Process an elliptical arc. */
463
        /* --------------------------------------------------------------------
464
         */
465
10.0k
        else if (nEdgeType == ET_SPLINE)
466
8.03k
        {
467
8.03k
            int nDegree = 3;
468
469
8.03k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 94)
470
6.43k
                nDegree = atoi(szLineBuf);
471
1.60k
            else
472
1.60k
                break;
473
474
            // Skip a few things we don't care about
475
6.43k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) != 73)
476
330
                break;
477
6.10k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) != 74)
478
575
                break;
479
480
5.52k
            int nKnots = 0;
481
482
5.52k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 95)
483
4.96k
                nKnots = atoi(szLineBuf);
484
562
            else
485
562
                break;
486
487
4.96k
            int nControlPoints = 0;
488
489
4.96k
            if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 96)
490
4.46k
                nControlPoints = atoi(szLineBuf);
491
499
            else
492
499
                break;
493
494
4.46k
            std::vector<double> adfKnots(FORTRAN_INDEXING, 0.0);
495
496
4.46k
            nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
497
4.46k
            if (nCode != 40)
498
397
                break;
499
500
16.4k
            while (nCode == 40)
501
12.4k
            {
502
12.4k
                adfKnots.push_back(CPLAtof(szLineBuf));
503
12.4k
                nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
504
12.4k
            }
505
506
4.07k
            std::vector<double> adfControlPoints(FORTRAN_INDEXING, 0.0);
507
4.07k
            std::vector<double> adfWeights(FORTRAN_INDEXING, 0.0);
508
509
4.07k
            if (nCode != 10)
510
440
                break;
511
512
9.49k
            while (nCode == 10)
513
8.18k
            {
514
8.18k
                adfControlPoints.push_back(CPLAtof(szLineBuf));
515
516
8.18k
                if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) ==
517
8.18k
                    20)
518
5.86k
                {
519
5.86k
                    adfControlPoints.push_back(CPLAtof(szLineBuf));
520
5.86k
                }
521
2.31k
                else
522
2.31k
                    break;
523
524
5.86k
                adfControlPoints.push_back(0.0);  // Z coordinate
525
526
                // 42 (weights) are optional
527
5.86k
                if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) ==
528
5.86k
                    42)
529
104
                {
530
104
                    adfWeights.push_back(CPLAtof(szLineBuf));
531
104
                    nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
532
104
                }
533
5.86k
            }
534
535
            // Skip past the number of fit points
536
3.63k
            if (nCode != 97)
537
1.31k
                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
2.31k
            nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
542
21.5k
            while (nCode > 0 && nCode != 72 && nCode != 97)
543
19.2k
                nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
544
2.31k
            if (nCode > 0)
545
1.31k
                poDS->UnreadValue();
546
547
2.31k
            auto poLS =
548
2.31k
                InsertSplineWithChecks(nDegree, adfControlPoints,
549
2.31k
                                       /* bHaZ = */ false, nControlPoints,
550
2.31k
                                       adfKnots, nKnots, adfWeights);
551
552
2.31k
            if (!poLS)
553
1.74k
            {
554
1.74k
                DXF_LAYER_READER_ERROR();
555
1.74k
                return OGRERR_FAILURE;
556
1.74k
            }
557
558
565
            poGC->addGeometryDirectly(poLS.release());
559
565
        }
560
561
1.98k
        else
562
1.98k
        {
563
1.98k
            CPLDebug("DXF", "Unsupported HATCH boundary line type:%d",
564
1.98k
                     nEdgeType);
565
1.98k
            return OGRERR_UNSUPPORTED_OPERATION;
566
1.98k
        }
567
56.2k
    }
568
569
27.5k
    if (nCode < 0)
570
1.79k
    {
571
1.79k
        DXF_LAYER_READER_ERROR();
572
1.79k
        return OGRERR_FAILURE;
573
1.79k
    }
574
575
    /* -------------------------------------------------------------------- */
576
    /*      Skip through source boundary objects if present.                */
577
    /* -------------------------------------------------------------------- */
578
25.7k
    nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
579
25.7k
    if (nCode != 97)
580
23.5k
    {
581
23.5k
        if (nCode < 0)
582
1.02k
            return OGRERR_FAILURE;
583
22.5k
        poDS->UnreadValue();
584
22.5k
    }
585
2.21k
    else
586
2.21k
    {
587
2.21k
        int iObj, nObjCount = atoi(szLineBuf);
588
589
10.3k
        for (iObj = 0; iObj < nObjCount; iObj++)
590
9.35k
        {
591
9.35k
            if (poDS->ReadValue(szLineBuf, sizeof(szLineBuf)) < 0)
592
1.16k
                return OGRERR_FAILURE;
593
9.35k
        }
594
2.21k
    }
595
596
23.5k
    return OGRERR_NONE;
597
25.7k
}
598
599
/************************************************************************/
600
/*                        CollectPolylinePath()                         */
601
/************************************************************************/
602
603
OGRErr OGRDXFLayer::CollectPolylinePath(OGRGeometryCollection *poGC,
604
                                        const double dfElevation)
605
606
60.8k
{
607
60.8k
    int nCode = 0;
608
60.8k
    char szLineBuf[257];
609
60.8k
    DXFSmoothPolyline oSmoothPolyline;
610
60.8k
    double dfBulge = 0.0;
611
60.8k
    double dfX = 0.0;
612
60.8k
    double dfY = 0.0;
613
60.8k
    bool bHaveX = false;
614
60.8k
    bool bHaveY = false;
615
60.8k
    bool bIsClosed = false;
616
60.8k
    int nVertexCount = -1;
617
60.8k
    bool bHaveBulges = false;
618
619
60.8k
    if (dfElevation != 0)
620
10.5k
        oSmoothPolyline.setCoordinateDimension(3);
621
622
    /* -------------------------------------------------------------------- */
623
    /*      Read the boundary path type.                                    */
624
    /* -------------------------------------------------------------------- */
625
1.54M
    while ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) > 0)
626
1.49M
    {
627
1.49M
        if (nVertexCount > 0 && (int)oSmoothPolyline.size() == nVertexCount)
628
11.7k
            break;
629
630
1.48M
        switch (nCode)
631
1.48M
        {
632
86.7k
            case 93:
633
86.7k
                nVertexCount = atoi(szLineBuf);
634
86.7k
                break;
635
636
29.7k
            case 72:
637
29.7k
                bHaveBulges = CPL_TO_BOOL(atoi(szLineBuf));
638
29.7k
                break;
639
640
13.3k
            case 73:
641
13.3k
                bIsClosed = CPL_TO_BOOL(atoi(szLineBuf));
642
13.3k
                break;
643
644
300k
            case 10:
645
300k
                if (bHaveX && bHaveY)
646
34.9k
                {
647
34.9k
                    oSmoothPolyline.AddPoint(dfX, dfY, dfElevation, dfBulge);
648
34.9k
                    dfBulge = 0.0;
649
34.9k
                    bHaveY = false;
650
34.9k
                }
651
300k
                dfX = CPLAtof(szLineBuf);
652
300k
                bHaveX = true;
653
300k
                break;
654
655
255k
            case 20:
656
255k
                if (bHaveX && bHaveY)
657
27.0k
                {
658
27.0k
                    oSmoothPolyline.AddPoint(dfX, dfY, dfElevation, dfBulge);
659
27.0k
                    dfBulge = 0.0;
660
27.0k
                    bHaveX = false;
661
27.0k
                }
662
255k
                dfY = CPLAtof(szLineBuf);
663
255k
                bHaveY = true;
664
255k
                if (bHaveX /* && bHaveY */ && !bHaveBulges)
665
121k
                {
666
121k
                    oSmoothPolyline.AddPoint(dfX, dfY, dfElevation, dfBulge);
667
121k
                    dfBulge = 0.0;
668
121k
                    bHaveX = false;
669
121k
                    bHaveY = false;
670
121k
                }
671
255k
                break;
672
673
87.5k
            case 42:
674
87.5k
                dfBulge = CPLAtof(szLineBuf);
675
87.5k
                if (bHaveX && bHaveY)
676
22.0k
                {
677
22.0k
                    oSmoothPolyline.AddPoint(dfX, dfY, dfElevation, dfBulge);
678
22.0k
                    dfBulge = 0.0;
679
22.0k
                    bHaveX = false;
680
22.0k
                    bHaveY = false;
681
22.0k
                }
682
87.5k
                break;
683
684
707k
            default:
685
707k
                break;
686
1.48M
        }
687
1.48M
    }
688
60.8k
    if (nCode < 0)
689
2.59k
    {
690
2.59k
        DXF_LAYER_READER_ERROR();
691
2.59k
        return OGRERR_FAILURE;
692
2.59k
    }
693
694
58.2k
    if (nCode != 10 && nCode != 20 && nCode != 42)
695
54.6k
        poDS->UnreadValue();
696
697
58.2k
    if (bHaveX && bHaveY)
698
6.24k
        oSmoothPolyline.AddPoint(dfX, dfY, dfElevation, dfBulge);
699
700
58.2k
    if (bIsClosed)
701
4.80k
        oSmoothPolyline.Close();
702
703
58.2k
    if (oSmoothPolyline.IsEmpty())
704
9.90k
    {
705
9.90k
        return OGRERR_FAILURE;
706
9.90k
    }
707
708
    // Only process polylines with at least 2 vertices
709
48.3k
    if (nVertexCount >= 2)
710
39.3k
    {
711
39.3k
        oSmoothPolyline.SetUseMaxGapWhenTessellatingArcs(poDS->InlineBlocks());
712
39.3k
        poGC->addGeometryDirectly(oSmoothPolyline.Tessellate(false));
713
39.3k
    }
714
715
    /* -------------------------------------------------------------------- */
716
    /*      Skip through source boundary objects if present.                */
717
    /* -------------------------------------------------------------------- */
718
48.3k
    nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
719
48.3k
    if (nCode != 97)
720
46.5k
    {
721
46.5k
        if (nCode < 0)
722
191
            return OGRERR_FAILURE;
723
46.3k
        poDS->UnreadValue();
724
46.3k
    }
725
1.79k
    else
726
1.79k
    {
727
1.79k
        int iObj, nObjCount = atoi(szLineBuf);
728
729
40.0k
        for (iObj = 0; iObj < nObjCount; iObj++)
730
38.5k
        {
731
38.5k
            if (poDS->ReadValue(szLineBuf, sizeof(szLineBuf)) < 0)
732
259
                return OGRERR_FAILURE;
733
38.5k
        }
734
1.79k
    }
735
47.8k
    return OGRERR_NONE;
736
48.3k
}