Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: KML Translator
4 : * Purpose: Implements OGRLIBKMLDriver
5 : * Author: Brian Case, rush at winkey dot org
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2010, Brian Case
9 : * Copyright (c) 2010-2014, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : *****************************************************************************/
13 :
14 : #include "libkml_headers.h"
15 :
16 : #include "ogr_geometry.h"
17 : #include "ogr_p.h"
18 : #include "ogrlibkmlgeometry.h"
19 :
20 : using kmlbase::Vec3;
21 : using kmldom::CoordinatesPtr;
22 : using kmldom::ElementPtr;
23 : using kmldom::GeometryPtr;
24 : using kmldom::GxLatLonQuadPtr;
25 : using kmldom::GxMultiTrackPtr;
26 : using kmldom::GxTrackPtr;
27 : using kmldom::InnerBoundaryIsPtr;
28 : using kmldom::KmlFactory;
29 : using kmldom::LatLonBoxPtr;
30 : using kmldom::LinearRingPtr;
31 : using kmldom::LineStringPtr;
32 : using kmldom::MultiGeometryPtr;
33 : using kmldom::OuterBoundaryIsPtr;
34 : using kmldom::PointPtr;
35 : using kmldom::PolygonPtr;
36 :
37 797 : static bool NormalizeLongLat(double &x, double &y)
38 : {
39 797 : if (x >= -180 && x <= 180)
40 : {
41 : // nominal
42 : }
43 6 : else if (x > 180 && x <= 180 + 360)
44 2 : x -= 360;
45 4 : else if (x < -180 && x >= -180 - 360)
46 2 : x += 360;
47 : else
48 : {
49 : const bool bStrictCompliance =
50 2 : CPLTestBool(CPLGetConfigOption("LIBKML_STRICT_COMPLIANCE", "TRUE"));
51 2 : CPLError(bStrictCompliance ? CE_Failure : CE_Warning, CPLE_AppDefined,
52 : "Invalid longitude %g", x);
53 2 : if (bStrictCompliance)
54 2 : return false;
55 : }
56 :
57 795 : constexpr double EPSILON = 1e-8;
58 795 : if (y >= -90 && y <= 90)
59 : {
60 : // nominal
61 : }
62 11 : else if (y > 90 && y < 90 + EPSILON)
63 : {
64 1 : y = 90;
65 : }
66 10 : else if (y < -90 && y > -90 - EPSILON)
67 : {
68 1 : y = -90;
69 : }
70 : else
71 : {
72 : const bool bStrictCompliance =
73 9 : CPLTestBool(CPLGetConfigOption("LIBKML_STRICT_COMPLIANCE", "TRUE"));
74 9 : CPLError(bStrictCompliance ? CE_Failure : CE_Warning, CPLE_AppDefined,
75 : "Invalid latitude %g", y);
76 9 : if (bStrictCompliance)
77 9 : return false;
78 : }
79 786 : return true;
80 : }
81 :
82 : /******************************************************************************
83 : Function to write out a ogr geometry to kml.
84 :
85 : Args:
86 : poOgrGeom the ogr geometry
87 : extra used in recursion, just pass -1
88 : poKmlFactory pointer to the libkml dom factory
89 :
90 : Returns:
91 : ElementPtr to the geometry created
92 :
93 : ******************************************************************************/
94 :
95 323 : ElementPtr geom2kml(OGRGeometry *poOgrGeom, int extra, KmlFactory *poKmlFactory)
96 : {
97 323 : if (!poOgrGeom)
98 : {
99 0 : return nullptr;
100 : }
101 :
102 : /***** libkml geom vars *****/
103 646 : CoordinatesPtr coordinates = nullptr;
104 :
105 : // This will be the return value.
106 646 : ElementPtr poKmlGeometry = nullptr;
107 :
108 : /***** Other vars *****/
109 323 : int numpoints = 0;
110 323 : const OGRwkbGeometryType type = poOgrGeom->getGeometryType();
111 :
112 323 : switch (type)
113 : {
114 64 : case wkbPoint:
115 : {
116 64 : const OGRPoint *poOgrPoint = poOgrGeom->toPoint();
117 64 : PointPtr poKmlPoint = nullptr;
118 64 : if (poOgrPoint->getCoordinateDimension() == 0)
119 : {
120 0 : poKmlPoint = poKmlFactory->CreatePoint();
121 0 : poKmlGeometry = poKmlPoint;
122 : }
123 : else
124 : {
125 64 : double x = poOgrPoint->getX();
126 64 : double y = poOgrPoint->getY();
127 :
128 64 : if (!NormalizeLongLat(x, y))
129 6 : return nullptr;
130 :
131 58 : coordinates = poKmlFactory->CreateCoordinates();
132 58 : coordinates->add_latlng(y, x);
133 58 : poKmlPoint = poKmlFactory->CreatePoint();
134 58 : poKmlGeometry = poKmlPoint;
135 58 : poKmlPoint->set_coordinates(coordinates);
136 : }
137 :
138 58 : break;
139 : }
140 26 : case wkbPoint25D:
141 : {
142 26 : const OGRPoint *poOgrPoint = poOgrGeom->toPoint();
143 :
144 26 : double x = poOgrPoint->getX();
145 26 : double y = poOgrPoint->getY();
146 26 : const double z = poOgrPoint->getZ();
147 :
148 26 : if (!NormalizeLongLat(x, y))
149 1 : return nullptr;
150 :
151 25 : coordinates = poKmlFactory->CreateCoordinates();
152 25 : coordinates->add_latlngalt(y, x, z);
153 50 : PointPtr poKmlPoint = poKmlFactory->CreatePoint();
154 25 : poKmlGeometry = poKmlPoint;
155 25 : poKmlPoint->set_coordinates(coordinates);
156 :
157 25 : break;
158 : }
159 53 : case wkbLineString:
160 : {
161 53 : OGRLineString *poOgrLineString = poOgrGeom->toLineString();
162 :
163 53 : if (extra >= 0)
164 : {
165 23 : poOgrGeom->toLinearRing()->closeRings();
166 : }
167 :
168 53 : numpoints = poOgrLineString->getNumPoints();
169 53 : if (extra >= 0)
170 : {
171 23 : if (numpoints < 4 && CPLTestBool(CPLGetConfigOption(
172 : "LIBKML_STRICT_COMPLIANCE", "TRUE")))
173 : {
174 0 : CPLError(CE_Failure, CPLE_NotSupported,
175 : "A linearring should have at least 4 points");
176 2 : return nullptr;
177 : }
178 : }
179 : else
180 : {
181 30 : if (numpoints < 2 && CPLTestBool(CPLGetConfigOption(
182 : "LIBKML_STRICT_COMPLIANCE", "TRUE")))
183 : {
184 0 : CPLError(CE_Failure, CPLE_NotSupported,
185 : "A linestring should have at least 2 points");
186 0 : return nullptr;
187 : }
188 : }
189 :
190 53 : coordinates = poKmlFactory->CreateCoordinates();
191 :
192 53 : OGRPoint point;
193 :
194 419 : for (int i = 0; i < numpoints; i++)
195 : {
196 368 : poOgrLineString->getPoint(i, &point);
197 :
198 368 : double x = point.getX();
199 368 : double y = point.getY();
200 :
201 368 : if (!NormalizeLongLat(x, y))
202 2 : return nullptr;
203 :
204 366 : coordinates->add_latlng(y, x);
205 : }
206 :
207 : /***** Check if its a wkbLinearRing *****/
208 51 : if (extra < 0)
209 : {
210 : LineStringPtr poKmlLineString =
211 58 : poKmlFactory->CreateLineString();
212 29 : poKmlGeometry = poKmlLineString;
213 29 : poKmlLineString->set_coordinates(coordinates);
214 :
215 29 : break;
216 : }
217 : [[fallthrough]];
218 : }
219 : /***** fallthrough *****/
220 :
221 : case wkbLinearRing: // This case is for readability only.
222 : {
223 44 : LinearRingPtr poKmlLinearRing = poKmlFactory->CreateLinearRing();
224 22 : poKmlLinearRing->set_coordinates(coordinates);
225 :
226 22 : if (!extra)
227 : {
228 : OuterBoundaryIsPtr poKmlOuterRing =
229 42 : poKmlFactory->CreateOuterBoundaryIs();
230 21 : poKmlOuterRing->set_linearring(poKmlLinearRing);
231 21 : poKmlGeometry = poKmlOuterRing;
232 : }
233 : else
234 : {
235 : InnerBoundaryIsPtr poKmlInnerRing =
236 2 : poKmlFactory->CreateInnerBoundaryIs();
237 1 : poKmlGeometry = poKmlInnerRing;
238 1 : poKmlInnerRing->set_linearring(poKmlLinearRing);
239 : }
240 :
241 22 : break;
242 : }
243 66 : case wkbLineString25D:
244 : {
245 66 : const OGRLineString *poOgrLineString = poOgrGeom->toLineString();
246 :
247 66 : if (extra >= 0)
248 : {
249 49 : poOgrGeom->toLinearRing()->closeRings();
250 : }
251 :
252 66 : numpoints = poOgrLineString->getNumPoints();
253 66 : if (extra >= 0)
254 : {
255 49 : if (numpoints < 4 && CPLTestBool(CPLGetConfigOption(
256 : "LIBKML_STRICT_COMPLIANCE", "TRUE")))
257 : {
258 0 : CPLError(CE_Failure, CPLE_NotSupported,
259 : "A linearring should have at least 4 points");
260 2 : return nullptr;
261 : }
262 : }
263 : else
264 : {
265 17 : if (numpoints < 2 && CPLTestBool(CPLGetConfigOption(
266 : "LIBKML_STRICT_COMPLIANCE", "TRUE")))
267 : {
268 0 : CPLError(CE_Failure, CPLE_NotSupported,
269 : "A linestring should have at least 2 points");
270 0 : return nullptr;
271 : }
272 : }
273 :
274 66 : coordinates = poKmlFactory->CreateCoordinates();
275 66 : OGRPoint point;
276 :
277 403 : for (int i = 0; i < numpoints; i++)
278 : {
279 339 : poOgrLineString->getPoint(i, &point);
280 :
281 339 : double x = point.getX();
282 339 : double y = point.getY();
283 339 : const double z = point.getZ();
284 :
285 339 : if (!NormalizeLongLat(x, y))
286 2 : return nullptr;
287 :
288 337 : coordinates->add_latlngalt(y, x, z);
289 : }
290 :
291 : /***** Check if its a wkbLinearRing *****/
292 64 : if (extra < 0)
293 : {
294 : LineStringPtr poKmlLineString =
295 32 : poKmlFactory->CreateLineString();
296 16 : poKmlGeometry = poKmlLineString;
297 16 : poKmlLineString->set_coordinates(coordinates);
298 :
299 16 : break;
300 : }
301 : /***** fallthrough *****/
302 :
303 : // case wkbLinearRing25D: // This case is for readability only.
304 :
305 96 : LinearRingPtr poKmlLinearRing = poKmlFactory->CreateLinearRing();
306 48 : poKmlLinearRing->set_coordinates(coordinates);
307 :
308 48 : if (!extra)
309 : {
310 : OuterBoundaryIsPtr poKmlOuterRing =
311 70 : poKmlFactory->CreateOuterBoundaryIs();
312 35 : poKmlGeometry = poKmlOuterRing;
313 35 : poKmlOuterRing->set_linearring(poKmlLinearRing);
314 : }
315 : else
316 : {
317 : InnerBoundaryIsPtr poKmlInnerRing =
318 26 : poKmlFactory->CreateInnerBoundaryIs();
319 13 : poKmlGeometry = poKmlInnerRing;
320 13 : poKmlInnerRing->set_linearring(poKmlLinearRing);
321 : }
322 :
323 48 : break;
324 : }
325 23 : case wkbPolygon:
326 : {
327 23 : if (CPLTestBool(
328 46 : CPLGetConfigOption("LIBKML_STRICT_COMPLIANCE", "TRUE")) &&
329 23 : OGRGeometryFactory::haveGEOS())
330 : {
331 23 : std::string osReason;
332 23 : if (!poOgrGeom->IsValid(&osReason))
333 : {
334 2 : CPLError(
335 : CE_Failure, CPLE_NotSupported, "Invalid polygon %s: %s",
336 2 : poOgrGeom->exportToWkt().c_str(), osReason.c_str());
337 1 : return nullptr;
338 : }
339 : }
340 :
341 22 : PolygonPtr poKmlPolygon = poKmlFactory->CreatePolygon();
342 22 : poKmlGeometry = poKmlPolygon;
343 :
344 22 : OGRPolygon *poOgrPolygon = poOgrGeom->toPolygon();
345 : ElementPtr poKmlTmpGeometry =
346 22 : geom2kml(poOgrPolygon->getExteriorRing(), 0, poKmlFactory);
347 22 : if (!poKmlTmpGeometry)
348 1 : return nullptr;
349 42 : poKmlPolygon->set_outerboundaryis(
350 42 : AsOuterBoundaryIs(poKmlTmpGeometry));
351 :
352 21 : const int nGeom = poOgrPolygon->getNumInteriorRings();
353 22 : for (int i = 0; i < nGeom; i++)
354 : {
355 2 : poKmlTmpGeometry = geom2kml(poOgrPolygon->getInteriorRing(i),
356 1 : i + 1, poKmlFactory);
357 1 : if (!poKmlTmpGeometry)
358 0 : return nullptr;
359 2 : poKmlPolygon->add_innerboundaryis(
360 2 : AsInnerBoundaryIs(poKmlTmpGeometry));
361 : }
362 :
363 21 : break;
364 : }
365 37 : case wkbPolygon25D:
366 : {
367 37 : if (CPLTestBool(
368 74 : CPLGetConfigOption("LIBKML_STRICT_COMPLIANCE", "TRUE")) &&
369 37 : OGRGeometryFactory::haveGEOS())
370 : {
371 37 : std::string osReason;
372 37 : if (!poOgrGeom->IsValid(&osReason))
373 : {
374 2 : CPLError(
375 : CE_Failure, CPLE_NotSupported, "Invalid polygon %s: %s",
376 2 : poOgrGeom->exportToWkt().c_str(), osReason.c_str());
377 1 : return nullptr;
378 : }
379 : }
380 :
381 36 : PolygonPtr poKmlPolygon = poKmlFactory->CreatePolygon();
382 36 : poKmlGeometry = poKmlPolygon;
383 :
384 36 : OGRPolygon *poOgrPolygon = poOgrGeom->toPolygon();
385 : ElementPtr poKmlTmpGeometry =
386 36 : geom2kml(poOgrPolygon->getExteriorRing(), 0, poKmlFactory);
387 36 : if (!poKmlTmpGeometry)
388 1 : return nullptr;
389 70 : poKmlPolygon->set_outerboundaryis(
390 70 : AsOuterBoundaryIs(poKmlTmpGeometry));
391 :
392 35 : const int nGeom = poOgrPolygon->getNumInteriorRings();
393 48 : for (int i = 0; i < nGeom; i++)
394 : {
395 26 : poKmlTmpGeometry = geom2kml(poOgrPolygon->getInteriorRing(i),
396 13 : i + 1, poKmlFactory);
397 13 : if (!poKmlTmpGeometry)
398 0 : return nullptr;
399 26 : poKmlPolygon->add_innerboundaryis(
400 26 : AsInnerBoundaryIs(poKmlTmpGeometry));
401 : }
402 :
403 35 : break;
404 : }
405 54 : case wkbMultiPoint:
406 : case wkbMultiLineString:
407 : case wkbMultiPolygon:
408 : case wkbGeometryCollection:
409 : case wkbMultiPoint25D:
410 : case wkbMultiLineString25D:
411 : case wkbMultiPolygon25D:
412 : case wkbGeometryCollection25D:
413 : {
414 : OGRGeometryCollection *poOgrMultiGeom =
415 54 : poOgrGeom->toGeometryCollection();
416 :
417 54 : const int nGeom = poOgrMultiGeom->getNumGeometries();
418 :
419 54 : if (nGeom == 1 && CPLTestBool(CPLGetConfigOption(
420 : "LIBKML_STRICT_COMPLIANCE", "TRUE")))
421 : {
422 21 : CPLDebug("LIBKML",
423 : "Turning multiple geometry into single geometry");
424 42 : poKmlGeometry = geom2kml(poOgrMultiGeom->getGeometryRef(0), -1,
425 21 : poKmlFactory);
426 21 : if (!poKmlGeometry)
427 1 : return nullptr;
428 : }
429 : else
430 : {
431 33 : if (nGeom == 0 && CPLTestBool(CPLGetConfigOption(
432 : "LIBKML_STRICT_COMPLIANCE", "TRUE")))
433 : {
434 1 : CPLError(CE_Warning, CPLE_AppDefined,
435 : "Empty multi geometry are not recommended");
436 : }
437 :
438 : MultiGeometryPtr poKmlMultiGeometry =
439 33 : poKmlFactory->CreateMultiGeometry();
440 33 : poKmlGeometry = poKmlMultiGeometry;
441 :
442 102 : for (int i = 0; i < nGeom; i++)
443 : {
444 : ElementPtr poKmlTmpGeometry = geom2kml(
445 70 : poOgrMultiGeom->getGeometryRef(i), -1, poKmlFactory);
446 70 : if (!poKmlTmpGeometry)
447 1 : return nullptr;
448 138 : poKmlMultiGeometry->add_geometry(
449 138 : AsGeometry(std::move(poKmlTmpGeometry)));
450 : }
451 : }
452 :
453 52 : break;
454 : }
455 0 : case wkbUnknown:
456 : case wkbNone:
457 : default:
458 0 : break;
459 : }
460 :
461 306 : return poKmlGeometry;
462 : }
463 :
464 : /******************************************************************************
465 : Recursive function to read a kml geometry and translate to ogr.
466 :
467 : Args:
468 : poKmlGeometry pointer to the kml geometry to translate
469 : poOgrSRS pointer to the spatial ref to set on the geometry
470 :
471 : Returns:
472 : pointer to the new ogr geometry object
473 :
474 : ******************************************************************************/
475 :
476 2091 : static OGRGeometry *kml2geom_rec(const GeometryPtr &poKmlGeometry,
477 : OGRSpatialReference *poOgrSRS)
478 : {
479 : /***** ogr geom vars *****/
480 2091 : OGRPoint *poOgrPoint = nullptr;
481 2091 : OGRLineString *poOgrLineString = nullptr;
482 2091 : OGRLinearRing *poOgrLinearRing = nullptr;
483 2091 : OGRPolygon *poOgrPolygon = nullptr;
484 2091 : OGRGeometryCollection *poOgrMultiGeometry = nullptr;
485 2091 : OGRGeometry *poOgrGeometry = nullptr;
486 2091 : OGRGeometry *poOgrTmpGeometry = nullptr;
487 :
488 2091 : switch (poKmlGeometry->Type())
489 : {
490 221 : case kmldom::Type_Point:
491 : {
492 442 : PointPtr poKmlPoint = AsPoint(poKmlGeometry);
493 221 : if (poKmlPoint->has_coordinates())
494 : {
495 440 : CoordinatesPtr poKmlCoordinates = poKmlPoint->get_coordinates();
496 : const size_t nCoords =
497 220 : poKmlCoordinates->get_coordinates_array_size();
498 220 : if (nCoords > 0)
499 : {
500 : const Vec3 oKmlVec =
501 219 : poKmlCoordinates->get_coordinates_array_at(0);
502 :
503 219 : if (oKmlVec.has_altitude())
504 422 : poOgrPoint = new OGRPoint(oKmlVec.get_longitude(),
505 211 : oKmlVec.get_latitude(),
506 211 : oKmlVec.get_altitude());
507 : else
508 16 : poOgrPoint = new OGRPoint(oKmlVec.get_longitude(),
509 8 : oKmlVec.get_latitude());
510 :
511 219 : poOgrGeometry = poOgrPoint;
512 : }
513 : else
514 : {
515 1 : poOgrGeometry = new OGRPoint();
516 : }
517 : }
518 : else
519 : {
520 1 : poOgrGeometry = new OGRPoint();
521 : }
522 :
523 221 : break;
524 : }
525 247 : case kmldom::Type_LineString:
526 : {
527 494 : LineStringPtr poKmlLineString = AsLineString(poKmlGeometry);
528 247 : poOgrLineString = new OGRLineString();
529 247 : if (poKmlLineString->has_coordinates())
530 : {
531 : CoordinatesPtr poKmlCoordinates =
532 492 : poKmlLineString->get_coordinates();
533 :
534 : const size_t nCoords =
535 246 : poKmlCoordinates->get_coordinates_array_size();
536 1922 : for (size_t i = 0; i < nCoords; i++)
537 : {
538 : const Vec3 oKmlVec =
539 1676 : poKmlCoordinates->get_coordinates_array_at(i);
540 1676 : if (oKmlVec.has_altitude())
541 1668 : poOgrLineString->addPoint(oKmlVec.get_longitude(),
542 : oKmlVec.get_latitude(),
543 : oKmlVec.get_altitude());
544 : else
545 8 : poOgrLineString->addPoint(oKmlVec.get_longitude(),
546 : oKmlVec.get_latitude());
547 : }
548 : }
549 247 : poOgrGeometry = poOgrLineString;
550 :
551 247 : break;
552 : }
553 824 : case kmldom::Type_LinearRing:
554 : {
555 1648 : LinearRingPtr poKmlLinearRing = AsLinearRing(poKmlGeometry);
556 824 : poOgrLinearRing = new OGRLinearRing();
557 824 : if (poKmlLinearRing->has_coordinates())
558 : {
559 : CoordinatesPtr poKmlCoordinates =
560 1642 : poKmlLinearRing->get_coordinates();
561 :
562 : const size_t nCoords =
563 821 : poKmlCoordinates->get_coordinates_array_size();
564 16037 : for (size_t i = 0; i < nCoords; i++)
565 : {
566 : const Vec3 oKmlVec =
567 15216 : poKmlCoordinates->get_coordinates_array_at(i);
568 15216 : if (oKmlVec.has_altitude())
569 15174 : poOgrLinearRing->addPoint(oKmlVec.get_longitude(),
570 : oKmlVec.get_latitude(),
571 : oKmlVec.get_altitude());
572 : else
573 42 : poOgrLinearRing->addPoint(oKmlVec.get_longitude(),
574 : oKmlVec.get_latitude());
575 : }
576 : }
577 824 : poOgrGeometry = poOgrLinearRing;
578 :
579 824 : break;
580 : }
581 768 : case kmldom::Type_Polygon:
582 : {
583 1536 : PolygonPtr poKmlPolygon = AsPolygon(poKmlGeometry);
584 :
585 768 : poOgrPolygon = new OGRPolygon();
586 768 : if (poKmlPolygon->has_outerboundaryis())
587 : {
588 : OuterBoundaryIsPtr poKmlOuterRing =
589 1534 : poKmlPolygon->get_outerboundaryis();
590 : LinearRingPtr poKmlLinearRing =
591 1534 : poKmlOuterRing->get_linearring();
592 767 : if (poKmlLinearRing)
593 : {
594 766 : poOgrTmpGeometry = kml2geom_rec(poKmlLinearRing, poOgrSRS);
595 :
596 1532 : poOgrPolygon->addRingDirectly(
597 766 : poOgrTmpGeometry->toLinearRing());
598 : }
599 : }
600 : const size_t nRings =
601 768 : poKmlPolygon->get_innerboundaryis_array_size();
602 824 : for (size_t i = 0; i < nRings; i++)
603 : {
604 : InnerBoundaryIsPtr poKmlInnerRing =
605 112 : poKmlPolygon->get_innerboundaryis_array_at(i);
606 : LinearRingPtr poKmlLinearRing =
607 112 : poKmlInnerRing->get_linearring();
608 56 : if (poKmlLinearRing)
609 : {
610 55 : poOgrTmpGeometry = kml2geom_rec(poKmlLinearRing, poOgrSRS);
611 :
612 110 : poOgrPolygon->addRingDirectly(
613 55 : poOgrTmpGeometry->toLinearRing());
614 : }
615 : }
616 768 : poOgrGeometry = poOgrPolygon;
617 :
618 768 : break;
619 : }
620 28 : case kmldom::Type_MultiGeometry:
621 : {
622 : MultiGeometryPtr poKmlMultiGeometry =
623 56 : AsMultiGeometry(poKmlGeometry);
624 28 : const size_t nGeom = poKmlMultiGeometry->get_geometry_array_size();
625 :
626 : // Detect subgeometry type to instantiate appropriate
627 : // multi geometry type.
628 28 : kmldom::KmlDomType type = kmldom::Type_Unknown;
629 67 : for (size_t i = 0; i < nGeom; i++)
630 : {
631 : GeometryPtr poKmlTmpGeometry =
632 44 : poKmlMultiGeometry->get_geometry_array_at(i);
633 44 : if (type == kmldom::Type_Unknown)
634 : {
635 25 : type = poKmlTmpGeometry->Type();
636 : }
637 19 : else if (type != poKmlTmpGeometry->Type())
638 : {
639 5 : type = kmldom::Type_Unknown;
640 5 : break;
641 : }
642 : }
643 :
644 28 : if (type == kmldom::Type_Point)
645 8 : poOgrMultiGeometry = new OGRMultiPoint();
646 20 : else if (type == kmldom::Type_LineString)
647 6 : poOgrMultiGeometry = new OGRMultiLineString();
648 14 : else if (type == kmldom::Type_Polygon)
649 6 : poOgrMultiGeometry = new OGRMultiPolygon();
650 : else
651 8 : poOgrMultiGeometry = new OGRGeometryCollection();
652 :
653 72 : for (size_t i = 0; i < nGeom; i++)
654 : {
655 : GeometryPtr poKmlTmpGeometry =
656 88 : poKmlMultiGeometry->get_geometry_array_at(i);
657 44 : poOgrTmpGeometry = kml2geom_rec(poKmlTmpGeometry, poOgrSRS);
658 :
659 44 : poOgrMultiGeometry->addGeometryDirectly(poOgrTmpGeometry);
660 : }
661 28 : poOgrGeometry = poOgrMultiGeometry;
662 28 : break;
663 : }
664 2 : case kmldom::Type_GxTrack:
665 : {
666 4 : GxTrackPtr poKmlGxTrack = AsGxTrack(poKmlGeometry);
667 : #if defined(__GNUC__)
668 : #pragma GCC diagnostic push
669 : #pragma GCC diagnostic ignored "-Wnull-dereference"
670 : #endif
671 2 : const size_t nCoords = poKmlGxTrack->get_gx_coord_array_size();
672 : #if defined(__GNUC__)
673 : #pragma GCC diagnostic pop
674 : #endif
675 2 : poOgrLineString = new OGRLineString();
676 11 : for (size_t i = 0; i < nCoords; i++)
677 : {
678 9 : const Vec3 oKmlVec = poKmlGxTrack->get_gx_coord_array_at(i);
679 9 : if (oKmlVec.has_altitude())
680 7 : poOgrLineString->addPoint(oKmlVec.get_longitude(),
681 : oKmlVec.get_latitude(),
682 : oKmlVec.get_altitude());
683 : else
684 2 : poOgrLineString->addPoint(oKmlVec.get_longitude(),
685 : oKmlVec.get_latitude());
686 : }
687 2 : poOgrGeometry = poOgrLineString;
688 2 : break;
689 : }
690 1 : case kmldom::Type_GxMultiTrack:
691 : {
692 2 : GxMultiTrackPtr poKmlGxMultiTrack = AsGxMultiTrack(poKmlGeometry);
693 : #if defined(__GNUC__)
694 : #pragma GCC diagnostic push
695 : #pragma GCC diagnostic ignored "-Wnull-dereference"
696 : #endif
697 1 : const size_t nGeom = poKmlGxMultiTrack->get_gx_track_array_size();
698 : #if defined(__GNUC__)
699 : #pragma GCC diagnostic pop
700 : #endif
701 1 : poOgrMultiGeometry = new OGRMultiLineString();
702 2 : for (size_t j = 0; j < nGeom; j++)
703 : {
704 : GxTrackPtr poKmlGxTrack =
705 2 : poKmlGxMultiTrack->get_gx_track_array_at(j);
706 1 : const size_t nCoords = poKmlGxTrack->get_gx_coord_array_size();
707 1 : poOgrLineString = new OGRLineString();
708 3 : for (size_t i = 0; i < nCoords; i++)
709 : {
710 2 : const Vec3 oKmlVec = poKmlGxTrack->get_gx_coord_array_at(i);
711 2 : if (oKmlVec.has_altitude())
712 0 : poOgrLineString->addPoint(oKmlVec.get_longitude(),
713 : oKmlVec.get_latitude(),
714 : oKmlVec.get_altitude());
715 : else
716 2 : poOgrLineString->addPoint(oKmlVec.get_longitude(),
717 : oKmlVec.get_latitude());
718 : }
719 1 : poOgrMultiGeometry->addGeometryDirectly(poOgrLineString);
720 : }
721 1 : poOgrGeometry = poOgrMultiGeometry;
722 1 : break;
723 : }
724 :
725 0 : default:
726 : {
727 0 : break;
728 : }
729 : }
730 :
731 2091 : if (poOgrGeometry)
732 2091 : poOgrGeometry->assignSpatialReference(poOgrSRS);
733 :
734 2091 : return poOgrGeometry;
735 : }
736 :
737 44 : static OGRGeometry *kml2geom_latlonbox_int(const LatLonBoxPtr &poKmlLatLonBox,
738 : OGRSpatialReference *poOgrSRS)
739 : {
740 88 : if (!poKmlLatLonBox->has_north() || !poKmlLatLonBox->has_south() ||
741 88 : !poKmlLatLonBox->has_east() || !poKmlLatLonBox->has_west())
742 : {
743 0 : return nullptr;
744 : }
745 44 : const double north = poKmlLatLonBox->get_north();
746 44 : const double south = poKmlLatLonBox->get_south();
747 44 : const double east = poKmlLatLonBox->get_east();
748 44 : const double west = poKmlLatLonBox->get_west();
749 :
750 44 : OGRLinearRing *poOgrRing = new OGRLinearRing();
751 44 : poOgrRing->addPoint(east, north, 0.0);
752 44 : poOgrRing->addPoint(east, south, 0.0);
753 44 : poOgrRing->addPoint(west, south, 0.0);
754 44 : poOgrRing->addPoint(west, north, 0.0);
755 44 : poOgrRing->addPoint(east, north, 0.0);
756 :
757 44 : OGRPolygon *poOgrPolygon = new OGRPolygon();
758 44 : poOgrPolygon->addRingDirectly(poOgrRing);
759 44 : poOgrPolygon->assignSpatialReference(poOgrSRS);
760 :
761 44 : return poOgrPolygon;
762 : }
763 :
764 : static OGRGeometry *
765 0 : kml2geom_latlonquad_int(const GxLatLonQuadPtr &poKmlLatLonQuad,
766 : OGRSpatialReference *poOgrSRS)
767 : {
768 0 : if (!poKmlLatLonQuad->has_coordinates())
769 0 : return nullptr;
770 :
771 0 : const CoordinatesPtr &poKmlCoordinates = poKmlLatLonQuad->get_coordinates();
772 :
773 0 : OGRLinearRing *poOgrLinearRing = new OGRLinearRing();
774 :
775 0 : size_t nCoords = poKmlCoordinates->get_coordinates_array_size();
776 0 : for (size_t i = 0; i < nCoords; i++)
777 : {
778 0 : Vec3 oKmlVec = poKmlCoordinates->get_coordinates_array_at(i);
779 0 : if (oKmlVec.has_altitude())
780 0 : poOgrLinearRing->addPoint(oKmlVec.get_longitude(),
781 : oKmlVec.get_latitude(),
782 : oKmlVec.get_altitude());
783 : else
784 0 : poOgrLinearRing->addPoint(oKmlVec.get_longitude(),
785 : oKmlVec.get_latitude());
786 : }
787 0 : poOgrLinearRing->closeRings();
788 :
789 0 : OGRPolygon *poOgrPolygon = new OGRPolygon();
790 0 : poOgrPolygon->addRingDirectly(poOgrLinearRing);
791 0 : poOgrPolygon->assignSpatialReference(poOgrSRS);
792 :
793 0 : return poOgrPolygon;
794 : }
795 :
796 : /******************************************************************************
797 : Main function to read a kml geometry and translate to ogr.
798 :
799 : Args:
800 : poKmlGeometry pointer to the kml geometry to translate
801 : poOgrSRS pointer to the spatial ref to set on the geometry
802 :
803 : Returns:
804 : pointer to the new ogr geometry object
805 :
806 : ******************************************************************************/
807 :
808 1226 : OGRGeometry *kml2geom(GeometryPtr poKmlGeometry, OGRSpatialReference *poOgrSRS)
809 : {
810 : /***** Get the geometry *****/
811 : OGRGeometry *poOgrGeometry =
812 1226 : kml2geom_rec(std::move(poKmlGeometry), poOgrSRS);
813 :
814 : /***** Split the geometry at the dateline? *****/
815 1226 : const char *pszWrap = CPLGetConfigOption("LIBKML_WRAPDATELINE", "no");
816 1226 : if (!CPLTestBool(pszWrap))
817 1226 : return poOgrGeometry;
818 :
819 0 : char **papszTransformOptions = CSLAddString(nullptr, "WRAPDATELINE=YES");
820 :
821 : /***** Transform *****/
822 0 : OGRGeometry *poOgrDstGeometry = OGRGeometryFactory::transformWithOptions(
823 : poOgrGeometry, nullptr, papszTransformOptions);
824 :
825 : /***** Replace the original geom *****/
826 0 : if (poOgrDstGeometry)
827 : {
828 0 : delete poOgrGeometry;
829 0 : poOgrGeometry = poOgrDstGeometry;
830 : }
831 :
832 0 : CSLDestroy(papszTransformOptions);
833 :
834 0 : return poOgrGeometry;
835 : }
836 :
837 44 : OGRGeometry *kml2geom_latlonbox(LatLonBoxPtr poKmlLatLonBox,
838 : OGRSpatialReference *poOgrSRS)
839 : {
840 : /***** Get the geometry *****/
841 : OGRGeometry *poOgrGeometry =
842 44 : kml2geom_latlonbox_int(poKmlLatLonBox, poOgrSRS);
843 :
844 : /***** Split the geometry at the dateline? *****/
845 44 : const char *pszWrap = CPLGetConfigOption("LIBKML_WRAPDATELINE", "no");
846 :
847 44 : if (!CPLTestBool(pszWrap))
848 44 : return poOgrGeometry;
849 :
850 0 : char **papszTransformOptions = CSLAddString(nullptr, "WRAPDATELINE=YES");
851 :
852 : /***** Transform *****/
853 0 : OGRGeometry *poOgrDstGeometry = OGRGeometryFactory::transformWithOptions(
854 : poOgrGeometry, nullptr, papszTransformOptions);
855 :
856 : /***** Replace the original geom *****/
857 0 : if (poOgrDstGeometry)
858 : {
859 0 : delete poOgrGeometry;
860 0 : poOgrGeometry = poOgrDstGeometry;
861 : }
862 :
863 0 : CSLDestroy(papszTransformOptions);
864 :
865 0 : return poOgrGeometry;
866 : }
867 :
868 0 : OGRGeometry *kml2geom_latlonquad(GxLatLonQuadPtr poKmlLatLonQuad,
869 : OGRSpatialReference *poOgrSRS)
870 : {
871 : /***** Get the geometry *****/
872 : OGRGeometry *poOgrGeometry =
873 0 : kml2geom_latlonquad_int(poKmlLatLonQuad, poOgrSRS);
874 :
875 : /***** Split the geometry at the dateline? *****/
876 0 : const char *pszWrap = CPLGetConfigOption("LIBKML_WRAPDATELINE", "no");
877 0 : if (!CPLTestBool(pszWrap))
878 0 : return poOgrGeometry;
879 :
880 0 : char **papszTransformOptions = CSLAddString(nullptr, "WRAPDATELINE=YES");
881 :
882 : /***** Transform *****/
883 0 : OGRGeometry *poOgrDstGeometry = OGRGeometryFactory::transformWithOptions(
884 : poOgrGeometry, nullptr, papszTransformOptions);
885 :
886 : /***** Replace the original geom *****/
887 0 : if (poOgrDstGeometry)
888 : {
889 0 : delete poOgrGeometry;
890 0 : poOgrGeometry = poOgrDstGeometry;
891 : }
892 :
893 0 : CSLDestroy(papszTransformOptions);
894 :
895 0 : return poOgrGeometry;
896 : }
|