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

Generated by: LCOV version 1.14