LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/dgn - ogrdgndatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 87 111 78.4 %
Date: 2024-11-25 13:07:18 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements OGRPGDataSource class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2000, Frank Warmerdam (warmerdam@pobox.com)
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "ogr_dgn.h"
      14             : #include "cpl_conv.h"
      15             : #include "cpl_string.h"
      16             : 
      17             : #ifdef EMBED_RESOURCE_FILES
      18             : #include "embedded_resources.h"
      19             : #endif
      20             : 
      21             : /************************************************************************/
      22             : /*                         OGRDGNDataSource()                           */
      23             : /************************************************************************/
      24             : 
      25             : OGRDGNDataSource::OGRDGNDataSource() = default;
      26             : 
      27             : /************************************************************************/
      28             : /*                        ~OGRDGNDataSource()                           */
      29             : /************************************************************************/
      30             : 
      31         154 : OGRDGNDataSource::~OGRDGNDataSource()
      32             : 
      33             : {
      34         153 :     for (int i = 0; i < nLayers; i++)
      35          76 :         delete papoLayers[i];
      36             : 
      37          77 :     CPLFree(papoLayers);
      38          77 :     CSLDestroy(papszOptions);
      39             : 
      40          77 :     if (hDGN != nullptr)
      41          76 :         DGNClose(hDGN);
      42         154 : }
      43             : 
      44             : /************************************************************************/
      45             : /*                                Open()                                */
      46             : /************************************************************************/
      47             : 
      48          42 : bool OGRDGNDataSource::Open(GDALOpenInfo *poOpenInfo)
      49             : 
      50             : {
      51             :     m_osEncoding =
      52          42 :         CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "ENCODING", "");
      53             : 
      54          42 :     CPLAssert(nLayers == 0);
      55             : 
      56             :     /* -------------------------------------------------------------------- */
      57             :     /*      Try to open the file as a DGN file.                             */
      58             :     /* -------------------------------------------------------------------- */
      59          42 :     const bool bUpdate = (poOpenInfo->eAccess == GA_Update);
      60          42 :     hDGN = DGNOpen(poOpenInfo->pszFilename, bUpdate);
      61          42 :     if (hDGN == nullptr)
      62             :     {
      63           0 :         CPLError(CE_Failure, CPLE_AppDefined,
      64             :                  "Unable to open %s as a Microstation .dgn file.",
      65             :                  poOpenInfo->pszFilename);
      66           0 :         return false;
      67             :     }
      68             : 
      69             :     /* -------------------------------------------------------------------- */
      70             :     /*      Create the layer object.                                        */
      71             :     /* -------------------------------------------------------------------- */
      72          42 :     OGRDGNLayer *poLayer = new OGRDGNLayer(this, "elements", hDGN, bUpdate);
      73             : 
      74             :     /* -------------------------------------------------------------------- */
      75             :     /*      Add layer to data source layer list.                            */
      76             :     /* -------------------------------------------------------------------- */
      77          42 :     papoLayers = static_cast<OGRDGNLayer **>(
      78          42 :         CPLRealloc(papoLayers, sizeof(OGRDGNLayer *) * (nLayers + 1)));
      79          42 :     papoLayers[nLayers++] = poLayer;
      80             : 
      81          42 :     return true;
      82             : }
      83             : 
      84             : /************************************************************************/
      85             : /*                           TestCapability()                           */
      86             : /************************************************************************/
      87             : 
      88          48 : int OGRDGNDataSource::TestCapability(const char *pszCap)
      89             : 
      90             : {
      91          48 :     if (EQUAL(pszCap, ODsCCreateLayer))
      92          32 :         return TRUE;
      93          16 :     else if (EQUAL(pszCap, ODsCZGeometries))
      94           0 :         return TRUE;
      95             : 
      96          16 :     return FALSE;
      97             : }
      98             : 
      99             : /************************************************************************/
     100             : /*                              GetLayer()                              */
     101             : /************************************************************************/
     102             : 
     103          13 : OGRLayer *OGRDGNDataSource::GetLayer(int iLayer)
     104             : 
     105             : {
     106          13 :     if (iLayer < 0 || iLayer >= nLayers)
     107           0 :         return nullptr;
     108             : 
     109          13 :     return papoLayers[iLayer];
     110             : }
     111             : 
     112             : /************************************************************************/
     113             : /*                             PreCreate()                              */
     114             : /*                                                                      */
     115             : /*      Called by OGRDGNDriver::Create() method to setup a stub         */
     116             : /*      OGRDataSource object without the associated file created        */
     117             : /*      yet.  It will be created by the ICreateLayer() call.            */
     118             : /************************************************************************/
     119             : 
     120          35 : void OGRDGNDataSource::PreCreate(CSLConstList papszOptionsIn)
     121             : 
     122             : {
     123          35 :     papszOptions = CSLDuplicate(papszOptionsIn);
     124             : 
     125          35 :     m_osEncoding = CSLFetchNameValueDef(papszOptionsIn, "ENCODING", "");
     126          35 : }
     127             : 
     128             : /************************************************************************/
     129             : /*                           ICreateLayer()                             */
     130             : /************************************************************************/
     131             : 
     132             : OGRLayer *
     133          51 : OGRDGNDataSource::ICreateLayer(const char *pszLayerName,
     134             :                                const OGRGeomFieldDefn *poGeomFieldDefn,
     135             :                                CSLConstList papszExtraOptions)
     136             : 
     137             : {
     138             :     /* -------------------------------------------------------------------- */
     139             :     /*      Ensure only one layer gets created.                             */
     140             :     /* -------------------------------------------------------------------- */
     141          51 :     if (nLayers > 0)
     142             :     {
     143          16 :         CPLError(CE_Failure, CPLE_AppDefined,
     144             :                  "DGN driver only supports one layer with all the elements "
     145             :                  "in it.");
     146          16 :         return nullptr;
     147             :     }
     148             : 
     149             :     const auto eGeomType =
     150          35 :         poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
     151             :     const auto poSRS =
     152          35 :         poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
     153             : 
     154             :     /* -------------------------------------------------------------------- */
     155             :     /*      If the coordinate system is geographic, we should use a         */
     156             :     /*      localized default origin and resolution.                        */
     157             :     /* -------------------------------------------------------------------- */
     158          35 :     const char *pszMasterUnit = "m";
     159          35 :     const char *pszSubUnit = "cm";
     160             : 
     161          35 :     int nUORPerSU = 1;
     162          35 :     int nSUPerMU = 100;
     163             : 
     164          35 :     double dfOriginX = -21474836.0;  // Default origin centered on zero
     165          35 :     double dfOriginY = -21474836.0;  // with two decimals of precision.
     166          35 :     double dfOriginZ = -21474836.0;
     167             : 
     168          35 :     if (poSRS != nullptr && poSRS->IsGeographic())
     169             :     {
     170           0 :         dfOriginX = -200.0;
     171           0 :         dfOriginY = -200.0;
     172             : 
     173           0 :         pszMasterUnit = "d";
     174           0 :         pszSubUnit = "s";
     175           0 :         nSUPerMU = 3600;
     176           0 :         nUORPerSU = 1000;
     177             :     }
     178             : 
     179             :     /* -------------------------------------------------------------------- */
     180             :     /*      Parse out various creation options.                             */
     181             :     /* -------------------------------------------------------------------- */
     182          35 :     papszOptions = CSLInsertStrings(papszOptions, 0, papszExtraOptions);
     183             : 
     184             :     const bool b3DRequested =
     185          35 :         CPLFetchBool(papszOptions, "3D", wkbHasZ(eGeomType));
     186             : 
     187          35 :     const char *pszRequestSeed = CSLFetchNameValue(papszOptions, "SEED");
     188          35 :     const char *pszSeed = pszRequestSeed;
     189          35 :     int nCreationFlags = 0;
     190             : #ifdef EMBED_RESOURCE_FILES
     191             :     std::string osTmpSeedFilename;
     192             : #endif
     193          35 :     if (pszSeed)
     194           0 :         nCreationFlags |= DGNCF_USE_SEED_ORIGIN | DGNCF_USE_SEED_UNITS;
     195             :     else
     196             :     {
     197          35 :         pszRequestSeed = b3DRequested ? "seed_3d.dgn" : "seed_2d.dgn";
     198             : #ifdef EMBED_RESOURCE_FILES
     199             :         CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
     200             : #endif
     201          35 :         pszSeed = CPLFindFile("gdal", pszRequestSeed);
     202             : #ifdef EMBED_RESOURCE_FILES
     203             :         if (!pszSeed)
     204             :         {
     205             :             if (b3DRequested)
     206             :             {
     207             :                 static const bool bOnce [[maybe_unused]] = []()
     208             :                 {
     209             :                     CPLDebug("DGN", "Using embedded seed_3d");
     210             :                     return true;
     211             :                 }();
     212             :             }
     213             :             else
     214             :             {
     215             :                 static const bool bOnce [[maybe_unused]] = []()
     216             :                 {
     217             :                     CPLDebug("DGN", "Using embedded seed_2d");
     218             :                     return true;
     219             :                 }();
     220             :             }
     221             :             unsigned nSize = 0;
     222             :             const unsigned char *pabyData =
     223             :                 b3DRequested ? DGNGetSeed3D(&nSize) : DGNGetSeed2D(&nSize);
     224             :             osTmpSeedFilename = VSIMemGenerateHiddenFilename(pszRequestSeed);
     225             :             pszSeed = osTmpSeedFilename.c_str();
     226             :             VSIFCloseL(VSIFileFromMemBuffer(osTmpSeedFilename.c_str(),
     227             :                                             const_cast<GByte *>(pabyData),
     228             :                                             static_cast<int>(nSize),
     229             :                                             /* bTakeOwnership = */ false));
     230             :         }
     231             : #endif
     232             :     }
     233             : 
     234          35 :     if (pszSeed == nullptr)
     235             :     {
     236           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     237             :                  "No seed file provided, and unable to find %s.",
     238             :                  pszRequestSeed);
     239           0 :         return nullptr;
     240             :     }
     241             : 
     242          35 :     if (CPLFetchBool(papszOptions, "COPY_WHOLE_SEED_FILE", true))
     243          35 :         nCreationFlags |= DGNCF_COPY_WHOLE_SEED_FILE;
     244          35 :     if (CPLFetchBool(papszOptions, "COPY_SEED_FILE_COLOR_TABLE", true))
     245          35 :         nCreationFlags |= DGNCF_COPY_SEED_FILE_COLOR_TABLE;
     246             : 
     247          35 :     const char *pszValue = CSLFetchNameValue(papszOptions, "MASTER_UNIT_NAME");
     248          35 :     if (pszValue != nullptr)
     249             :     {
     250           0 :         nCreationFlags &= ~DGNCF_USE_SEED_UNITS;
     251           0 :         pszMasterUnit = pszValue;
     252             :     }
     253             : 
     254          35 :     pszValue = CSLFetchNameValue(papszOptions, "SUB_UNIT_NAME");
     255          35 :     if (pszValue != nullptr)
     256             :     {
     257           0 :         nCreationFlags &= ~DGNCF_USE_SEED_UNITS;
     258           0 :         pszSubUnit = pszValue;
     259             :     }
     260             : 
     261          35 :     pszValue = CSLFetchNameValue(papszOptions, "SUB_UNITS_PER_MASTER_UNIT");
     262          35 :     if (pszValue != nullptr)
     263             :     {
     264           1 :         nCreationFlags &= ~DGNCF_USE_SEED_UNITS;
     265           1 :         nSUPerMU = atoi(pszValue);
     266             :     }
     267             : 
     268          35 :     pszValue = CSLFetchNameValue(papszOptions, "UOR_PER_SUB_UNIT");
     269          35 :     if (pszValue != nullptr)
     270             :     {
     271           1 :         nCreationFlags &= ~DGNCF_USE_SEED_UNITS;
     272           1 :         nUORPerSU = atoi(pszValue);
     273             :     }
     274             : 
     275          35 :     pszValue = CSLFetchNameValue(papszOptions, "ORIGIN");
     276          35 :     if (pszValue != nullptr)
     277             :     {
     278             :         char **papszTuple =
     279           1 :             CSLTokenizeStringComplex(pszValue, " ,", FALSE, FALSE);
     280             : 
     281           1 :         nCreationFlags &= ~DGNCF_USE_SEED_ORIGIN;
     282           1 :         if (CSLCount(papszTuple) == 3)
     283             :         {
     284           1 :             dfOriginX = CPLAtof(papszTuple[0]);
     285           1 :             dfOriginY = CPLAtof(papszTuple[1]);
     286           1 :             dfOriginZ = CPLAtof(papszTuple[2]);
     287             :         }
     288           0 :         else if (CSLCount(papszTuple) == 2)
     289             :         {
     290           0 :             dfOriginX = CPLAtof(papszTuple[0]);
     291           0 :             dfOriginY = CPLAtof(papszTuple[1]);
     292           0 :             dfOriginZ = 0.0;
     293             :         }
     294             :         else
     295             :         {
     296           0 :             CSLDestroy(papszTuple);
     297           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     298             :                      "ORIGIN is not a valid 2d or 3d tuple.\n"
     299             :                      "Separate tuple values with comma.");
     300             : #ifdef EMBED_RESOURCE_FILES
     301             :             if (!osTmpSeedFilename.empty())
     302             :                 VSIUnlink(osTmpSeedFilename.c_str());
     303             : #endif
     304           0 :             return nullptr;
     305             :         }
     306           1 :         CSLDestroy(papszTuple);
     307             :     }
     308             : 
     309             :     /* -------------------------------------------------------------------- */
     310             :     /*      Try creating the base file.                                     */
     311             :     /* -------------------------------------------------------------------- */
     312          35 :     hDGN = DGNCreate(GetDescription(), pszSeed, nCreationFlags, dfOriginX,
     313             :                      dfOriginY, dfOriginZ, nSUPerMU, nUORPerSU, pszMasterUnit,
     314             :                      pszSubUnit);
     315             : #ifdef EMBED_RESOURCE_FILES
     316             :     if (!osTmpSeedFilename.empty())
     317             :         VSIUnlink(osTmpSeedFilename.c_str());
     318             : #endif
     319             : 
     320          35 :     if (hDGN == nullptr)
     321           1 :         return nullptr;
     322             : 
     323             :     /* -------------------------------------------------------------------- */
     324             :     /*      Create the layer object.                                        */
     325             :     /* -------------------------------------------------------------------- */
     326          34 :     OGRDGNLayer *poLayer = new OGRDGNLayer(this, pszLayerName, hDGN, TRUE);
     327             : 
     328             :     /* -------------------------------------------------------------------- */
     329             :     /*      Add layer to data source layer list.                            */
     330             :     /* -------------------------------------------------------------------- */
     331          34 :     papoLayers = static_cast<OGRDGNLayer **>(
     332          34 :         CPLRealloc(papoLayers, sizeof(OGRDGNLayer *) * (nLayers + 1)));
     333          34 :     papoLayers[nLayers++] = poLayer;
     334             : 
     335          34 :     return poLayer;
     336             : }

Generated by: LCOV version 1.14