LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/sosi - ogrsosidatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 200 344 58.1 %
Date: 2024-05-14 23:54:21 Functions: 8 13 61.5 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  SOSI Data Source
       4             :  * Purpose:  Provide SOSI Data to OGR.
       5             :  * Author:   Thomas Hirsch, <thomas.hirsch statkart no>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2010, Thomas Hirsch
       9             :  * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #include "ogr_sosi.h"
      31             : #include <map>
      32             : #include <math.h>
      33             : 
      34             : /* This is the most common encoding for SOSI files. Let's at least try if
      35             :  * it is supported, or generate a meaningful error message.               */
      36             : #ifndef CPL_ENC_ISO8859_10
      37             : #define CPL_ENC_ISO8859_10 "ISO8859-10"
      38             : #endif
      39             : 
      40             : #ifdef WRITE_SUPPORT
      41             : /************************************************************************/
      42             : /*                              utility methods                         */
      43             : /************************************************************************/
      44             : 
      45             : static int epsg2sosi(int nEPSG)
      46             : {
      47             :     int nSOSI = 23;
      48             :     switch (nEPSG)
      49             :     {
      50             :         case 27391: /* NGO 1984 Axis I-VIII */
      51             :         case 27392:
      52             :         case 27393:
      53             :         case 27394:
      54             :         case 27395:
      55             :         case 27396:
      56             :         case 27397:
      57             :         case 27398:
      58             :         {
      59             :             nSOSI = nEPSG - 27390;
      60             :             break;
      61             :         }
      62             :         case 3043: /* UTM ZONE 31-36 */
      63             :         case 3044:
      64             :         case 3045:
      65             :         case 3046:
      66             :         case 3047:
      67             :         case 3048:
      68             :         {
      69             :             nSOSI = nEPSG - 3022;
      70             :             break;
      71             :         }
      72             :         case 23031: /* UTM ZONE 31-36 / ED50 */
      73             :         case 23032:
      74             :         case 23033:
      75             :         case 23034:
      76             :         case 23035:
      77             :         case 23036:
      78             :         {
      79             :             nSOSI = nEPSG - 23000;
      80             :             break;
      81             :         }
      82             :         case 4326:
      83             :         { /* WSG84 */
      84             :             nSOSI = 84;
      85             :             break;
      86             :         }
      87             :         default:
      88             :         {
      89             :             CPLError(CE_Warning, CPLE_AppDefined,
      90             :                      "(Yet) unsupported coordinate system writing to SOSI "
      91             :                      "file: %i. Defaulting to EPSG:4326/SOSI 84.",
      92             :                      nEPSG);
      93             :         }
      94             :     }
      95             :     return nSOSI;
      96             : }
      97             : #endif
      98             : 
      99           3 : static int sosi2epsg(int nSOSI)
     100             : {
     101           3 :     int nEPSG = 4326;
     102           3 :     switch (nSOSI)
     103             :     {
     104           0 :         case 1: /* NGO 1984 Axis I-VIII */
     105             :         case 2:
     106             :         case 3:
     107             :         case 4:
     108             :         case 5:
     109             :         case 6:
     110             :         case 7:
     111             :         case 8:
     112             :         {
     113           0 :             nEPSG = 27390 + nSOSI;
     114           0 :             break;
     115             :         }
     116           3 :         case 21: /* UTM ZONE 31-36 */
     117             :         case 22:
     118             :         case 23:
     119             :         case 24:
     120             :         case 25:
     121             :         case 26:
     122             :         {
     123           3 :             nEPSG = 3022 + nSOSI;
     124           3 :             break;
     125             :         }
     126           0 :         case 31: /* UTM ZONE 31-36 / ED50 */
     127             :         case 32:
     128             :         case 33:
     129             :         case 34:
     130             :         case 35:
     131             :         case 36:
     132             :         {
     133           0 :             nEPSG = 23000 + nSOSI;
     134           0 :             break;
     135             :         }
     136           0 :         case 84:
     137             :         { /* WSG84 */
     138           0 :             nEPSG = 4326;
     139           0 :             break;
     140             :         }
     141           0 :         default:
     142             :         {
     143           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     144             :                      "(Yet) unsupported coordinate system in SOSI-file: %i. "
     145             :                      "Defaulting to EPSG:4326.",
     146             :                      nSOSI);
     147             :         }
     148             :     }
     149           3 :     return nEPSG;
     150             : }
     151             : 
     152             : /************************************************************************/
     153             : /*                              OGRSOSIDataSource()                     */
     154             : /************************************************************************/
     155             : 
     156           3 : OGRSOSIDataSource::OGRSOSIDataSource()
     157             : {
     158           3 :     nLayers = 0;
     159             : 
     160           3 :     poFileadm = nullptr;
     161           3 :     poBaseadm = nullptr;
     162           3 :     papoBuiltGeometries = nullptr;
     163           3 :     papoLayers = nullptr;
     164           3 :     pszName = nullptr;
     165           3 :     poSRS = nullptr;
     166             : 
     167           3 :     poPolyHeaders = nullptr;
     168           3 :     poTextHeaders = nullptr;
     169           3 :     poPointHeaders = nullptr;
     170           3 :     poCurveHeaders = nullptr;
     171             : 
     172           3 :     pszEncoding = CPL_ENC_UTF8;
     173           3 :     nNumFeatures = 0;
     174             : 
     175           3 :     nMode = MODE_READING;
     176           3 : }
     177             : 
     178             : /************************************************************************/
     179             : /*                              ~OGRSOSIDataSource()                    */
     180             : /************************************************************************/
     181             : 
     182           6 : OGRSOSIDataSource::~OGRSOSIDataSource()
     183             : {
     184           3 :     if (papoBuiltGeometries != nullptr)
     185             :     {
     186          60 :         for (unsigned int i = 0; i < nNumFeatures; i++)
     187             :         {
     188          57 :             if (papoBuiltGeometries[i] != nullptr)
     189             :             {
     190          51 :                 delete papoBuiltGeometries[i];
     191          51 :                 papoBuiltGeometries[i] = nullptr;
     192             :             }
     193             :         }
     194           3 :         CPLFree(papoBuiltGeometries);
     195           3 :         papoBuiltGeometries = nullptr;
     196             :     }
     197             : 
     198           3 :     if (poPolyHeaders != nullptr)
     199           3 :         delete poPolyHeaders;
     200           3 :     if (poTextHeaders != nullptr)
     201           0 :         delete poTextHeaders;
     202           3 :     if (poPointHeaders != nullptr)
     203           0 :         delete poPointHeaders;
     204           3 :     if (poCurveHeaders != nullptr)
     205           3 :         delete poCurveHeaders;
     206             : 
     207           3 :     if (nMode == MODE_WRITING)
     208             :     {
     209           0 :         if (poFileadm != nullptr)
     210           0 :             LC_CloseSos(poFileadm, RESET_IDX);
     211           0 :         if (poBaseadm != nullptr)
     212           0 :             LC_CloseBase(poBaseadm, RESET_IDX);
     213             :     }
     214             :     else
     215             :     {
     216           3 :         if (poFileadm != nullptr)
     217           3 :             LC_CloseSos(poFileadm, SAVE_IDX);
     218           3 :         if (poBaseadm != nullptr)
     219           3 :             LC_CloseBase(poBaseadm, SAVE_IDX);
     220             :     }
     221           3 :     poFileadm = nullptr;
     222           3 :     poBaseadm = nullptr;
     223             : 
     224           3 :     if (papoLayers != nullptr)
     225             :     {
     226           9 :         for (int i = 0; i < nLayers; i++)
     227             :         {
     228           6 :             delete papoLayers[i];
     229             :         }
     230           3 :         CPLFree(papoLayers);
     231             :     }
     232             : 
     233           3 :     if (poSRS != nullptr)
     234           3 :         poSRS->Release();
     235           3 :     if (pszName != nullptr)
     236           3 :         CPLFree(pszName);
     237           6 : }
     238             : 
     239           6 : static OGRFeatureDefn *defineLayer(const char *szName,
     240             :                                    OGRwkbGeometryType szType, S2I *poHeaders,
     241             :                                    S2I **ppoHeadersNew)
     242             : {
     243           6 :     OGRFeatureDefn *poFeatureDefn = new OGRFeatureDefn(szName);
     244           6 :     poFeatureDefn->SetGeomType(szType);
     245           6 :     S2I *poHeadersNew = *ppoHeadersNew;
     246             : 
     247          57 :     for (S2I::iterator i = poHeaders->begin(); i != poHeaders->end(); ++i)
     248             :     {
     249          51 :         OGRSOSIDataType *poType = SOSIGetType(i->first);
     250          51 :         OGRSOSISimpleDataType *poElements = poType->getElements();
     251         132 :         for (int k = 0; k < poType->getElementCount(); k++)
     252             :         {
     253          81 :             if (strcmp(poElements[k].GetName(), "") == 0)
     254           9 :                 continue;
     255          72 :             OGRFieldDefn oFieldTemplate(poElements[k].GetName(),
     256         144 :                                         poElements[k].GetType());
     257          72 :             (*poHeadersNew)[CPLString(poElements[k].GetName())] =
     258          72 :                 poFeatureDefn->GetFieldCount();
     259          72 :             poFeatureDefn->AddFieldDefn(&oFieldTemplate);
     260             :         }
     261             :     }
     262           6 :     return poFeatureDefn;
     263             : }
     264             : 
     265             : /************************************************************************/
     266             : /*                              Open()                                  */
     267             : /************************************************************************/
     268             : 
     269           3 : int OGRSOSIDataSource::Open(const char *pszFilename, int bUpdate)
     270             : {
     271           3 :     papoBuiltGeometries = nullptr;
     272           3 :     poFileadm = nullptr;
     273           3 :     poBaseadm = nullptr;
     274             :     char *pszPos;
     275             : 
     276           3 :     if (bUpdate)
     277             :     {
     278           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     279             :                  "Update access not supported by the SOSI driver.");
     280           0 :         return FALSE;
     281             :     }
     282             : 
     283             :     /* Check that the file exists otherwise HO_TestSOSI() emits an error */
     284             :     VSIStatBuf sStat;
     285           3 :     if (VSIStat(pszFilename, &sStat) != 0)
     286           0 :         return FALSE;
     287             : 
     288           3 :     pszName = CPLStrdup(pszFilename);
     289             :     /* We ignore any layer parameters for now. */
     290           3 :     pszPos = strchr(pszName, ',');
     291           3 :     if (pszPos != nullptr)
     292             :     {
     293           0 :         pszPos[0] = '\0';
     294             :     }
     295             : 
     296             :     /* Confirm that we are dealing with a SOSI file. Used also by data
     297             :      * format auto-detection in some ogr utilities. */
     298           3 :     UT_INT64 nEnd = 0;
     299           3 :     int bIsSosi = HO_TestSOSI(pszName, &nEnd);
     300           3 :     if (bIsSosi == UT_FALSE)
     301             :     {
     302           0 :         return FALSE; /* No error message: This is used by file format
     303             :                          auto-detection */
     304             :     }
     305             : 
     306           3 :     short nStatus = 0, nDetStatus = 0; /* immediate status, detailed status */
     307             : 
     308             :     /* open index base and sosi file */
     309           3 :     poBaseadm = LC_OpenBase(LC_BASE);
     310           3 :     nStatus = LC_OpenSos(pszName, LC_BASE_FRAMGR, LC_GML_IDX, LC_INGEN_STATUS,
     311             :                          &poFileadm, &nDetStatus);
     312           3 :     if (nStatus == UT_FALSE)
     313             :     {
     314             :         char *pszErrorMessage;
     315           0 :         LC_StrError(nDetStatus, &pszErrorMessage);
     316           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     317             :                  "File %s could not be opened by SOSI Driver: %s", pszName,
     318             :                  pszErrorMessage);
     319           0 :         return FALSE;
     320             :     }
     321             : 
     322             :     /* --------------------------------------------------------------------*
     323             :      *      Prefetch all the information needed to determine layers        *
     324             :      *      and prebuild LineString features for later assembly.           *
     325             :      * --------------------------------------------------------------------*/
     326             : 
     327             :     /* allocate room for one pointer per feature */
     328           3 :     nNumFeatures = static_cast<unsigned int>(poFileadm->lAntGr);
     329           3 :     papoBuiltGeometries = static_cast<OGRGeometry **>(
     330           3 :         VSI_MALLOC2_VERBOSE(nNumFeatures, sizeof(OGRGeometry *)));
     331           3 :     if (papoBuiltGeometries == nullptr)
     332             :     {
     333           0 :         nNumFeatures = 0;
     334           0 :         return FALSE;
     335             :     }
     336          60 :     for (unsigned int i = 0; i < nNumFeatures; i++)
     337          57 :         papoBuiltGeometries[i] = nullptr;
     338             : 
     339             :     /* Various iterators and return values used to iterate through SOSI features
     340             :      */
     341             :     short nName, nNumLines;
     342             :     long nNumCoo;
     343             :     unsigned short nInfo;
     344             :     LC_SNR_ADM oSnradm;
     345             :     LC_BGR oNextSerial;
     346             :     LC_BGR *poNextSerial;
     347           3 :     poNextSerial = &oNextSerial;
     348             : 
     349           3 :     bool bPointLayer =
     350             :         FALSE; /* Initialize four layers for the different geometry types */
     351           3 :     bool bCurveLayer = FALSE;
     352           3 :     bool bPolyLayer = FALSE;
     353           3 :     bool bTextLayer = FALSE;
     354           3 :     poPolyHeaders = new S2I();
     355           3 :     poPointHeaders = new S2I();
     356           3 :     poCurveHeaders = new S2I();
     357           3 :     poTextHeaders = new S2I();
     358             : 
     359           3 :     LC_SBSn(&oSnradm, poFileadm, 0, nNumFeatures); /* Set FYBA search limits  */
     360           3 :     LC_InitNextBgr(poNextSerial);
     361             : 
     362             :     /* Prebuilding simple features and extracting layer information. */
     363          60 :     while (LC_NextBgr(poNextSerial, LC_FRAMGR))
     364             :     {
     365             :         /* Fetch next group information */
     366             :         nName =
     367          57 :             LC_RxGr(poNextSerial, LES_OPTIMALT, &nNumLines, &nNumCoo, &nInfo);
     368             : 
     369          57 :         S2S oHeaders;
     370          57 :         S2S::iterator iHeaders;
     371             :         int iH;
     372             :         /* Extract all strings from group header. */
     373         510 :         for (short i = 1; i <= nNumLines; i++)
     374             :         {
     375         453 :             char *pszLine = LC_GetGi(i); /* Get one header line */
     376         453 :             if ((pszLine[0] == ':') || (pszLine[0] == '('))
     377           3 :                 continue; /* If we have a continued REF line, skip it. */
     378         450 :             if (pszLine[0] == '!')
     379           0 :                 continue; /* If we have a comment line, skip it. */
     380             : 
     381         450 :             char *pszUTFLine = CPLRecode(
     382             :                 pszLine, pszEncoding, CPL_ENC_UTF8); /* switch to UTF encoding
     383             :                                                         here, if it is known. */
     384         450 :             char *pszUTFLineIter = pszUTFLine;
     385        1308 :             while (pszUTFLineIter[0] == '.')
     386         858 :                 pszUTFLineIter++; /* Skipping the dots at the beginning of a
     387             :                                      SOSI line */
     388             :             char *pszPos2 =
     389         450 :                 strstr(pszUTFLineIter, " "); /* Split header and value */
     390         450 :             if (pszPos2 != nullptr)
     391             :             {
     392         882 :                 const std::string osKey(pszUTFLineIter, pszPos2);
     393         441 :                 oHeaders[osKey] =
     394         882 :                     CPLString(pszPos2 + 1); /* Add to header map */
     395         441 :                 switch (nName)
     396             :                 { /* Add to header list for the corresponding layer, if it is
     397             :                      not */
     398          27 :                     case L_FLATE:
     399             :                     { /* in there already */
     400          27 :                         if (poPolyHeaders->find(osKey) == poPolyHeaders->end())
     401             :                         {
     402          24 :                             iH = static_cast<int>(poPolyHeaders->size());
     403          24 :                             (*poPolyHeaders)[osKey] = iH;
     404             :                         }
     405          27 :                         break;
     406             :                     }
     407         387 :                     case L_KURVE:
     408             :                     case L_LINJE:
     409             :                     case L_BUEP:
     410             :                     { /* FIXME: maybe not use the same headers for both */
     411         387 :                         if (poCurveHeaders->find(osKey) ==
     412         774 :                             poCurveHeaders->end())
     413             :                         {
     414          27 :                             iH = static_cast<int>(poCurveHeaders->size());
     415          27 :                             (*poCurveHeaders)[osKey] = iH;
     416             :                         }
     417         387 :                         break;
     418             :                     }
     419           0 :                     case L_PUNKT:
     420             :                     case L_SYMBOL:
     421             :                     {
     422           0 :                         if (poPointHeaders->find(osKey) ==
     423           0 :                             poPointHeaders->end())
     424             :                         {
     425           0 :                             iH = static_cast<int>(poPointHeaders->size());
     426           0 :                             (*poPointHeaders)[osKey] = iH;
     427             :                         }
     428           0 :                         break;
     429             :                     }
     430           0 :                     case L_TEKST:
     431             :                     {
     432           0 :                         if (poTextHeaders->find(osKey) == poTextHeaders->end())
     433             :                         {
     434           0 :                             iH = static_cast<int>(poTextHeaders->size());
     435           0 :                             (*poTextHeaders)[osKey] = iH;
     436             :                         }
     437           0 :                         break;
     438             :                     }
     439             :                 }
     440             :             }
     441         450 :             CPLFree(pszUTFLine);
     442             :         }
     443             : 
     444             :         /* Feature-specific tasks */
     445          57 :         switch (nName)
     446             :         {
     447           0 :             case L_PUNKT:
     448             :             {
     449             :                 /* Pre-build a point feature. Activate point layer. */
     450           0 :                 bPointLayer = TRUE;
     451           0 :                 buildOGRPoint(oNextSerial.lNr);
     452           0 :                 break;
     453             :             }
     454           3 :             case L_FLATE:
     455             :             {
     456             :                 /* Activate polygon layer. */
     457           3 :                 bPolyLayer = TRUE;
     458             :                 /* cannot build geometries that reference others yet */
     459           3 :                 break;
     460             :             }
     461          51 :             case L_KURVE:
     462             :             case L_LINJE:
     463             :             {
     464             :                 /* Pre-build a line feature. Activate line/curve layer. */
     465          51 :                 bCurveLayer = TRUE;
     466          51 :                 buildOGRLineString(static_cast<int>(nNumCoo), oNextSerial.lNr);
     467          51 :                 break;
     468             :             }
     469           0 :             case L_BUEP:
     470             :             {
     471             :                 /* Pre-build a line feature as interpolation from an arc.
     472             :                  * Activate line/curve layer. */
     473           0 :                 bCurveLayer = TRUE;
     474           0 :                 buildOGRLineStringFromArc(oNextSerial.lNr);
     475           0 :                 break;
     476             :             }
     477           0 :             case L_TEKST:
     478             :             {
     479             :                 /* Pre-build a text line contour feature. Activate text layer.
     480             :                  */
     481             :                 /* Todo: observe only points 2ff if more than one point is given
     482             :                  * for follow mode */
     483           0 :                 bTextLayer = TRUE;
     484           0 :                 buildOGRMultiPoint(static_cast<int>(nNumCoo), oNextSerial.lNr);
     485           0 :                 break;
     486             :             }
     487           3 :             case L_HODE:
     488             :             {
     489             :                 /* Get SRS from SOSI header. */
     490           3 :                 unsigned short nMask = LC_TR_ALLT;
     491             :                 LC_TRANSPAR oTrans;
     492           3 :                 if (LC_GetTransEx(&nMask, &oTrans) == UT_FALSE)
     493             :                 {
     494           0 :                     CPLError(CE_Failure, CPLE_OpenFailed,
     495             :                              "TRANSPAR section not found - No reference system "
     496             :                              "information available.");
     497           0 :                     return FALSE;
     498             :                 }
     499           3 :                 poSRS = new OGRSpatialReference();
     500           3 :                 poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     501             : 
     502             :                 /* Get coordinate system from SOSI header. */
     503           3 :                 int nEPSG = sosi2epsg(oTrans.sKoordsys);
     504           3 :                 if (poSRS->importFromEPSG(nEPSG) != OGRERR_NONE)
     505             :                 {
     506           0 :                     CPLError(CE_Failure, CPLE_OpenFailed,
     507             :                              "OGR could not load coordinate system definition "
     508             :                              "EPSG:%i.",
     509             :                              nEPSG);
     510           0 :                     return FALSE;
     511             :                 }
     512             : 
     513             :                 /* Get character encoding from SOSI header. */
     514           3 :                 iHeaders = oHeaders.find("TEGNSETT");
     515           3 :                 if (iHeaders != oHeaders.end())
     516             :                 {
     517           6 :                     CPLString osLine = iHeaders->second;
     518           3 :                     if (osLine.compare("ISO8859-1") == 0)
     519             :                     {
     520           3 :                         pszEncoding = CPL_ENC_ISO8859_1;
     521             :                     }
     522           0 :                     else if (osLine.compare("ISO8859-10") == 0)
     523             :                     {
     524           0 :                         pszEncoding = CPL_ENC_ISO8859_10;
     525             :                     }
     526           0 :                     else if (osLine.compare("UTF-8") == 0)
     527             :                     {
     528           0 :                         pszEncoding = CPL_ENC_UTF8;
     529             :                     }
     530             :                 }
     531             : 
     532           3 :                 break;
     533             :             }
     534           0 :             default:
     535             :             {
     536           0 :                 break;
     537             :             }
     538             :         }
     539             :     }
     540             : 
     541             :     /* -------------------------------------------------------------------- *
     542             :      *      Create a corresponding layers. One per geometry type            *
     543             :      * -------------------------------------------------------------------- */
     544           3 :     int l_nLayers = 0;
     545           3 :     if (bPolyLayer)
     546           3 :         l_nLayers++;
     547           3 :     if (bCurveLayer)
     548           3 :         l_nLayers++;
     549           3 :     if (bPointLayer)
     550           0 :         l_nLayers++;
     551           3 :     if (bTextLayer)
     552           0 :         l_nLayers++;
     553           3 :     this->nLayers = l_nLayers;
     554             :     /* allocate some memory for up to three layers */
     555           3 :     papoLayers =
     556           3 :         (OGRSOSILayer **)VSI_MALLOC2_VERBOSE(sizeof(void *), l_nLayers);
     557           3 :     if (papoLayers == nullptr)
     558             :     {
     559           0 :         this->nLayers = 0;
     560           0 :         return FALSE;
     561             :     }
     562             : 
     563             :     /* Define each layer, using a proper feature definition, geometry type,
     564             :      * and adding every SOSI header encountered in the file as field. */
     565           3 :     if (bPolyLayer)
     566             :     {
     567           3 :         S2I *poHeadersNew = new S2I();
     568             :         OGRFeatureDefn *poFeatureDefn =
     569           3 :             defineLayer("polygons", wkbPolygon, poPolyHeaders, &poHeadersNew);
     570           3 :         delete poPolyHeaders;
     571           3 :         poPolyHeaders = poHeadersNew;
     572           3 :         poFeatureDefn->Reference();
     573           3 :         papoLayers[--l_nLayers] =
     574           3 :             new OGRSOSILayer(this, poFeatureDefn, poFileadm, poPolyHeaders);
     575             :     }
     576             :     else
     577             :     {
     578           0 :         delete poPolyHeaders;
     579           0 :         poPolyHeaders = nullptr;
     580             :     }
     581           3 :     if (bCurveLayer)
     582             :     {
     583           3 :         S2I *poHeadersNew = new S2I();
     584             :         OGRFeatureDefn *poFeatureDefn =
     585           3 :             defineLayer("lines", wkbLineString, poCurveHeaders, &poHeadersNew);
     586           3 :         delete poCurveHeaders;
     587           3 :         poCurveHeaders = poHeadersNew;
     588           3 :         poFeatureDefn->Reference();
     589           3 :         papoLayers[--l_nLayers] =
     590           3 :             new OGRSOSILayer(this, poFeatureDefn, poFileadm, poCurveHeaders);
     591             :     }
     592             :     else
     593             :     {
     594           0 :         delete poCurveHeaders;
     595           0 :         poCurveHeaders = nullptr;
     596             :     }
     597           3 :     if (bPointLayer)
     598             :     {
     599           0 :         S2I *poHeadersNew = new S2I();
     600             :         OGRFeatureDefn *poFeatureDefn =
     601           0 :             defineLayer("points", wkbPoint, poPointHeaders, &poHeadersNew);
     602           0 :         delete poPointHeaders;
     603           0 :         poPointHeaders = poHeadersNew;
     604           0 :         poFeatureDefn->Reference();
     605           0 :         papoLayers[--l_nLayers] =
     606           0 :             new OGRSOSILayer(this, poFeatureDefn, poFileadm, poPointHeaders);
     607             :     }
     608             :     else
     609             :     {
     610           3 :         delete poPointHeaders;
     611           3 :         poPointHeaders = nullptr;
     612             :     }
     613           3 :     if (bTextLayer)
     614             :     {
     615           0 :         S2I *poHeadersNew = new S2I();
     616             :         OGRFeatureDefn *poFeatureDefn =
     617           0 :             defineLayer("text", wkbMultiPoint, poTextHeaders, &poHeadersNew);
     618           0 :         delete poTextHeaders;
     619           0 :         poTextHeaders = poHeadersNew;
     620           0 :         poFeatureDefn->Reference();
     621           0 :         papoLayers[--l_nLayers] =
     622           0 :             new OGRSOSILayer(this, poFeatureDefn, poFileadm, poTextHeaders);
     623             :     }
     624             :     else
     625             :     {
     626           3 :         delete poTextHeaders;
     627           3 :         poTextHeaders = nullptr;
     628             :     }
     629           3 :     return TRUE;
     630             : }
     631             : 
     632             : #ifdef WRITE_SUPPORT
     633             : /************************************************************************/
     634             : /*                              Create()                                */
     635             : /************************************************************************/
     636             : 
     637             : int OGRSOSIDataSource::Create(const char *pszFilename)
     638             : {
     639             :     short nStatus;
     640             :     short nDetStatus;
     641             : 
     642             :     poBaseadm = LC_OpenBase(LC_KLADD);
     643             :     nStatus = LC_OpenSos(pszFilename, LC_SEKV_SKRIV, LC_NY_IDX, LC_INGEN_STATUS,
     644             :                          &poFileadm, &nDetStatus);
     645             :     if (nStatus == UT_FALSE)
     646             :     {
     647             :         CPLError(CE_Failure, CPLE_OpenFailed,
     648             :                  "Could not open SOSI file for writing (Status %i).",
     649             :                  nDetStatus);
     650             :         return FALSE;
     651             :     }
     652             : 
     653             :     LC_NyttHode(); /* Create new file header, will be written to file when all
     654             :                       header information elements are set. */
     655             : 
     656             :     return TRUE;
     657             : }
     658             : 
     659             : /************************************************************************/
     660             : /*                             ICreateLayer()                           */
     661             : /************************************************************************/
     662             : 
     663             : OGRLayer *OGRSOSIDataSource::ICreateLayer(
     664             :     const char *pszNameIn, const OGRSpatialReference *poSpatialRef,
     665             :     OGRwkbGeometryType eGType, CPL_UNUSED char **papszOptions)
     666             : {
     667             :     /* SOSI does not really support layers - so let's first see that the global
     668             :      * settings are consistent */
     669             :     if (poSRS == NULL)
     670             :     {
     671             :         if (poSpatialRef != NULL)
     672             :         {
     673             :             poSRS = poSpatialRef->Clone();
     674             : 
     675             :             const char *pszKoosys = poSRS->GetAuthorityCode("PROJCS");
     676             :             if (pszKoosys == NULL)
     677             :             {
     678             :                 OGRErr err = poSRS->AutoIdentifyEPSG();
     679             :                 if (err == OGRERR_UNSUPPORTED_SRS)
     680             :                 {
     681             :                     CPLError(CE_Failure, CPLE_OpenFailed,
     682             :                              "Could not identify EPSG code for spatial "
     683             :                              "reference system");
     684             :                     return NULL;
     685             :                 }
     686             :                 pszKoosys = poSRS->GetAuthorityCode("PROJCS");
     687             :             }
     688             : 
     689             :             if (pszKoosys != NULL)
     690             :             {
     691             :                 int nKoosys = epsg2sosi(atoi(pszKoosys));
     692             :                 CPLDebug("[CreateLayer]", "Projection set to SOSI %i", nKoosys);
     693             :                 LC_PutTrans(nKoosys, 0, 0, 0.01, 0.01, 0.01);
     694             :             }
     695             :             else
     696             :             {
     697             :                 pszKoosys = poSRS->GetAuthorityCode("GEOGCS");
     698             :                 if (pszKoosys != NULL)
     699             :                 {
     700             :                     int nKoosys = epsg2sosi(atoi(pszKoosys));
     701             :                     LC_PutTrans(nKoosys, 0, 0, 0.01, 0.01, 0.01);
     702             :                 }
     703             :                 else
     704             :                 {
     705             :                     CPLError(CE_Failure, CPLE_OpenFailed,
     706             :                              "Could not retrieve EPSG code for spatial "
     707             :                              "reference system");
     708             :                     return NULL;
     709             :                 }
     710             :             }
     711             :         }
     712             :         LC_WsGr(poFileadm); /* Writing the header here! */
     713             :     }
     714             :     else
     715             :     {
     716             :         if (!poSRS->IsSame(poSpatialRef))
     717             :         {
     718             :             CPLError(CE_Failure, CPLE_AppDefined,
     719             :                      "SOSI driver does not support different spatial reference "
     720             :                      "systems in one file.");
     721             :         }
     722             :     }
     723             : 
     724             :     OGRFeatureDefn *poFeatureDefn = new OGRFeatureDefn(pszNameIn);
     725             :     poFeatureDefn->Reference();
     726             :     poFeatureDefn->SetGeomType(eGType);
     727             :     OGRSOSILayer *poLayer =
     728             :         new OGRSOSILayer(this, poFeatureDefn, poFileadm, NULL /*poHeaderDefn*/);
     729             :     /* todo: where do we delete poLayer and poFeatureDefn? */
     730             :     return poLayer;
     731             : }
     732             : #endif
     733             : 
     734             : /************************************************************************/
     735             : /*                              GetLayer()                              */
     736             : /************************************************************************/
     737             : 
     738           6 : OGRLayer *OGRSOSIDataSource::GetLayer(int iLayer)
     739             : {
     740           6 :     if (iLayer < 0 || iLayer >= nLayers)
     741           0 :         return nullptr;
     742             :     else
     743           6 :         return papoLayers[iLayer];
     744             : }
     745             : 
     746           0 : void OGRSOSIDataSource::buildOGRMultiPoint(int nNumCoo, long iSerial)
     747             : {
     748           0 :     if (papoBuiltGeometries[iSerial] != nullptr)
     749             :     {
     750           0 :         return;
     751             :     }
     752             : 
     753           0 :     OGRMultiPoint *poMP = new OGRMultiPoint();
     754             : 
     755             :     long i;
     756           0 :     double dfEast = 0.0;
     757           0 :     double dfNorth = 0.0;
     758           0 :     for (i = (nNumCoo > 1) ? 2 : 1; i <= nNumCoo; i++)
     759             :     {
     760           0 :         LC_GetTK(i, &dfEast, &dfNorth);
     761           0 :         OGRPoint poP = OGRPoint(dfEast, dfNorth);
     762           0 :         poMP->addGeometry(&poP); /*poP will be cloned before returning*/
     763             :     }
     764           0 :     papoBuiltGeometries[iSerial] = poMP;
     765             : }
     766             : 
     767          51 : void OGRSOSIDataSource::buildOGRLineString(int nNumCoo, long iSerial)
     768             : {
     769          51 :     if (papoBuiltGeometries[iSerial] != nullptr)
     770             :     {
     771           0 :         return;
     772             :     }
     773             : 
     774          51 :     OGRLineString *poLS = new OGRLineString();
     775          51 :     poLS->setNumPoints(nNumCoo);
     776             : 
     777             :     int i;
     778          51 :     double dfEast = 0, dfNorth = 0;
     779         516 :     for (i = 1; i <= nNumCoo; i++)
     780             :     {
     781         465 :         LC_GetTK(i, &dfEast, &dfNorth);
     782         465 :         poLS->setPoint(i - 1, dfEast, dfNorth);
     783             :     }
     784          51 :     papoBuiltGeometries[iSerial] = poLS;
     785             : }
     786             : 
     787           0 : static double sqr(double x)
     788             : {
     789           0 :     return x * x;
     790             : }
     791             : 
     792           0 : void OGRSOSIDataSource::buildOGRLineStringFromArc(long iSerial)
     793             : {
     794           0 :     if (papoBuiltGeometries[iSerial] != nullptr)
     795             :     {
     796           0 :         return;
     797             :     }
     798             : 
     799           0 :     OGRLineString *poLS = new OGRLineString();
     800             : 
     801             :     /* fetch reference points on circle (easting, northing) */
     802           0 :     double e1 = 0, e2 = 0, e3 = 0;
     803           0 :     double n1 = 0, n2 = 0, n3 = 0;
     804           0 :     LC_GetTK(1, &e1, &n1);
     805           0 :     LC_GetTK(2, &e2, &n2);
     806           0 :     LC_GetTK(3, &e3, &n3);
     807             : 
     808             :     /* helper constants */
     809           0 :     double p12 = (e1 * e1 - e2 * e2 + n1 * n1 - n2 * n2) / 2;
     810           0 :     double p13 = (e1 * e1 - e3 * e3 + n1 * n1 - n3 * n3) / 2;
     811             : 
     812           0 :     double dE12 = e1 - e2;
     813           0 :     double dE13 = e1 - e3;
     814           0 :     double dN12 = n1 - n2;
     815           0 :     double dN13 = n1 - n3;
     816             : 
     817             :     /* center of the circle */
     818           0 :     double cE = (dN13 * p12 - dN12 * p13) / (dE12 * dN13 - dN12 * dE13);
     819           0 :     double cN = (dE13 * p12 - dE12 * p13) / (dN12 * dE13 - dE12 * dN13);
     820             : 
     821             :     /* radius of the circle */
     822           0 :     double r = sqrt(sqr(e1 - cE) + sqr(n1 - cN));
     823             : 
     824             :     /* angles of points A and B (1 and 3) */
     825           0 :     double th1 = atan2(n1 - cN, e1 - cE);
     826           0 :     double th3 = atan2(n3 - cN, e3 - cE);
     827             : 
     828             :     /* interpolation step in radians */
     829           0 :     double dth = th3 - th1;
     830           0 :     if (dth < 0)
     831             :     {
     832           0 :         dth += 2 * M_PI;
     833             :     }
     834           0 :     if (dth > M_PI)
     835             :     {
     836           0 :         dth = -2 * M_PI + dth;
     837             :     }
     838           0 :     int npt = (int)(ARC_INTERPOLATION_FULL_CIRCLE * dth / 2 * M_PI);
     839           0 :     if (npt < 0)
     840           0 :         npt = -npt;
     841           0 :     if (npt < 3)
     842           0 :         npt = 3;
     843           0 :     poLS->setNumPoints(npt);
     844           0 :     dth = dth / (npt - 1);
     845             : 
     846           0 :     for (int i = 0; i < npt; i++)
     847             :     {
     848           0 :         const double dfEast = cE + r * cos(th1 + dth * i);
     849           0 :         const double dfNorth = cN + r * sin(th1 + dth * i);
     850           0 :         if (dfEast != dfEast)
     851             :         { /* which is a wonderful property of nans */
     852           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     853             :                      "Calculated %lf for point %d of %d in curve %li.", dfEast,
     854             :                      i, npt, iSerial);
     855             :         }
     856           0 :         poLS->setPoint(i, dfEast, dfNorth);
     857             :     }
     858           0 :     papoBuiltGeometries[iSerial] = poLS;
     859             : }
     860             : 
     861           0 : void OGRSOSIDataSource::buildOGRPoint(long iSerial)
     862             : {
     863           0 :     double dfEast = 0, dfNorth = 0;
     864           0 :     LC_GetTK(1, &dfEast, &dfNorth);
     865           0 :     papoBuiltGeometries[iSerial] = new OGRPoint(dfEast, dfNorth);
     866           0 : }
     867             : 
     868             : /************************************************************************/
     869             : /*                              TestCapability()                        */
     870             : /************************************************************************/
     871             : 
     872           0 : int OGRSOSIDataSource::TestCapability(CPL_UNUSED const char *pszCap)
     873             : {
     874             : #ifdef WRITE_SUPPORT
     875             :     if (strcmp("CreateLayer", pszCap) == 0)
     876             :     {
     877             :         return TRUE;
     878             :     }
     879             : #endif
     880           0 :     return FALSE;
     881             : }

Generated by: LCOV version 1.14