LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/vfk - vfkdatablock.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 151 470 32.1 %
Date: 2024-05-04 12:52:34 Functions: 19 33 57.6 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  VFK Reader - Data block definition
       4             :  * Purpose:  Implements VFKDataBlock class.
       5             :  * Author:   Martin Landa, landa.martin gmail.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2009-2013, Martin Landa <landa.martin gmail.com>
       9             :  * Copyright (c) 2012-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * Permission is hereby granted, free of charge, to any person
      12             :  * obtaining a copy of this software and associated documentation
      13             :  * files (the "Software"), to deal in the Software without
      14             :  * restriction, including without limitation the rights to use, copy,
      15             :  * modify, merge, publish, distribute, sublicense, and/or sell copies
      16             :  * of the Software, and to permit persons to whom the Software is
      17             :  * furnished to do so, subject to the following conditions:
      18             :  *
      19             :  * The above copyright notice and this permission notice shall be
      20             :  * included in all copies or substantial portions of the Software.
      21             :  *
      22             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      23             :  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      24             :  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      25             :  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
      26             :  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
      27             :  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
      28             :  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      29             :  * SOFTWARE.
      30             :  ****************************************************************************/
      31             : 
      32             : #include <ctime>
      33             : 
      34             : #include "vfkreader.h"
      35             : #include "vfkreaderp.h"
      36             : 
      37             : #include "cpl_conv.h"
      38             : #include "cpl_error.h"
      39             : 
      40             : /*!
      41             :   \brief VFK Data Block constructor
      42             : 
      43             :   \param pszName data block name
      44             : */
      45         976 : IVFKDataBlock::IVFKDataBlock(const char *pszName, const IVFKReader *poReader)
      46             :     : m_papoFeature(nullptr), m_nPropertyCount(0), m_papoProperty(nullptr),
      47        1952 :       m_pszName(CPLStrdup(pszName)),
      48             :       m_bGeometry(false),  // Geometry is not loaded by default.
      49             :       m_nGeometryType(wkbUnknown),
      50             :       m_bGeometryPerBlock(true),  // Load geometry per block/feature.
      51             :       m_nFeatureCount(-1),        // Load data on first request.
      52         976 :       m_iNextFeature(-1), m_poReader(const_cast<IVFKReader *>(poReader))
      53             : {
      54         976 :     m_nRecordCount[RecordValid] = 0L;    // Number of valid records.
      55         976 :     m_nRecordCount[RecordSkipped] = 0L;  // Number of skipped (invalid) records.
      56         976 :     m_nRecordCount[RecordDuplicated] = 0L;  // Number of duplicated records.
      57         976 : }
      58             : 
      59             : /*!
      60             :   \brief VFKDataBlock destructor
      61             : */
      62        1952 : IVFKDataBlock::~IVFKDataBlock()
      63             : {
      64         976 :     CPLFree(m_pszName);
      65             : 
      66       10208 :     for (int i = 0; i < m_nPropertyCount; i++)
      67             :     {
      68        9232 :         if (m_papoProperty[i])
      69        9232 :             delete m_papoProperty[i];
      70             :     }
      71         976 :     CPLFree(m_papoProperty);
      72             : 
      73        1664 :     for (int i = 0; i < m_nFeatureCount; i++)
      74             :     {
      75         688 :         if (m_papoFeature[i])
      76         688 :             delete m_papoFeature[i];
      77             :     }
      78         976 :     CPLFree(m_papoFeature);
      79         976 : }
      80             : 
      81             : /*!
      82             :   \brief Get property definition
      83             : 
      84             :   \param iIndex property index
      85             : 
      86             :   \return pointer to VFKPropertyDefn definition or NULL on failure
      87             : */
      88       38080 : VFKPropertyDefn *IVFKDataBlock::GetProperty(int iIndex) const
      89             : {
      90       38080 :     if (iIndex < 0 || iIndex >= m_nPropertyCount)
      91           0 :         return nullptr;
      92             : 
      93       38080 :     return m_papoProperty[iIndex];
      94             : }
      95             : 
      96             : /*!
      97             :   \brief Set properties
      98             : 
      99             :   \param poLine pointer to line
     100             : */
     101         976 : void IVFKDataBlock::SetProperties(const char *poLine)
     102             : {
     103             :     /* skip data block name */
     104         976 :     const char *poChar = strchr(poLine, ';');
     105         976 :     if (poChar == nullptr)
     106           0 :         return;
     107             : 
     108         976 :     poChar++;
     109             : 
     110             :     /* read property name/type */
     111         976 :     const char *poProp = poChar;
     112         976 :     char *pszName = nullptr;
     113         976 :     char *pszType = nullptr;
     114         976 :     int nLength = 0;
     115      115120 :     while (*poChar != '\0')
     116             :     {
     117      114144 :         if (*poChar == ' ')
     118             :         {
     119        9232 :             pszName = (char *)CPLRealloc(pszName, nLength + 1);
     120        9232 :             strncpy(pszName, poProp, nLength);
     121        9232 :             pszName[nLength] = '\0';
     122             : 
     123        9232 :             poProp = ++poChar;
     124        9232 :             nLength = 0;
     125        9232 :             if (*poProp == '\0')
     126           0 :                 break;
     127             :         }
     128      104912 :         else if (*poChar == ';')
     129             :         {
     130        8256 :             pszType = (char *)CPLRealloc(pszType, nLength + 1);
     131        8256 :             strncpy(pszType, poProp, nLength);
     132        8256 :             pszType[nLength] = '\0';
     133             : 
     134             :             /* add property */
     135        8256 :             if (pszName && *pszName != '\0' && *pszType != '\0')
     136        8256 :                 AddProperty(pszName, pszType);
     137             : 
     138        8256 :             poProp = ++poChar;
     139        8256 :             nLength = 0;
     140        8256 :             if (*poProp == '\0')
     141           0 :                 break;
     142             :         }
     143      114144 :         poChar++;
     144      114144 :         nLength++;
     145             :     }
     146             : 
     147         976 :     pszType = (char *)CPLRealloc(pszType, nLength + 1);
     148         976 :     if (nLength > 0)
     149         976 :         strncpy(pszType, poProp, nLength);
     150         976 :     pszType[nLength] = '\0';
     151             : 
     152             :     /* add property */
     153         976 :     if (pszName && *pszName != '\0' && *pszType != '\0')
     154         976 :         AddProperty(pszName, pszType);
     155             : 
     156         976 :     CPLFree(pszName);
     157         976 :     CPLFree(pszType);
     158             : }
     159             : 
     160             : /*!
     161             :   \brief Add data block property
     162             : 
     163             :   \param pszName property name
     164             :   \param pszType property type
     165             : 
     166             :   \return number of properties
     167             : */
     168        9232 : int IVFKDataBlock::AddProperty(const char *pszName, const char *pszType)
     169             : {
     170             :     /* Force text attributes to avoid int64 overflow
     171             :        see https://github.com/OSGeo/gdal/issues/672 */
     172        9232 :     if (EQUAL(m_pszName, "VLA") &&
     173         192 :         (EQUAL(pszName, "PODIL_CITATEL") || EQUAL(pszName, "PODIL_JMENOVATEL")))
     174          32 :         pszType = "T30";
     175             : 
     176             :     VFKPropertyDefn *poNewProperty =
     177        9232 :         new VFKPropertyDefn(pszName, pszType, m_poReader->GetEncoding());
     178             : 
     179        9232 :     m_nPropertyCount++;
     180             : 
     181       18464 :     m_papoProperty = (VFKPropertyDefn **)CPLRealloc(
     182        9232 :         m_papoProperty, sizeof(VFKPropertyDefn *) * m_nPropertyCount);
     183        9232 :     m_papoProperty[m_nPropertyCount - 1] = poNewProperty;
     184             : 
     185        9232 :     return m_nPropertyCount;
     186             : }
     187             : 
     188             : /*!
     189             :   \brief Get number of features for given data block
     190             : 
     191             :   \param bForce true to force reading VFK data blocks if needed
     192             : 
     193             :   \return number of features
     194             : */
     195        1968 : GIntBig IVFKDataBlock::GetFeatureCount(bool bForce)
     196             : {
     197        1968 :     if (bForce && m_nFeatureCount == -1)
     198             :     {
     199           0 :         m_poReader->ReadDataRecords(this); /* read VFK data records */
     200           0 :         if (m_bGeometryPerBlock && !m_bGeometry)
     201             :         {
     202           0 :             LoadGeometry(); /* get real number of features */
     203             :         }
     204             :     }
     205             : #if defined(__GNUC__)
     206             : #pragma GCC diagnostic push
     207             : #pragma GCC diagnostic ignored "-Wnull-dereference"
     208             : #endif
     209        1968 :     return m_nFeatureCount;
     210             : #if defined(__GNUC__)
     211             : #pragma GCC diagnostic pop
     212             : #endif
     213             : }
     214             : 
     215             : /*!
     216             :   \brief Set number of features per data block
     217             : 
     218             :   \param nNewCount number of features
     219             :   \param bIncrement increment current value
     220             : */
     221         976 : void IVFKDataBlock::SetFeatureCount(int nNewCount, bool bIncrement)
     222             : {
     223         976 :     if (bIncrement)
     224             :     {
     225           0 :         m_nFeatureCount += nNewCount;
     226             :     }
     227             :     else
     228             :     {
     229         976 :         m_nFeatureCount = nNewCount;
     230             :     }
     231         976 : }
     232             : 
     233             : /*!
     234             :   \brief Reset reading
     235             : 
     236             :   \param iIdx force index
     237             : */
     238           7 : void IVFKDataBlock::ResetReading(int iIdx)
     239             : {
     240           7 :     if (iIdx > -1)
     241             :     {
     242           0 :         m_iNextFeature = iIdx;
     243             :     }
     244             :     else
     245             :     {
     246           7 :         m_iNextFeature = 0;
     247             :     }
     248           7 : }
     249             : 
     250             : /*!
     251             :   \brief Get next feature
     252             : 
     253             :   \return pointer to VFKFeature instance or NULL on error
     254             : */
     255          33 : IVFKFeature *IVFKDataBlock::GetNextFeature()
     256             : {
     257          33 :     if (m_nFeatureCount < 0)
     258             :     {
     259           0 :         m_poReader->ReadDataRecords(this);
     260             :     }
     261             : 
     262          33 :     if (m_bGeometryPerBlock && !m_bGeometry)
     263             :     {
     264           0 :         LoadGeometry();
     265             :     }
     266             : 
     267          33 :     if (m_iNextFeature < 0)
     268           0 :         ResetReading();
     269             : 
     270          33 :     if (m_iNextFeature < 0 || m_iNextFeature >= m_nFeatureCount)
     271           3 :         return nullptr;
     272             : 
     273          30 :     return m_papoFeature[m_iNextFeature++];
     274             : }
     275             : 
     276             : /*!
     277             :   \brief Get previous feature
     278             : 
     279             :   \return pointer to VFKFeature instance or NULL on error
     280             : */
     281           0 : IVFKFeature *IVFKDataBlock::GetPreviousFeature()
     282             : {
     283           0 :     if (m_nFeatureCount < 0)
     284             :     {
     285           0 :         m_poReader->ReadDataRecords(this);
     286             :     }
     287             : 
     288           0 :     if (m_bGeometryPerBlock && !m_bGeometry)
     289             :     {
     290           0 :         LoadGeometry();
     291             :     }
     292             : 
     293           0 :     if (m_iNextFeature < 0)
     294           0 :         ResetReading();
     295             : 
     296           0 :     if (m_iNextFeature < 0 || m_iNextFeature >= m_nFeatureCount)
     297           0 :         return nullptr;
     298             : 
     299           0 :     return m_papoFeature[m_iNextFeature--];
     300             : }
     301             : 
     302             : /*!
     303             :   \brief Get first feature
     304             : 
     305             :   \return pointer to VFKFeature instance or NULL on error
     306             : */
     307           0 : IVFKFeature *IVFKDataBlock::GetFirstFeature()
     308             : {
     309           0 :     if (m_nFeatureCount < 0)
     310             :     {
     311           0 :         m_poReader->ReadDataRecords(this);
     312             :     }
     313             : 
     314           0 :     if (m_bGeometryPerBlock && !m_bGeometry)
     315             :     {
     316           0 :         LoadGeometry();
     317             :     }
     318             : 
     319           0 :     if (m_nFeatureCount < 1)
     320           0 :         return nullptr;
     321             : 
     322           0 :     return m_papoFeature[0];
     323             : }
     324             : 
     325             : /*!
     326             :   \brief Get last feature
     327             : 
     328             :   \return pointer to VFKFeature instance or NULL on error
     329             : */
     330           0 : IVFKFeature *IVFKDataBlock::GetLastFeature()
     331             : {
     332           0 :     if (m_nFeatureCount < 0)
     333             :     {
     334           0 :         m_poReader->ReadDataRecords(this);
     335             :     }
     336             : 
     337           0 :     if (m_bGeometryPerBlock && !m_bGeometry)
     338             :     {
     339           0 :         LoadGeometry();
     340             :     }
     341             : 
     342           0 :     if (m_nFeatureCount < 1)
     343           0 :         return nullptr;
     344             : 
     345           0 :     return m_papoFeature[m_nFeatureCount - 1];
     346             : }
     347             : 
     348             : /*!
     349             :   \brief Get property index by name
     350             : 
     351             :   \param pszName property name
     352             : 
     353             :   \return property index or -1 on error (property name not found)
     354             : */
     355         435 : int IVFKDataBlock::GetPropertyIndex(const char *pszName) const
     356             : {
     357        3915 :     for (int i = 0; i < m_nPropertyCount; i++)
     358        3915 :         if (EQUAL(pszName, m_papoProperty[i]->GetName()))
     359         435 :             return i;
     360             : 
     361           0 :     return -1;
     362             : }
     363             : 
     364             : /*!
     365             :   \brief Set geometry type (point, linestring, polygon)
     366             : 
     367             :   \param bSuppressGeometry True for forcing wkbNone type
     368             : 
     369             :   \return geometry type
     370             : */
     371         976 : OGRwkbGeometryType IVFKDataBlock::SetGeometryType(bool bSuppressGeometry)
     372             : {
     373         976 :     m_nGeometryType = wkbNone; /* pure attribute records */
     374         976 :     if (bSuppressGeometry)
     375             :     {
     376          61 :         m_bGeometry = true; /* pretend that geometry is already loaded */
     377             : 
     378          61 :         return m_nGeometryType;
     379             :     }
     380             : 
     381         915 :     if (EQUAL(m_pszName, "SOBR") || EQUAL(m_pszName, "OBBP") ||
     382         885 :         EQUAL(m_pszName, "SPOL") || EQUAL(m_pszName, "OB") ||
     383         855 :         EQUAL(m_pszName, "OP") || EQUAL(m_pszName, "OBPEJ"))
     384          90 :         m_nGeometryType = wkbPoint;
     385             : 
     386         825 :     else if (EQUAL(m_pszName, "SBP") || EQUAL(m_pszName, "SBPG") ||
     387         810 :              EQUAL(m_pszName, "HP") || EQUAL(m_pszName, "DPM") ||
     388         780 :              EQUAL(m_pszName, "ZVB"))
     389          60 :         m_nGeometryType = wkbLineString;
     390             : 
     391         765 :     else if (EQUAL(m_pszName, "PAR") || EQUAL(m_pszName, "BUD"))
     392          30 :         m_nGeometryType = wkbPolygon;
     393             : 
     394         915 :     return m_nGeometryType;
     395             : }
     396             : 
     397             : /*!
     398             :   \brief Get geometry type
     399             : 
     400             :   \return geometry type
     401             : */
     402        5295 : OGRwkbGeometryType IVFKDataBlock::GetGeometryType() const
     403             : {
     404        5295 :     return m_nGeometryType;
     405             : }
     406             : 
     407             : /*!
     408             :   \brief Get feature by index
     409             : 
     410             :   \param iIndex feature index
     411             : 
     412             :   \return pointer to feature definition or NULL on failure
     413             : */
     414        1386 : IVFKFeature *IVFKDataBlock::GetFeatureByIndex(int iIndex) const
     415             : {
     416        1386 :     if (iIndex < 0 || iIndex >= m_nFeatureCount)
     417           0 :         return nullptr;
     418             : 
     419        1386 :     return m_papoFeature[iIndex];
     420             : }
     421             : 
     422             : /*!
     423             :   \brief Get feature by FID
     424             : 
     425             :   Modifies next feature id.
     426             : 
     427             :   \param nFID feature id
     428             : 
     429             :   \return pointer to feature definition or NULL on failure (not found)
     430             : */
     431           1 : IVFKFeature *IVFKDataBlock::GetFeature(GIntBig nFID)
     432             : {
     433           1 :     if (m_nFeatureCount < 0)
     434             :     {
     435           0 :         m_poReader->ReadDataRecords(this);
     436             :     }
     437             : 
     438           1 :     if (nFID < 1 || nFID > m_nFeatureCount)
     439           0 :         return nullptr;
     440             : 
     441           1 :     if (m_bGeometryPerBlock && !m_bGeometry)
     442             :     {
     443           0 :         LoadGeometry();
     444             :     }
     445             : 
     446           1 :     return GetFeatureByIndex(int(nFID) - 1); /* zero-based index */
     447             : }
     448             : 
     449             : /*!
     450             :   \brief Load geometry
     451             : 
     452             :   Print warning when some invalid features are detected.
     453             : 
     454             :   \return number of invalid features or -1 on failure
     455             : */
     456        1035 : int IVFKDataBlock::LoadGeometry()
     457             : {
     458             : #if defined(__GNUC__)
     459             : #pragma GCC diagnostic push
     460             : #pragma GCC diagnostic ignored "-Wnull-dereference"
     461             : #endif
     462        1035 :     if (m_bGeometry)
     463         120 :         return 0;
     464             : #if defined(__GNUC__)
     465             : #pragma GCC diagnostic pop
     466             : #endif
     467             : 
     468         915 :     m_bGeometry = true;
     469         915 :     int nInvalid = 0;
     470             : 
     471             : #ifdef DEBUG_TIMING
     472             :     const clock_t start = clock();
     473             : #endif
     474             : 
     475         915 :     if (m_nFeatureCount < 0)
     476             :     {
     477           0 :         m_poReader->ReadDataRecords(this);
     478             :     }
     479             : 
     480         915 :     if (EQUAL(m_pszName, "SOBR") || EQUAL(m_pszName, "SPOL") ||
     481         885 :         EQUAL(m_pszName, "OP") || EQUAL(m_pszName, "OBPEJ") ||
     482         855 :         EQUAL(m_pszName, "OB") || EQUAL(m_pszName, "OBBP"))
     483             :     {
     484             :         /* -> wkbPoint */
     485          90 :         nInvalid = LoadGeometryPoint();
     486             :     }
     487         825 :     else if (EQUAL(m_pszName, "SBP") || EQUAL(m_pszName, "SBPG"))
     488             :     {
     489             :         /* -> wkbLineString */
     490          15 :         nInvalid = LoadGeometryLineStringSBP();
     491             :     }
     492         810 :     else if (EQUAL(m_pszName, "HP") || EQUAL(m_pszName, "DPM") ||
     493         780 :              EQUAL(m_pszName, "ZVB"))
     494             :     {
     495             :         /* -> wkbLineString */
     496          45 :         nInvalid = LoadGeometryLineStringHP();
     497             :     }
     498         765 :     else if (EQUAL(m_pszName, "PAR") || EQUAL(m_pszName, "BUD"))
     499             :     {
     500             :         /* -> wkbPolygon */
     501          30 :         nInvalid = LoadGeometryPolygon();
     502             :     }
     503             : 
     504             : #ifdef DEBUG_TIMING
     505             :     const clock_t end = clock();
     506             : #endif
     507             : 
     508         915 :     if (nInvalid > 0)
     509             :     {
     510           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     511             :                  "%s: %d features with invalid or empty geometry", m_pszName,
     512             :                  nInvalid);
     513             :     }
     514             : 
     515             : #ifdef DEBUG_TIMING
     516             :     CPLDebug("OGR-VFK", "VFKDataBlock::LoadGeometry(): name=%s time=%ld sec",
     517             :              m_pszName, (long)((end - start) / CLOCKS_PER_SEC));
     518             : #endif
     519             : 
     520         915 :     return nInvalid;
     521             : }
     522             : 
     523         182 : void IVFKDataBlock::FillPointList(PointList *poList,
     524             :                                   const OGRLineString *poLine)
     525             : {
     526         182 :     poList->reserve(poLine->getNumPoints());
     527             : 
     528             :     /* OGRLineString -> PointList */
     529         546 :     for (int i = 0; i < poLine->getNumPoints(); i++)
     530             :     {
     531         728 :         OGRPoint pt;
     532         364 :         poLine->getPoint(i, &pt);
     533         364 :         poList->emplace_back(std::move(pt));
     534             :     }
     535         182 : }
     536             : 
     537             : /*!
     538             :   \brief Add linestring to a ring (private)
     539             : 
     540             :   \param[in,out] papoRing list of rings
     541             :   \param poLine pointer to linestring to be added to a ring
     542             :   \param bNewRing  create new ring
     543             :   \param bBackward allow backward direction
     544             : 
     545             :   \return true on success or false on failure
     546             : */
     547           0 : bool IVFKDataBlock::AppendLineToRing(PointListArray *papoRing,
     548             :                                      const OGRLineString *poLine, bool bNewRing,
     549             :                                      bool bBackward)
     550             : {
     551             :     /* create new ring */
     552           0 :     if (bNewRing)
     553             :     {
     554           0 :         PointList *poList = new PointList();
     555           0 :         FillPointList(poList, poLine);
     556           0 :         papoRing->emplace_back(poList);
     557           0 :         return true;
     558             :     }
     559             : 
     560           0 :     if (poLine->getNumPoints() < 2)
     561           0 :         return false;
     562           0 :     OGRPoint oFirstNew;
     563           0 :     OGRPoint oLastNew;
     564           0 :     poLine->StartPoint(&oFirstNew);
     565           0 :     poLine->EndPoint(&oLastNew);
     566             : 
     567           0 :     for (PointList *ring : *papoRing)
     568             :     {
     569           0 :         const OGRPoint &oFirst = ring->front();
     570           0 :         const OGRPoint &oLast = ring->back();
     571             : 
     572           0 :         if (oFirstNew.getX() == oLast.getX() &&
     573           0 :             oFirstNew.getY() == oLast.getY())
     574             :         {
     575           0 :             PointList oList;
     576           0 :             FillPointList(&oList, poLine);
     577             :             /* forward, skip first point */
     578           0 :             ring->insert(ring->end(), oList.begin() + 1, oList.end());
     579           0 :             return true;
     580             :         }
     581             : 
     582           0 :         if (bBackward && oFirstNew.getX() == oFirst.getX() &&
     583           0 :             oFirstNew.getY() == oFirst.getY())
     584             :         {
     585           0 :             PointList oList;
     586           0 :             FillPointList(&oList, poLine);
     587             :             /* backward, skip last point */
     588           0 :             ring->insert(ring->begin(), oList.rbegin(), oList.rend() - 1);
     589           0 :             return true;
     590             :         }
     591             : 
     592           0 :         if (oLastNew.getX() == oLast.getX() && oLastNew.getY() == oLast.getY())
     593             :         {
     594           0 :             PointList oList;
     595           0 :             FillPointList(&oList, poLine);
     596             :             /* backward, skip first point */
     597           0 :             ring->insert(ring->end(), oList.rbegin() + 1, oList.rend());
     598           0 :             return true;
     599             :         }
     600             : 
     601           0 :         if (bBackward && oLastNew.getX() == oFirst.getX() &&
     602           0 :             oLastNew.getY() == oFirst.getY())
     603             :         {
     604           0 :             PointList oList;
     605           0 :             FillPointList(&oList, poLine);
     606             :             /* forward, skip last point */
     607           0 :             ring->insert(ring->begin(), oList.begin(), oList.end() - 1);
     608           0 :             return true;
     609             :         }
     610             :     }
     611             : 
     612           0 :     return false;
     613             : }
     614             : 
     615             : /*!
     616             :   \brief Set next feature
     617             : 
     618             :   \param poFeature pointer to current feature
     619             : 
     620             :   \return index of current feature or -1 on failure
     621             : */
     622           0 : int IVFKDataBlock::SetNextFeature(const IVFKFeature *poFeature)
     623             : {
     624           0 :     for (int i = 0; i < m_nFeatureCount; i++)
     625             :     {
     626           0 :         if (m_papoFeature[i] == poFeature)
     627             :         {
     628           0 :             m_iNextFeature = i + 1;
     629           0 :             return i;
     630             :         }
     631             :     }
     632             : 
     633           0 :     return -1;
     634             : }
     635             : 
     636             : /*!
     637             :   \brief Add feature
     638             : 
     639             :   \param poNewFeature pointer to VFKFeature instance
     640             : */
     641         688 : void IVFKDataBlock::AddFeature(IVFKFeature *poNewFeature)
     642             : {
     643         688 :     m_nFeatureCount++;
     644             : 
     645        1376 :     m_papoFeature = (IVFKFeature **)CPLRealloc(
     646         688 :         m_papoFeature, sizeof(IVFKFeature *) * m_nFeatureCount);
     647         688 :     m_papoFeature[m_nFeatureCount - 1] = poNewFeature;
     648         688 : }
     649             : 
     650             : /*!
     651             :   \brief Get number of records
     652             : 
     653             :   \param iRec record type (valid, skipped, duplicated)
     654             : 
     655             :   \return number of records
     656             : */
     657        4305 : int IVFKDataBlock::GetRecordCount(RecordType iRec) const
     658             : {
     659        4305 :     return (int)m_nRecordCount[iRec];
     660             : }
     661             : 
     662             : /*!
     663             :   \brief Increment number of records
     664             : 
     665             :   \param iRec record type (valid, skipped, duplicated)
     666             : */
     667         870 : void IVFKDataBlock::SetIncRecordCount(RecordType iRec)
     668             : {
     669         870 :     m_nRecordCount[iRec]++;
     670         870 : }
     671             : 
     672             : /*!
     673             :   \brief Get first found feature based on its properties
     674             : 
     675             :   Note: modifies next feature.
     676             : 
     677             :   \param idx property index
     678             :   \param value property value
     679             :   \param poList list of features (NULL to loop all features)
     680             : 
     681             :   \return pointer to feature definition or NULL on failure (not found)
     682             : */
     683           0 : VFKFeature *VFKDataBlock::GetFeature(int idx, GUIntBig value,
     684             :                                      VFKFeatureList *poList)
     685             : {
     686           0 :     if (poList)
     687             :     {
     688           0 :         for (VFKFeatureList::iterator i = poList->begin(), e = poList->end();
     689           0 :              i != e; ++i)
     690             :         {
     691           0 :             VFKFeature *poVfkFeature = *i;
     692           0 :             const GUIntBig iPropertyValue = strtoul(
     693             :                 poVfkFeature->GetProperty(idx)->GetValueS(), nullptr, 0);
     694           0 :             if (iPropertyValue == value)
     695             :             {
     696           0 :                 poList->erase(i); /* ??? */
     697           0 :                 return poVfkFeature;
     698             :             }
     699             :         }
     700             :     }
     701             :     else
     702             :     {
     703           0 :         for (int i = 0; i < m_nFeatureCount; i++)
     704             :         {
     705           0 :             VFKFeature *poVfkFeature = (VFKFeature *)GetFeatureByIndex(i);
     706           0 :             const GUIntBig iPropertyValue = strtoul(
     707             :                 poVfkFeature->GetProperty(idx)->GetValueS(), nullptr, 0);
     708           0 :             if (iPropertyValue == value)
     709             :             {
     710           0 :                 m_iNextFeature = i + 1;
     711           0 :                 return poVfkFeature;
     712             :             }
     713             :         }
     714             :     }
     715             : 
     716           0 :     return nullptr;
     717             : }
     718             : 
     719             : /*!
     720             :   \brief Get features based on properties
     721             : 
     722             :   \param idx property index
     723             :   \param value property value
     724             : 
     725             :   \return list of features
     726             : */
     727           0 : VFKFeatureList VFKDataBlock::GetFeatures(int idx, GUIntBig value)
     728             : {
     729           0 :     std::vector<VFKFeature *> poResult;
     730             : 
     731           0 :     for (int i = 0; i < m_nFeatureCount; i++)
     732             :     {
     733           0 :         VFKFeature *poVfkFeature = (VFKFeature *)GetFeatureByIndex(i);
     734             :         const GUIntBig iPropertyValue =
     735           0 :             strtoul(poVfkFeature->GetProperty(idx)->GetValueS(), nullptr, 0);
     736           0 :         if (iPropertyValue == value)
     737             :         {
     738           0 :             poResult.push_back(poVfkFeature);
     739             :         }
     740             :     }
     741             : 
     742           0 :     return poResult;
     743             : }
     744             : 
     745             : /*!
     746             :   \brief Get features based on properties
     747             : 
     748             :   \param idx1 property index
     749             :   \param idx2 property index
     750             :   \param value property value
     751             : 
     752             :   \return list of features
     753             : */
     754           0 : VFKFeatureList VFKDataBlock::GetFeatures(int idx1, int idx2, GUIntBig value)
     755             : {
     756           0 :     std::vector<VFKFeature *> poResult;
     757             : 
     758           0 :     for (int i = 0; i < m_nFeatureCount; i++)
     759             :     {
     760           0 :         VFKFeature *poVfkFeature = (VFKFeature *)GetFeatureByIndex(i);
     761             :         const GUIntBig iPropertyValue1 =
     762           0 :             strtoul(poVfkFeature->GetProperty(idx1)->GetValueS(), nullptr, 0);
     763           0 :         if (idx2 < 0)
     764             :         {
     765           0 :             if (iPropertyValue1 == value)
     766             :             {
     767           0 :                 poResult.push_back(poVfkFeature);
     768             :             }
     769             :         }
     770             :         else
     771             :         {
     772           0 :             const GUIntBig iPropertyValue2 = strtoul(
     773             :                 poVfkFeature->GetProperty(idx2)->GetValueS(), nullptr, 0);
     774           0 :             if (iPropertyValue1 == value || iPropertyValue2 == value)
     775             :             {
     776           0 :                 poResult.push_back(poVfkFeature);
     777             :             }
     778             :         }
     779             :     }
     780             : 
     781           0 :     return poResult;
     782             : }
     783             : 
     784             : /*!
     785             :   \brief Get feature count based on property value
     786             : 
     787             :   \param pszName property name
     788             :   \param pszValue property value
     789             : 
     790             :   \return number of features or -1 on error
     791             : */
     792           0 : GIntBig VFKDataBlock::GetFeatureCount(const char *pszName, const char *pszValue)
     793             : {
     794           0 :     const int propIdx = GetPropertyIndex(pszName);
     795           0 :     if (propIdx < 0)
     796           0 :         return -1;
     797             : 
     798           0 :     int nfeatures = 0;
     799           0 :     for (int i = 0; i < ((IVFKDataBlock *)this)->GetFeatureCount(); i++)
     800             :     {
     801             :         VFKFeature *poVFKFeature =
     802           0 :             (VFKFeature *)((IVFKDataBlock *)this)->GetFeature(i);
     803           0 :         if (!poVFKFeature)
     804           0 :             return -1;
     805           0 :         if (EQUAL(poVFKFeature->GetProperty(propIdx)->GetValueS(), pszValue))
     806           0 :             nfeatures++;
     807             :     }
     808             : 
     809           0 :     return nfeatures;
     810             : }
     811             : 
     812             : /*!
     813             :   \brief Load geometry (point layers)
     814             : 
     815             :   \return number of invalid features
     816             : */
     817           0 : int VFKDataBlock::LoadGeometryPoint()
     818             : {
     819           0 :     int nInvalid = 0;
     820           0 :     int i_idxY = GetPropertyIndex("SOURADNICE_Y");
     821           0 :     int i_idxX = GetPropertyIndex("SOURADNICE_X");
     822           0 :     if (i_idxY < 0 || i_idxX < 0)
     823             :     {
     824           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
     825             :                  m_pszName);
     826           0 :         return nInvalid;
     827             :     }
     828             : 
     829           0 :     for (int j = 0; j < ((IVFKDataBlock *)this)->GetFeatureCount(); j++)
     830             :     {
     831           0 :         VFKFeature *poFeature = (VFKFeature *)GetFeatureByIndex(j);
     832           0 :         double x = -1.0 * poFeature->GetProperty(i_idxY)->GetValueD();
     833           0 :         double y = -1.0 * poFeature->GetProperty(i_idxX)->GetValueD();
     834           0 :         OGRPoint pt(x, y);
     835           0 :         if (!poFeature->SetGeometry(&pt))
     836           0 :             nInvalid++;
     837             :     }
     838             : 
     839           0 :     return nInvalid;
     840             : }
     841             : 
     842             : /*!
     843             :   \brief Load geometry (linestring SBP/SBPG layer)
     844             : 
     845             :   \return number of invalid features
     846             : */
     847           0 : int VFKDataBlock::LoadGeometryLineStringSBP()
     848             : {
     849             :     VFKDataBlock *poDataBlockPoints =
     850           0 :         (VFKDataBlock *)m_poReader->GetDataBlock("SOBR");
     851           0 :     if (nullptr == poDataBlockPoints)
     852             :     {
     853           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Data block %s not found.\n",
     854             :                  m_pszName);
     855           0 :         return 0;
     856             :     }
     857             : 
     858           0 :     poDataBlockPoints->LoadGeometry();
     859           0 :     int idxId = poDataBlockPoints->GetPropertyIndex("ID");
     860           0 :     int idxBp_Id = GetPropertyIndex("BP_ID");
     861           0 :     int idxPCB = GetPropertyIndex("PORADOVE_CISLO_BODU");
     862           0 :     if (idxId < 0 || idxBp_Id < 0 || idxPCB < 0)
     863             :     {
     864           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
     865             :                  m_pszName);
     866           0 :         return 0;
     867             :     }
     868             : 
     869           0 :     OGRLineString oOGRLine;
     870           0 :     VFKFeature *poLine = nullptr;
     871           0 :     int nInvalid = 0;
     872             : 
     873           0 :     for (int j = 0; j < ((IVFKDataBlock *)this)->GetFeatureCount(); j++)
     874             :     {
     875           0 :         VFKFeature *poFeature = (VFKFeature *)GetFeatureByIndex(j);
     876           0 :         CPLAssert(nullptr != poFeature);
     877             : 
     878           0 :         poFeature->SetGeometry(nullptr);
     879             :         GUIntBig id =
     880           0 :             strtoul(poFeature->GetProperty(idxBp_Id)->GetValueS(), nullptr, 0);
     881             :         GUIntBig ipcb =
     882           0 :             strtoul(poFeature->GetProperty(idxPCB)->GetValueS(), nullptr, 0);
     883           0 :         if (ipcb == 1)
     884             :         {
     885           0 :             if (!oOGRLine.IsEmpty())
     886             :             {
     887           0 :                 oOGRLine.setCoordinateDimension(2); /* force 2D */
     888           0 :                 if (poLine != nullptr && !poLine->SetGeometry(&oOGRLine))
     889           0 :                     nInvalid++;
     890           0 :                 oOGRLine.empty(); /* restore line */
     891             :             }
     892           0 :             poLine = poFeature;
     893             :         }
     894             :         else
     895             :         {
     896           0 :             poFeature->SetGeometryType(wkbUnknown);
     897             :         }
     898           0 :         VFKFeature *poPoint = poDataBlockPoints->GetFeature(idxId, id);
     899           0 :         if (!poPoint)
     900           0 :             continue;
     901           0 :         const OGRPoint *pt = poPoint->GetGeometry()->toPoint();
     902           0 :         oOGRLine.addPoint(pt);
     903             :     }
     904             :     /* add last line */
     905           0 :     oOGRLine.setCoordinateDimension(2); /* force 2D */
     906           0 :     if (poLine)
     907             :     {
     908           0 :         if (!poLine->SetGeometry(&oOGRLine))
     909           0 :             nInvalid++;
     910             :     }
     911           0 :     poDataBlockPoints->ResetReading();
     912             : 
     913           0 :     return nInvalid;
     914             : }
     915             : 
     916             : /*!
     917             :   \brief Load geometry (linestring HP/DPM/ZVB layer)
     918             : 
     919             :   \return number of invalid features
     920             : */
     921           0 : int VFKDataBlock::LoadGeometryLineStringHP()
     922             : {
     923           0 :     int nInvalid = 0;
     924             : 
     925             :     VFKDataBlock *poDataBlockLines =
     926           0 :         (VFKDataBlock *)m_poReader->GetDataBlock("SBP");
     927           0 :     if (nullptr == poDataBlockLines)
     928             :     {
     929           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Data block %s not found.\n",
     930             :                  m_pszName);
     931           0 :         return nInvalid;
     932             :     }
     933             : 
     934           0 :     poDataBlockLines->LoadGeometry();
     935           0 :     const int idxId = GetPropertyIndex("ID");
     936           0 :     CPLString osColumn;
     937           0 :     osColumn.Printf("%s_ID", m_pszName);
     938           0 :     const int idxMy_Id = poDataBlockLines->GetPropertyIndex(osColumn);
     939             :     const int idxPCB =
     940           0 :         poDataBlockLines->GetPropertyIndex("PORADOVE_CISLO_BODU");
     941           0 :     if (idxId < 0 || idxMy_Id < 0 || idxPCB < 0)
     942             :     {
     943           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
     944             :                  m_pszName);
     945           0 :         return nInvalid;
     946             :     }
     947             : 
     948             :     // Reduce to first segment.
     949           0 :     VFKFeatureList poLineList = poDataBlockLines->GetFeatures(idxPCB, 1);
     950           0 :     for (int i = 0; i < ((IVFKDataBlock *)this)->GetFeatureCount(); i++)
     951             :     {
     952           0 :         VFKFeature *poFeature = (VFKFeature *)GetFeatureByIndex(i);
     953           0 :         CPLAssert(nullptr != poFeature);
     954             :         GUIntBig id =
     955           0 :             strtoul(poFeature->GetProperty(idxId)->GetValueS(), nullptr, 0);
     956             :         VFKFeature *poLine =
     957           0 :             poDataBlockLines->GetFeature(idxMy_Id, id, &poLineList);
     958           0 :         if (!poLine || !poLine->GetGeometry())
     959           0 :             continue;
     960           0 :         if (!poFeature->SetGeometry(poLine->GetGeometry()))
     961           0 :             nInvalid++;
     962             :     }
     963           0 :     poDataBlockLines->ResetReading();
     964             : 
     965           0 :     return nInvalid;
     966             : }
     967             : 
     968             : /*!
     969             :   \brief Load geometry (polygon BUD/PAR layers)
     970             : 
     971             :   \return number of invalid features
     972             : */
     973           0 : int VFKDataBlock::LoadGeometryPolygon()
     974             : {
     975           0 :     VFKDataBlock *poDataBlockLines1 = nullptr;
     976           0 :     VFKDataBlock *poDataBlockLines2 = nullptr;
     977             : 
     978           0 :     bool bIsPar = false;
     979           0 :     if (EQUAL(m_pszName, "PAR"))
     980             :     {
     981           0 :         poDataBlockLines1 = (VFKDataBlock *)m_poReader->GetDataBlock("HP");
     982           0 :         poDataBlockLines2 = poDataBlockLines1;
     983           0 :         bIsPar = true;
     984             :     }
     985             :     else
     986             :     {
     987           0 :         poDataBlockLines1 = (VFKDataBlock *)m_poReader->GetDataBlock("OB");
     988           0 :         poDataBlockLines2 = (VFKDataBlock *)m_poReader->GetDataBlock("SBP");
     989           0 :         bIsPar = false;
     990             :     }
     991             : 
     992           0 :     int nInvalid = 0;
     993           0 :     if (nullptr == poDataBlockLines1 || nullptr == poDataBlockLines2)
     994             :     {
     995           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Data block %s not found.\n",
     996             :                  m_pszName);
     997           0 :         return nInvalid;
     998             :     }
     999             : 
    1000           0 :     poDataBlockLines1->LoadGeometry();
    1001           0 :     poDataBlockLines2->LoadGeometry();
    1002           0 :     int idxId = GetPropertyIndex("ID");
    1003           0 :     if (idxId < 0)
    1004             :     {
    1005           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
    1006             :                  m_pszName);
    1007           0 :         return nInvalid;
    1008             :     }
    1009             : 
    1010           0 :     int idxBud = 0;
    1011           0 :     int idxOb = 0;
    1012           0 :     int idxIdOb = 0;
    1013           0 :     int idxPar1 = 0;
    1014           0 :     int idxPar2 = 0;
    1015           0 :     if (bIsPar)
    1016             :     {
    1017           0 :         idxPar1 = poDataBlockLines1->GetPropertyIndex("PAR_ID_1");
    1018           0 :         idxPar2 = poDataBlockLines1->GetPropertyIndex("PAR_ID_2");
    1019           0 :         if (idxPar1 < 0 || idxPar2 < 0)
    1020             :         {
    1021           0 :             CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
    1022             :                      m_pszName);
    1023           0 :             return nInvalid;
    1024             :         }
    1025             :     }
    1026             :     else
    1027             :     { /* BUD */
    1028           0 :         idxIdOb = poDataBlockLines1->GetPropertyIndex("ID");
    1029           0 :         idxBud = poDataBlockLines1->GetPropertyIndex("BUD_ID");
    1030           0 :         idxOb = poDataBlockLines2->GetPropertyIndex("OB_ID");
    1031           0 :         if (idxIdOb < 0 || idxBud < 0 || idxOb < 0)
    1032             :         {
    1033           0 :             CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
    1034             :                      m_pszName);
    1035           0 :             return nInvalid;
    1036             :         }
    1037             :     }
    1038             : 
    1039           0 :     VFKFeatureList poLineList;
    1040           0 :     PointListArray poRingList; /* first is to be considered as exterior */
    1041           0 :     OGRLinearRing ogrRing;
    1042           0 :     OGRPolygon ogrPolygon;
    1043             : 
    1044           0 :     for (int i = 0; i < ((IVFKDataBlock *)this)->GetFeatureCount(); i++)
    1045             :     {
    1046           0 :         VFKFeature *poFeature = (VFKFeature *)GetFeatureByIndex(i);
    1047           0 :         CPLAssert(nullptr != poFeature);
    1048             :         const GUIntBig id =
    1049           0 :             strtoul(poFeature->GetProperty(idxId)->GetValueS(), nullptr, 0);
    1050           0 :         if (bIsPar)
    1051             :         {
    1052           0 :             poLineList = poDataBlockLines1->GetFeatures(idxPar1, idxPar2, id);
    1053             :         }
    1054             :         else
    1055             :         {
    1056             :             VFKFeature *poLineOb, *poLineSbp;
    1057           0 :             std::vector<VFKFeature *> poLineListOb;
    1058           0 :             poLineListOb = poDataBlockLines1->GetFeatures(idxBud, id);
    1059           0 :             for (std::vector<VFKFeature *>::const_iterator
    1060           0 :                      iOb = poLineListOb.begin(),
    1061           0 :                      eOb = poLineListOb.end();
    1062           0 :                  iOb != eOb; ++iOb)
    1063             :             {
    1064           0 :                 poLineOb = (*iOb);
    1065           0 :                 GUIntBig idOb = strtoul(
    1066             :                     poLineOb->GetProperty(idxIdOb)->GetValueS(), nullptr, 0);
    1067           0 :                 poLineSbp = poDataBlockLines2->GetFeature(idxOb, idOb);
    1068           0 :                 if (poLineSbp)
    1069           0 :                     poLineList.push_back(poLineSbp);
    1070             :             }
    1071             :         }
    1072           0 :         if (poLineList.size() < 1)
    1073           0 :             continue;
    1074             : 
    1075             :         /* clear */
    1076           0 :         ogrPolygon.empty();
    1077           0 :         poRingList.clear();
    1078             : 
    1079             :         /* collect rings (points) */
    1080           0 :         bool bFound = false;
    1081           0 :         int nCount = 0;
    1082           0 :         int nCountMax = static_cast<int>(poLineList.size()) * 2;
    1083           0 :         while (!poLineList.empty() && nCount < nCountMax)
    1084             :         {
    1085           0 :             bool bNewRing = !bFound;
    1086           0 :             bFound = false;
    1087           0 :             for (VFKFeatureList::iterator iHp = poLineList.begin(),
    1088           0 :                                           eHp = poLineList.end();
    1089           0 :                  iHp != eHp; ++iHp)
    1090             :             {
    1091           0 :                 auto pGeom = (*iHp)->GetGeometry();
    1092           0 :                 if (pGeom && AppendLineToRing(&poRingList,
    1093             :                                               pGeom->toLineString(), bNewRing))
    1094             :                 {
    1095           0 :                     bFound = true;
    1096           0 :                     poLineList.erase(iHp);
    1097           0 :                     break;
    1098             :                 }
    1099             :             }
    1100           0 :             nCount++;
    1101             :         }
    1102             :         /* create rings */
    1103           0 :         for (PointListArray::const_iterator iRing = poRingList.begin(),
    1104           0 :                                             eRing = poRingList.end();
    1105           0 :              iRing != eRing; ++iRing)
    1106             :         {
    1107           0 :             PointList *poList = *iRing;
    1108           0 :             ogrRing.empty();
    1109           0 :             for (PointList::iterator iPoint = poList->begin(),
    1110           0 :                                      ePoint = poList->end();
    1111           0 :                  iPoint != ePoint; ++iPoint)
    1112             :             {
    1113           0 :                 ogrRing.addPoint(&(*iPoint));
    1114             :             }
    1115           0 :             ogrPolygon.addRing(&ogrRing);
    1116             :         }
    1117             :         /* set polygon */
    1118           0 :         ogrPolygon.setCoordinateDimension(2); /* force 2D */
    1119           0 :         if (!poFeature->SetGeometry(&ogrPolygon))
    1120           0 :             nInvalid++;
    1121             :     }
    1122             : 
    1123             :     /* free ring list */
    1124           0 :     for (PointListArray::iterator iRing = poRingList.begin(),
    1125           0 :                                   eRing = poRingList.end();
    1126           0 :          iRing != eRing; ++iRing)
    1127             :     {
    1128           0 :         delete (*iRing);
    1129           0 :         *iRing = nullptr;
    1130             :     }
    1131           0 :     poDataBlockLines1->ResetReading();
    1132           0 :     poDataBlockLines2->ResetReading();
    1133             : 
    1134           0 :     return nInvalid;
    1135             : }

Generated by: LCOV version 1.14