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 : }
|