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