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