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