LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/kml - kmlnode.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 331 402 82.3 %
Date: 2025-05-31 00:00:17 Functions: 30 34 88.2 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  KML Driver
       4             :  * Purpose:  Class for building up the node structure of the kml file.
       5             :  * Author:   Jens Oberender, j.obi@troja.net
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2007, Jens Oberender
       9             :  * Copyright (c) 2007-2012, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "kmlnode.h"
      16             : 
      17             : #include <cstring>
      18             : #include <limits>
      19             : #include <memory>
      20             : #include <string>
      21             : #include <vector>
      22             : 
      23             : #include "cpl_conv.h"
      24             : #include "cpl_error.h"
      25             : #include "ogr_geometry.h"
      26             : 
      27             : /************************************************************************/
      28             : /*                           Help functions                             */
      29             : /************************************************************************/
      30             : 
      31         790 : std::string Nodetype2String(Nodetype const &type)
      32             : {
      33         790 :     if (type == Empty)
      34           0 :         return "Empty";
      35         790 :     else if (type == Rest)
      36           0 :         return "Rest";
      37         790 :     else if (type == Mixed)
      38           3 :         return "Mixed";
      39         787 :     else if (type == Point)
      40         187 :         return "Point";
      41         600 :     else if (type == LineString)
      42         243 :         return "LineString";
      43         357 :     else if (type == Polygon)
      44         357 :         return "Polygon";
      45           0 :     else if (type == MultiGeometry)
      46           0 :         return "MultiGeometry";
      47           0 :     else if (type == MultiPoint)
      48           0 :         return "MultiPoint";
      49           0 :     else if (type == MultiLineString)
      50           0 :         return "MultiLineString";
      51           0 :     else if (type == MultiPolygon)
      52           0 :         return "MultiPolygon";
      53             :     else
      54           0 :         return "Unknown";
      55             : }
      56             : 
      57      234484 : static bool isNumberDigit(const char cIn)
      58             : {
      59      228109 :     return (cIn == '-' || cIn == '+' || (cIn >= '0' && cIn <= '9') ||
      60      462593 :             cIn == '.' || cIn == 'e' || cIn == 'E');
      61             : }
      62             : 
      63        6469 : static Coordinate *ParseCoordinate(std::string const &text)
      64             : {
      65        6469 :     int pos = 0;
      66        6469 :     const char *pszStr = text.c_str();
      67        6469 :     Coordinate *psTmp = new Coordinate();
      68             : 
      69             :     // X coordinate
      70        6469 :     psTmp->dfLongitude = CPLAtof(pszStr);
      71      120403 :     while (isNumberDigit(pszStr[pos++]))
      72             :         ;
      73             : 
      74             :     // Y coordinate
      75        6469 :     if (pszStr[pos - 1] != ',')
      76             :     {
      77           0 :         delete psTmp;
      78           0 :         return nullptr;
      79             :     }
      80             : 
      81        6469 :     psTmp->dfLatitude = CPLAtof(pszStr + pos);
      82      114081 :     while (isNumberDigit(pszStr[pos++]))
      83             :         ;
      84             : 
      85             :     // Z coordinate
      86        6469 :     if (pszStr[pos - 1] != ',')
      87             :     {
      88          87 :         psTmp->bHasZ = false;
      89          87 :         psTmp->dfAltitude = 0;
      90          87 :         return psTmp;
      91             :     }
      92             : 
      93        6382 :     psTmp->bHasZ = true;
      94        6382 :     psTmp->dfAltitude = CPLAtof(pszStr + pos);
      95             : 
      96        6382 :     return psTmp;
      97             : }
      98             : 
      99             : /************************************************************************/
     100             : /*                         KMLNode methods                              */
     101             : /************************************************************************/
     102             : 
     103        5659 : KMLNode::KMLNode()
     104        5659 :     : pvpoChildren_(new std::vector<KMLNode *>),
     105        5659 :       pvsContent_(new std::vector<std::string>),
     106       11318 :       pvoAttributes_(new std::vector<Attribute *>)
     107             : {
     108        5659 : }
     109             : 
     110        5659 : KMLNode::~KMLNode()
     111             : {
     112        5659 :     CPLAssert(nullptr != pvpoChildren_);
     113        5659 :     CPLAssert(nullptr != pvoAttributes_);
     114             : 
     115        5659 :     kml_nodes_t::iterator itChild;
     116        7699 :     for (itChild = pvpoChildren_->begin(); itChild != pvpoChildren_->end();
     117        2040 :          ++itChild)
     118             :     {
     119        2040 :         delete (*itChild);
     120             :     }
     121        5659 :     delete pvpoChildren_;
     122             : 
     123        5659 :     kml_attributes_t::iterator itAttr;
     124        7095 :     for (itAttr = pvoAttributes_->begin(); itAttr != pvoAttributes_->end();
     125        1436 :          ++itAttr)
     126             :     {
     127        1436 :         delete (*itAttr);
     128             :     }
     129        5659 :     delete pvoAttributes_;
     130             : 
     131        5659 :     delete pvsContent_;
     132        5659 : }
     133             : 
     134           0 : void KMLNode::print(unsigned int what)
     135             : {
     136           0 :     std::string indent;
     137           0 :     for (std::size_t l = 0; l < nLevel_; l++)
     138           0 :         indent += " ";
     139             : 
     140           0 :     if (nLevel_ > 0)
     141             :     {
     142           0 :         if (nLayerNumber_ > -1)
     143             :         {
     144           0 :             CPLDebug("KML",
     145             :                      "%s%s (nLevel: %d Type: %s poParent: %s "
     146             :                      "pvpoChildren_: %d pvsContent_: %d pvoAttributes_: %d) "
     147             :                      "<--- Layer #%d",
     148           0 :                      indent.c_str(), sName_.c_str(), static_cast<int>(nLevel_),
     149           0 :                      Nodetype2String(eType_).c_str(), poParent_->sName_.c_str(),
     150           0 :                      static_cast<int>(pvpoChildren_->size()),
     151           0 :                      static_cast<int>(pvsContent_->size()),
     152           0 :                      static_cast<int>(pvoAttributes_->size()), nLayerNumber_);
     153             :         }
     154             :         else
     155             :         {
     156           0 :             CPLDebug("KML",
     157             :                      "%s%s (nLevel: %d Type: %s poParent: %s "
     158             :                      "pvpoChildren_: %d pvsContent_: %d pvoAttributes_: %d)",
     159           0 :                      indent.c_str(), sName_.c_str(), static_cast<int>(nLevel_),
     160           0 :                      Nodetype2String(eType_).c_str(), poParent_->sName_.c_str(),
     161           0 :                      static_cast<int>(pvpoChildren_->size()),
     162           0 :                      static_cast<int>(pvsContent_->size()),
     163           0 :                      static_cast<int>(pvoAttributes_->size()));
     164             :         }
     165             :     }
     166             :     else
     167             :     {
     168           0 :         CPLDebug("KML",
     169             :                  "%s%s (nLevel: %d Type: %s pvpoChildren_: %d "
     170             :                  "pvsContent_: %d pvoAttributes_: %d)",
     171           0 :                  indent.c_str(), sName_.c_str(), static_cast<int>(nLevel_),
     172           0 :                  Nodetype2String(eType_).c_str(),
     173           0 :                  static_cast<int>(pvpoChildren_->size()),
     174           0 :                  static_cast<int>(pvsContent_->size()),
     175           0 :                  static_cast<int>(pvoAttributes_->size()));
     176             :     }
     177             : 
     178           0 :     if (what == 1 || what == 3)
     179             :     {
     180           0 :         for (kml_content_t::size_type z = 0; z < pvsContent_->size(); z++)
     181           0 :             CPLDebug("KML", "%s|->pvsContent_: '%s'", indent.c_str(),
     182           0 :                      (*pvsContent_)[z].c_str());
     183             :     }
     184             : 
     185           0 :     if (what == 2 || what == 3)
     186             :     {
     187           0 :         for (kml_attributes_t::size_type z = 0; z < pvoAttributes_->size(); z++)
     188           0 :             CPLDebug("KML", "%s|->pvoAttributes_: %s = '%s'", indent.c_str(),
     189           0 :                      (*pvoAttributes_)[z]->sName.c_str(),
     190           0 :                      (*pvoAttributes_)[z]->sValue.c_str());
     191             :     }
     192             : 
     193           0 :     for (kml_nodes_t::size_type z = 0; z < pvpoChildren_->size(); z++)
     194           0 :         (*pvpoChildren_)[z]->print(what);
     195           0 : }
     196             : 
     197        1995 : int KMLNode::classify(KML *poKML, int nRecLevel)
     198             : {
     199        1995 :     Nodetype all = Empty;
     200             : 
     201             :     /* Arbitrary value, but certainly large enough for reasonable usages ! */
     202        1995 :     if (nRecLevel == 32)
     203             :     {
     204           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     205             :                  "Too many recursion levels (%d) while parsing KML geometry.",
     206             :                  nRecLevel);
     207           0 :         return FALSE;
     208             :     }
     209             : 
     210        1995 :     if (sName_.compare("Point") == 0)
     211          63 :         eType_ = Point;
     212        1932 :     else if (sName_.compare("LineString") == 0)
     213          78 :         eType_ = LineString;
     214        1854 :     else if (sName_.compare("Polygon") == 0)
     215         113 :         eType_ = Polygon;
     216        1741 :     else if (poKML->isRest(sName_))
     217         261 :         eType_ = Empty;
     218        1480 :     else if (sName_.compare("coordinates") == 0)
     219             :     {
     220        2372 :         for (unsigned int nCountP = 0; nCountP < pvsContent_->size(); nCountP++)
     221             :         {
     222        2105 :             const char *pszCoord = (*pvsContent_)[nCountP].c_str();
     223        2105 :             int nComma = 0;
     224             :             while (true)
     225             :             {
     226        4116 :                 pszCoord = strchr(pszCoord, ',');
     227        6221 :                 if (pszCoord)
     228             :                 {
     229        4116 :                     nComma++;
     230        4116 :                     pszCoord++;
     231             :                 }
     232             :                 else
     233        2105 :                     break;
     234             :             }
     235        2105 :             if (nComma == 2)
     236        2011 :                 b25D_ = true;
     237             :         }
     238             :     }
     239             : 
     240        1995 :     const kml_nodes_t::size_type size = pvpoChildren_->size();
     241        3967 :     for (kml_nodes_t::size_type z = 0; z < size; z++)
     242             :     {
     243             :         // Classify pvpoChildren_
     244        1972 :         if (!(*pvpoChildren_)[z]->classify(poKML, nRecLevel + 1))
     245           0 :             return FALSE;
     246             : 
     247        1972 :         Nodetype curr = (*pvpoChildren_)[z]->eType_;
     248        1972 :         b25D_ |= (*pvpoChildren_)[z]->b25D_;
     249             : 
     250             :         // Compare and return if it is mixed
     251        1972 :         if (curr != all && all != Empty && curr != Empty)
     252             :         {
     253          90 :             if (sName_.compare("MultiGeometry") == 0 ||
     254          88 :                 sName_.compare("MultiPolygon") == 0 ||
     255         134 :                 sName_.compare("MultiLineString") == 0 ||
     256          44 :                 sName_.compare("MultiPoint") == 0)
     257           2 :                 eType_ = MultiGeometry;
     258             :             else
     259          44 :                 eType_ = Mixed;
     260             :         }
     261        1926 :         else if (curr != Empty)
     262             :         {
     263         582 :             all = curr;
     264             :         }
     265             :     }
     266             : 
     267        1995 :     if (eType_ == Unknown)
     268             :     {
     269        2917 :         if (sName_.compare("MultiGeometry") == 0 ||
     270        2907 :             sName_.compare("MultiPolygon") == 0 ||
     271        4370 :             sName_.compare("MultiLineString") == 0 ||
     272        1452 :             sName_.compare("MultiPoint") == 0)
     273             :         {
     274          12 :             if (all == Point)
     275           4 :                 eType_ = MultiPoint;
     276           8 :             else if (all == LineString)
     277           3 :                 eType_ = MultiLineString;
     278           5 :             else if (all == Polygon)
     279           3 :                 eType_ = MultiPolygon;
     280             :             else
     281           2 :                 eType_ = MultiGeometry;
     282             :         }
     283             :         else
     284        1451 :             eType_ = all;
     285             :     }
     286             : 
     287        1995 :     return TRUE;
     288             : }
     289             : 
     290         116 : void KMLNode::unregisterLayerIfMatchingThisNode(KML *poKML)
     291             : {
     292         190 :     for (std::size_t z = 0; z < countChildren(); z++)
     293             :     {
     294          74 :         getChild(z)->unregisterLayerIfMatchingThisNode(poKML);
     295             :     }
     296         116 :     poKML->unregisterLayerIfMatchingThisNode(this);
     297         116 : }
     298             : 
     299        1868 : void KMLNode::eliminateEmpty(KML *poKML)
     300             : {
     301        3756 :     for (kml_nodes_t::size_type z = 0; z < pvpoChildren_->size();)
     302             :     {
     303        3148 :         if ((*pvpoChildren_)[z]->eType_ == Empty &&
     304        1260 :             (poKML->isContainer((*pvpoChildren_)[z]->sName_) ||
     305        1236 :              poKML->isFeatureContainer((*pvpoChildren_)[z]->sName_)))
     306             :         {
     307          42 :             (*pvpoChildren_)[z]->unregisterLayerIfMatchingThisNode(poKML);
     308          42 :             delete (*pvpoChildren_)[z];
     309          42 :             pvpoChildren_->erase(pvpoChildren_->begin() + z);
     310             :         }
     311             :         else
     312             :         {
     313        1846 :             (*pvpoChildren_)[z]->eliminateEmpty(poKML);
     314        1846 :             ++z;
     315             :         }
     316             :     }
     317        1868 : }
     318             : 
     319          43 : bool KMLNode::hasOnlyEmpty() const
     320             : {
     321          63 :     for (kml_nodes_t::size_type z = 0; z < pvpoChildren_->size(); z++)
     322             :     {
     323          39 :         if ((*pvpoChildren_)[z]->eType_ != Empty)
     324             :         {
     325          19 :             return false;
     326             :         }
     327             :         else
     328             :         {
     329          20 :             if (!(*pvpoChildren_)[z]->hasOnlyEmpty())
     330           0 :                 return false;
     331             :         }
     332             :     }
     333             : 
     334          24 :     return true;
     335             : }
     336             : 
     337           0 : void KMLNode::setType(Nodetype oNotet)
     338             : {
     339           0 :     eType_ = oNotet;
     340           0 : }
     341             : 
     342         285 : Nodetype KMLNode::getType() const
     343             : {
     344         285 :     return eType_;
     345             : }
     346             : 
     347        5659 : void KMLNode::setName(std::string const &sIn)
     348             : {
     349        5659 :     sName_ = sIn;
     350        5659 : }
     351             : 
     352       18605 : const std::string &KMLNode::getName() const
     353             : {
     354       18605 :     return sName_;
     355             : }
     356             : 
     357        5659 : void KMLNode::setLevel(std::size_t nLev)
     358             : {
     359        5659 :     nLevel_ = nLev;
     360        5659 : }
     361             : 
     362           0 : std::size_t KMLNode::getLevel() const
     363             : {
     364           0 :     return nLevel_;
     365             : }
     366             : 
     367        1436 : void KMLNode::addAttribute(Attribute *poAttr)
     368             : {
     369        1436 :     pvoAttributes_->push_back(poAttr);
     370        1436 : }
     371             : 
     372        5635 : void KMLNode::setParent(KMLNode *poPar)
     373             : {
     374        5635 :     poParent_ = poPar;
     375        5635 : }
     376             : 
     377       11294 : KMLNode *KMLNode::getParent() const
     378             : {
     379       11294 :     return poParent_;
     380             : }
     381             : 
     382        2082 : void KMLNode::addChildren(KMLNode *poChil)
     383             : {
     384        2082 :     pvpoChildren_->push_back(poChil);
     385        2082 : }
     386             : 
     387         920 : std::size_t KMLNode::countChildren() const
     388             : {
     389         920 :     return pvpoChildren_->size();
     390             : }
     391             : 
     392        1246 : KMLNode *KMLNode::getChild(std::size_t index) const
     393             : {
     394        1246 :     return (*pvpoChildren_)[index];
     395             : }
     396             : 
     397        9192 : void KMLNode::addContent(std::string const &text)
     398             : {
     399        9192 :     pvsContent_->push_back(text);
     400        9192 : }
     401             : 
     402       19024 : void KMLNode::appendContent(std::string const &text)
     403             : {
     404       19024 :     pvsContent_->back() += text;
     405       19024 : }
     406             : 
     407        5232 : std::string KMLNode::getContent(std::size_t index) const
     408             : {
     409        5232 :     return (*pvsContent_)[index];
     410             : }
     411             : 
     412        2117 : void KMLNode::deleteContent(std::size_t index)
     413             : {
     414        2117 :     if (index < pvsContent_->size())
     415             :     {
     416        2117 :         pvsContent_->erase(pvsContent_->begin() + index);
     417             :     }
     418        2117 : }
     419             : 
     420       30182 : std::size_t KMLNode::numContent() const
     421             : {
     422       30182 :     return pvsContent_->size();
     423             : }
     424             : 
     425          83 : void KMLNode::setLayerNumber(int nNum)
     426             : {
     427          83 :     nLayerNumber_ = nNum;
     428          83 : }
     429             : 
     430           0 : int KMLNode::getLayerNumber() const
     431             : {
     432           0 :     return nLayerNumber_;
     433             : }
     434             : 
     435         809 : std::string KMLNode::getNameElement() const
     436             : {
     437         809 :     const kml_nodes_t::size_type size = pvpoChildren_->size();
     438             : 
     439         844 :     for (kml_nodes_t::size_type i = 0; i < size; ++i)
     440             :     {
     441         808 :         if ((*pvpoChildren_)[i]->sName_.compare("name") == 0)
     442             :         {
     443         773 :             const auto subsize = (*pvpoChildren_)[i]->pvsContent_->size();
     444         773 :             if (subsize > 0)
     445             :             {
     446         773 :                 return (*(*pvpoChildren_)[i]->pvsContent_)[0];
     447             :             }
     448           0 :             break;
     449             :         }
     450             :     }
     451          36 :     return "";
     452             : }
     453             : 
     454         727 : std::string KMLNode::getDescriptionElement() const
     455             : {
     456         727 :     const kml_nodes_t::size_type size = pvpoChildren_->size();
     457        1812 :     for (kml_nodes_t::size_type i = 0; i < size; ++i)
     458             :     {
     459        1422 :         if ((*pvpoChildren_)[i]->sName_.compare("description") == 0)
     460             :         {
     461         337 :             const auto subsize = (*pvpoChildren_)[i]->pvsContent_->size();
     462         337 :             if (subsize > 0)
     463             :             {
     464         337 :                 return (*(*pvpoChildren_)[i]->pvsContent_)[0];
     465             :             }
     466           0 :             break;
     467             :         }
     468             :     }
     469         390 :     return "";
     470             : }
     471             : 
     472         977 : std::size_t KMLNode::getNumFeatures()
     473             : {
     474         977 :     if (nNumFeatures_ == std::numeric_limits<size_t>::max())
     475             :     {
     476          27 :         nNumFeatures_ = 0;
     477          27 :         kml_nodes_t::size_type size = pvpoChildren_->size();
     478             : 
     479         154 :         for (kml_nodes_t::size_type i = 0; i < size; ++i)
     480             :         {
     481         127 :             if ((*pvpoChildren_)[i]->sName_ == "Placemark")
     482          88 :                 nNumFeatures_++;
     483             :         }
     484             :     }
     485         977 :     return nNumFeatures_;
     486             : }
     487             : 
     488         745 : OGRGeometry *KMLNode::getGeometry(Nodetype eType)
     489             : {
     490         745 :     OGRGeometry *poGeom = nullptr;
     491         745 :     KMLNode *poCoor = nullptr;
     492         745 :     Coordinate *psCoord = nullptr;
     493             : 
     494         745 :     if (sName_.compare("Point") == 0)
     495             :     {
     496             :         // Search coordinate Element
     497         232 :         for (unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
     498             :         {
     499         230 :             if ((*pvpoChildren_)[nCount]->sName_.compare("coordinates") == 0)
     500             :             {
     501         166 :                 poCoor = (*pvpoChildren_)[nCount];
     502         166 :                 for (unsigned int nCountP = 0;
     503         166 :                      nCountP < poCoor->pvsContent_->size(); nCountP++)
     504             :                 {
     505         165 :                     psCoord = ParseCoordinate((*poCoor->pvsContent_)[nCountP]);
     506         165 :                     if (psCoord != nullptr)
     507             :                     {
     508         165 :                         if (psCoord->bHasZ)
     509         156 :                             poGeom = new OGRPoint(psCoord->dfLongitude,
     510             :                                                   psCoord->dfLatitude,
     511         156 :                                                   psCoord->dfAltitude);
     512             :                         else
     513           9 :                             poGeom = new OGRPoint(psCoord->dfLongitude,
     514           9 :                                                   psCoord->dfLatitude);
     515         165 :                         delete psCoord;
     516         165 :                         return poGeom;
     517             :                     }
     518             :                 }
     519             :             }
     520             :         }
     521           2 :         poGeom = new OGRPoint();
     522             :     }
     523         578 :     else if (sName_.compare("LineString") == 0)
     524             :     {
     525             :         // Search coordinate Element
     526         236 :         poGeom = new OGRLineString();
     527         607 :         for (unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
     528             :         {
     529         371 :             if ((*pvpoChildren_)[nCount]->sName_.compare("coordinates") == 0)
     530             :             {
     531         235 :                 poCoor = (*pvpoChildren_)[nCount];
     532        1927 :                 for (unsigned int nCountP = 0;
     533        1927 :                      nCountP < poCoor->pvsContent_->size(); nCountP++)
     534             :                 {
     535        1692 :                     psCoord = ParseCoordinate((*poCoor->pvsContent_)[nCountP]);
     536        1692 :                     if (psCoord != nullptr)
     537             :                     {
     538        1692 :                         if (psCoord->bHasZ)
     539        1678 :                             poGeom->toLineString()->addPoint(
     540             :                                 psCoord->dfLongitude, psCoord->dfLatitude,
     541             :                                 psCoord->dfAltitude);
     542             :                         else
     543          14 :                             poGeom->toLineString()->addPoint(
     544             :                                 psCoord->dfLongitude, psCoord->dfLatitude);
     545        1692 :                         delete psCoord;
     546             :                     }
     547             :                 }
     548             :             }
     549             :         }
     550             :     }
     551         342 :     else if (sName_.compare("Polygon") == 0)
     552             :     {
     553             :         //*********************************
     554             :         // Search outerBoundaryIs Element
     555             :         //*********************************
     556         328 :         poGeom = new OGRPolygon();
     557        1018 :         for (unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
     558             :         {
     559         690 :             if ((*pvpoChildren_)[nCount]->sName_.compare("outerBoundaryIs") ==
     560        1017 :                     0 &&
     561         327 :                 !(*pvpoChildren_)[nCount]->pvpoChildren_->empty())
     562             :             {
     563         326 :                 poCoor = (*(*pvpoChildren_)[nCount]->pvpoChildren_)[0];
     564             :             }
     565             :         }
     566             :         // No outer boundary found
     567         328 :         if (poCoor == nullptr)
     568             :         {
     569           2 :             return poGeom;
     570             :         }
     571             :         // Search coordinate Element
     572         326 :         OGRLinearRing *poLinearRing = nullptr;
     573         651 :         for (unsigned int nCount = 0; nCount < poCoor->pvpoChildren_->size();
     574             :              nCount++)
     575             :         {
     576         325 :             if ((*poCoor->pvpoChildren_)[nCount]->sName_.compare(
     577         325 :                     "coordinates") == 0)
     578             :             {
     579        4668 :                 for (unsigned int nCountP = 0;
     580        4668 :                      nCountP <
     581        4668 :                      (*poCoor->pvpoChildren_)[nCount]->pvsContent_->size();
     582             :                      nCountP++)
     583             :                 {
     584        8686 :                     psCoord = ParseCoordinate((*(*poCoor->pvpoChildren_)[nCount]
     585        4343 :                                                     ->pvsContent_)[nCountP]);
     586        4343 :                     if (psCoord != nullptr)
     587             :                     {
     588        4343 :                         if (poLinearRing == nullptr)
     589             :                         {
     590         324 :                             poLinearRing = new OGRLinearRing();
     591             :                         }
     592        4343 :                         if (psCoord->bHasZ)
     593        4296 :                             poLinearRing->addPoint(psCoord->dfLongitude,
     594             :                                                    psCoord->dfLatitude,
     595             :                                                    psCoord->dfAltitude);
     596             :                         else
     597          47 :                             poLinearRing->addPoint(psCoord->dfLongitude,
     598             :                                                    psCoord->dfLatitude);
     599        4343 :                         delete psCoord;
     600             :                     }
     601             :                 }
     602             :             }
     603             :         }
     604             :         // No outer boundary coordinates found
     605         326 :         if (poLinearRing == nullptr)
     606             :         {
     607           2 :             return poGeom;
     608             :         }
     609             : 
     610         324 :         poGeom->toPolygon()->addRingDirectly(poLinearRing);
     611         324 :         poLinearRing = nullptr;
     612             : 
     613             :         //*********************************
     614             :         // Search innerBoundaryIs Elements
     615             :         //*********************************
     616             : 
     617        1011 :         for (unsigned int nCount2 = 0; nCount2 < pvpoChildren_->size();
     618             :              nCount2++)
     619             :         {
     620         687 :             if ((*pvpoChildren_)[nCount2]->sName_.compare("innerBoundaryIs") ==
     621             :                 0)
     622             :             {
     623          49 :                 if (poLinearRing)
     624           0 :                     poGeom->toPolygon()->addRingDirectly(poLinearRing);
     625          49 :                 poLinearRing = nullptr;
     626             : 
     627          49 :                 if ((*pvpoChildren_)[nCount2]->pvpoChildren_->empty())
     628           1 :                     continue;
     629             : 
     630          48 :                 poLinearRing = new OGRLinearRing();
     631             : 
     632          48 :                 poCoor = (*(*pvpoChildren_)[nCount2]->pvpoChildren_)[0];
     633             :                 // Search coordinate Element
     634          95 :                 for (unsigned int nCount = 0;
     635          95 :                      nCount < poCoor->pvpoChildren_->size(); nCount++)
     636             :                 {
     637          47 :                     if ((*poCoor->pvpoChildren_)[nCount]->sName_.compare(
     638          47 :                             "coordinates") == 0)
     639             :                     {
     640         316 :                         for (unsigned int nCountP = 0;
     641         632 :                              nCountP < (*poCoor->pvpoChildren_)[nCount]
     642         316 :                                            ->pvsContent_->size();
     643             :                              nCountP++)
     644             :                         {
     645         269 :                             psCoord = ParseCoordinate(
     646         269 :                                 (*(*poCoor->pvpoChildren_)[nCount]
     647         269 :                                       ->pvsContent_)[nCountP]);
     648         269 :                             if (psCoord != nullptr)
     649             :                             {
     650         269 :                                 if (psCoord->bHasZ)
     651         252 :                                     poLinearRing->addPoint(psCoord->dfLongitude,
     652             :                                                            psCoord->dfLatitude,
     653             :                                                            psCoord->dfAltitude);
     654             :                                 else
     655          17 :                                     poLinearRing->addPoint(psCoord->dfLongitude,
     656             :                                                            psCoord->dfLatitude);
     657         269 :                                 delete psCoord;
     658             :                             }
     659             :                         }
     660             :                     }
     661             :                 }
     662             :             }
     663             :         }
     664             : 
     665         324 :         if (poLinearRing)
     666          48 :             poGeom->toPolygon()->addRingDirectly(poLinearRing);
     667             :     }
     668          17 :     else if (sName_.compare("MultiGeometry") == 0 ||
     669           5 :              sName_.compare("MultiPolygon") == 0 ||
     670          19 :              sName_.compare("MultiLineString") == 0 ||
     671           1 :              sName_.compare("MultiPoint") == 0)
     672             :     {
     673          14 :         if (eType == MultiPoint)
     674           4 :             poGeom = new OGRMultiPoint();
     675          10 :         else if (eType == MultiLineString)
     676           3 :             poGeom = new OGRMultiLineString();
     677           7 :         else if (eType == MultiPolygon)
     678           3 :             poGeom = new OGRMultiPolygon();
     679             :         else
     680           4 :             poGeom = new OGRGeometryCollection();
     681          32 :         for (unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
     682             :         {
     683          18 :             OGRGeometry *poSubGeom = (*pvpoChildren_)[nCount]->getGeometry();
     684          18 :             if (poSubGeom)
     685          18 :                 poGeom->toGeometryCollection()->addGeometryDirectly(poSubGeom);
     686             :         }
     687             :     }
     688             : 
     689         576 :     return poGeom;
     690             : }
     691             : 
     692         916 : Feature *KMLNode::getFeature(std::size_t nNum, int &nLastAsked, int &nLastCount)
     693             : {
     694         916 :     if (nNum >= getNumFeatures())
     695         189 :         return nullptr;
     696             : 
     697         727 :     unsigned int nCount = 0;
     698         727 :     unsigned int nCountP = 0;
     699         727 :     KMLNode *poFeat = nullptr;
     700         727 :     KMLNode *poTemp = nullptr;
     701             : 
     702         727 :     if (nLastAsked + 1 != static_cast<int>(nNum))
     703             :     {
     704             :         // nCount = 0;
     705             :         // nCountP = 0;
     706             :     }
     707             :     else
     708             :     {
     709         727 :         nCount = nLastCount + 1;
     710         727 :         nCountP = nLastAsked + 1;
     711             :     }
     712             : 
     713        1262 :     for (; nCount < pvpoChildren_->size(); nCount++)
     714             :     {
     715        1262 :         if ((*pvpoChildren_)[nCount]->sName_.compare("Placemark") == 0)
     716             :         {
     717         727 :             if (nCountP == nNum)
     718             :             {
     719         727 :                 poFeat = (*pvpoChildren_)[nCount];
     720         727 :                 break;
     721             :             }
     722           0 :             nCountP++;
     723             :         }
     724             :     }
     725             : 
     726         727 :     nLastAsked = static_cast<int>(nNum);
     727         727 :     nLastCount = nCount;
     728             : 
     729         727 :     if (poFeat == nullptr)
     730           0 :         return nullptr;
     731             : 
     732             :     // Create a feature structure
     733         727 :     Feature *psReturn = new Feature;
     734             :     // Build up the name
     735         727 :     psReturn->sName = poFeat->getNameElement();
     736             :     // Build up the description
     737         727 :     psReturn->sDescription = poFeat->getDescriptionElement();
     738             :     // the type
     739         727 :     psReturn->eType = poFeat->eType_;
     740             : 
     741        1454 :     std::string sElementName;
     742         727 :     if (poFeat->eType_ == Point || poFeat->eType_ == LineString ||
     743         338 :         poFeat->eType_ == Polygon)
     744         713 :         sElementName = Nodetype2String(poFeat->eType_);
     745          14 :     else if (poFeat->eType_ == MultiGeometry || poFeat->eType_ == MultiPoint ||
     746           6 :              poFeat->eType_ == MultiLineString ||
     747           3 :              poFeat->eType_ == MultiPolygon)
     748          14 :         sElementName = "MultiGeometry";
     749             :     else
     750             :     {
     751           0 :         delete psReturn;
     752           0 :         return nullptr;
     753             :     }
     754             : 
     755        1759 :     for (nCount = 0; nCount < poFeat->pvpoChildren_->size(); nCount++)
     756             :     {
     757        1759 :         const auto &sName = (*poFeat->pvpoChildren_)[nCount]->sName_;
     758        2797 :         if (sName.compare(sElementName) == 0 ||
     759        1038 :             (sElementName == "MultiGeometry" &&
     760           6 :              (sName == "MultiPolygon" || sName == "MultiLineString" ||
     761           1 :               sName == "MultiPoint")))
     762             :         {
     763         727 :             poTemp = (*poFeat->pvpoChildren_)[nCount];
     764         727 :             psReturn->poGeom.reset(poTemp->getGeometry(poFeat->eType_));
     765         727 :             if (psReturn->poGeom)
     766         727 :                 return psReturn;
     767             :             else
     768             :             {
     769           0 :                 delete psReturn;
     770           0 :                 return nullptr;
     771             :             }
     772             :         }
     773             :     }
     774             : 
     775           0 :     delete psReturn;
     776           0 :     return nullptr;
     777             : }

Generated by: LCOV version 1.14