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