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 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ****************************************************************************/
29
30 #include "cpl_port.h"
31 #include "kmlnode.h"
32
33 #include <cstring>
34 #include <memory>
35 #include <string>
36 #include <vector>
37
38 #include "cpl_conv.h"
39 #include "cpl_error.h"
40 #include "ogr_geometry.h"
41
42 CPL_CVSID("$Id: kmlnode.cpp 8ca42e1b9c2e54b75d35e49885df9789a2643aa4 2020-05-17 21:43:40 +0200 Even Rouault $")
43
44 /************************************************************************/
45 /* Help functions */
46 /************************************************************************/
47
Nodetype2String(Nodetype const & type)48 std::string Nodetype2String(Nodetype const& type)
49 {
50 if(type == Empty)
51 return "Empty";
52 else if(type == Rest)
53 return "Rest";
54 else if(type == Mixed)
55 return "Mixed";
56 else if(type == Point)
57 return "Point";
58 else if(type == LineString)
59 return "LineString";
60 else if(type == Polygon)
61 return "Polygon";
62 else if(type == MultiGeometry)
63 return "MultiGeometry";
64 else if(type == MultiPoint)
65 return "MultiPoint";
66 else if(type == MultiLineString)
67 return "MultiLineString";
68 else if(type == MultiPolygon)
69 return "MultiPolygon";
70 else
71 return "Unknown";
72 }
73
74 static
isNumberDigit(const char cIn)75 bool isNumberDigit(const char cIn)
76 {
77 return ( cIn == '-' || cIn == '+' ||
78 (cIn >= '0' && cIn <= '9') ||
79 cIn == '.' || cIn == 'e' || cIn == 'E' );
80 }
81
82 static
ParseCoordinate(std::string const & text)83 Coordinate* ParseCoordinate(std::string const& text)
84 {
85 int pos = 0;
86 const char* pszStr = text.c_str();
87 Coordinate *psTmp = new Coordinate();
88
89 // X coordinate
90 psTmp->dfLongitude = CPLAtof(pszStr);
91 while(isNumberDigit(pszStr[pos++]));
92
93 // Y coordinate
94 if(pszStr[pos - 1] != ',')
95 {
96 delete psTmp;
97 return nullptr;
98 }
99
100 psTmp->dfLatitude = CPLAtof(pszStr + pos);
101 while(isNumberDigit(pszStr[pos++]));
102
103 // Z coordinate
104 if(pszStr[pos - 1] != ',')
105 {
106 psTmp->bHasZ = false;
107 psTmp->dfAltitude = 0;
108 return psTmp;
109 }
110
111 psTmp->bHasZ = true;
112 psTmp->dfAltitude = CPLAtof(pszStr + pos);
113
114 return psTmp;
115 }
116
117 /************************************************************************/
118 /* KMLNode methods */
119 /************************************************************************/
120
KMLNode()121 KMLNode::KMLNode() :
122 pvpoChildren_(new std::vector<KMLNode*>),
123 pvsContent_(new std::vector<std::string>),
124 pvoAttributes_(new std::vector<Attribute*>),
125 poParent_(nullptr),
126 nLevel_(0),
127 eType_(Unknown),
128 b25D_(false),
129 nLayerNumber_(-1),
130 nNumFeatures_(-1)
131 {}
132
~KMLNode()133 KMLNode::~KMLNode()
134 {
135 CPLAssert( nullptr != pvpoChildren_ );
136 CPLAssert( nullptr != pvoAttributes_ );
137
138 kml_nodes_t::iterator itChild;
139 for( itChild = pvpoChildren_->begin();
140 itChild != pvpoChildren_->end(); ++itChild)
141 {
142 delete (*itChild);
143 }
144 delete pvpoChildren_;
145
146 kml_attributes_t::iterator itAttr;
147 for( itAttr = pvoAttributes_->begin();
148 itAttr != pvoAttributes_->end(); ++itAttr)
149 {
150 delete (*itAttr);
151 }
152 delete pvoAttributes_;
153
154 delete pvsContent_;
155 }
156
print(unsigned int what)157 void KMLNode::print(unsigned int what)
158 {
159 std::string indent;
160 for(std::size_t l = 0; l < nLevel_; l++)
161 indent += " ";
162
163 if(nLevel_ > 0)
164 {
165 if(nLayerNumber_ > -1)
166 {
167 CPLDebug( "KML",
168 "%s%s (nLevel: %d Type: %s poParent: %s "
169 "pvpoChildren_: %d pvsContent_: %d pvoAttributes_: %d) "
170 "<--- Layer #%d",
171 indent.c_str(), sName_.c_str(),
172 static_cast<int>(nLevel_),
173 Nodetype2String(eType_).c_str(),
174 poParent_->sName_.c_str(),
175 static_cast<int>(pvpoChildren_->size()),
176 static_cast<int>(pvsContent_->size()),
177 static_cast<int>(pvoAttributes_->size()),
178 nLayerNumber_ );
179 }
180 else
181 {
182 CPLDebug( "KML",
183 "%s%s (nLevel: %d Type: %s poParent: %s "
184 "pvpoChildren_: %d pvsContent_: %d pvoAttributes_: %d)",
185 indent.c_str(), sName_.c_str(), static_cast<int>(nLevel_),
186 Nodetype2String(eType_).c_str(),
187 poParent_->sName_.c_str(),
188 static_cast<int>(pvpoChildren_->size()),
189 static_cast<int>(pvsContent_->size()),
190 static_cast<int>(pvoAttributes_->size()) );
191 }
192 }
193 else
194 {
195 CPLDebug( "KML",
196 "%s%s (nLevel: %d Type: %s pvpoChildren_: %d "
197 "pvsContent_: %d pvoAttributes_: %d)",
198 indent.c_str(), sName_.c_str(), static_cast<int>(nLevel_),
199 Nodetype2String(eType_).c_str(),
200 static_cast<int>(pvpoChildren_->size()),
201 static_cast<int>(pvsContent_->size()),
202 static_cast<int>(pvoAttributes_->size()) );
203 }
204
205 if(what == 1 || what == 3)
206 {
207 for(kml_content_t::size_type z = 0; z < pvsContent_->size(); z++)
208 CPLDebug( "KML", "%s|->pvsContent_: '%s'",
209 indent.c_str(), (*pvsContent_)[z].c_str() );
210 }
211
212 if(what == 2 || what == 3)
213 {
214 for(kml_attributes_t::size_type z = 0; z < pvoAttributes_->size(); z++)
215 CPLDebug( "KML", "%s|->pvoAttributes_: %s = '%s'",
216 indent.c_str(), (*pvoAttributes_)[z]->sName.c_str(),
217 (*pvoAttributes_)[z]->sValue.c_str() );
218 }
219
220 for(kml_nodes_t::size_type z = 0; z < pvpoChildren_->size(); z++)
221 (*pvpoChildren_)[z]->print(what);
222 }
223
classify(KML * poKML,int nRecLevel)224 int KMLNode::classify(KML* poKML, int nRecLevel)
225 {
226 Nodetype all = Empty;
227
228 /* Arbitrary value, but certainly large enough for reasonable usages ! */
229 if( nRecLevel == 32 )
230 {
231 CPLError( CE_Failure, CPLE_AppDefined,
232 "Too many recursion levels (%d) while parsing KML geometry.",
233 nRecLevel );
234 return FALSE;
235 }
236
237 if(sName_.compare("Point") == 0)
238 eType_ = Point;
239 else if(sName_.compare("LineString") == 0)
240 eType_ = LineString;
241 else if(sName_.compare("Polygon") == 0)
242 eType_ = Polygon;
243 else if(poKML->isRest(sName_))
244 eType_ = Empty;
245 else if(sName_.compare("coordinates") == 0)
246 {
247 for( unsigned int nCountP = 0;
248 nCountP < pvsContent_->size();
249 nCountP++ )
250 {
251 const char* pszCoord = (*pvsContent_)[nCountP].c_str();
252 int nComma = 0;
253 while( true )
254 {
255 pszCoord = strchr(pszCoord, ',');
256 if (pszCoord)
257 {
258 nComma ++;
259 pszCoord ++;
260 }
261 else
262 break;
263 }
264 if (nComma == 2)
265 b25D_ = true;
266 }
267 }
268
269 const kml_nodes_t::size_type size = pvpoChildren_->size();
270 for(kml_nodes_t::size_type z = 0; z < size; z++)
271 {
272 // Classify pvpoChildren_
273 if (!(*pvpoChildren_)[z]->classify(poKML, nRecLevel + 1))
274 return FALSE;
275
276 Nodetype curr = (*pvpoChildren_)[z]->eType_;
277 b25D_ |= (*pvpoChildren_)[z]->b25D_;
278
279 // Compare and return if it is mixed
280 if(curr != all && all != Empty && curr != Empty)
281 {
282 if (sName_.compare("MultiGeometry") == 0)
283 eType_ = MultiGeometry;
284 else
285 eType_ = Mixed;
286 }
287 else if(curr != Empty)
288 {
289 all = curr;
290 }
291 }
292
293 if(eType_ == Unknown)
294 {
295 if (sName_.compare("MultiGeometry") == 0)
296 {
297 if (all == Point)
298 eType_ = MultiPoint;
299 else if (all == LineString)
300 eType_ = MultiLineString;
301 else if (all == Polygon)
302 eType_ = MultiPolygon;
303 else
304 eType_ = MultiGeometry;
305 }
306 else
307 eType_ = all;
308 }
309
310 return TRUE;
311 }
312
313
unregisterLayerIfMatchingThisNode(KML * poKML)314 void KMLNode::unregisterLayerIfMatchingThisNode(KML* poKML)
315 {
316 for(std::size_t z = 0; z < countChildren(); z++)
317 {
318 getChild(z)->unregisterLayerIfMatchingThisNode(poKML);
319 }
320 poKML->unregisterLayerIfMatchingThisNode(this);
321 }
322
eliminateEmpty(KML * poKML)323 void KMLNode::eliminateEmpty(KML* poKML)
324 {
325 for(kml_nodes_t::size_type z = 0; z < pvpoChildren_->size();)
326 {
327 if((*pvpoChildren_)[z]->eType_ == Empty
328 && (poKML->isContainer((*pvpoChildren_)[z]->sName_)
329 || poKML->isFeatureContainer((*pvpoChildren_)[z]->sName_)))
330 {
331 (*pvpoChildren_)[z]->unregisterLayerIfMatchingThisNode(poKML);
332 delete (*pvpoChildren_)[z];
333 pvpoChildren_->erase(pvpoChildren_->begin() + z);
334 }
335 else
336 {
337 (*pvpoChildren_)[z]->eliminateEmpty(poKML);
338 ++z;
339 }
340 }
341 }
342
hasOnlyEmpty() const343 bool KMLNode::hasOnlyEmpty() const
344 {
345 for(kml_nodes_t::size_type z = 0; z < pvpoChildren_->size(); z++)
346 {
347 if((*pvpoChildren_)[z]->eType_ != Empty)
348 {
349 return false;
350 }
351 else
352 {
353 if (!(*pvpoChildren_)[z]->hasOnlyEmpty())
354 return false;
355 }
356 }
357
358 return true;
359 }
360
setType(Nodetype oNotet)361 void KMLNode::setType(Nodetype oNotet)
362 {
363 eType_ = oNotet;
364 }
365
getType() const366 Nodetype KMLNode::getType() const
367 {
368 return eType_;
369 }
370
setName(std::string const & sIn)371 void KMLNode::setName(std::string const& sIn)
372 {
373 sName_ = sIn;
374 }
375
getName() const376 const std::string& KMLNode::getName() const
377 {
378 return sName_;
379 }
380
setLevel(std::size_t nLev)381 void KMLNode::setLevel(std::size_t nLev)
382 {
383 nLevel_ = nLev;
384 }
385
getLevel() const386 std::size_t KMLNode::getLevel() const
387 {
388 return nLevel_;
389 }
390
addAttribute(Attribute * poAttr)391 void KMLNode::addAttribute(Attribute *poAttr)
392 {
393 pvoAttributes_->push_back(poAttr);
394 }
395
setParent(KMLNode * poPar)396 void KMLNode::setParent(KMLNode* poPar)
397 {
398 poParent_ = poPar;
399 }
400
getParent() const401 KMLNode* KMLNode::getParent() const
402 {
403 return poParent_;
404 }
405
addChildren(KMLNode * poChil)406 void KMLNode::addChildren(KMLNode *poChil)
407 {
408 pvpoChildren_->push_back(poChil);
409 }
410
countChildren() const411 std::size_t KMLNode::countChildren() const
412 {
413 return pvpoChildren_->size();
414 }
415
getChild(std::size_t index) const416 KMLNode* KMLNode::getChild(std::size_t index) const
417 {
418 return (*pvpoChildren_)[index];
419 }
420
addContent(std::string const & text)421 void KMLNode::addContent(std::string const& text)
422 {
423 pvsContent_->push_back(text);
424 }
425
appendContent(std::string const & text)426 void KMLNode::appendContent(std::string const& text)
427 {
428 pvsContent_->back() += text;
429 }
430
getContent(std::size_t index) const431 std::string KMLNode::getContent(std::size_t index) const
432 {
433 return (*pvsContent_)[index];
434 }
435
deleteContent(std::size_t index)436 void KMLNode::deleteContent(std::size_t index)
437 {
438 if( index < pvsContent_->size() )
439 {
440 pvsContent_->erase(pvsContent_->begin() + index);
441 }
442 }
443
numContent() const444 std::size_t KMLNode::numContent() const
445 {
446 return pvsContent_->size();
447 }
448
setLayerNumber(int nNum)449 void KMLNode::setLayerNumber(int nNum)
450 {
451 nLayerNumber_ = nNum;
452 }
453
getLayerNumber() const454 int KMLNode::getLayerNumber() const
455 {
456 return nLayerNumber_;
457 }
458
getNameElement() const459 std::string KMLNode::getNameElement() const
460 {
461 const kml_nodes_t::size_type size = pvpoChildren_->size();
462
463 for( kml_nodes_t::size_type i = 0; i < size; ++i )
464 {
465 if( (*pvpoChildren_)[i]->sName_.compare("name") == 0 )
466 {
467 const auto subsize = (*pvpoChildren_)[i]->pvsContent_->size();
468 if( subsize > 0 )
469 {
470 return (*(*pvpoChildren_)[i]->pvsContent_)[0];
471 }
472 break;
473 }
474 }
475 return "";
476 }
477
getDescriptionElement() const478 std::string KMLNode::getDescriptionElement() const
479 {
480 const kml_nodes_t::size_type size = pvpoChildren_->size();
481 for( kml_nodes_t::size_type i = 0; i < size; ++i )
482 {
483 if( (*pvpoChildren_)[i]->sName_.compare("description") == 0 )
484 {
485 const auto subsize = (*pvpoChildren_)[i]->pvsContent_->size();
486 if ( subsize > 0 )
487 {
488 return (*(*pvpoChildren_)[i]->pvsContent_)[0];
489 }
490 break;
491 }
492 }
493 return "";
494 }
495
getNumFeatures()496 std::size_t KMLNode::getNumFeatures()
497 {
498 if (nNumFeatures_ < 0)
499 {
500 std::size_t nNum = 0;
501 kml_nodes_t::size_type size = pvpoChildren_->size();
502
503 for( kml_nodes_t::size_type i = 0; i < size; ++i )
504 {
505 if( (*pvpoChildren_)[i]->sName_ == "Placemark" )
506 nNum++;
507 }
508 nNumFeatures_ = (int)nNum;
509 }
510 return nNumFeatures_;
511 }
512
getGeometry(Nodetype eType)513 OGRGeometry* KMLNode::getGeometry(Nodetype eType)
514 {
515 OGRGeometry* poGeom = nullptr;
516 KMLNode* poCoor = nullptr;
517 Coordinate* psCoord = nullptr;
518
519 if (sName_.compare("Point") == 0)
520 {
521 // Search coordinate Element
522 for( unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
523 {
524 if((*pvpoChildren_)[nCount]->sName_.compare("coordinates") == 0)
525 {
526 poCoor = (*pvpoChildren_)[nCount];
527 for( unsigned int nCountP = 0;
528 nCountP < poCoor->pvsContent_->size();
529 nCountP++)
530 {
531 psCoord = ParseCoordinate((*poCoor->pvsContent_)[nCountP]);
532 if(psCoord != nullptr)
533 {
534 if( psCoord->bHasZ )
535 poGeom = new OGRPoint(psCoord->dfLongitude,
536 psCoord->dfLatitude,
537 psCoord->dfAltitude);
538 else
539 poGeom = new OGRPoint(psCoord->dfLongitude,
540 psCoord->dfLatitude);
541 delete psCoord;
542 return poGeom;
543 }
544 }
545 }
546 }
547 poGeom = new OGRPoint();
548 }
549 else if (sName_.compare("LineString") == 0)
550 {
551 // Search coordinate Element
552 poGeom = new OGRLineString();
553 for( unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
554 {
555 if((*pvpoChildren_)[nCount]->sName_.compare("coordinates") == 0)
556 {
557 poCoor = (*pvpoChildren_)[nCount];
558 for( unsigned int nCountP = 0;
559 nCountP < poCoor->pvsContent_->size();
560 nCountP++ )
561 {
562 psCoord = ParseCoordinate((*poCoor->pvsContent_)[nCountP]);
563 if(psCoord != nullptr)
564 {
565 if( psCoord->bHasZ )
566 poGeom->toLineString()->addPoint(psCoord->dfLongitude,
567 psCoord->dfLatitude,
568 psCoord->dfAltitude);
569 else
570 poGeom->toLineString()->addPoint(psCoord->dfLongitude,
571 psCoord->dfLatitude);
572 delete psCoord;
573 }
574 }
575 }
576 }
577 }
578 else if (sName_.compare("Polygon") == 0)
579 {
580 //*********************************
581 // Search outerBoundaryIs Element
582 //*********************************
583 poGeom = new OGRPolygon();
584 for(unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
585 {
586 if((*pvpoChildren_)[nCount]->sName_.compare("outerBoundaryIs") == 0 &&
587 !(*pvpoChildren_)[nCount]->pvpoChildren_->empty())
588 {
589 poCoor = (*(*pvpoChildren_)[nCount]->pvpoChildren_)[0];
590 }
591 }
592 // No outer boundary found
593 if(poCoor == nullptr)
594 {
595 return poGeom;
596 }
597 // Search coordinate Element
598 OGRLinearRing* poLinearRing = nullptr;
599 for( unsigned int nCount = 0;
600 nCount < poCoor->pvpoChildren_->size();
601 nCount++)
602 {
603 if((*poCoor->pvpoChildren_)[nCount]->sName_.compare("coordinates") == 0)
604 {
605 for( unsigned int nCountP = 0;
606 nCountP <
607 (*poCoor->pvpoChildren_)[nCount]->pvsContent_->size();
608 nCountP++)
609 {
610 psCoord = ParseCoordinate((*(*poCoor->pvpoChildren_)[nCount]->pvsContent_)[nCountP]);
611 if(psCoord != nullptr)
612 {
613 if (poLinearRing == nullptr)
614 {
615 poLinearRing = new OGRLinearRing();
616 }
617 if( psCoord->bHasZ )
618 poLinearRing->addPoint(psCoord->dfLongitude,
619 psCoord->dfLatitude,
620 psCoord->dfAltitude);
621 else
622 poLinearRing->addPoint(psCoord->dfLongitude,
623 psCoord->dfLatitude);
624 delete psCoord;
625 }
626 }
627 }
628 }
629 // No outer boundary coordinates found
630 if(poLinearRing == nullptr)
631 {
632 return poGeom;
633 }
634
635 poGeom->toPolygon()->addRingDirectly(poLinearRing);
636 poLinearRing = nullptr;
637
638 //*********************************
639 // Search innerBoundaryIs Elements
640 //*********************************
641
642 for( unsigned int nCount2 = 0;
643 nCount2 < pvpoChildren_->size();
644 nCount2++ )
645 {
646 if((*pvpoChildren_)[nCount2]->sName_.compare("innerBoundaryIs") == 0)
647 {
648 if (poLinearRing)
649 poGeom->toPolygon()->addRingDirectly(poLinearRing);
650 poLinearRing = nullptr;
651
652 if ((*pvpoChildren_)[nCount2]->pvpoChildren_->empty())
653 continue;
654
655 poLinearRing = new OGRLinearRing();
656
657 poCoor = (*(*pvpoChildren_)[nCount2]->pvpoChildren_)[0];
658 // Search coordinate Element
659 for( unsigned int nCount = 0;
660 nCount < poCoor->pvpoChildren_->size();
661 nCount++ )
662 {
663 if((*poCoor->pvpoChildren_)[nCount]->sName_.compare("coordinates") == 0)
664 {
665 for( unsigned int nCountP = 0;
666 nCountP < (*poCoor->pvpoChildren_)[nCount]->pvsContent_->size();
667 nCountP++)
668 {
669 psCoord = ParseCoordinate((*(*poCoor->pvpoChildren_)[nCount]->pvsContent_)[nCountP]);
670 if(psCoord != nullptr)
671 {
672 if( psCoord->bHasZ )
673 poLinearRing->addPoint(psCoord->dfLongitude,
674 psCoord->dfLatitude,
675 psCoord->dfAltitude);
676 else
677 poLinearRing->addPoint(psCoord->dfLongitude,
678 psCoord->dfLatitude);
679 delete psCoord;
680 }
681 }
682 }
683 }
684 }
685 }
686
687 if( poLinearRing )
688 poGeom->toPolygon()->addRingDirectly(poLinearRing);
689 }
690 else if (sName_.compare("MultiGeometry") == 0)
691 {
692 if (eType == MultiPoint)
693 poGeom = new OGRMultiPoint();
694 else if (eType == MultiLineString)
695 poGeom = new OGRMultiLineString();
696 else if (eType == MultiPolygon)
697 poGeom = new OGRMultiPolygon();
698 else
699 poGeom = new OGRGeometryCollection();
700 for(unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
701 {
702 OGRGeometry* poSubGeom = (*pvpoChildren_)[nCount]->getGeometry();
703 if (poSubGeom)
704 poGeom->toGeometryCollection()->addGeometryDirectly(poSubGeom);
705 }
706 }
707
708 return poGeom;
709 }
710
getFeature(std::size_t nNum,int & nLastAsked,int & nLastCount)711 Feature* KMLNode::getFeature(std::size_t nNum, int& nLastAsked, int &nLastCount)
712 {
713 if( nNum >= getNumFeatures() )
714 return nullptr;
715
716 unsigned int nCount = 0;
717 unsigned int nCountP = 0;
718 KMLNode* poFeat = nullptr;
719 KMLNode* poTemp = nullptr;
720
721 if (nLastAsked + 1 != static_cast<int>(nNum ))
722 {
723 // nCount = 0;
724 // nCountP = 0;
725 }
726 else
727 {
728 nCount = nLastCount + 1;
729 nCountP = nLastAsked + 1;
730 }
731
732 for(; nCount < pvpoChildren_->size(); nCount++)
733 {
734 if((*pvpoChildren_)[nCount]->sName_.compare("Placemark") == 0)
735 {
736 if(nCountP == nNum)
737 {
738 poFeat = (*pvpoChildren_)[nCount];
739 break;
740 }
741 nCountP++;
742 }
743 }
744
745 nLastAsked = static_cast<int>(nNum);
746 nLastCount = nCount;
747
748 if(poFeat == nullptr)
749 return nullptr;
750
751 // Create a feature structure
752 Feature *psReturn = new Feature;
753 // Build up the name
754 psReturn->sName = poFeat->getNameElement();
755 // Build up the description
756 psReturn->sDescription = poFeat->getDescriptionElement();
757 // the type
758 psReturn->eType = poFeat->eType_;
759
760 std::string sElementName;
761 if(poFeat->eType_ == Point ||
762 poFeat->eType_ == LineString ||
763 poFeat->eType_ == Polygon)
764 sElementName = Nodetype2String(poFeat->eType_);
765 else if (poFeat->eType_ == MultiGeometry ||
766 poFeat->eType_ == MultiPoint ||
767 poFeat->eType_ == MultiLineString ||
768 poFeat->eType_ == MultiPolygon)
769 sElementName = "MultiGeometry";
770 else
771 {
772 delete psReturn;
773 return nullptr;
774 }
775
776 for(nCount = 0; nCount < poFeat->pvpoChildren_->size(); nCount++)
777 {
778 if((*poFeat->pvpoChildren_)[nCount]->sName_.compare(sElementName) == 0)
779 {
780 poTemp = (*poFeat->pvpoChildren_)[nCount];
781 psReturn->poGeom = poTemp->getGeometry(poFeat->eType_);
782 if(psReturn->poGeom)
783 return psReturn;
784 else
785 {
786 delete psReturn;
787 return nullptr;
788 }
789 }
790 }
791
792 delete psReturn;
793 return nullptr;
794 }
795