LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/vfk - vfkfeature.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 173 395 43.8 %
Date: 2024-11-21 22:18:42 Functions: 9 21 42.9 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  VFK Reader - Feature definition
       4             :  * Purpose:  Implements IVFKFeature/VFKFeature class.
       5             :  * Author:   Martin Landa, landa.martin gmail.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2009-2010, 2012-2015, Martin Landa <landa.martin gmail.com>
       9             :  * Copyright (c) 2012, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "vfkreader.h"
      15             : #include "vfkreaderp.h"
      16             : 
      17             : #include "cpl_conv.h"
      18             : #include "cpl_error.h"
      19             : 
      20             : /*!
      21             :   \brief IVFKFeature constructor
      22             : 
      23             :   \param poDataBlock pointer to VFKDataBlock instance
      24             : */
      25        1558 : IVFKFeature::IVFKFeature(IVFKDataBlock *poDataBlock)
      26             :     : m_poDataBlock(poDataBlock), m_nFID(-1),
      27        3116 :       m_nGeometryType(poDataBlock->GetGeometryType()), m_bGeometry(false),
      28        1558 :       m_bValid(false)
      29             : {
      30        1558 :     CPLAssert(nullptr != poDataBlock);
      31        1558 : }
      32             : 
      33             : /*!
      34             :   \brief IVFKFeature destructor
      35             : */
      36        3116 : IVFKFeature::~IVFKFeature()
      37             : {
      38        1558 :     m_poDataBlock = nullptr;
      39        1558 : }
      40             : 
      41             : /*!
      42             :   \brief Set feature geometry type
      43             : */
      44           0 : void IVFKFeature::SetGeometryType(OGRwkbGeometryType nGeomType)
      45             : {
      46           0 :     m_nGeometryType = nGeomType;
      47           0 : }
      48             : 
      49             : /*!
      50             :   \brief Set feature id
      51             : 
      52             :   FID: 0 for next, -1 for same
      53             : 
      54             :   \param nFID feature id
      55             : */
      56           0 : void IVFKFeature::SetFID(GIntBig nFID)
      57             : {
      58           0 :     if (m_nFID > 0)
      59             :     {
      60           0 :         m_nFID = nFID;
      61             :     }
      62             :     else
      63             :     {
      64           0 :         m_nFID = m_poDataBlock->GetFeatureCount() + 1;
      65             :     }
      66           0 : }
      67             : 
      68             : /*!
      69             :   \brief Compute determinant of matrix with columns x,y and z
      70             : 
      71             :   Simple formula requires reasonable numbers
      72             : 
      73             :   \param x first column array
      74             :   \param y second column array
      75             :   \param z third column array
      76             : 
      77             :   \return double determinant value
      78             : */
      79           0 : double IVFKFeature::GetDeterminatOfMatrixDim3(double x[3], double y[3],
      80             :                                               double z[3])
      81             : {
      82           0 :     return x[0] * y[1] * z[2] - x[0] * z[1] * y[2] - y[0] * x[1] * z[2] +
      83           0 :            y[0] * x[2] * z[1] + z[0] * x[1] * y[2] - z[0] * y[1] * x[2];
      84             : }
      85             : 
      86             : /*!
      87             :   \brief Find circle center determined by three point
      88             : 
      89             :   \param c_xy circle center coordinates array
      90             :   \param x array of three x coordinates
      91             :   \param y array of three x coordinates
      92             : */
      93           0 : void IVFKFeature::GetCircleCenterFrom3Points(double c_xy[2], double x[3],
      94             :                                              double y[3])
      95             : {
      96             :     /* reduce coordinates by average coordinate */
      97           0 :     int n = 3;
      98           0 :     double sum_x = 0.0f, sum_y = 0.0f;
      99           0 :     for (int i = 0; i < n; i++)
     100             :     {
     101           0 :         sum_x += x[i];
     102           0 :         sum_y += y[i];
     103             :     }
     104             : 
     105           0 :     const double x_t = sum_x / 3;
     106           0 :     const double y_t = sum_y / 3;
     107             : 
     108             :     double x_r[3], y_r[3];
     109             : 
     110           0 :     for (int i = 0; i < n; i++)
     111             :     {
     112           0 :         x_r[i] = x[i] - x_t;
     113           0 :         y_r[i] = y[i] - y_t;
     114             :     }
     115             : 
     116             :     /* limits to test reasonable value of determinant */
     117           0 :     const double epsilon_min = 0.0001;
     118           0 :     const double epsilon_max = 10000e6;
     119             : 
     120             :     /* solve three linear equations */
     121           0 :     double z[3] = {1.0, 1.0, 1.0};
     122           0 :     double c[3] = {-(pow(x_r[0], 2) + pow(y_r[0], 2)),
     123           0 :                    -(pow(x_r[1], 2) + pow(y_r[1], 2)),
     124           0 :                    -(pow(x_r[2], 2) + pow(y_r[2], 2))};
     125           0 :     const double det_A = GetDeterminatOfMatrixDim3(x_r, y_r, z);
     126             : 
     127           0 :     if (epsilon_min <= std::fabs(det_A) && std::fabs(det_A) <= epsilon_max)
     128             :     {
     129           0 :         const double det_a = GetDeterminatOfMatrixDim3(c, y_r, z);
     130           0 :         const double det_b = GetDeterminatOfMatrixDim3(x_r, c, z);
     131           0 :         c_xy[0] = -det_a / det_A / 2 + x_t;
     132           0 :         c_xy[1] = -det_b / det_A / 2 + y_t;
     133             :     }
     134             :     else
     135             :     {
     136           0 :         c_xy[0] = -1.0;
     137           0 :         c_xy[1] = -1.0;
     138             :     }
     139           0 : }
     140             : 
     141             : /*!
     142             :   \brief Add points to circle geometry
     143             : 
     144             :   \param poGeomString pointer to OGRCircularString
     145             :   \param c_x circle center x coordinate
     146             :   \param c_y circle center y coordinate
     147             :   \param r circle radius
     148             : */
     149           0 : void IVFKFeature::AddCirclePointsToGeomString(OGRCircularString &poGeomString,
     150             :                                               double c_x, double c_y, double r)
     151             : {
     152           0 :     OGRPoint pt;
     153             : 
     154             :     /* define first point on a circle */
     155           0 :     pt.setX(c_x + r);
     156           0 :     pt.setY(c_y);
     157           0 :     poGeomString.addPoint(&pt);
     158             : 
     159             :     /* define second point on a circle */
     160           0 :     pt.setX(c_x);
     161           0 :     pt.setY(c_y + r);
     162           0 :     poGeomString.addPoint(&pt);
     163             : 
     164             :     /* define third point on a circle */
     165           0 :     pt.setX(c_x - r);
     166           0 :     pt.setY(c_y);
     167           0 :     poGeomString.addPoint(&pt);
     168             : 
     169             :     /* define fourth point on a circle */
     170           0 :     pt.setX(c_x);
     171           0 :     pt.setY(c_y - r);
     172           0 :     poGeomString.addPoint(&pt);
     173             : 
     174             :     /* define last point (=first) on a circle */
     175           0 :     pt.setX(c_x + r);
     176           0 :     pt.setY(c_y);
     177           0 :     poGeomString.addPoint(&pt);
     178           0 : }
     179             : 
     180             : /*!
     181             :   \brief Set feature geometry
     182             : 
     183             :   Also checks if given geometry is valid
     184             : 
     185             :   \param poGeom pointer to OGRGeometry
     186             :   \param ftype geometry VFK type
     187             : 
     188             :   \return true on valid feature or otherwise false
     189             : */
     190         615 : bool IVFKFeature::SetGeometry(const OGRGeometry *poGeom, const char *ftype)
     191             : {
     192         615 :     m_bGeometry = true;
     193             : 
     194         615 :     m_bValid = true;
     195             : 
     196         615 :     if (!poGeom)
     197             :     {
     198           0 :         return m_bValid;
     199             :     }
     200             : 
     201             :     /* check empty geometries */
     202         615 :     if (m_nGeometryType == wkbNone && poGeom->IsEmpty())
     203             :     {
     204           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     205             :                  "%s: empty geometry fid = " CPL_FRMT_GIB,
     206           0 :                  m_poDataBlock->GetName(), m_nFID);
     207           0 :         m_bValid = false;
     208             :     }
     209             : 
     210             :     /* check coordinates */
     211         615 :     if (m_nGeometryType == wkbPoint)
     212             :     {
     213         195 :         auto poPoint = poGeom->toPoint();
     214         195 :         const double x = poPoint->getX();
     215         195 :         const double y = poPoint->getY();
     216         195 :         if (x > -430000 || x < -910000 || y > -930000 || y < -1230000)
     217             :         {
     218           0 :             CPLDebug("OGR-VFK", "%s: invalid point fid = " CPL_FRMT_GIB,
     219           0 :                      m_poDataBlock->GetName(), m_nFID);
     220           0 :             m_bValid = false;
     221             :         }
     222             :     }
     223             : 
     224             :     /* check degenerated polygons */
     225         615 :     if (m_nGeometryType == wkbPolygon)
     226             :     {
     227          15 :         const OGRLinearRing *poRing = poGeom->toPolygon()->getExteriorRing();
     228          15 :         if (!poRing || poRing->getNumPoints() < 3)
     229             :         {
     230           0 :             CPLDebug("OGR-VFK", "%s: invalid polygon fid = " CPL_FRMT_GIB,
     231           0 :                      m_poDataBlock->GetName(), m_nFID);
     232           0 :             m_bValid = false;
     233             :         }
     234             :     }
     235             : 
     236         615 :     std::unique_ptr<OGRGeometry> newGeom;
     237         615 :     if (m_bValid)
     238             :     {
     239         615 :         if (ftype)
     240             :         {
     241         196 :             OGRPoint pt;
     242         196 :             OGRCircularString poGeomString;
     243             : 
     244         196 :             OGRGeometry *poGeomCurved = nullptr;
     245         196 :             if (EQUAL(ftype, "15") || EQUAL(ftype, "16"))
     246             :             { /* -> circle or arc */
     247          14 :                 auto poLS = poGeom->toLineString();
     248          14 :                 const int npoints = poLS->getNumPoints();
     249          14 :                 if (!EQUAL(ftype, "15"))
     250             :                 {
     251          56 :                     for (int i = 0; i < npoints; i++)
     252             :                     {
     253          42 :                         poLS->getPoint(i, &pt);
     254          42 :                         poGeomString.addPoint(&pt);
     255             :                     }
     256             :                 }
     257          14 :                 if (EQUAL(ftype, "15"))
     258             :                 {
     259           0 :                     if (npoints < 3)
     260             :                     {
     261           0 :                         CPLError(CE_Warning, CPLE_AppDefined,
     262             :                                  "npoints is %d.  expected 3", npoints);
     263             :                     }
     264           0 :                     if (npoints > 3)
     265             :                     {
     266           0 :                         CPLError(CE_Warning, CPLE_AppDefined,
     267             :                                  "npoints is %d.  Will overflow buffers.  "
     268             :                                  "Cannot continue.",
     269             :                                  npoints);
     270           0 :                         m_bValid = false;
     271           0 :                         return false;
     272             :                     }
     273             : 
     274             :                     /* compute center and radius of a circle */
     275           0 :                     double x[3] = {0.0, 0.0, 0.0};
     276           0 :                     double y[3] = {0.0, 0.0, 0.0};
     277             : 
     278           0 :                     for (int i = 0; i < npoints; i++)
     279             :                     {
     280           0 :                         poLS->getPoint(i, &pt);
     281           0 :                         x[i] = pt.getX();
     282           0 :                         y[i] = pt.getY();
     283             :                     }
     284             : 
     285             :                     /* solve as 3 linear equation x^2+y^2+2ax+2by+c=0 */
     286             :                     double c_xy[2];
     287           0 :                     double r = 0.0f;
     288           0 :                     GetCircleCenterFrom3Points(c_xy, x, y);
     289             : 
     290             :                     /* TODO (seidlmic) how to correctly handle invalid configuration */
     291           0 :                     if (c_xy[0] == -1.0f && c_xy[1] == -1.0f)
     292             :                     {
     293           0 :                         CPLError(CE_Warning, CPLE_AppDefined,
     294             :                                  "Invalid 3 points circle configuration. Can "
     295             :                                  "not find circle center");
     296           0 :                         m_bValid = false;
     297           0 :                         return false;
     298             :                     }
     299             : 
     300           0 :                     r = pow(pow((c_xy[0] - x[0]), 2) + pow((c_xy[1] - y[0]), 2),
     301             :                             0.5);
     302             : 
     303           0 :                     CPLDebug(
     304             :                         "OGR-VFK",
     305             :                         "Circle center point (ftype 15) X: %f, Y: %f, r: %f",
     306             :                         c_xy[0], c_xy[1], r);
     307             : 
     308           0 :                     AddCirclePointsToGeomString(poGeomString, c_xy[0], c_xy[1],
     309             :                                                 r);
     310          14 :                 }
     311             :             }
     312         182 :             else if (strlen(ftype) > 2 && STARTS_WITH_CI(ftype, "15"))
     313             :             {                   /* -> circle with radius */
     314           0 :                 char s[3] = {}; /* 15 */
     315             : 
     316           0 :                 float r = 0.0f;
     317           0 :                 if (2 != sscanf(ftype, "%2s %f", s, &r) || r < 0)
     318             :                 {
     319           0 :                     CPLDebug("OGR-VFK",
     320             :                              "%s: invalid circle (unknown or negative radius) "
     321             :                              "fid = " CPL_FRMT_GIB,
     322           0 :                              m_poDataBlock->GetName(), m_nFID);
     323           0 :                     m_bValid = false;
     324             :                 }
     325             :                 else
     326             :                 {
     327           0 :                     auto poLS = poGeom->toLineString();
     328           0 :                     poLS->getPoint(0, &pt);
     329           0 :                     const double c_x = pt.getX();
     330           0 :                     const double c_y = pt.getY();
     331             : 
     332           0 :                     AddCirclePointsToGeomString(poGeomString, c_x, c_y, r);
     333           0 :                 }
     334             :             }
     335         182 :             else if (EQUAL(ftype, "11"))
     336             :             { /* curve */
     337           0 :                 auto poLS = poGeom->toLineString();
     338           0 :                 const int npoints = poLS->getNumPoints();
     339           0 :                 if (npoints > 2)
     340             :                 { /* circular otherwise line string */
     341           0 :                     for (int i = 0; i < npoints; i++)
     342             :                     {
     343           0 :                         poLS->getPoint(i, &pt);
     344           0 :                         poGeomString.addPoint(&pt);
     345             :                     }
     346             :                 }
     347             :             }
     348             : 
     349         196 :             if (!poGeomString.IsEmpty())
     350          14 :                 poGeomCurved = poGeomString.CurveToLine();
     351             : 
     352         196 :             if (poGeomCurved)
     353             :             {
     354             :                 const int npoints =
     355          14 :                     poGeomCurved->toLineString()->getNumPoints();
     356          14 :                 CPLDebug("OGR-VFK",
     357             :                          "%s: curve (type=%s) to linestring (npoints=%d) fid "
     358             :                          "= " CPL_FRMT_GIB,
     359          14 :                          m_poDataBlock->GetName(), ftype, npoints, m_nFID);
     360          14 :                 if (npoints > 1)
     361          14 :                     newGeom.reset(poGeomCurved->clone());
     362          14 :                 delete poGeomCurved;
     363             :             }
     364             :         }
     365             : 
     366         615 :         if (!newGeom)
     367             :         {
     368             :             /* check degenerated linestrings */
     369         601 :             if (m_nGeometryType == wkbLineString)
     370             :             {
     371         391 :                 auto poLS = poGeom->toLineString();
     372         391 :                 const int npoints = poLS->getNumPoints();
     373         391 :                 if (npoints < 2)
     374             :                 {
     375           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     376             :                              "%s: invalid linestring (%d vertices) fid "
     377             :                              "= " CPL_FRMT_GIB,
     378           0 :                              m_poDataBlock->GetName(), npoints, m_nFID);
     379           0 :                     m_bValid = false;
     380             :                 }
     381             :             }
     382             : 
     383         601 :             if (m_bValid)
     384         601 :                 newGeom.reset(poGeom->clone()); /* make copy */
     385             :         }
     386             :     }
     387             : 
     388         615 :     m_paGeom = std::move(newGeom);
     389             : 
     390         615 :     return m_bValid;
     391             : }
     392             : 
     393             : /*!
     394             :   \brief Get feature geometry
     395             : 
     396             :   \return pointer to OGRGeometry or NULL on error
     397             : */
     398        1529 : const OGRGeometry *IVFKFeature::GetGeometry()
     399             : {
     400        1529 :     if (m_nGeometryType != wkbNone && !m_bGeometry)
     401           0 :         LoadGeometry();
     402             : 
     403        1529 :     return m_paGeom.get();
     404             : }
     405             : 
     406             : /*!
     407             :   \brief Load geometry
     408             : 
     409             :   \return true on success or false on failure
     410             : */
     411           0 : bool IVFKFeature::LoadGeometry()
     412             : {
     413           0 :     if (m_bGeometry)
     414           0 :         return true;
     415             : 
     416           0 :     const char *pszName = m_poDataBlock->GetName();
     417             : 
     418           0 :     if (EQUAL(pszName, "SOBR") || EQUAL(pszName, "OBBP") ||
     419           0 :         EQUAL(pszName, "SPOL") || EQUAL(pszName, "OB") ||
     420           0 :         EQUAL(pszName, "OP") || EQUAL(pszName, "OBPEJ"))
     421             :     {
     422             :         /* -> wkbPoint */
     423             : 
     424           0 :         return LoadGeometryPoint();
     425             :     }
     426           0 :     else if (EQUAL(pszName, "SBP") || EQUAL(pszName, "SBPG"))
     427             :     {
     428             :         /* -> wkbLineString */
     429           0 :         return LoadGeometryLineStringSBP();
     430             :     }
     431           0 :     else if (EQUAL(pszName, "HP") || EQUAL(pszName, "DPM") ||
     432           0 :              EQUAL(pszName, "ZVB"))
     433             :     {
     434             :         /* -> wkbLineString */
     435           0 :         return LoadGeometryLineStringHP();
     436             :     }
     437           0 :     else if (EQUAL(pszName, "PAR") || EQUAL(pszName, "BUD"))
     438             :     {
     439             :         /* -> wkbPolygon */
     440           0 :         return LoadGeometryPolygon();
     441             :     }
     442             : 
     443           0 :     return false;
     444             : }
     445             : 
     446             : /*!
     447             :   \brief VFKFeature constructor
     448             : 
     449             :   \param poDataBlock pointer to VFKDataBlock instance
     450             : */
     451         870 : VFKFeature::VFKFeature(IVFKDataBlock *poDataBlock, GIntBig iFID)
     452         870 :     : IVFKFeature(poDataBlock)
     453             : {
     454         870 :     m_nFID = iFID;
     455         870 :     m_propertyList.assign(poDataBlock->GetPropertyCount(), VFKProperty());
     456         870 :     CPLAssert(size_t(poDataBlock->GetPropertyCount()) == m_propertyList.size());
     457         870 : }
     458             : 
     459             : /*!
     460             :   \brief Set feature properties
     461             : 
     462             :   \param pszLine pointer to line containing feature definition
     463             : 
     464             :   \return true on success or false on failure
     465             : */
     466         870 : bool VFKFeature::SetProperties(const char *pszLine)
     467             : {
     468         870 :     const char *poChar = pszLine;  // Used after for.
     469        5310 :     for (; *poChar != '\0' && *poChar != ';'; poChar++)
     470             :         /* skip data block name */
     471             :         ;
     472         870 :     if (*poChar == '\0')
     473           0 :         return false; /* nothing to read */
     474             : 
     475         870 :     poChar++; /* skip ';' after data block name */
     476             : 
     477             :     /* remove extra quotes (otherwise due to buggy format the parsing is
     478             :      * almost impossible) */
     479        1740 :     CPLString osLine;
     480       68760 :     while (*poChar != '\0')
     481             :     {
     482       67890 :         if (*poChar == '"')
     483             :         {
     484             :             /* count quotes */
     485        4380 :             int nQuotes = 1;
     486        5280 :             while (*(++poChar) == '"')
     487         900 :                 nQuotes++;
     488             : 
     489        4380 :             if (nQuotes % 2 != 0)
     490             :             {
     491             :                 /* even number of quotes -> only last quote used */
     492        3480 :                 poChar -= 1;
     493             :             }
     494             :             else
     495             :             {
     496         900 :                 if ((*poChar == ';' || *poChar == '\0') &&
     497         855 :                     *(poChar - nQuotes - 1) == ';')
     498             :                 {
     499             :                     /* empty values (;""; / ;"" / ;""""; / ...)
     500             :                        -> only last two quotes used */
     501         840 :                     poChar -= 2;
     502             :                 }
     503          60 :                 else if (*poChar == '\0')
     504           0 :                     break;
     505             :                 /* odd number of quotes -> none of quotes used */
     506             :             }
     507             :         }
     508       67890 :         osLine += *(poChar++);
     509             :     }
     510         870 :     poChar = osLine;
     511             : 
     512             :     /* read properties into the list */
     513         870 :     const char *poProp = poChar;
     514         870 :     unsigned int iIndex = 0;
     515         870 :     unsigned int nLength = 0;
     516         870 :     unsigned int nQuotes = 0;
     517         870 :     bool inString = false;
     518         870 :     char *pszProp = nullptr;
     519        1740 :     std::vector<CPLString> oPropList;
     520       64440 :     while (*poChar != '\0')
     521             :     {
     522       63615 :         if ((!inString && *poChar == '"') ||               /* begin of string */
     523       17265 :             (inString && *poChar == '"' && nQuotes == 1 && /* end of string */
     524        1320 :              (*(poChar + 1) == ';' || *(poChar + 1) == '\0')))
     525             :         {
     526             : 
     527        3480 :             poChar++; /* skip '"' */
     528        3480 :             inString = !inString;
     529        3480 :             if (inString)
     530             :             {
     531        2160 :                 nQuotes = 1;
     532        2160 :                 poProp = poChar;
     533        2160 :                 if (*poChar == '"' &&
     534         840 :                     (*(poChar + 1) == ';' || *(poChar + 1) == '\0'))
     535             :                 {
     536             :                     /* process empty string */
     537         840 :                     poChar++;
     538         840 :                     inString = false;
     539             :                 }
     540             :                 else
     541             :                 {
     542             :                     /* count number of starting quotes */
     543        1320 :                     while (*poChar == '"')
     544             :                     {
     545           0 :                         nQuotes++;
     546           0 :                         nLength++;
     547           0 :                         poChar++;
     548             :                     }
     549             :                 }
     550             :             }
     551        3480 :             if (*poChar == '\0')
     552             :             {
     553             :                 /* end of line */
     554          45 :                 break;
     555             :             }
     556             :         }
     557       63570 :         if (*poChar == ';' && !inString)
     558             :         {
     559             :             /* end of property */
     560       10050 :             pszProp = (char *)CPLRealloc(pszProp, nLength + 1);
     561       10050 :             if (nLength > 0)
     562        7380 :                 strncpy(pszProp, poProp, nLength);
     563       10050 :             pszProp[nLength] = '\0';
     564             :             /* add new property into the list */
     565       10050 :             oPropList.push_back(pszProp);
     566             :             /* prepare for next property */
     567       10050 :             iIndex++;
     568       10050 :             poProp = ++poChar;
     569       10050 :             nLength = 0;
     570       10050 :             nQuotes = 0;
     571             :         }
     572             :         else
     573             :         {
     574       53520 :             if (*poChar == '"' && nQuotes > 1)
     575           0 :                 nQuotes--;
     576             : 
     577             :             /* add character to property */
     578       53520 :             poChar++;
     579       53520 :             nLength++;
     580             :         }
     581             :     }
     582             :     /* append last property */
     583         870 :     if (inString && nLength > 0)
     584             :     {
     585           0 :         nLength--; /* ignore '"' */
     586             :     }
     587         870 :     pszProp = (char *)CPLRealloc(pszProp, nLength + 1);
     588         870 :     if (nLength > 0)
     589         405 :         strncpy(pszProp, poProp, nLength);
     590         870 :     pszProp[nLength] = '\0';
     591         870 :     oPropList.push_back(pszProp);
     592             : 
     593             :     /* set properties from the list */
     594         870 :     if (oPropList.size() != (size_t)m_poDataBlock->GetPropertyCount())
     595             :     {
     596             :         /* try to read also invalid records */
     597           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     598             :                  "%s: invalid number of properties %d should be %d\n%s",
     599           0 :                  m_poDataBlock->GetName(), (int)oPropList.size(),
     600           0 :                  m_poDataBlock->GetPropertyCount(), pszLine);
     601           0 :         CPLFree(pszProp);
     602           0 :         return false;
     603             :     }
     604         870 :     iIndex = 0;
     605       11790 :     for (std::vector<CPLString>::iterator ip = oPropList.begin();
     606       22710 :          ip != oPropList.end(); ++ip)
     607             :     {
     608       10920 :         SetProperty(iIndex++, (*ip).c_str());
     609             :     }
     610             : 
     611             :     // TODO(martinl): Why was this block disabled?
     612             :     /* set fid
     613             :     if (EQUAL(m_poDataBlock->GetName(), "SBP")) {
     614             :         const VFKProperty *poVfkProperty = GetProperty("PORADOVE_CISLO_BODU");
     615             :         if (poVfkProperty)
     616             :         {
     617             :             GUIntBig id = strtoul(poVfkProperty->GetValueS(), NULL, 0);
     618             :             if (id == 1)
     619             :                 SetFID(0);
     620             :             else
     621             :                 SetFID(-1);
     622             :         }
     623             :     }
     624             :     else {
     625             :         SetFID(0);
     626             :     }
     627             :     */
     628         870 :     CPLFree(pszProp);
     629             : 
     630         870 :     return true;
     631             : }
     632             : 
     633             : /*!
     634             :   \brief Set feature property
     635             : 
     636             :   \param iIndex property index
     637             :   \param pszValue property value
     638             : 
     639             :   \return true on success, false on failure
     640             : */
     641       10920 : bool VFKFeature::SetProperty(int iIndex, const char *pszValue)
     642             : {
     643       21840 :     if (iIndex < 0 || iIndex >= m_poDataBlock->GetPropertyCount() ||
     644       10920 :         size_t(iIndex) >= m_propertyList.size())
     645           0 :         return false;
     646             : 
     647       10920 :     if (strlen(pszValue) < 1)
     648             :     {
     649        3135 :         m_propertyList[iIndex] = VFKProperty();
     650        3135 :         return true;
     651             :     }
     652             : 
     653        7785 :     const OGRFieldType fType = m_poDataBlock->GetProperty(iIndex)->GetType();
     654             : 
     655        7785 :     switch (fType)
     656             :     {
     657        6075 :         case OFTInteger:
     658             :         case OFTInteger64:
     659             :         {
     660        6075 :             errno = 0;
     661        6075 :             int pbOverflow = 0;
     662        6075 :             char *pszLast = nullptr;
     663        6075 :             if (fType == OFTInteger)
     664        4410 :                 m_propertyList[iIndex] = VFKProperty(
     665        4410 :                     static_cast<int>(strtol(pszValue, &pszLast, 10)));
     666             :             else /* OFTInteger64 */
     667        3870 :                 m_propertyList[iIndex] =
     668        7740 :                     VFKProperty(CPLAtoGIntBigEx(pszValue, true, &pbOverflow));
     669             : 
     670        8280 :             if ((fType == OFTInteger &&
     671        2205 :                  (errno == ERANGE || !pszLast || *pszLast)) ||
     672        8280 :                 CPLGetValueType(pszValue) != CPL_VALUE_INTEGER || pbOverflow)
     673           0 :                 CPLError(
     674             :                     CE_Warning, CPLE_AppDefined,
     675             :                     "Value '%s' parsed incompletely to integer " CPL_FRMT_GIB
     676             :                     ".",
     677             :                     pszValue,
     678             :                     (fType == OFTInteger)
     679           0 :                         ? m_propertyList[iIndex].GetValueI()
     680           0 :                         : m_propertyList[iIndex].GetValueI64());
     681        6075 :             break;
     682             :         }
     683         390 :         case OFTReal:
     684         390 :             m_propertyList[iIndex] = VFKProperty(CPLAtof(pszValue));
     685         390 :             break;
     686        1320 :         default:
     687             :             const char *pszEncoding =
     688        1320 :                 m_poDataBlock->GetProperty(iIndex)->GetEncoding();
     689        1320 :             if (pszEncoding)
     690             :             {
     691             :                 char *pszValueEnc =
     692         615 :                     CPLRecode(pszValue, pszEncoding, CPL_ENC_UTF8);
     693         615 :                 m_propertyList[iIndex] = VFKProperty(pszValueEnc);
     694         615 :                 CPLFree(pszValueEnc);
     695             :             }
     696             :             else
     697             :             {
     698         705 :                 m_propertyList[iIndex] = VFKProperty(pszValue);
     699             :             }
     700        1320 :             break;
     701             :     }
     702             : 
     703        7785 :     return true;
     704             : }
     705             : 
     706             : /*!
     707             :   \brief Get property value by index
     708             : 
     709             :   \param iIndex property index
     710             : 
     711             :   \return property value, NULL on error
     712             : */
     713       11355 : const VFKProperty *VFKFeature::GetProperty(int iIndex) const
     714             : {
     715       22710 :     if (iIndex < 0 || iIndex >= m_poDataBlock->GetPropertyCount() ||
     716       11355 :         size_t(iIndex) >= m_propertyList.size())
     717           0 :         return nullptr;
     718             : 
     719       11355 :     const VFKProperty *poProperty = &m_propertyList[iIndex];
     720       11355 :     return poProperty;
     721             : }
     722             : 
     723             : /*!
     724             :   \brief Get property value by name
     725             : 
     726             :   \param pszName property name
     727             : 
     728             :   \return property value, NULL on error
     729             : */
     730         435 : const VFKProperty *VFKFeature::GetProperty(const char *pszName) const
     731             : {
     732         435 :     return GetProperty(m_poDataBlock->GetPropertyIndex(pszName));
     733             : }
     734             : 
     735             : /*!
     736             :   \brief Load geometry (point layers)
     737             : 
     738             :   \todo Really needed?
     739             : 
     740             :   \return true on success, false on failure
     741             : */
     742           0 : bool VFKFeature::LoadGeometryPoint()
     743             : {
     744           0 :     const int i_idxY = m_poDataBlock->GetPropertyIndex("SOURADNICE_Y");
     745           0 :     const int i_idxX = m_poDataBlock->GetPropertyIndex("SOURADNICE_X");
     746           0 :     if (i_idxY < 0 || i_idxX < 0)
     747           0 :         return false;
     748             : 
     749           0 :     auto propertyY = GetProperty(i_idxY);
     750           0 :     auto propertyX = GetProperty(i_idxX);
     751           0 :     if (!propertyY || !propertyX)
     752           0 :         return false;
     753           0 :     const double x = -1.0 * propertyY->GetValueD();
     754           0 :     const double y = -1.0 * propertyX->GetValueD();
     755           0 :     OGRPoint pt(x, y);
     756           0 :     SetGeometry(&pt);
     757             : 
     758           0 :     return true;
     759             : }
     760             : 
     761             : /*!
     762             :   \brief Load geometry (linestring SBP/SBPG layer)
     763             : 
     764             :   \todo Really needed?
     765             : 
     766             :   \return true on success or false on failure
     767             : */
     768           0 : bool VFKFeature::LoadGeometryLineStringSBP()
     769             : {
     770             :     VFKDataBlock *poDataBlockPoints =
     771           0 :         (VFKDataBlock *)m_poDataBlock->GetReader()->GetDataBlock("SOBR");
     772           0 :     if (!poDataBlockPoints)
     773           0 :         return false;
     774             : 
     775           0 :     const int idxId = poDataBlockPoints->GetPropertyIndex("ID");
     776           0 :     const int idxBp_Id = m_poDataBlock->GetPropertyIndex("BP_ID");
     777           0 :     const int idxPCB = m_poDataBlock->GetPropertyIndex("PORADOVE_CISLO_BODU");
     778           0 :     if (idxId < 0 || idxBp_Id < 0 || idxPCB < 0)
     779           0 :         return false;
     780             : 
     781           0 :     VFKFeature *poLine = this;
     782           0 :     OGRLineString OGRLine;
     783             :     while (true)
     784             :     {
     785           0 :         auto property_idxBp_Id = poLine->GetProperty(idxBp_Id);
     786           0 :         if (!property_idxBp_Id)
     787           0 :             break;
     788           0 :         auto property_idxPCB = poLine->GetProperty(idxPCB);
     789           0 :         if (!property_idxPCB)
     790           0 :             break;
     791             : 
     792           0 :         const int id = property_idxBp_Id->GetValueI();
     793           0 :         const int ipcb = property_idxPCB->GetValueI();
     794           0 :         if (OGRLine.getNumPoints() > 0 && ipcb == 1)
     795             :         {
     796           0 :             m_poDataBlock->GetPreviousFeature(); /* push back */
     797           0 :             break;
     798             :         }
     799             : 
     800           0 :         VFKFeature *poPoint = poDataBlockPoints->GetFeature(idxId, id);
     801           0 :         if (!poPoint)
     802             :         {
     803           0 :             continue;
     804             :         }
     805           0 :         const OGRPoint *pt = poPoint->GetGeometry()->toPoint();
     806           0 :         OGRLine.addPoint(pt);
     807             : 
     808           0 :         poLine = (VFKFeature *)m_poDataBlock->GetNextFeature();
     809           0 :         if (!poLine)
     810           0 :             break;
     811           0 :     };
     812             : 
     813           0 :     OGRLine.setCoordinateDimension(2); /* force 2D */
     814           0 :     SetGeometry(&OGRLine);
     815             : 
     816             :     /* reset reading */
     817           0 :     poDataBlockPoints->ResetReading();
     818             : 
     819           0 :     return true;
     820             : }
     821             : 
     822             : /*!
     823             :   \brief Load geometry (linestring HP/DPM layer)
     824             : 
     825             :   \todo Really needed?
     826             : 
     827             :   \return true on success or false on failure
     828             : */
     829           0 : bool VFKFeature::LoadGeometryLineStringHP()
     830             : {
     831             :     VFKDataBlock *poDataBlockLines =
     832           0 :         (VFKDataBlock *)m_poDataBlock->GetReader()->GetDataBlock("SBP");
     833           0 :     if (!poDataBlockLines)
     834           0 :         return false;
     835             : 
     836           0 :     const int idxId = m_poDataBlock->GetPropertyIndex("ID");
     837           0 :     const int idxHp_Id = poDataBlockLines->GetPropertyIndex("HP_ID");
     838           0 :     if (idxId < 0 || idxHp_Id < 0)
     839           0 :         return false;
     840             : 
     841           0 :     auto property = GetProperty(idxId);
     842           0 :     if (!property)
     843           0 :         return false;
     844           0 :     const int id = property->GetValueI();
     845           0 :     VFKFeature *poLine = poDataBlockLines->GetFeature(idxHp_Id, id);
     846           0 :     if (!poLine || !poLine->GetGeometry())
     847           0 :         return false;
     848             : 
     849           0 :     SetGeometry(poLine->GetGeometry());
     850           0 :     poDataBlockLines->ResetReading();
     851             : 
     852           0 :     return true;
     853             : }
     854             : 
     855             : /*!
     856             :   \brief Load geometry (polygon BUD/PAR layers)
     857             : 
     858             :   \todo Implement (really needed?)
     859             : 
     860             :   \return true on success or false on failure
     861             : */
     862           0 : bool VFKFeature::LoadGeometryPolygon()
     863             : {
     864           0 :     return false;
     865             : }
     866             : 
     867           0 : OGRErr VFKFeature::LoadProperties(OGRFeature *poFeature)
     868             : {
     869           0 :     for (int iField = 0; iField < m_poDataBlock->GetPropertyCount(); iField++)
     870             :     {
     871           0 :         auto property = GetProperty(iField);
     872           0 :         if (!property || property->IsNull())
     873           0 :             continue;
     874             : 
     875             :         OGRFieldType fType =
     876           0 :             poFeature->GetDefnRef()->GetFieldDefn(iField)->GetType();
     877           0 :         if (fType == OFTInteger)
     878           0 :             poFeature->SetField(iField, property->GetValueI());
     879           0 :         else if (fType == OFTReal)
     880           0 :             poFeature->SetField(iField, property->GetValueD());
     881             :         else
     882           0 :             poFeature->SetField(iField, property->GetValueS());
     883             :     }
     884             : 
     885           0 :     return OGRERR_NONE;
     886             : }

Generated by: LCOV version 1.14