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