LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/dxf - ogrdxf_hatch.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 270 352 76.7 %
Date: 2025-08-01 10:10:57 Functions: 3 3 100.0 %

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

Generated by: LCOV version 1.14