LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/dxf - ogr_dxf.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 167 181 92.3 %
Date: 2026-02-12 23:49:34 Functions: 55 63 87.3 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  DXF Translator
       4             :  * Purpose:  Definition of classes for OGR .dxf driver.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2009,  Frank Warmerdam
       9             :  * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  * Copyright (c) 2017, Alan Thomas <alant@outlook.com.au>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #ifndef OGR_DXF_H_INCLUDED
      16             : #define OGR_DXF_H_INCLUDED
      17             : 
      18             : #include "ogrsf_frmts.h"
      19             : #include "ogr_autocad_services.h"
      20             : #include "cpl_conv.h"
      21             : #include <array>
      22             : #include <vector>
      23             : #include <map>
      24             : #include <optional>
      25             : #include <set>
      26             : #include <queue>
      27             : #include <memory>
      28             : #include <utility>
      29             : 
      30             : class OGRDXFDataSource;
      31             : class OGRDXFFeature;
      32             : 
      33             : constexpr std::array<char, 22> AUTOCAD_BINARY_DXF_SIGNATURE = {
      34             :     'A', 'u', 't', 'o', 'C', 'A', 'D', ' ',  'B',  'i',    'n',
      35             :     'a', 'r', 'y', ' ', 'D', 'X', 'F', '\r', '\n', '\x1A', '\x00'};
      36             : 
      37             : /************************************************************************/
      38             : /*                          DXFBlockDefinition                          */
      39             : /*                                                                      */
      40             : /*      Container for info about a block.                               */
      41             : /************************************************************************/
      42             : 
      43             : class DXFBlockDefinition
      44             : {
      45             :   public:
      46          87 :     DXFBlockDefinition()
      47          87 :     {
      48          87 :     }
      49             : 
      50             :     ~DXFBlockDefinition();
      51             : 
      52             :     std::vector<OGRDXFFeature *> apoFeatures;
      53             : };
      54             : 
      55             : /************************************************************************/
      56             : /*                          OGRDXFFeatureQueue                          */
      57             : /************************************************************************/
      58             : 
      59             : class OGRDXFFeatureQueue
      60             : {
      61             :     std::queue<OGRDXFFeature *> apoFeatures;
      62             : 
      63             :   public:
      64         745 :     OGRDXFFeatureQueue()
      65         745 :     {
      66         745 :     }
      67             : 
      68             :     void push(OGRDXFFeature *poFeature);
      69             : 
      70        4383 :     OGRDXFFeature *front() const
      71             :     {
      72        4383 :         return apoFeatures.front();
      73             :     }
      74             : 
      75             :     void pop();
      76             : 
      77       10063 :     bool empty() const
      78             :     {
      79       10063 :         return apoFeatures.empty();
      80             :     }
      81             : 
      82             :     size_t size() const
      83             :     {
      84             :         return apoFeatures.size();
      85             :     }
      86             : };
      87             : 
      88             : /************************************************************************/
      89             : /*                          OGRDXFBlocksLayer                           */
      90             : /************************************************************************/
      91             : 
      92             : class OGRDXFBlocksLayer final : public OGRLayer
      93             : {
      94             :     OGRDXFDataSource *poDS;
      95             : 
      96             :     OGRFeatureDefn *poFeatureDefn;
      97             : 
      98             :     GIntBig iNextFID;
      99             : 
     100             :     std::map<CPLString, DXFBlockDefinition>::iterator oIt;
     101             :     CPLString osBlockName;
     102             : 
     103             :     OGRDXFFeatureQueue apoPendingFeatures;
     104             : 
     105             :   public:
     106             :     explicit OGRDXFBlocksLayer(OGRDXFDataSource *poDS);
     107             :     ~OGRDXFBlocksLayer() override;
     108             : 
     109             :     void ResetReading() override;
     110             :     OGRFeature *GetNextFeature() override;
     111             : 
     112          17 :     const OGRFeatureDefn *GetLayerDefn() const override
     113             :     {
     114          17 :         return poFeatureDefn;
     115             :     }
     116             : 
     117             :     int TestCapability(const char *) const override;
     118             : 
     119             :     OGRDXFFeature *GetNextUnfilteredFeature();
     120             : };
     121             : 
     122             : /************************************************************************/
     123             : /*                       OGRDXFInsertTransformer                        */
     124             : /*                                                                      */
     125             : /*      Stores the transformation needed to insert a block reference.   */
     126             : /************************************************************************/
     127             : 
     128             : class OGRDXFInsertTransformer final : public OGRCoordinateTransformation
     129             : {
     130             :   public:
     131         441 :     OGRDXFInsertTransformer() = default;
     132             : 
     133             :     double dfXOffset = 0.0;
     134             :     double dfYOffset = 0.0;
     135             :     double dfZOffset = 0.0;
     136             :     double dfXScale = 1.0;
     137             :     double dfYScale = 1.0;
     138             :     double dfZScale = 1.0;
     139             :     double dfAngle = 0.0;
     140             : 
     141        2429 :     OGRDXFInsertTransformer GetOffsetTransformer()
     142             :     {
     143        2429 :         OGRDXFInsertTransformer oResult;
     144        2429 :         oResult.dfXOffset = this->dfXOffset;
     145        2429 :         oResult.dfYOffset = this->dfYOffset;
     146        2429 :         oResult.dfZOffset = this->dfZOffset;
     147        2429 :         return oResult;
     148             :     }
     149             : 
     150        2429 :     OGRDXFInsertTransformer GetRotateScaleTransformer()
     151             :     {
     152        2429 :         OGRDXFInsertTransformer oResult;
     153        2429 :         oResult.dfXScale = this->dfXScale;
     154        2429 :         oResult.dfYScale = this->dfYScale;
     155        2429 :         oResult.dfZScale = this->dfZScale;
     156        2429 :         oResult.dfAngle = this->dfAngle;
     157        2429 :         return oResult;
     158             :     }
     159             : 
     160             :     OGRCoordinateTransformation *Clone() const override;
     161             : 
     162           0 :     const OGRSpatialReference *GetSourceCS() const override
     163             :     {
     164           0 :         return nullptr;
     165             :     }
     166             : 
     167        6962 :     const OGRSpatialReference *GetTargetCS() const override
     168             :     {
     169        6962 :         return nullptr;
     170             :     }
     171             : 
     172        6815 :     int Transform(size_t nCount, double *x, double *y, double *z,
     173             :                   double * /* t */, int *pabSuccess) override
     174             :     {
     175       29723 :         for (size_t i = 0; i < nCount; i++)
     176             :         {
     177       22908 :             x[i] *= dfXScale;
     178       22908 :             y[i] *= dfYScale;
     179       22908 :             if (z)
     180       22908 :                 z[i] *= dfZScale;
     181             : 
     182       22908 :             const double dfXNew = x[i] * cos(dfAngle) - y[i] * sin(dfAngle);
     183       22908 :             const double dfYNew = x[i] * sin(dfAngle) + y[i] * cos(dfAngle);
     184             : 
     185       22908 :             x[i] = dfXNew;
     186       22908 :             y[i] = dfYNew;
     187             : 
     188       22908 :             x[i] += dfXOffset;
     189       22908 :             y[i] += dfYOffset;
     190       22908 :             if (z)
     191       22908 :                 z[i] += dfZOffset;
     192             : 
     193       22908 :             if (pabSuccess)
     194       22908 :                 pabSuccess[i] = TRUE;
     195             :         }
     196        6815 :         return TRUE;
     197             :     }
     198             : 
     199           0 :     OGRCoordinateTransformation *GetInverse() const override
     200             :     {
     201           0 :         return nullptr;
     202             :     }
     203             : };
     204             : 
     205             : /************************************************************************/
     206             : /*                         OGRDXFAffineTransform                        */
     207             : /*                                                                      */
     208             : /*    A simple 3D affine transform used to keep track of the            */
     209             : /*    transformation to be applied to an ASM entity.                    */
     210             : /************************************************************************/
     211             : 
     212             : class OGRDXFAffineTransform
     213             : {
     214             :   public:
     215           2 :     OGRDXFAffineTransform()
     216           2 :         : adfData{1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0}
     217             :     {
     218           2 :     }
     219             : 
     220             :     double adfData[12];  // Column-major: adfMatrix[5] is column 2, row 3
     221             : 
     222             :     // Last 3 elements are translation
     223             : 
     224             :     // Left composition (composes oOther o this), modifying this
     225           6 :     void ComposeWith(const OGRDXFInsertTransformer &oCT)
     226             :     {
     227             :         double adfNew[12];
     228             : 
     229           6 :         adfNew[0] = oCT.dfXScale * cos(oCT.dfAngle) * adfData[0] -
     230           6 :                     oCT.dfYScale * sin(oCT.dfAngle) * adfData[1];
     231           6 :         adfNew[1] = oCT.dfXScale * sin(oCT.dfAngle) * adfData[0] +
     232           6 :                     oCT.dfYScale * cos(oCT.dfAngle) * adfData[1];
     233           6 :         adfNew[2] = oCT.dfZScale * adfData[2];
     234             : 
     235           6 :         adfNew[3] = oCT.dfXScale * cos(oCT.dfAngle) * adfData[3] -
     236           6 :                     oCT.dfYScale * sin(oCT.dfAngle) * adfData[4];
     237           6 :         adfNew[4] = oCT.dfXScale * sin(oCT.dfAngle) * adfData[3] +
     238           6 :                     oCT.dfYScale * cos(oCT.dfAngle) * adfData[4];
     239           6 :         adfNew[5] = oCT.dfZScale * adfData[5];
     240             : 
     241           6 :         adfNew[6] = oCT.dfXScale * cos(oCT.dfAngle) * adfData[6] -
     242           6 :                     oCT.dfYScale * sin(oCT.dfAngle) * adfData[7];
     243           6 :         adfNew[7] = oCT.dfXScale * sin(oCT.dfAngle) * adfData[6] +
     244           6 :                     oCT.dfYScale * cos(oCT.dfAngle) * adfData[7];
     245           6 :         adfNew[8] = oCT.dfZScale * adfData[8];
     246             : 
     247           6 :         adfNew[9] = oCT.dfXScale * cos(oCT.dfAngle) * adfData[9] -
     248           6 :                     oCT.dfYScale * sin(oCT.dfAngle) * adfData[10] +
     249           6 :                     oCT.dfXOffset;
     250           6 :         adfNew[10] = oCT.dfXScale * sin(oCT.dfAngle) * adfData[9] +
     251           6 :                      oCT.dfYScale * cos(oCT.dfAngle) * adfData[10] +
     252           6 :                      oCT.dfYOffset;
     253           6 :         adfNew[11] = oCT.dfZScale * adfData[11] + oCT.dfZOffset;
     254             : 
     255           6 :         memcpy(adfData, adfNew, sizeof(adfNew));
     256           6 :     }
     257             : 
     258           5 :     void SetField(OGRFeature *poFeature, const char *pszFieldName) const
     259             :     {
     260           5 :         poFeature->SetField(pszFieldName, 12, adfData);
     261           5 :     }
     262             : };
     263             : 
     264             : /************************************************************************/
     265             : /*                         OGRDXFOCSTransformer                         */
     266             : /************************************************************************/
     267             : 
     268             : class OGRDXFOCSTransformer final : public OGRCoordinateTransformation
     269             : {
     270             :   private:
     271             :     double adfN[3];
     272             :     double adfAX[3];
     273             :     double adfAY[3];
     274             : 
     275             :     double dfDeterminant;
     276             :     double aadfInverse[4][4];
     277             : 
     278             :   public:
     279             :     explicit OGRDXFOCSTransformer(double adfNIn[3], bool bInverse = false);
     280             : 
     281           0 :     const OGRSpatialReference *GetSourceCS() const override
     282             :     {
     283           0 :         return nullptr;
     284             :     }
     285             : 
     286        3994 :     const OGRSpatialReference *GetTargetCS() const override
     287             :     {
     288        3994 :         return nullptr;
     289             :     }
     290             : 
     291             :     int Transform(size_t nCount, double *adfX, double *adfY, double *adfZ,
     292             :                   double *adfT, int *pabSuccess) override;
     293             : 
     294             :     int InverseTransform(size_t nCount, double *adfX, double *adfY,
     295             :                          double *adfZ);
     296             : 
     297             :     void ComposeOnto(OGRDXFAffineTransform &poCT) const;
     298             : 
     299           0 :     OGRCoordinateTransformation *Clone() const override
     300             :     {
     301           0 :         return new OGRDXFOCSTransformer(*this);
     302             :     }
     303             : 
     304           0 :     OGRCoordinateTransformation *GetInverse() const override
     305             :     {
     306           0 :         return nullptr;
     307             :     }
     308             : };
     309             : 
     310             : /************************************************************************/
     311             : /*                              DXFTriple                               */
     312             : /*                                                                      */
     313             : /*     Represents a triple (X, Y, Z) used for various purposes in       */
     314             : /*     DXF files.  We do not use OGRPoint for this purpose, as the      */
     315             : /*     triple does not always represent a point as such (for            */
     316             : /*     example, it could contain a scale factor for each dimension).    */
     317             : /************************************************************************/
     318             : struct DXFTriple
     319             : {
     320             :     double dfX, dfY, dfZ;
     321             : 
     322          27 :     DXFTriple() : dfX(0.0), dfY(0.0), dfZ(0.0)
     323             :     {
     324          27 :     }
     325             : 
     326       16151 :     DXFTriple(double x, double y, double z) : dfX(x), dfY(y), dfZ(z)
     327             :     {
     328       16151 :     }
     329             : 
     330        3842 :     void ToArray(double adfOut[3]) const
     331             :     {
     332        3842 :         adfOut[0] = dfX;
     333        3842 :         adfOut[1] = dfY;
     334        3842 :         adfOut[2] = dfZ;
     335        3842 :     }
     336             : 
     337          18 :     DXFTriple &operator*=(const double dfValue)
     338             :     {
     339          18 :         dfX *= dfValue;
     340          18 :         dfY *= dfValue;
     341          18 :         dfZ *= dfValue;
     342          18 :         return *this;
     343             :     }
     344             : 
     345           2 :     DXFTriple &operator/=(const double dfValue)
     346             :     {
     347           2 :         dfX /= dfValue;
     348           2 :         dfY /= dfValue;
     349           2 :         dfZ /= dfValue;
     350           2 :         return *this;
     351             :     }
     352             : 
     353             :     bool operator==(const DXFTriple &oOther) const
     354             :     {
     355             :         return dfX == oOther.dfX && dfY == oOther.dfY && dfZ == oOther.dfZ;
     356             :     }
     357             : };
     358             : 
     359             : /************************************************************************/
     360             : /*                            OGRDXFFeature                             */
     361             : /*                                                                      */
     362             : /*     Extends OGRFeature with some DXF-specific members.               */
     363             : /************************************************************************/
     364        9088 : class OGRDXFFeature final : public OGRFeature
     365             : {
     366             :     friend class OGRDXFLayer;
     367             : 
     368             :   protected:
     369             :     // The feature's Object Coordinate System (OCS) unit normal vector
     370             :     DXFTriple oOCS;
     371             : 
     372             :     // A list of properties that are used to construct the style string
     373             :     std::map<CPLString, CPLString> oStyleProperties;
     374             : 
     375             :     // Additional data for INSERT entities
     376             :     bool bIsBlockReference;
     377             :     CPLString osBlockName;
     378             :     double dfBlockAngle;
     379             :     DXFTriple oBlockScale;
     380             : 
     381             :     // Used for INSERT entities when DXF_INLINE_BLOCKS is false, to store
     382             :     // the OCS insertion point
     383             :     DXFTriple oOriginalCoords;
     384             : 
     385             :     // Used in 3D mode to store transformation parameters for ASM entities
     386             :     std::unique_ptr<OGRDXFAffineTransform> poASMTransform;
     387             : 
     388             :     // Additional data for ATTRIB and ATTDEF entities
     389             :     CPLString osAttributeTag;
     390             : 
     391             :     // Store ATTRIB entities associated with an INSERT, for use when
     392             :     // DXF_INLINE_BLOCKS is true and a block with attributes is INSERTed
     393             :     // in another block
     394             :     std::vector<std::unique_ptr<OGRDXFFeature>> apoAttribFeatures;
     395             : 
     396             :   public:
     397             :     explicit OGRDXFFeature(const OGRFeatureDefn *poFeatureDefn);
     398             :     ~OGRDXFFeature() override;
     399             : 
     400             :     OGRDXFFeature *CloneDXFFeature();
     401             : 
     402             :     DXFTriple GetOCS() const
     403             :     {
     404             :         return oOCS;
     405             :     }
     406             : 
     407        3786 :     bool IsBlockReference() const
     408             :     {
     409        3786 :         return bIsBlockReference;
     410             :     }
     411             : 
     412             :     CPLString GetBlockName() const
     413             :     {
     414             :         return osBlockName;
     415             :     }
     416             : 
     417             :     double GetBlockAngle() const
     418             :     {
     419             :         return dfBlockAngle;
     420             :     }
     421             : 
     422             :     DXFTriple GetBlockScale() const
     423             :     {
     424             :         return oBlockScale;
     425             :     }
     426             : 
     427         806 :     DXFTriple GetInsertOCSCoords() const
     428             :     {
     429         806 :         return oOriginalCoords;
     430             :     }
     431             : 
     432          45 :     CPLString GetAttributeTag() const
     433             :     {
     434          45 :         return osAttributeTag;
     435             :     }
     436             : 
     437             :     const std::vector<std::unique_ptr<OGRDXFFeature>> &GetAttribFeatures() const
     438             :     {
     439             :         return apoAttribFeatures;
     440             :     }
     441             : 
     442         806 :     void SetInsertOCSCoords(const DXFTriple &oTriple)
     443             :     {
     444         806 :         oOriginalCoords = oTriple;
     445         806 :     }
     446             : 
     447             :     void ApplyOCSTransformer(OGRGeometry *const poGeometry) const;
     448             :     void ApplyOCSTransformer(OGRDXFAffineTransform *const poCT) const;
     449             :     const CPLString GetColor(OGRDXFDataSource *const poDS,
     450             :                              OGRDXFFeature *const poBlockFeature = nullptr);
     451             : };
     452             : 
     453             : /************************************************************************/
     454             : /*                             OGRDXFLayer                              */
     455             : /************************************************************************/
     456             : class OGRDXFLayer final : public OGRLayer
     457             : {
     458             :     friend class OGRDXFBlocksLayer;
     459             : 
     460             :     OGRDXFDataSource *poDS;
     461             : 
     462             :     OGRFeatureDefn *poFeatureDefn;
     463             :     GIntBig iNextFID;
     464             : 
     465             :     std::set<CPLString> oIgnoredEntities;
     466             : 
     467             :     OGRDXFFeatureQueue apoPendingFeatures;
     468             : 
     469             :     struct InsertState
     470             :     {
     471             :         OGRDXFInsertTransformer m_oTransformer{};
     472             :         CPLString m_osBlockName{};
     473             :         CPLStringList m_aosAttribs{};
     474             :         int m_nColumnCount = 0;
     475             :         int m_nRowCount = 0;
     476             :         int m_iCurCol = 0;
     477             :         int m_iCurRow = 0;
     478             :         double m_dfColumnSpacing = 0.0;
     479             :         double m_dfRowSpacing = 0.0;
     480             :         std::vector<std::unique_ptr<OGRDXFFeature>> m_apoAttribs{};
     481             :         std::unique_ptr<OGRDXFFeature> m_poTemplateFeature{};
     482             :     };
     483             : 
     484             :     InsertState m_oInsertState{};
     485             : 
     486             :     void ClearPendingFeatures();
     487             : 
     488             :     void TranslateGenericProperty(OGRDXFFeature *poFeature, int nCode,
     489             :                                   char *pszValue);
     490             : 
     491             :     void PrepareFeatureStyle(OGRDXFFeature *const poFeature,
     492             :                              OGRDXFFeature *const poBlockFeature = nullptr);
     493             :     void PrepareBrushStyle(OGRDXFFeature *const poFeature,
     494             :                            OGRDXFFeature *const poBlockFeature = nullptr);
     495             :     void PrepareLineStyle(OGRDXFFeature *const poFeature,
     496             :                           OGRDXFFeature *const poBlockFeature = nullptr);
     497             : 
     498             :     OGRDXFFeature *TranslatePOINT();
     499             :     OGRDXFFeature *TranslateLINE();
     500             :     OGRDXFFeature *TranslatePOLYLINE();
     501             :     OGRDXFFeature *TranslateLWPOLYLINE();
     502             :     OGRDXFFeature *TranslateMLINE();
     503             :     OGRDXFFeature *TranslateCIRCLE();
     504             :     OGRDXFFeature *TranslateELLIPSE();
     505             :     OGRDXFFeature *TranslateARC();
     506             :     OGRDXFFeature *TranslateSPLINE();
     507             :     OGRDXFFeature *Translate3DFACE();
     508             :     bool TranslateINSERT();
     509             :     OGRDXFFeature *TranslateMTEXT();
     510             :     OGRDXFFeature *TranslateTEXT(const bool bIsAttribOrAttdef);
     511             :     OGRDXFFeature *TranslateDIMENSION();
     512             :     OGRDXFFeature *TranslateHATCH();
     513             :     OGRDXFFeature *TranslateSOLID();
     514             :     OGRDXFFeature *TranslateLEADER();
     515             :     OGRDXFFeature *TranslateMLEADER();
     516             :     OGRDXFFeature *TranslateWIPEOUT();
     517             :     OGRDXFFeature *TranslateASMEntity();
     518             : 
     519             :     static constexpr int FORTRAN_INDEXING = 1;
     520             : 
     521             :     bool GenerateINSERTFeatures();
     522             :     std::unique_ptr<OGRLineString>
     523             :     InsertSplineWithChecks(const int nDegree,
     524             :                            std::vector<double> &adfControlPoints, bool bHasZ,
     525             :                            int nControlPoints, std::vector<double> &adfKnots,
     526             :                            int nKnots, std::vector<double> &adfWeights);
     527             :     static OGRGeometry *SimplifyBlockGeometry(OGRGeometryCollection *);
     528             :     OGRDXFFeature *InsertBlockInline(GUInt32 nInitialErrorCounter,
     529             :                                      const CPLString &osBlockName,
     530             :                                      OGRDXFInsertTransformer oTransformer,
     531             :                                      OGRDXFFeature *const poFeature,
     532             :                                      OGRDXFFeatureQueue &apoExtraFeatures,
     533             :                                      const bool bInlineNestedBlocks,
     534             :                                      const bool bMergeGeometry);
     535             :     static OGRDXFFeature *
     536             :     InsertBlockReference(const CPLString &osBlockName,
     537             :                          const OGRDXFInsertTransformer &oTransformer,
     538             :                          OGRDXFFeature *const poFeature);
     539             :     static void FormatDimension(CPLString &osText, const double dfValue,
     540             :                                 int nPrecision);
     541             :     void InsertArrowhead(OGRDXFFeature *const poFeature,
     542             :                          const CPLString &osBlockName,
     543             :                          OGRLineString *const poLine,
     544             :                          const double dfArrowheadSize,
     545             :                          const bool bReverse = false);
     546             :     OGRErr CollectBoundaryPath(OGRGeometryCollection *poGC,
     547             :                                const double dfElevation);
     548             :     OGRErr CollectPolylinePath(OGRGeometryCollection *poGC,
     549             :                                const double dfElevation);
     550             : 
     551             :     CPLString TextRecode(const char *);
     552             :     CPLString TextUnescape(const char *, bool);
     553             : 
     554             :   public:
     555             :     explicit OGRDXFLayer(OGRDXFDataSource *poDS);
     556             :     ~OGRDXFLayer() override;
     557             : 
     558             :     void ResetReading() override;
     559             :     OGRFeature *GetNextFeature() override;
     560             : 
     561         406 :     const OGRFeatureDefn *GetLayerDefn() const override
     562             :     {
     563         406 :         return poFeatureDefn;
     564             :     }
     565             : 
     566             :     int TestCapability(const char *) const override;
     567             : 
     568             :     GDALDataset *GetDataset() override;
     569             : 
     570             :     OGRDXFFeature *GetNextUnfilteredFeature();
     571             : };
     572             : 
     573             : /************************************************************************/
     574             : /*                             OGRDXFReader                             */
     575             : /*                                                                      */
     576             : /*      A class for very low level DXF reading without interpretation.  */
     577             : /************************************************************************/
     578             : 
     579             : #define DXF_READER_ERROR()                                                     \
     580             :     do                                                                         \
     581             :     {                                                                          \
     582             :         CPLError(CE_Failure, CPLE_AppDefined,                                  \
     583             :                  "%s, %d: error at line %d of %s", __FILE__, __LINE__,         \
     584             :                  GetLineNumber(), GetDescription());                           \
     585             :     } while (0)
     586             : #define DXF_LAYER_READER_ERROR()                                               \
     587             :     do                                                                         \
     588             :     {                                                                          \
     589             :         CPLError(CE_Failure, CPLE_AppDefined,                                  \
     590             :                  "%s, %d: error at line %d of %s", __FILE__, __LINE__,         \
     591             :                  poDS->GetLineNumber(), poDS->GetDescription());               \
     592             :     } while (0)
     593             : 
     594         426 : class OGRDXFReaderBase /* non final */
     595             : {
     596             :   protected:
     597         224 :     OGRDXFReaderBase() = default;
     598             : 
     599             :   public:
     600             :     virtual ~OGRDXFReaderBase();
     601             : 
     602             :     void Initialize(VSILFILE *fp);
     603             : 
     604             :     VSILFILE *fp = nullptr;
     605             : 
     606             :     unsigned int nLastValueSize = 0;
     607             :     int nLineNumber = 0;
     608             : 
     609             :     virtual uint64_t GetCurrentFilePos() const = 0;
     610             :     virtual int ReadValue(char *pszValueBuffer, int nValueBufferSize = 81) = 0;
     611             :     virtual void UnreadValue() = 0;
     612             :     virtual void ResetReadPointer(uint64_t iNewOffset,
     613             :                                   int nNewLineNumber = 0) = 0;
     614             : };
     615             : 
     616             : class OGRDXFReaderASCII final : public OGRDXFReaderBase
     617             : {
     618             :     int ReadValueRaw(char *pszValueBuffer, int nValueBufferSize);
     619             :     void LoadDiskChunk();
     620             : 
     621             :     unsigned int iSrcBufferOffset = 0;
     622             :     unsigned int nSrcBufferBytes = 0;
     623             :     uint64_t iSrcBufferFileOffset = 0;
     624             :     std::array<char, 1025> achSrcBuffer{};
     625             : 
     626             :   public:
     627         219 :     OGRDXFReaderASCII() = default;
     628             : 
     629         339 :     uint64_t GetCurrentFilePos() const override
     630             :     {
     631         339 :         return iSrcBufferFileOffset + iSrcBufferOffset;
     632             :     }
     633             : 
     634             :     int ReadValue(char *pszValueBuffer, int nValueBufferSize) override;
     635             :     void UnreadValue() override;
     636             :     void ResetReadPointer(uint64_t, int nNewLineNumber) override;
     637             : };
     638             : 
     639             : class OGRDXFReaderBinary final : public OGRDXFReaderBase
     640             : {
     641             :     bool m_bIsR12 = false;
     642             :     uint64_t m_nPrevPos = static_cast<uint64_t>(-1);
     643             : 
     644             :   public:
     645           5 :     OGRDXFReaderBinary() = default;
     646             : 
     647          10 :     uint64_t GetCurrentFilePos() const override
     648             :     {
     649          10 :         return VSIFTellL(fp);
     650             :     }
     651             : 
     652             :     int ReadValue(char *pszValueBuffer, int nValueBufferSize) override;
     653             :     void UnreadValue() override;
     654             :     void ResetReadPointer(uint64_t, int nNewLineNumber) override;
     655             : };
     656             : 
     657             : /************************************************************************/
     658             : /*                           OGRDXFFieldModes                           */
     659             : /*                                                                      */
     660             : /*    Represents which fields should be included in the data source.    */
     661             : /************************************************************************/
     662             : 
     663             : enum OGRDXFFieldModes
     664             : {
     665             :     ODFM_None = 0,
     666             :     ODFM_IncludeRawCodeValues = 0x1,
     667             :     ODFM_IncludeBlockFields = 0x2,
     668             :     ODFM_Include3DModeFields = 0x4
     669             : };
     670             : 
     671             : /************************************************************************/
     672             : /*                           OGRDXFDataSource                           */
     673             : /************************************************************************/
     674             : 
     675             : class OGRDXFDataSource final : public GDALDataset
     676             : {
     677             :     VSILFILE *fp;
     678             : 
     679             :     std::vector<OGRLayer *> apoLayers;
     680             : 
     681             :     uint64_t iEntitiesOffset;
     682             :     int iEntitiesLineNumber;
     683             : 
     684             :     std::map<CPLString, DXFBlockDefinition> oBlockMap;
     685             :     std::map<CPLString, CPLString> oBlockRecordHandles;
     686             :     std::map<CPLString, CPLString> oHeaderVariables;
     687             : 
     688             :     CPLString osEncoding;
     689             : 
     690             :     // indexed by layer name, then by property name.
     691             :     std::map<CPLString, std::map<CPLString, CPLString>> oLayerTable;
     692             : 
     693             :     // indexed by style name, then by property name.
     694             :     std::map<CPLString, std::map<CPLString, CPLString>> oTextStyleTable;
     695             :     std::map<CPLString, CPLString> oTextStyleHandles;
     696             : 
     697             :     // indexed by dimstyle name, then by DIM... variable name
     698             :     std::map<CPLString, std::map<CPLString, CPLString>> oDimStyleTable;
     699             : 
     700             :     std::map<CPLString, std::vector<double>> oLineTypeTable;
     701             : 
     702             :     bool bInlineBlocks;
     703             :     bool bMergeBlockGeometries;
     704             :     bool bTranslateEscapeSequences;
     705             :     bool bIncludeRawCodeValues;
     706             :     bool m_bClosedLineAsPolygon = false;
     707             :     double m_dfHatchTolerance = -1.0;
     708             : 
     709             :     bool b3DExtensibleMode;
     710             :     bool bHaveReadSolidData;
     711             :     std::map<CPLString, std::vector<GByte>> oSolidBinaryData;
     712             : 
     713             :     std::unique_ptr<OGRDXFReaderBase> poReader{};
     714             : 
     715             :     std::vector<CPLString> aosBlockInsertionStack;
     716             : 
     717             :   public:
     718             :     OGRDXFDataSource();
     719             :     ~OGRDXFDataSource() override;
     720             : 
     721             :     bool Open(const char *pszFilename, VSILFILE *fpIn, bool bHeaderOnly,
     722             :               CSLConstList papszOptionsIn);
     723             : 
     724         613 :     int GetLayerCount() const override
     725             :     {
     726         613 :         return static_cast<int>(apoLayers.size());
     727             :     }
     728             : 
     729             :     const OGRLayer *GetLayer(int) const override;
     730             : 
     731             :     int TestCapability(const char *) const override;
     732             : 
     733             :     // The following is only used by OGRDXFLayer
     734             : 
     735        1528 :     bool InlineBlocks() const
     736             :     {
     737        1528 :         return bInlineBlocks;
     738             :     }
     739             : 
     740         141 :     bool ShouldMergeBlockGeometries() const
     741             :     {
     742         141 :         return bMergeBlockGeometries;
     743             :     }
     744             : 
     745         150 :     bool ShouldTranslateEscapes() const
     746             :     {
     747         150 :         return bTranslateEscapeSequences;
     748             :     }
     749             : 
     750        3179 :     bool ShouldIncludeRawCodeValues() const
     751             :     {
     752        3179 :         return bIncludeRawCodeValues;
     753             :     }
     754             : 
     755         247 :     bool In3DExtensibleMode() const
     756             :     {
     757         247 :         return b3DExtensibleMode;
     758             :     }
     759             : 
     760          27 :     bool ClosedLineAsPolygon() const
     761             :     {
     762          27 :         return m_bClosedLineAsPolygon;
     763             :     }
     764             : 
     765          45 :     double HatchTolerance() const
     766             :     {
     767          45 :         return m_dfHatchTolerance;
     768             :     }
     769             : 
     770             :     static void AddStandardFields(OGRFeatureDefn *poDef, const int nFieldModes);
     771             : 
     772             :     // Implemented in ogrdxf_blockmap.cpp
     773             :     bool ReadBlocksSection();
     774             :     DXFBlockDefinition *LookupBlock(const char *pszName);
     775             :     CPLString GetBlockNameByRecordHandle(const char *pszID);
     776             : 
     777          48 :     std::map<CPLString, DXFBlockDefinition> &GetBlockMap()
     778             :     {
     779          48 :         return oBlockMap;
     780             :     }
     781             : 
     782             :     bool PushBlockInsertion(const CPLString &osBlockName);
     783             : 
     784         424 :     void PopBlockInsertion()
     785             :     {
     786         424 :         aosBlockInsertionStack.pop_back();
     787         424 :     }
     788             : 
     789             :     // Layer and other Table Handling (ogrdatasource.cpp)
     790             :     bool ReadTablesSection();
     791             :     bool ReadLayerDefinition();
     792             :     bool ReadLineTypeDefinition();
     793             :     bool ReadTextStyleDefinition();
     794             :     bool ReadDimStyleDefinition();
     795             :     std::optional<CPLString> LookupLayerProperty(const char *pszLayer,
     796             :                                                  const char *pszProperty) const;
     797             :     const char *LookupTextStyleProperty(const char *pszTextStyle,
     798             :                                         const char *pszProperty,
     799             :                                         const char *pszDefault);
     800             :     bool LookupDimStyle(const char *pszDimstyle,
     801             :                         std::map<CPLString, CPLString> &oDimStyleProperties);
     802             : 
     803           4 :     const std::map<CPLString, std::vector<double>> &GetLineTypeTable() const
     804             :     {
     805           4 :         return oLineTypeTable;
     806             :     }
     807             : 
     808             :     std::vector<double> LookupLineType(const char *pszName);
     809             :     bool TextStyleExists(const char *pszTextStyle);
     810             :     CPLString GetTextStyleNameByHandle(const char *pszID);
     811             :     static void PopulateDefaultDimStyleProperties(
     812             :         std::map<CPLString, CPLString> &oDimStyleProperties);
     813             :     size_t GetEntryFromAcDsDataSection(const char *pszEntityHandle,
     814             :                                        const GByte **pabyBuffer);
     815             : 
     816             :     // Header variables.
     817             :     bool ReadHeaderSection(CSLConstList papszOpenOptionsIn);
     818             :     const char *GetVariable(const char *pszName,
     819             :                             const char *pszDefault = nullptr);
     820             : 
     821        3363 :     const char *GetEncoding()
     822             :     {
     823        3363 :         return osEncoding;
     824             :     }
     825             : 
     826             :     // reader related.
     827           6 :     int GetLineNumber() const
     828             :     {
     829           6 :         return poReader->nLineNumber;
     830             :     }
     831             : 
     832      166607 :     int ReadValue(char *pszValueBuffer, int nValueBufferSize = 81)
     833             :     {
     834      166607 :         return poReader->ReadValue(pszValueBuffer, nValueBufferSize);
     835             :     }
     836             : 
     837         218 :     void RestartEntities()
     838             :     {
     839         218 :         poReader->ResetReadPointer(iEntitiesOffset, iEntitiesLineNumber);
     840         218 :     }
     841             : 
     842        2651 :     void UnreadValue()
     843             :     {
     844        2651 :         poReader->UnreadValue();
     845        2651 :     }
     846             : 
     847          66 :     void ResetReadPointer(uint64_t iNewOffset)
     848             :     {
     849          66 :         poReader->ResetReadPointer(iNewOffset);
     850          66 :     }
     851             : };
     852             : 
     853             : /************************************************************************/
     854             : /*                          OGRDXFWriterLayer                           */
     855             : /************************************************************************/
     856             : 
     857             : class OGRDXFWriterDS;
     858             : 
     859             : class OGRDXFWriterLayer final : public OGRLayer
     860             : {
     861             :     VSILFILE *fp;
     862             :     OGRFeatureDefn *poFeatureDefn;
     863             : 
     864             :     OGRDXFWriterDS *poDS;
     865             : 
     866             :     int WriteValue(int nCode, const char *pszValue);
     867             :     int WriteValue(int nCode, int nValue);
     868             :     int WriteValue(int nCode, double dfValue);
     869             : 
     870             :     static constexpr int PROP_RGBA_COLOR = -1;
     871             : 
     872             :     using CorePropertiesType = std::vector<std::pair<int, std::string>>;
     873             : 
     874             :     OGRErr WriteCore(OGRFeature *, const CorePropertiesType &oCoreProperties);
     875             :     OGRErr WritePOINT(OGRFeature *);
     876             :     OGRErr WriteTEXT(OGRFeature *);
     877             :     OGRErr WritePOLYLINE(OGRFeature *, const OGRGeometry * = nullptr);
     878             :     OGRErr WriteHATCH(OGRFeature *, OGRGeometry * = nullptr);
     879             :     OGRErr WriteINSERT(OGRFeature *);
     880             : 
     881             :     static CPLString TextEscape(const char *);
     882             :     static int ColorStringToDXFColor(const char *, bool &bPerfectMatch);
     883             :     static std::vector<double> PrepareLineTypeDefinition(OGRStylePen *);
     884             :     static std::map<CPLString, CPLString>
     885             :     PrepareTextStyleDefinition(OGRStyleLabel *);
     886             : 
     887             :     std::map<CPLString, std::vector<double>> oNewLineTypes;
     888             :     std::map<CPLString, std::map<CPLString, CPLString>> oNewTextStyles;
     889             :     int nNextAutoID;
     890             :     int bWriteHatch;
     891             : 
     892             :   public:
     893             :     OGRDXFWriterLayer(OGRDXFWriterDS *poDS, VSILFILE *fp);
     894             :     ~OGRDXFWriterLayer() override;
     895             : 
     896          16 :     void ResetReading() override
     897             :     {
     898          16 :     }
     899             : 
     900          16 :     OGRFeature *GetNextFeature() override
     901             :     {
     902          16 :         return nullptr;
     903             :     }
     904             : 
     905         537 :     const OGRFeatureDefn *GetLayerDefn() const override
     906             :     {
     907         537 :         return poFeatureDefn;
     908             :     }
     909             : 
     910             :     int TestCapability(const char *) const override;
     911             :     OGRErr ICreateFeature(OGRFeature *poFeature) override;
     912             :     OGRErr CreateField(const OGRFieldDefn *poField,
     913             :                        int bApproxOK = TRUE) override;
     914             : 
     915             :     GDALDataset *GetDataset() override;
     916             : 
     917             :     void ResetFP(VSILFILE *);
     918             : 
     919          58 :     std::map<CPLString, std::vector<double>> &GetNewLineTypeMap()
     920             :     {
     921          58 :         return oNewLineTypes;
     922             :     }
     923             : 
     924          58 :     std::map<CPLString, std::map<CPLString, CPLString>> &GetNewTextStyleMap()
     925             :     {
     926          58 :         return oNewTextStyles;
     927             :     }
     928             : };
     929             : 
     930             : /************************************************************************/
     931             : /*                       OGRDXFBlocksWriterLayer                        */
     932             : /************************************************************************/
     933             : 
     934             : class OGRDXFBlocksWriterLayer final : public OGRLayer
     935             : {
     936             :     OGRFeatureDefn *poFeatureDefn;
     937             : 
     938             :   public:
     939             :     explicit OGRDXFBlocksWriterLayer(OGRDXFWriterDS *poDS);
     940             :     ~OGRDXFBlocksWriterLayer() override;
     941             : 
     942           0 :     void ResetReading() override
     943             :     {
     944           0 :     }
     945             : 
     946           0 :     OGRFeature *GetNextFeature() override
     947             :     {
     948           0 :         return nullptr;
     949             :     }
     950             : 
     951          10 :     const OGRFeatureDefn *GetLayerDefn() const override
     952             :     {
     953          10 :         return poFeatureDefn;
     954             :     }
     955             : 
     956             :     int TestCapability(const char *) const override;
     957             :     OGRErr ICreateFeature(OGRFeature *poFeature) override;
     958             :     OGRErr CreateField(const OGRFieldDefn *poField,
     959             :                        int bApproxOK = TRUE) override;
     960             : 
     961             :     std::vector<OGRFeature *> apoBlocks;
     962             :     OGRFeature *FindBlock(const char *);
     963             : };
     964             : 
     965             : /************************************************************************/
     966             : /*                            OGRDXFWriterDS                            */
     967             : /************************************************************************/
     968             : 
     969             : class OGRDXFWriterDS final : public GDALDataset
     970             : {
     971             :     friend class OGRDXFWriterLayer;
     972             : 
     973             :     int nNextFID;
     974             : 
     975             :     OGRDXFWriterLayer *poLayer;
     976             :     OGRDXFBlocksWriterLayer *poBlocksLayer;
     977             :     VSILFILE *fp;
     978             :     CPLString osTrailerFile;
     979             : 
     980             :     CPLString osTempFilename;
     981             :     VSILFILE *fpTemp;
     982             : 
     983             :     CPLString osHeaderFile;
     984             :     OGRDXFDataSource oHeaderDS;
     985             :     char **papszLayersToCreate;
     986             : 
     987             :     vsi_l_offset nHANDSEEDOffset;
     988             : 
     989             :     std::vector<int> anDefaultLayerCode;
     990             :     std::vector<CPLString> aosDefaultLayerText;
     991             : 
     992             :     std::set<CPLString> aosUsedEntities;
     993             :     void ScanForEntities(const char *pszFilename, const char *pszTarget);
     994             : 
     995             :     bool WriteNewLineTypeRecords(VSILFILE *fp);
     996             :     bool WriteNewTextStyleRecords(VSILFILE *fp);
     997             :     bool WriteNewBlockRecords(VSILFILE *);
     998             :     bool WriteNewBlockDefinitions(VSILFILE *);
     999             :     bool WriteNewLayerDefinitions(VSILFILE *);
    1000             :     bool TransferUpdateHeader(VSILFILE *);
    1001             :     bool TransferUpdateTrailer(VSILFILE *);
    1002             :     bool FixupHANDSEED(VSILFILE *);
    1003             : 
    1004             :     OGREnvelope oGlobalEnvelope;
    1005             : 
    1006             :     bool m_bHeaderFileIsTemp = false;
    1007             :     bool m_bTrailerFileIsTemp = false;
    1008             :     OGRSpatialReference m_oSRS{};
    1009             :     std::string m_osINSUNITS = "AUTO";
    1010             :     std::string m_osMEASUREMENT = "HEADER_VALUE";
    1011             : 
    1012             :   public:
    1013             :     OGRDXFWriterDS();
    1014             :     ~OGRDXFWriterDS() override;
    1015             : 
    1016             :     int Open(const char *pszFilename, CSLConstList papszOptions);
    1017             : 
    1018             :     int GetLayerCount() const override;
    1019             :     const OGRLayer *GetLayer(int) const override;
    1020             : 
    1021             :     int TestCapability(const char *) const override;
    1022             : 
    1023             :     OGRLayer *ICreateLayer(const char *pszName,
    1024             :                            const OGRGeomFieldDefn *poGeomFieldDefn,
    1025             :                            CSLConstList papszOptions) override;
    1026             : 
    1027             :     bool CheckEntityID(const char *pszEntityID);
    1028             :     bool WriteEntityID(VSILFILE *fp, unsigned int &nAssignedFID,
    1029             :                        GIntBig nPreferredFID = OGRNullFID);
    1030             : 
    1031             :     void UpdateExtent(OGREnvelope *psEnvelope);
    1032             : };
    1033             : 
    1034             : #endif /* ndef OGR_DXF_H_INCLUDED */

Generated by: LCOV version 1.14