LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/vfk - vfkdatablock.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 144 470 30.6 %
Date: 2025-05-31 00:00:17 Functions: 18 33 54.5 %

          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           0 : void IVFKDataBlock::FillPointList(PointList *poList,
     506             :                                   const OGRLineString *poLine)
     507             : {
     508           0 :     poList->reserve(poLine->getNumPoints());
     509             : 
     510             :     /* OGRLineString -> PointList */
     511           0 :     for (int i = 0; i < poLine->getNumPoints(); i++)
     512             :     {
     513           0 :         OGRPoint pt;
     514           0 :         poLine->getPoint(i, &pt);
     515           0 :         poList->emplace_back(std::move(pt));
     516             :     }
     517           0 : }
     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             :             VFKFeature *poVfkFeature =
     688           0 :                 cpl::down_cast<VFKFeature *>(GetFeatureByIndex(i));
     689           0 :             const GUIntBig iPropertyValue = strtoul(
     690             :                 poVfkFeature->GetProperty(idx)->GetValueS(), nullptr, 0);
     691           0 :             if (iPropertyValue == value)
     692             :             {
     693           0 :                 m_iNextFeature = i + 1;
     694           0 :                 return poVfkFeature;
     695             :             }
     696             :         }
     697             :     }
     698             : 
     699           0 :     return nullptr;
     700             : }
     701             : 
     702             : /*!
     703             :   \brief Get features based on properties
     704             : 
     705             :   \param idx property index
     706             :   \param value property value
     707             : 
     708             :   \return list of features
     709             : */
     710           0 : VFKFeatureList VFKDataBlock::GetFeatures(int idx, GUIntBig value)
     711             : {
     712           0 :     std::vector<VFKFeature *> poResult;
     713             : 
     714           0 :     for (int i = 0; i < m_nFeatureCount; i++)
     715             :     {
     716             :         VFKFeature *poVfkFeature =
     717           0 :             cpl::down_cast<VFKFeature *>(GetFeatureByIndex(i));
     718             :         const GUIntBig iPropertyValue =
     719           0 :             strtoul(poVfkFeature->GetProperty(idx)->GetValueS(), nullptr, 0);
     720           0 :         if (iPropertyValue == value)
     721             :         {
     722           0 :             poResult.push_back(poVfkFeature);
     723             :         }
     724             :     }
     725             : 
     726           0 :     return poResult;
     727             : }
     728             : 
     729             : /*!
     730             :   \brief Get features based on properties
     731             : 
     732             :   \param idx1 property index
     733             :   \param idx2 property index
     734             :   \param value property value
     735             : 
     736             :   \return list of features
     737             : */
     738           0 : VFKFeatureList VFKDataBlock::GetFeatures(int idx1, int idx2, GUIntBig value)
     739             : {
     740           0 :     std::vector<VFKFeature *> poResult;
     741             : 
     742           0 :     for (int i = 0; i < m_nFeatureCount; i++)
     743             :     {
     744             :         VFKFeature *poVfkFeature =
     745           0 :             cpl::down_cast<VFKFeature *>(GetFeatureByIndex(i));
     746             :         const GUIntBig iPropertyValue1 =
     747           0 :             strtoul(poVfkFeature->GetProperty(idx1)->GetValueS(), nullptr, 0);
     748           0 :         if (idx2 < 0)
     749             :         {
     750           0 :             if (iPropertyValue1 == value)
     751             :             {
     752           0 :                 poResult.push_back(poVfkFeature);
     753             :             }
     754             :         }
     755             :         else
     756             :         {
     757           0 :             const GUIntBig iPropertyValue2 = strtoul(
     758             :                 poVfkFeature->GetProperty(idx2)->GetValueS(), nullptr, 0);
     759           0 :             if (iPropertyValue1 == value || iPropertyValue2 == value)
     760             :             {
     761           0 :                 poResult.push_back(poVfkFeature);
     762             :             }
     763             :         }
     764             :     }
     765             : 
     766           0 :     return poResult;
     767             : }
     768             : 
     769             : /*!
     770             :   \brief Get feature count based on property value
     771             : 
     772             :   \param pszName property name
     773             :   \param pszValue property value
     774             : 
     775             :   \return number of features or -1 on error
     776             : */
     777           0 : GIntBig VFKDataBlock::GetFeatureCount(const char *pszName, const char *pszValue)
     778             : {
     779           0 :     const int propIdx = GetPropertyIndex(pszName);
     780           0 :     if (propIdx < 0)
     781           0 :         return -1;
     782             : 
     783           0 :     int nfeatures = 0;
     784           0 :     for (int i = 0; i < ((IVFKDataBlock *)this)->GetFeatureCount(); i++)
     785             :     {
     786           0 :         VFKFeature *poVFKFeature = cpl::down_cast<VFKFeature *>(
     787             :             ((IVFKDataBlock *)this)->GetFeature(i));
     788           0 :         if (!poVFKFeature)
     789           0 :             return -1;
     790           0 :         if (EQUAL(poVFKFeature->GetProperty(propIdx)->GetValueS(), pszValue))
     791           0 :             nfeatures++;
     792             :     }
     793             : 
     794           0 :     return nfeatures;
     795             : }
     796             : 
     797             : /*!
     798             :   \brief Load geometry (point layers)
     799             : 
     800             :   \return number of invalid features
     801             : */
     802           0 : int VFKDataBlock::LoadGeometryPoint()
     803             : {
     804           0 :     int nInvalid = 0;
     805           0 :     int i_idxY = GetPropertyIndex("SOURADNICE_Y");
     806           0 :     int i_idxX = GetPropertyIndex("SOURADNICE_X");
     807           0 :     if (i_idxY < 0 || i_idxX < 0)
     808             :     {
     809           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
     810             :                  m_pszName);
     811           0 :         return nInvalid;
     812             :     }
     813             : 
     814           0 :     for (int j = 0; j < ((IVFKDataBlock *)this)->GetFeatureCount(); j++)
     815             :     {
     816             :         VFKFeature *poFeature =
     817           0 :             cpl::down_cast<VFKFeature *>(GetFeatureByIndex(j));
     818           0 :         double x = -1.0 * poFeature->GetProperty(i_idxY)->GetValueD();
     819           0 :         double y = -1.0 * poFeature->GetProperty(i_idxX)->GetValueD();
     820           0 :         OGRPoint pt(x, y);
     821           0 :         if (!poFeature->SetGeometry(&pt))
     822           0 :             nInvalid++;
     823             :     }
     824             : 
     825           0 :     return nInvalid;
     826             : }
     827             : 
     828             : /*!
     829             :   \brief Load geometry (linestring SBP/SBPG layer)
     830             : 
     831             :   \return number of invalid features
     832             : */
     833           0 : int VFKDataBlock::LoadGeometryLineStringSBP()
     834             : {
     835             :     VFKDataBlock *poDataBlockPoints =
     836           0 :         cpl::down_cast<VFKDataBlock *>(m_poReader->GetDataBlock("SOBR"));
     837           0 :     if (nullptr == poDataBlockPoints)
     838             :     {
     839           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Data block %s not found.\n",
     840             :                  m_pszName);
     841           0 :         return 0;
     842             :     }
     843             : 
     844           0 :     poDataBlockPoints->LoadGeometry();
     845           0 :     int idxId = poDataBlockPoints->GetPropertyIndex("ID");
     846           0 :     int idxBp_Id = GetPropertyIndex("BP_ID");
     847           0 :     int idxPCB = GetPropertyIndex("PORADOVE_CISLO_BODU");
     848           0 :     if (idxId < 0 || idxBp_Id < 0 || idxPCB < 0)
     849             :     {
     850           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
     851             :                  m_pszName);
     852           0 :         return 0;
     853             :     }
     854             : 
     855           0 :     OGRLineString oOGRLine;
     856           0 :     VFKFeature *poLine = nullptr;
     857           0 :     int nInvalid = 0;
     858             : 
     859           0 :     for (int j = 0; j < ((IVFKDataBlock *)this)->GetFeatureCount(); j++)
     860             :     {
     861             :         VFKFeature *poFeature =
     862           0 :             cpl::down_cast<VFKFeature *>(GetFeatureByIndex(j));
     863           0 :         CPLAssert(nullptr != poFeature);
     864             : 
     865           0 :         poFeature->SetGeometry(nullptr);
     866             :         GUIntBig id =
     867           0 :             strtoul(poFeature->GetProperty(idxBp_Id)->GetValueS(), nullptr, 0);
     868             :         GUIntBig ipcb =
     869           0 :             strtoul(poFeature->GetProperty(idxPCB)->GetValueS(), nullptr, 0);
     870           0 :         if (ipcb == 1)
     871             :         {
     872           0 :             if (!oOGRLine.IsEmpty())
     873             :             {
     874           0 :                 oOGRLine.setCoordinateDimension(2); /* force 2D */
     875           0 :                 if (poLine != nullptr && !poLine->SetGeometry(&oOGRLine))
     876           0 :                     nInvalid++;
     877           0 :                 oOGRLine.empty(); /* restore line */
     878             :             }
     879           0 :             poLine = poFeature;
     880             :         }
     881             :         else
     882             :         {
     883           0 :             poFeature->SetGeometryType(wkbUnknown);
     884             :         }
     885           0 :         VFKFeature *poPoint = poDataBlockPoints->GetFeature(idxId, id);
     886           0 :         if (!poPoint)
     887           0 :             continue;
     888           0 :         const OGRPoint *pt = poPoint->GetGeometry()->toPoint();
     889           0 :         oOGRLine.addPoint(pt);
     890             :     }
     891             :     /* add last line */
     892           0 :     oOGRLine.setCoordinateDimension(2); /* force 2D */
     893           0 :     if (poLine)
     894             :     {
     895           0 :         if (!poLine->SetGeometry(&oOGRLine))
     896           0 :             nInvalid++;
     897             :     }
     898           0 :     poDataBlockPoints->ResetReading();
     899             : 
     900           0 :     return nInvalid;
     901             : }
     902             : 
     903             : /*!
     904             :   \brief Load geometry (linestring HP/DPM/ZVB layer)
     905             : 
     906             :   \return number of invalid features
     907             : */
     908           0 : int VFKDataBlock::LoadGeometryLineStringHP()
     909             : {
     910           0 :     int nInvalid = 0;
     911             : 
     912             :     VFKDataBlock *poDataBlockLines =
     913           0 :         cpl::down_cast<VFKDataBlock *>(m_poReader->GetDataBlock("SBP"));
     914           0 :     if (nullptr == poDataBlockLines)
     915             :     {
     916           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Data block %s not found.\n",
     917             :                  m_pszName);
     918           0 :         return nInvalid;
     919             :     }
     920             : 
     921           0 :     poDataBlockLines->LoadGeometry();
     922           0 :     const int idxId = GetPropertyIndex("ID");
     923           0 :     CPLString osColumn;
     924           0 :     osColumn.Printf("%s_ID", m_pszName);
     925           0 :     const int idxMy_Id = poDataBlockLines->GetPropertyIndex(osColumn);
     926             :     const int idxPCB =
     927           0 :         poDataBlockLines->GetPropertyIndex("PORADOVE_CISLO_BODU");
     928           0 :     if (idxId < 0 || idxMy_Id < 0 || idxPCB < 0)
     929             :     {
     930           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
     931             :                  m_pszName);
     932           0 :         return nInvalid;
     933             :     }
     934             : 
     935             :     // Reduce to first segment.
     936           0 :     VFKFeatureList poLineList = poDataBlockLines->GetFeatures(idxPCB, 1);
     937           0 :     for (int i = 0; i < ((IVFKDataBlock *)this)->GetFeatureCount(); i++)
     938             :     {
     939             :         VFKFeature *poFeature =
     940           0 :             cpl::down_cast<VFKFeature *>(GetFeatureByIndex(i));
     941           0 :         CPLAssert(nullptr != poFeature);
     942             :         GUIntBig id =
     943           0 :             strtoul(poFeature->GetProperty(idxId)->GetValueS(), nullptr, 0);
     944             :         VFKFeature *poLine =
     945           0 :             poDataBlockLines->GetFeature(idxMy_Id, id, &poLineList);
     946           0 :         if (!poLine || !poLine->GetGeometry())
     947           0 :             continue;
     948           0 :         if (!poFeature->SetGeometry(poLine->GetGeometry()))
     949           0 :             nInvalid++;
     950             :     }
     951           0 :     poDataBlockLines->ResetReading();
     952             : 
     953           0 :     return nInvalid;
     954             : }
     955             : 
     956             : /*!
     957             :   \brief Load geometry (polygon BUD/PAR layers)
     958             : 
     959             :   \return number of invalid features
     960             : */
     961           0 : int VFKDataBlock::LoadGeometryPolygon()
     962             : {
     963           0 :     VFKDataBlock *poDataBlockLines1 = nullptr;
     964           0 :     VFKDataBlock *poDataBlockLines2 = nullptr;
     965             : 
     966           0 :     bool bIsPar = false;
     967           0 :     if (EQUAL(m_pszName, "PAR"))
     968             :     {
     969             :         poDataBlockLines1 =
     970           0 :             cpl::down_cast<VFKDataBlock *>(m_poReader->GetDataBlock("HP"));
     971           0 :         poDataBlockLines2 = poDataBlockLines1;
     972           0 :         bIsPar = true;
     973             :     }
     974             :     else
     975             :     {
     976             :         poDataBlockLines1 =
     977           0 :             cpl::down_cast<VFKDataBlock *>(m_poReader->GetDataBlock("OB"));
     978             :         poDataBlockLines2 =
     979           0 :             cpl::down_cast<VFKDataBlock *>(m_poReader->GetDataBlock("SBP"));
     980           0 :         bIsPar = false;
     981             :     }
     982             : 
     983           0 :     int nInvalid = 0;
     984           0 :     if (nullptr == poDataBlockLines1 || nullptr == poDataBlockLines2)
     985             :     {
     986           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Data block %s not found.\n",
     987             :                  m_pszName);
     988           0 :         return nInvalid;
     989             :     }
     990             : 
     991           0 :     poDataBlockLines1->LoadGeometry();
     992           0 :     poDataBlockLines2->LoadGeometry();
     993           0 :     int idxId = GetPropertyIndex("ID");
     994           0 :     if (idxId < 0)
     995             :     {
     996           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
     997             :                  m_pszName);
     998           0 :         return nInvalid;
     999             :     }
    1000             : 
    1001           0 :     int idxBud = 0;
    1002           0 :     int idxOb = 0;
    1003           0 :     int idxIdOb = 0;
    1004           0 :     int idxPar1 = 0;
    1005           0 :     int idxPar2 = 0;
    1006           0 :     if (bIsPar)
    1007             :     {
    1008           0 :         idxPar1 = poDataBlockLines1->GetPropertyIndex("PAR_ID_1");
    1009           0 :         idxPar2 = poDataBlockLines1->GetPropertyIndex("PAR_ID_2");
    1010           0 :         if (idxPar1 < 0 || idxPar2 < 0)
    1011             :         {
    1012           0 :             CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
    1013             :                      m_pszName);
    1014           0 :             return nInvalid;
    1015             :         }
    1016             :     }
    1017             :     else
    1018             :     { /* BUD */
    1019           0 :         idxIdOb = poDataBlockLines1->GetPropertyIndex("ID");
    1020           0 :         idxBud = poDataBlockLines1->GetPropertyIndex("BUD_ID");
    1021           0 :         idxOb = poDataBlockLines2->GetPropertyIndex("OB_ID");
    1022           0 :         if (idxIdOb < 0 || idxBud < 0 || idxOb < 0)
    1023             :         {
    1024           0 :             CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
    1025             :                      m_pszName);
    1026           0 :             return nInvalid;
    1027             :         }
    1028             :     }
    1029             : 
    1030           0 :     VFKFeatureList poLineList;
    1031           0 :     PointListArray poRingList; /* first is to be considered as exterior */
    1032           0 :     OGRLinearRing ogrRing;
    1033           0 :     OGRPolygon ogrPolygon;
    1034             : 
    1035           0 :     for (int i = 0; i < ((IVFKDataBlock *)this)->GetFeatureCount(); i++)
    1036             :     {
    1037             :         VFKFeature *poFeature =
    1038           0 :             cpl::down_cast<VFKFeature *>(GetFeatureByIndex(i));
    1039           0 :         CPLAssert(nullptr != poFeature);
    1040             :         const GUIntBig id =
    1041           0 :             strtoul(poFeature->GetProperty(idxId)->GetValueS(), nullptr, 0);
    1042           0 :         if (bIsPar)
    1043             :         {
    1044           0 :             poLineList = poDataBlockLines1->GetFeatures(idxPar1, idxPar2, id);
    1045             :         }
    1046             :         else
    1047             :         {
    1048             :             VFKFeature *poLineOb, *poLineSbp;
    1049           0 :             std::vector<VFKFeature *> poLineListOb;
    1050           0 :             poLineListOb = poDataBlockLines1->GetFeatures(idxBud, id);
    1051           0 :             for (std::vector<VFKFeature *>::const_iterator
    1052           0 :                      iOb = poLineListOb.begin(),
    1053           0 :                      eOb = poLineListOb.end();
    1054           0 :                  iOb != eOb; ++iOb)
    1055             :             {
    1056           0 :                 poLineOb = (*iOb);
    1057           0 :                 GUIntBig idOb = strtoul(
    1058             :                     poLineOb->GetProperty(idxIdOb)->GetValueS(), nullptr, 0);
    1059           0 :                 poLineSbp = poDataBlockLines2->GetFeature(idxOb, idOb);
    1060           0 :                 if (poLineSbp)
    1061           0 :                     poLineList.push_back(poLineSbp);
    1062             :             }
    1063             :         }
    1064           0 :         if (poLineList.size() < 1)
    1065           0 :             continue;
    1066             : 
    1067             :         /* clear */
    1068           0 :         ogrPolygon.empty();
    1069           0 :         poRingList.clear();
    1070             : 
    1071             :         /* collect rings (points) */
    1072           0 :         bool bFound = false;
    1073           0 :         int nCount = 0;
    1074           0 :         int nCountMax = static_cast<int>(poLineList.size()) * 2;
    1075           0 :         while (!poLineList.empty() && nCount < nCountMax)
    1076             :         {
    1077           0 :             bool bNewRing = !bFound;
    1078           0 :             bFound = false;
    1079           0 :             for (VFKFeatureList::iterator iHp = poLineList.begin(),
    1080           0 :                                           eHp = poLineList.end();
    1081           0 :                  iHp != eHp; ++iHp)
    1082             :             {
    1083           0 :                 auto pGeom = (*iHp)->GetGeometry();
    1084           0 :                 if (pGeom && AppendLineToRing(&poRingList,
    1085             :                                               pGeom->toLineString(), bNewRing))
    1086             :                 {
    1087           0 :                     bFound = true;
    1088           0 :                     poLineList.erase(iHp);
    1089           0 :                     break;
    1090             :                 }
    1091             :             }
    1092           0 :             nCount++;
    1093             :         }
    1094             :         /* create rings */
    1095           0 :         for (PointListArray::const_iterator iRing = poRingList.begin(),
    1096           0 :                                             eRing = poRingList.end();
    1097           0 :              iRing != eRing; ++iRing)
    1098             :         {
    1099           0 :             PointList *poList = *iRing;
    1100           0 :             ogrRing.empty();
    1101           0 :             for (PointList::iterator iPoint = poList->begin(),
    1102           0 :                                      ePoint = poList->end();
    1103           0 :                  iPoint != ePoint; ++iPoint)
    1104             :             {
    1105           0 :                 ogrRing.addPoint(&(*iPoint));
    1106             :             }
    1107           0 :             ogrPolygon.addRing(&ogrRing);
    1108             :         }
    1109             :         /* set polygon */
    1110           0 :         ogrPolygon.setCoordinateDimension(2); /* force 2D */
    1111           0 :         if (!poFeature->SetGeometry(&ogrPolygon))
    1112           0 :             nInvalid++;
    1113             :     }
    1114             : 
    1115             :     /* free ring list */
    1116           0 :     for (PointListArray::iterator iRing = poRingList.begin(),
    1117           0 :                                   eRing = poRingList.end();
    1118           0 :          iRing != eRing; ++iRing)
    1119             :     {
    1120           0 :         delete (*iRing);
    1121           0 :         *iRing = nullptr;
    1122             :     }
    1123           0 :     poDataBlockLines1->ResetReading();
    1124           0 :     poDataBlockLines2->ResetReading();
    1125             : 
    1126           0 :     return nInvalid;
    1127             : }

Generated by: LCOV version 1.14