text: /******************************************************************************
   *
   * Project:  KML Driver
   * Purpose:  Class for building up the node structure of the kml file.
   * Author:   Jens Oberender, j.obi@troja.net
   *
   ******************************************************************************
   * Copyright (c) 2007, Jens Oberender
   * Copyright (c) 2007-2012, Even Rouault <even dot rouault at spatialys.com>
   *
   * Permission is hereby granted, free of charge, to any person obtaining a
   * copy of this software and associated documentation files (the "Software"),
   * to deal in the Software without restriction, including without limitation
   * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   * and/or sell copies of the Software, and to permit persons to whom the
   * Software is furnished to do so, subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included
   * in all copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   * DEALINGS IN THE SOFTWARE.
   ****************************************************************************/
  
  #include "cpl_port.h"
  #include "kmlnode.h"
  
  #include <cstring>
  #include <memory>
  #include <string>
  #include <vector>
  
  #include "cpl_conv.h"
  #include "cpl_error.h"
  #include "ogr_geometry.h"
  
  CPL_CVSID("$Id: kmlnode.cpp 8ae5111b5f0775a230a3d583e861627917c370d8 2021-07-06 12:15:32 +0200 Even Rouault $")
  
  /************************************************************************/
  /*                           Help functions                             */
  /************************************************************************/
  
  std::string Nodetype2String(Nodetype const& type)
  {
      if(type == Empty)
          return "Empty";
      else if(type == Rest)
          return "Rest";
      else if(type == Mixed)
          return "Mixed";
      else if(type == Point)
          return "Point";
      else if(type == LineString)
          return "LineString";
      else if(type == Polygon)
          return "Polygon";
      else if(type == MultiGeometry)
          return "MultiGeometry";
      else if(type == MultiPoint)
          return "MultiPoint";
      else if(type == MultiLineString)
          return "MultiLineString";
      else if(type == MultiPolygon)
          return "MultiPolygon";
      else
          return "Unknown";
  }
  
  static
  bool isNumberDigit(const char cIn)
  {
      return ( cIn == '-' || cIn == '+' ||
              (cIn >= '0' && cIn <= '9') ||
               cIn == '.' || cIn == 'e' || cIn == 'E' );
  }
  
  static
  Coordinate* ParseCoordinate(std::string const& text)
  {
      int pos = 0;
      const char* pszStr = text.c_str();
      Coordinate *psTmp = new Coordinate();
  
      // X coordinate
      psTmp->dfLongitude = CPLAtof(pszStr);
      while(isNumberDigit(pszStr[pos++]));
  
      // Y coordinate
      if(pszStr[pos - 1] != ',')
      {
          delete psTmp;
          return nullptr;
      }
  
      psTmp->dfLatitude = CPLAtof(pszStr + pos);
      while(isNumberDigit(pszStr[pos++]));
  
      // Z coordinate
      if(pszStr[pos - 1] != ',')
      {
          psTmp->bHasZ = false;
          psTmp->dfAltitude = 0;
          return psTmp;
      }
  
      psTmp->bHasZ = true;
      psTmp->dfAltitude = CPLAtof(pszStr + pos);
  
      return psTmp;
  }
  
  /************************************************************************/
  /*                         KMLNode methods                              */
  /************************************************************************/
  
  KMLNode::KMLNode() :
      pvpoChildren_(new std::vector<KMLNode*>),
      pvsContent_(new std::vector<std::string>),
      pvoAttributes_(new std::vector<Attribute*>),
      poParent_(nullptr),
      nLevel_(0),
      eType_(Unknown),
      b25D_(false),
      nLayerNumber_(-1),
      nNumFeatures_(-1)
  {}
  
  KMLNode::~KMLNode()
  {
      CPLAssert( nullptr != pvpoChildren_ );
      CPLAssert( nullptr != pvoAttributes_ );
  
      kml_nodes_t::iterator itChild;
      for( itChild = pvpoChildren_->begin();
           itChild != pvpoChildren_->end(); ++itChild)
      {
          delete (*itChild);
      }
      delete pvpoChildren_;
  
      kml_attributes_t::iterator itAttr;
      for( itAttr = pvoAttributes_->begin();
           itAttr != pvoAttributes_->end(); ++itAttr)
      {
          delete (*itAttr);
      }
      delete pvoAttributes_;
  
      delete pvsContent_;
  }
  
  void KMLNode::print(unsigned int what)
  {
      std::string indent;
      for(std::size_t l = 0; l < nLevel_; l++)
          indent += " ";
  
      if(nLevel_ > 0)
      {
          if(nLayerNumber_ > -1)
          {
              CPLDebug( "KML",
                        "%s%s (nLevel: %d Type: %s poParent: %s "
                        "pvpoChildren_: %d pvsContent_: %d pvoAttributes_: %d) "
                        "<--- Layer #%d",
                        indent.c_str(), sName_.c_str(),
                        static_cast<int>(nLevel_),
                        Nodetype2String(eType_).c_str(),
                        poParent_->sName_.c_str(),
                        static_cast<int>(pvpoChildren_->size()),
                        static_cast<int>(pvsContent_->size()),
                        static_cast<int>(pvoAttributes_->size()),
                        nLayerNumber_ );
          }
          else
          {
              CPLDebug( "KML",
                        "%s%s (nLevel: %d Type: %s poParent: %s "
                        "pvpoChildren_: %d pvsContent_: %d pvoAttributes_: %d)",
                        indent.c_str(), sName_.c_str(), static_cast<int>(nLevel_),
                        Nodetype2String(eType_).c_str(),
                        poParent_->sName_.c_str(),
                        static_cast<int>(pvpoChildren_->size()),
                        static_cast<int>(pvsContent_->size()),
                        static_cast<int>(pvoAttributes_->size()) );
          }
      }
      else
      {
          CPLDebug( "KML",
                    "%s%s (nLevel: %d Type: %s pvpoChildren_: %d "
                    "pvsContent_: %d pvoAttributes_: %d)",
                    indent.c_str(), sName_.c_str(), static_cast<int>(nLevel_),
                    Nodetype2String(eType_).c_str(),
                    static_cast<int>(pvpoChildren_->size()),
                    static_cast<int>(pvsContent_->size()),
                    static_cast<int>(pvoAttributes_->size()) );
      }
  
      if(what == 1 || what == 3)
      {
          for(kml_content_t::size_type z = 0; z < pvsContent_->size(); z++)
              CPLDebug( "KML", "%s|->pvsContent_: '%s'",
                        indent.c_str(), (*pvsContent_)[z].c_str() );
      }
  
      if(what == 2 || what == 3)
      {
          for(kml_attributes_t::size_type z = 0; z < pvoAttributes_->size(); z++)
              CPLDebug( "KML", "%s|->pvoAttributes_: %s = '%s'",
                        indent.c_str(), (*pvoAttributes_)[z]->sName.c_str(),
                        (*pvoAttributes_)[z]->sValue.c_str() );
      }
  
      for(kml_nodes_t::size_type z = 0; z < pvpoChildren_->size(); z++)
          (*pvpoChildren_)[z]->print(what);
  }
  
  int KMLNode::classify(KML* poKML, int nRecLevel)
  {
      Nodetype all = Empty;
  
      /* Arbitrary value, but certainly large enough for reasonable usages ! */
      if( nRecLevel == 32 )
      {
          CPLError( CE_Failure, CPLE_AppDefined,
                    "Too many recursion levels (%d) while parsing KML geometry.",
                    nRecLevel );
          return FALSE;
      }
  
      if(sName_.compare("Point") == 0)
          eType_ = Point;
      else if(sName_.compare("LineString") == 0)
          eType_ = LineString;
      else if(sName_.compare("Polygon") == 0)
          eType_ = Polygon;
      else if(poKML->isRest(sName_))
          eType_ = Empty;
      else if(sName_.compare("coordinates") == 0)
      {
          for( unsigned int nCountP = 0;
               nCountP < pvsContent_->size();
               nCountP++ )
          {
              const char* pszCoord = (*pvsContent_)[nCountP].c_str();
              int nComma = 0;
              while( true )
              {
                  pszCoord = strchr(pszCoord, ',');
                  if (pszCoord)
                  {
                      nComma ++;
                      pszCoord ++;
                  }
                  else
                      break;
              }
              if (nComma == 2)
                  b25D_ = true;
          }
      }
  
      const kml_nodes_t::size_type size = pvpoChildren_->size();
      for(kml_nodes_t::size_type z = 0; z < size; z++)
      {
          // Classify pvpoChildren_
          if (!(*pvpoChildren_)[z]->classify(poKML, nRecLevel + 1))
              return FALSE;
  
          Nodetype curr = (*pvpoChildren_)[z]->eType_;
          b25D_ |= (*pvpoChildren_)[z]->b25D_;
  
          // Compare and return if it is mixed
          if(curr != all && all != Empty && curr != Empty)
          {
              if (sName_.compare("MultiGeometry") == 0 ||
                  sName_.compare("MultiPolygon") == 0 ||
                  sName_.compare("MultiLineString") == 0 ||
                  sName_.compare("MultiPoint") == 0 )
                  eType_ = MultiGeometry;
              else
                  eType_ = Mixed;
          }
          else if(curr != Empty)
          {
              all = curr;
          }
      }
  
      if(eType_ == Unknown)
      {
          if (sName_.compare("MultiGeometry") == 0 ||
              sName_.compare("MultiPolygon") == 0 ||
              sName_.compare("MultiLineString") == 0 ||
              sName_.compare("MultiPoint") == 0 )
          {
              if (all == Point)
                  eType_ = MultiPoint;
              else if (all == LineString)
                  eType_ = MultiLineString;
              else if (all == Polygon)
                  eType_ = MultiPolygon;
              else
                  eType_ = MultiGeometry;
          }
          else
              eType_ = all;
      }
  
      return TRUE;
  }
  
  
  void KMLNode::unregisterLayerIfMatchingThisNode(KML* poKML)
  {
      for(std::size_t z = 0; z < countChildren(); z++)
      {
          getChild(z)->unregisterLayerIfMatchingThisNode(poKML);
      }
      poKML->unregisterLayerIfMatchingThisNode(this);
  }
  
  void KMLNode::eliminateEmpty(KML* poKML)
  {
      for(kml_nodes_t::size_type z = 0; z < pvpoChildren_->size();)
      {
          if((*pvpoChildren_)[z]->eType_ == Empty
             && (poKML->isContainer((*pvpoChildren_)[z]->sName_)
                 || poKML->isFeatureContainer((*pvpoChildren_)[z]->sName_)))
          {
              (*pvpoChildren_)[z]->unregisterLayerIfMatchingThisNode(poKML);
              delete (*pvpoChildren_)[z];
              pvpoChildren_->erase(pvpoChildren_->begin() + z);
          }
          else
          {
              (*pvpoChildren_)[z]->eliminateEmpty(poKML);
              ++z;
          }
      }
  }
  
  bool KMLNode::hasOnlyEmpty() const
  {
      for(kml_nodes_t::size_type z = 0; z < pvpoChildren_->size(); z++)
      {
          if((*pvpoChildren_)[z]->eType_ != Empty)
          {
              return false;
          }
          else
          {
              if (!(*pvpoChildren_)[z]->hasOnlyEmpty())
                  return false;
          }
      }
  
      return true;
  }
  
  void KMLNode::setType(Nodetype oNotet)
  {
      eType_ = oNotet;
  }
  
  Nodetype KMLNode::getType() const
  {
      return eType_;
  }
  
  void KMLNode::setName(std::string const& sIn)
  {
      sName_ = sIn;
  }
  
  const std::string& KMLNode::getName() const
  {
      return sName_;
  }
  
  void KMLNode::setLevel(std::size_t nLev)
  {
      nLevel_ = nLev;
  }
  
  std::size_t KMLNode::getLevel() const
  {
      return nLevel_;
  }
  
  void KMLNode::addAttribute(Attribute *poAttr)
  {
      pvoAttributes_->push_back(poAttr);
  }
  
  void KMLNode::setParent(KMLNode* poPar)
  {
      poParent_ = poPar;
  }
  
  KMLNode* KMLNode::getParent() const
  {
      return poParent_;
  }
  
  void KMLNode::addChildren(KMLNode *poChil)
  {
      pvpoChildren_->push_back(poChil);
  }
  
  std::size_t KMLNode::countChildren() const
  {
      return pvpoChildren_->size();
  }
  
  KMLNode* KMLNode::getChild(std::size_t index) const
  {
      return (*pvpoChildren_)[index];
  }
  
  void KMLNode::addContent(std::string const& text)
  {
      pvsContent_->push_back(text);
  }
  
  void KMLNode::appendContent(std::string const& text)
  {
      pvsContent_->back() += text;
  }
  
  std::string KMLNode::getContent(std::size_t index) const
  {
      return (*pvsContent_)[index];
  }
  
  void KMLNode::deleteContent(std::size_t index)
  {
      if( index < pvsContent_->size() )
      {
          pvsContent_->erase(pvsContent_->begin() + index);
      }
  }
  
  std::size_t KMLNode::numContent() const
  {
      return pvsContent_->size();
  }
  
  void KMLNode::setLayerNumber(int nNum)
  {
      nLayerNumber_ = nNum;
  }
  
  int KMLNode::getLayerNumber() const
  {
      return nLayerNumber_;
  }
  
  std::string KMLNode::getNameElement() const
  {
      const kml_nodes_t::size_type size = pvpoChildren_->size();
  
      for( kml_nodes_t::size_type i = 0; i < size; ++i )
      {
          if( (*pvpoChildren_)[i]->sName_.compare("name") == 0 )
          {
              const auto subsize = (*pvpoChildren_)[i]->pvsContent_->size();
              if( subsize > 0 )
              {
                  return (*(*pvpoChildren_)[i]->pvsContent_)[0];
              }
              break;
          }
      }
      return "";
  }
  
  std::string KMLNode::getDescriptionElement() const
  {
      const kml_nodes_t::size_type size = pvpoChildren_->size();
      for( kml_nodes_t::size_type i = 0; i < size; ++i )
      {
          if( (*pvpoChildren_)[i]->sName_.compare("description") == 0 )
          {
              const auto subsize = (*pvpoChildren_)[i]->pvsContent_->size();
              if ( subsize > 0 )
              {
                  return (*(*pvpoChildren_)[i]->pvsContent_)[0];
              }
              break;
          }
      }
      return "";
  }
  
  std::size_t KMLNode::getNumFeatures()
  {
      if (nNumFeatures_ < 0)
      {
          std::size_t nNum = 0;
          kml_nodes_t::size_type size = pvpoChildren_->size();
  
          for( kml_nodes_t::size_type i = 0; i < size; ++i )
          {
              if( (*pvpoChildren_)[i]->sName_ == "Placemark" )
                  nNum++;
          }
          nNumFeatures_ = (int)nNum;
      }
      return nNumFeatures_;
  }
  
  OGRGeometry* KMLNode::getGeometry(Nodetype eType)
  {
      OGRGeometry* poGeom = nullptr;
      KMLNode* poCoor = nullptr;
      Coordinate* psCoord = nullptr;
  
      if (sName_.compare("Point") == 0)
      {
          // Search coordinate Element
          for( unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
          {
              if((*pvpoChildren_)[nCount]->sName_.compare("coordinates") == 0)
              {
                  poCoor = (*pvpoChildren_)[nCount];
                  for( unsigned int nCountP = 0;
                       nCountP < poCoor->pvsContent_->size();
                       nCountP++)
                  {
                      psCoord = ParseCoordinate((*poCoor->pvsContent_)[nCountP]);
                      if(psCoord != nullptr)
                      {
                          if( psCoord->bHasZ )
                              poGeom = new OGRPoint(psCoord->dfLongitude,
                                                    psCoord->dfLatitude,
                                                    psCoord->dfAltitude);
                          else
                              poGeom = new OGRPoint(psCoord->dfLongitude,
                                                    psCoord->dfLatitude);
                          delete psCoord;
                          return poGeom;
                      }
                  }
              }
          }
          poGeom = new OGRPoint();
      }
      else if (sName_.compare("LineString") == 0)
      {
          // Search coordinate Element
          poGeom = new OGRLineString();
          for( unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
          {
              if((*pvpoChildren_)[nCount]->sName_.compare("coordinates") == 0)
              {
                  poCoor = (*pvpoChildren_)[nCount];
                  for( unsigned int nCountP = 0;
                       nCountP < poCoor->pvsContent_->size();
                       nCountP++ )
                  {
                      psCoord = ParseCoordinate((*poCoor->pvsContent_)[nCountP]);
                      if(psCoord != nullptr)
                      {
                          if( psCoord->bHasZ )
                              poGeom->toLineString()->addPoint(psCoord->dfLongitude,
                                                                 psCoord->dfLatitude,
                                                                 psCoord->dfAltitude);
                          else
                              poGeom->toLineString()->addPoint(psCoord->dfLongitude,
                                                                 psCoord->dfLatitude);
                          delete psCoord;
                      }
                  }
              }
          }
      }
      else if (sName_.compare("Polygon") == 0)
      {
          //*********************************
          // Search outerBoundaryIs Element
          //*********************************
          poGeom = new OGRPolygon();
          for(unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
          {
              if((*pvpoChildren_)[nCount]->sName_.compare("outerBoundaryIs") == 0 &&
                 !(*pvpoChildren_)[nCount]->pvpoChildren_->empty())
              {
                  poCoor = (*(*pvpoChildren_)[nCount]->pvpoChildren_)[0];
              }
          }
          // No outer boundary found
          if(poCoor == nullptr)
          {
              return poGeom;
          }
          // Search coordinate Element
          OGRLinearRing* poLinearRing = nullptr;
          for( unsigned int nCount = 0;
               nCount < poCoor->pvpoChildren_->size();
               nCount++)
          {
              if((*poCoor->pvpoChildren_)[nCount]->sName_.compare("coordinates") == 0)
              {
                  for( unsigned int nCountP = 0;
                       nCountP <
                         (*poCoor->pvpoChildren_)[nCount]->pvsContent_->size();
                       nCountP++)
                  {
                      psCoord = ParseCoordinate((*(*poCoor->pvpoChildren_)[nCount]->pvsContent_)[nCountP]);
                      if(psCoord != nullptr)
                      {
                          if (poLinearRing == nullptr)
                          {
                              poLinearRing = new OGRLinearRing();
                          }
                          if( psCoord->bHasZ )
                              poLinearRing->addPoint(psCoord->dfLongitude,
                                                     psCoord->dfLatitude,
                                                     psCoord->dfAltitude);
                          else
                              poLinearRing->addPoint(psCoord->dfLongitude,
                                                     psCoord->dfLatitude);
                          delete psCoord;
                      }
                  }
              }
          }
          // No outer boundary coordinates found
          if(poLinearRing == nullptr)
          {
              return poGeom;
          }
  
          poGeom->toPolygon()->addRingDirectly(poLinearRing);
          poLinearRing = nullptr;
  
          //*********************************
          // Search innerBoundaryIs Elements
          //*********************************
  
          for( unsigned int nCount2 = 0;
               nCount2 < pvpoChildren_->size();
               nCount2++ )
          {
              if((*pvpoChildren_)[nCount2]->sName_.compare("innerBoundaryIs") == 0)
              {
                  if (poLinearRing)
                      poGeom->toPolygon()->addRingDirectly(poLinearRing);
                  poLinearRing = nullptr;
  
                  if ((*pvpoChildren_)[nCount2]->pvpoChildren_->empty())
                      continue;
  
                  poLinearRing = new OGRLinearRing();
  
                  poCoor = (*(*pvpoChildren_)[nCount2]->pvpoChildren_)[0];
                  // Search coordinate Element
                  for( unsigned int nCount = 0;
                       nCount < poCoor->pvpoChildren_->size();
                       nCount++ )
                  {
                      if((*poCoor->pvpoChildren_)[nCount]->sName_.compare("coordinates") == 0)
                      {
                          for( unsigned int nCountP = 0;
                               nCountP < (*poCoor->pvpoChildren_)[nCount]->pvsContent_->size();
                               nCountP++)
                          {
                              psCoord = ParseCoordinate((*(*poCoor->pvpoChildren_)[nCount]->pvsContent_)[nCountP]);
                              if(psCoord != nullptr)
                              {
                                  if( psCoord->bHasZ )
                                      poLinearRing->addPoint(psCoord->dfLongitude,
                                                          psCoord->dfLatitude,
                                                          psCoord->dfAltitude);
                                  else
                                      poLinearRing->addPoint(psCoord->dfLongitude,
                                                          psCoord->dfLatitude);
                                  delete psCoord;
                              }
                          }
                      }
                  }
              }
          }
  
          if( poLinearRing )
              poGeom->toPolygon()->addRingDirectly(poLinearRing);
      }
      else if (sName_.compare("MultiGeometry") == 0  ||
               sName_.compare("MultiPolygon") == 0 ||
               sName_.compare("MultiLineString") == 0 ||
               sName_.compare("MultiPoint") == 0)
      {
          if (eType == MultiPoint)
              poGeom = new OGRMultiPoint();
          else if (eType == MultiLineString)
              poGeom = new OGRMultiLineString();
          else if (eType == MultiPolygon)
              poGeom = new OGRMultiPolygon();
          else
              poGeom = new OGRGeometryCollection();
          for(unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
          {
              OGRGeometry* poSubGeom = (*pvpoChildren_)[nCount]->getGeometry();
              if (poSubGeom)
                  poGeom->toGeometryCollection()->addGeometryDirectly(poSubGeom);
          }
      }
  
      return poGeom;
  }
  
  Feature* KMLNode::getFeature(std::size_t nNum, int& nLastAsked, int &nLastCount)
  {
      if( nNum >= getNumFeatures() )
          return nullptr;
  
      unsigned int nCount = 0;
      unsigned int nCountP = 0;
      KMLNode* poFeat = nullptr;
      KMLNode* poTemp = nullptr;
  
      if (nLastAsked + 1 != static_cast<int>(nNum ))
      {
          // nCount = 0;
          // nCountP = 0;
      }
      else
      {
          nCount = nLastCount + 1;
          nCountP = nLastAsked + 1;
      }
  
      for(; nCount < pvpoChildren_->size(); nCount++)
      {
          if((*pvpoChildren_)[nCount]->sName_.compare("Placemark") == 0)
          {
              if(nCountP == nNum)
              {
                  poFeat = (*pvpoChildren_)[nCount];
                  break;
              }
              nCountP++;
          }
      }
  
      nLastAsked = static_cast<int>(nNum);
      nLastCount = nCount;
  
      if(poFeat == nullptr)
          return nullptr;
  
      // Create a feature structure
      Feature *psReturn = new Feature;
      // Build up the name
      psReturn->sName = poFeat->getNameElement();
      // Build up the description
      psReturn->sDescription = poFeat->getDescriptionElement();
      // the type
      psReturn->eType = poFeat->eType_;
  
      std::string sElementName;
      if(poFeat->eType_ == Point ||
         poFeat->eType_ == LineString ||
         poFeat->eType_ == Polygon)
          sElementName = Nodetype2String(poFeat->eType_);
      else if (poFeat->eType_ == MultiGeometry ||
               poFeat->eType_ == MultiPoint ||
               poFeat->eType_ == MultiLineString ||
               poFeat->eType_ == MultiPolygon)
          sElementName = "MultiGeometry";
      else
      {
          delete psReturn;
          return nullptr;
      }
  
      for(nCount = 0; nCount < poFeat->pvpoChildren_->size(); nCount++)
      {
          const auto& sName = (*poFeat->pvpoChildren_)[nCount]->sName_;
          if(sName.compare(sElementName) == 0 ||
              (sElementName == "MultiGeometry" &&
               (sName == "MultiPolygon" || sName == "MultiLineString" ||
                sName == "MultiPoint")))
          {
              poTemp = (*poFeat->pvpoChildren_)[nCount];
              psReturn->poGeom = poTemp->getGeometry(poFeat->eType_);
              if(psReturn->poGeom)
                  return psReturn;
              else
              {
                  delete psReturn;
                  return nullptr;
              }
          }
      }
  
      delete psReturn;
      return nullptr;
  }
  