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