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 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : *****************************************************************************/
28 :
29 : #include <ogr_geometry.h>
30 : #include "ogr_p.h"
31 : #include <kml/dom.h>
32 :
33 : using kmldom::KmlFactory;
34 : using kmldom::CoordinatesPtr;
35 : using kmldom::PointPtr;
36 : using kmldom::LineStringPtr;
37 : using kmldom::LinearRingPtr;
38 : using kmldom::OuterBoundaryIsPtr;
39 : using kmldom::InnerBoundaryIsPtr;
40 : using kmldom::PolygonPtr;
41 : using kmldom::MultiGeometryPtr;
42 : using kmldom::GeometryPtr;
43 : using kmldom::ElementPtr;
44 : using kmldom::GeometryPtr;
45 :
46 : using kmlbase::Vec3;
47 :
48 : #include "ogrlibkmlgeometry.h"
49 :
50 : /******************************************************************************
51 : funtion to write out a ogr geometry to kml
52 :
53 : args:
54 : poOgrGeom the ogr geometry
55 : extra used in recursion, just pass -1
56 : wkb25D used in recursion, just pass 0
57 : poKmlFactory pointer to the libkml dom factory
58 :
59 : returns:
60 : ElementPtr to the geometry created
61 :
62 : ******************************************************************************/
63 :
64 138 : ElementPtr geom2kml (
65 : OGRGeometry * poOgrGeom,
66 : int extra,
67 : int wkb25D,
68 : KmlFactory * poKmlFactory )
69 : {
70 : int i;
71 :
72 138 : if ( !poOgrGeom ) {
73 0 : return NULL;
74 : }
75 :
76 : /***** ogr geom vars *****/
77 :
78 138 : OGRPoint *poOgrPoint = NULL;
79 : OGRLineString *poOgrLineString;
80 : OGRPolygon *poOgrPolygon;
81 : OGRGeometryCollection *poOgrMultiGeom;
82 :
83 : /***** libkml geom vars *****/
84 :
85 138 : CoordinatesPtr coordinates;
86 138 : PointPtr poKmlPoint;
87 138 : LineStringPtr poKmlLineString;
88 138 : LinearRingPtr poKmlLinearRing;
89 138 : OuterBoundaryIsPtr poKmlOuterRing;
90 138 : InnerBoundaryIsPtr poKmlInnerRing;
91 138 : PolygonPtr poKmlPolygon;
92 138 : MultiGeometryPtr poKmlMultiGeometry;
93 :
94 138 : ElementPtr poKmlGeometry;
95 138 : ElementPtr poKmlTmpGeometry;
96 :
97 : /***** other vars *****/
98 :
99 : double x,
100 : y,
101 : z;
102 :
103 138 : int numpoints = 0;
104 : int nGeom;
105 138 : int type = poOgrGeom->getGeometryType ( );
106 :
107 138 : wkb25D = type & wkb25DBit;
108 :
109 138 : switch ( type ) {
110 :
111 : case wkbPoint:
112 :
113 24 : poOgrPoint = ( OGRPoint * ) poOgrGeom;
114 24 : if (poOgrPoint->getCoordinateDimension() == 0)
115 : {
116 0 : poKmlGeometry = poKmlPoint = poKmlFactory->CreatePoint ( );
117 : }
118 : else
119 : {
120 24 : x = poOgrPoint->getX ( );
121 24 : y = poOgrPoint->getY ( );
122 :
123 24 : if ( x > 180 )
124 0 : x -= 360;
125 :
126 24 : coordinates = poKmlFactory->CreateCoordinates ( );
127 24 : coordinates->add_latlng ( y, x );
128 24 : poKmlGeometry = poKmlPoint = poKmlFactory->CreatePoint ( );
129 24 : poKmlPoint->set_coordinates ( coordinates );
130 : }
131 :
132 24 : break;
133 :
134 : case wkbPoint25D:
135 12 : poOgrPoint = ( OGRPoint * ) poOgrGeom;
136 :
137 12 : x = poOgrPoint->getX ( );
138 12 : y = poOgrPoint->getY ( );
139 12 : z = poOgrPoint->getZ ( );
140 :
141 12 : if ( x > 180 )
142 0 : x -= 360;
143 :
144 12 : coordinates = poKmlFactory->CreateCoordinates ( );
145 12 : coordinates->add_latlngalt ( y, x, z );
146 12 : poKmlGeometry = poKmlPoint = poKmlFactory->CreatePoint ( );
147 12 : poKmlPoint->set_coordinates ( coordinates );
148 :
149 12 : break;
150 :
151 : case wkbLineString:
152 24 : poOgrLineString = ( OGRLineString * ) poOgrGeom;
153 :
154 24 : coordinates = poKmlFactory->CreateCoordinates ( );
155 :
156 24 : numpoints = poOgrLineString->getNumPoints ( );
157 24 : poOgrPoint = new OGRPoint ( );
158 :
159 72 : for ( i = 0; i < numpoints; i++ ) {
160 48 : poOgrLineString->getPoint ( i, poOgrPoint );
161 :
162 48 : x = poOgrPoint->getX ( );
163 48 : y = poOgrPoint->getY ( );
164 :
165 48 : if ( x > 180 )
166 0 : x -= 360;
167 :
168 48 : coordinates->add_latlng ( y, x );
169 : }
170 24 : delete poOgrPoint;
171 :
172 : /***** check if its a wkbLinearRing *****/
173 :
174 24 : if ( extra < 0 ) {
175 :
176 : poKmlGeometry = poKmlLineString =
177 24 : poKmlFactory->CreateLineString ( );
178 24 : poKmlLineString->set_coordinates ( coordinates );
179 :
180 24 : break;
181 : }
182 :
183 : /***** fallthough *****/
184 :
185 : case wkbLinearRing: //this case is for readability only
186 :
187 0 : poKmlLinearRing = poKmlFactory->CreateLinearRing ( );
188 0 : poKmlLinearRing->set_coordinates ( coordinates );
189 :
190 0 : if ( !extra ) {
191 0 : poKmlOuterRing = poKmlFactory->CreateOuterBoundaryIs ( );
192 0 : poKmlOuterRing->set_linearring ( poKmlLinearRing );
193 0 : poKmlGeometry = poKmlOuterRing;
194 : }
195 : else {
196 : poKmlGeometry = poKmlInnerRing =
197 0 : poKmlFactory->CreateInnerBoundaryIs ( );
198 0 : poKmlInnerRing->set_linearring ( poKmlLinearRing );
199 : }
200 :
201 : case wkbLineString25D:
202 :
203 36 : poOgrLineString = ( OGRLineString * ) poOgrGeom;
204 :
205 36 : coordinates = poKmlFactory->CreateCoordinates ( );
206 36 : poOgrPoint = new OGRPoint ( );
207 72 : numpoints = poOgrLineString->getNumPoints ( );
208 180 : for ( i = 0; i < numpoints; i++ ) {
209 144 : poOgrLineString->getPoint ( i, poOgrPoint );
210 :
211 144 : x = poOgrPoint->getX ( );
212 144 : y = poOgrPoint->getY ( );
213 144 : z = poOgrPoint->getZ ( );
214 :
215 144 : if ( x > 180 )
216 0 : x -= 360;
217 :
218 144 : coordinates->add_latlngalt ( y, x, z );
219 : }
220 36 : delete poOgrPoint;
221 :
222 : /***** check if its a wkbLinearRing *****/
223 :
224 36 : if ( extra < 0 ) {
225 :
226 : poKmlGeometry = poKmlLineString =
227 0 : poKmlFactory->CreateLineString ( );
228 0 : poKmlLineString->set_coordinates ( coordinates );
229 :
230 0 : break;
231 : }
232 : /***** fallthough *****/
233 :
234 : //case wkbLinearRing25D: // this case is for readability only
235 :
236 36 : poKmlLinearRing = poKmlFactory->CreateLinearRing ( );
237 36 : poKmlLinearRing->set_coordinates ( coordinates );
238 :
239 36 : if ( !extra ) {
240 : poKmlGeometry = poKmlOuterRing =
241 18 : poKmlFactory->CreateOuterBoundaryIs ( );
242 18 : poKmlOuterRing->set_linearring ( poKmlLinearRing );
243 : }
244 : else {
245 : poKmlGeometry = poKmlInnerRing =
246 18 : poKmlFactory->CreateInnerBoundaryIs ( );
247 18 : poKmlInnerRing->set_linearring ( poKmlLinearRing );
248 : }
249 :
250 36 : break;
251 :
252 : case wkbPolygon:
253 :
254 0 : poOgrPolygon = ( OGRPolygon * ) poOgrGeom;
255 :
256 0 : poKmlGeometry = poKmlPolygon = poKmlFactory->CreatePolygon ( );
257 :
258 : poKmlTmpGeometry = geom2kml ( poOgrPolygon->getExteriorRing ( ),
259 0 : 0, wkb25D, poKmlFactory );
260 : poKmlPolygon->
261 0 : set_outerboundaryis ( AsOuterBoundaryIs ( poKmlTmpGeometry ) );
262 :
263 0 : nGeom = poOgrPolygon->getNumInteriorRings ( );
264 0 : for ( i = 0; i < nGeom; i++ ) {
265 : poKmlTmpGeometry = geom2kml ( poOgrPolygon->getInteriorRing ( i ),
266 0 : i + 1, wkb25D, poKmlFactory );
267 : poKmlPolygon->
268 0 : add_innerboundaryis ( AsInnerBoundaryIs ( poKmlTmpGeometry ) );
269 : }
270 :
271 0 : break;
272 :
273 : case wkbPolygon25D:
274 :
275 18 : poOgrPolygon = ( OGRPolygon * ) poOgrGeom;
276 :
277 18 : poKmlGeometry = poKmlPolygon = poKmlFactory->CreatePolygon ( );
278 :
279 : poKmlTmpGeometry = geom2kml ( poOgrPolygon->getExteriorRing ( ),
280 18 : 0, wkb25D, poKmlFactory );
281 : poKmlPolygon->
282 18 : set_outerboundaryis ( AsOuterBoundaryIs ( poKmlTmpGeometry ) );
283 :
284 18 : nGeom = poOgrPolygon->getNumInteriorRings ( );
285 36 : for ( i = 0; i < nGeom; i++ ) {
286 : poKmlTmpGeometry = geom2kml ( poOgrPolygon->getInteriorRing ( i ),
287 18 : i + 1, wkb25D, poKmlFactory );
288 : poKmlPolygon->
289 18 : add_innerboundaryis ( AsInnerBoundaryIs ( poKmlTmpGeometry ) );
290 : }
291 :
292 18 : break;
293 :
294 : case wkbMultiPoint:
295 : case wkbMultiLineString:
296 : case wkbMultiPolygon:
297 : case wkbGeometryCollection:
298 : case wkbMultiPoint25D:
299 : case wkbMultiLineString25D:
300 : case wkbMultiPolygon25D:
301 : case wkbGeometryCollection25D:
302 :
303 24 : poOgrMultiGeom = ( OGRGeometryCollection * ) poOgrGeom;
304 :
305 : poKmlGeometry = poKmlMultiGeometry =
306 24 : poKmlFactory->CreateMultiGeometry ( );
307 :
308 24 : nGeom = poOgrMultiGeom->getNumGeometries ( );
309 72 : for ( i = 0; i < nGeom; i++ ) {
310 : poKmlTmpGeometry = geom2kml ( poOgrMultiGeom->getGeometryRef ( i ),
311 48 : -1, wkb25D, poKmlFactory );
312 : poKmlMultiGeometry->
313 48 : add_geometry ( AsGeometry ( poKmlTmpGeometry ) );
314 : }
315 :
316 : break;
317 :
318 : case wkbUnknown:
319 : case wkbNone:
320 : default:
321 : break;
322 :
323 : }
324 :
325 138 : return poKmlGeometry;
326 : }
327 :
328 : /******************************************************************************
329 : recursive function to read a kml geometry and translate to ogr
330 :
331 : Args:
332 : poKmlGeometry pointer to the kml geometry to translate
333 : poOgrSRS pointer to the spatial ref to set on the geometry
334 :
335 : Returns:
336 : pointer to the new ogr geometry object
337 :
338 : ******************************************************************************/
339 :
340 882 : OGRGeometry *kml2geom_rec (
341 : GeometryPtr poKmlGeometry,
342 : OGRSpatialReference *poOgrSRS)
343 :
344 : {
345 :
346 : /***** ogr geom vars *****/
347 :
348 : OGRPoint *poOgrPoint;
349 : OGRLineString *poOgrLineString;
350 : OGRLinearRing *poOgrLinearRing;
351 : OGRPolygon *poOgrPolygon;
352 : OGRGeometryCollection *poOgrMultiGeometry;
353 882 : OGRGeometry *poOgrGeometry = NULL;
354 882 : OGRGeometry *poOgrTmpGeometry = NULL;
355 :
356 :
357 : /***** libkml geom vars *****/
358 :
359 882 : CoordinatesPtr poKmlCoordinates;
360 882 : PointPtr poKmlPoint;
361 882 : LineStringPtr poKmlLineString;
362 882 : LinearRingPtr poKmlLinearRing;
363 882 : OuterBoundaryIsPtr poKmlOuterRing;
364 882 : InnerBoundaryIsPtr poKmlInnerRing;
365 882 : PolygonPtr poKmlPolygon;
366 882 : MultiGeometryPtr poKmlMultiGeometry;
367 882 : GeometryPtr poKmlTmpGeometry;
368 :
369 882 : Vec3 oKmlVec;
370 :
371 : size_t nRings,
372 : nCoords,
373 : nGeom,
374 : i;
375 :
376 882 : switch ( poKmlGeometry->Type ( ) ) {
377 : case kmldom::Type_Point:
378 150 : poKmlPoint = AsPoint ( poKmlGeometry );
379 150 : if ( poKmlPoint->has_coordinates ( ) ) {
380 148 : poKmlCoordinates = poKmlPoint->get_coordinates ( );
381 148 : nCoords = poKmlCoordinates->get_coordinates_array_size ( );
382 148 : if (nCoords > 0)
383 : {
384 146 : oKmlVec = poKmlCoordinates->get_coordinates_array_at ( 0 );
385 :
386 146 : if ( oKmlVec.has_altitude ( ) )
387 : poOgrPoint = new OGRPoint ( oKmlVec.get_longitude ( ),
388 : oKmlVec.get_latitude ( ),
389 136 : oKmlVec.get_altitude ( ) );
390 : else
391 : poOgrPoint = new OGRPoint ( oKmlVec.get_longitude ( ),
392 10 : oKmlVec.get_latitude ( ) );
393 :
394 146 : poOgrGeometry = poOgrPoint;
395 : }
396 : else
397 : {
398 2 : poOgrGeometry = new OGRPoint();
399 : }
400 : }
401 : else
402 : {
403 2 : poOgrGeometry = new OGRPoint();
404 : }
405 :
406 150 : break;
407 :
408 : case kmldom::Type_LineString:
409 162 : poKmlLineString = AsLineString ( poKmlGeometry );
410 162 : poOgrLineString = new OGRLineString ( );
411 324 : if ( poKmlLineString->has_coordinates ( ) ) {
412 160 : poKmlCoordinates = poKmlLineString->get_coordinates ( );
413 :
414 160 : nCoords = poKmlCoordinates->get_coordinates_array_size ( );
415 1160 : for ( i = 0; i < nCoords; i++ ) {
416 1000 : oKmlVec = poKmlCoordinates->get_coordinates_array_at ( i );
417 1000 : if ( oKmlVec.has_altitude ( ) )
418 : poOgrLineString->
419 : addPoint ( oKmlVec.get_longitude ( ),
420 : oKmlVec.get_latitude ( ),
421 988 : oKmlVec.get_altitude ( ) );
422 : else
423 : poOgrLineString->
424 : addPoint ( oKmlVec.get_longitude ( ),
425 12 : oKmlVec.get_latitude ( ) );
426 : }
427 : }
428 162 : poOgrGeometry = poOgrLineString;
429 :
430 162 : break;
431 : case kmldom::Type_LinearRing:
432 292 : poKmlLinearRing = AsLinearRing ( poKmlGeometry );
433 292 : poOgrLinearRing = new OGRLinearRing ( );
434 584 : if ( poKmlLinearRing->has_coordinates ( ) ) {
435 286 : poKmlCoordinates = poKmlLinearRing->get_coordinates ( );
436 :
437 286 : nCoords = poKmlCoordinates->get_coordinates_array_size ( );
438 3516 : for ( i = 0; i < nCoords; i++ ) {
439 3230 : oKmlVec = poKmlCoordinates->get_coordinates_array_at ( i );
440 3230 : if ( oKmlVec.has_altitude ( ) )
441 : poOgrLinearRing->
442 : addPoint ( oKmlVec.get_longitude ( ),
443 : oKmlVec.get_latitude ( ),
444 3156 : oKmlVec.get_altitude ( ) );
445 : else
446 : poOgrLinearRing->
447 : addPoint ( oKmlVec.get_longitude ( ),
448 74 : oKmlVec.get_latitude ( ) );
449 : }
450 : }
451 292 : poOgrGeometry = poOgrLinearRing;
452 :
453 292 : break;
454 : case kmldom::Type_Polygon:
455 240 : poKmlPolygon = AsPolygon ( poKmlGeometry );
456 :
457 240 : poOgrPolygon = new OGRPolygon ( );
458 480 : if ( poKmlPolygon->has_outerboundaryis ( ) ) {
459 :
460 238 : poKmlOuterRing = poKmlPolygon->get_outerboundaryis ( );
461 238 : poKmlLinearRing = poKmlOuterRing->get_linearring ( );
462 238 : if (poKmlLinearRing)
463 : {
464 236 : poOgrTmpGeometry = kml2geom_rec ( poKmlLinearRing, poOgrSRS );
465 :
466 : poOgrPolygon->
467 236 : addRingDirectly ( ( OGRLinearRing * ) poOgrTmpGeometry );
468 : }
469 :
470 : }
471 240 : nRings = poKmlPolygon->get_innerboundaryis_array_size ( );
472 292 : for ( i = 0; i < nRings; i++ ) {
473 52 : poKmlInnerRing = poKmlPolygon->get_innerboundaryis_array_at ( i );
474 52 : poKmlLinearRing = poKmlInnerRing->get_linearring ( );
475 52 : if (poKmlLinearRing)
476 : {
477 50 : poOgrTmpGeometry = kml2geom_rec ( poKmlLinearRing, poOgrSRS );
478 :
479 : poOgrPolygon->
480 50 : addRingDirectly ( ( OGRLinearRing * ) poOgrTmpGeometry );
481 : }
482 : }
483 240 : poOgrGeometry = poOgrPolygon;
484 :
485 240 : break;
486 : case kmldom::Type_MultiGeometry:
487 : {
488 38 : poKmlMultiGeometry = AsMultiGeometry ( poKmlGeometry );
489 38 : nGeom = poKmlMultiGeometry->get_geometry_array_size ( );
490 :
491 : /* Detect subgeometry type to instanciate appropriate Multi geometry type */
492 38 : kmldom::KmlDomType type = kmldom::Type_Unknown;
493 92 : for ( i = 0; i < nGeom; i++ ) {
494 62 : poKmlTmpGeometry = poKmlMultiGeometry->get_geometry_array_at ( i );
495 62 : if (type == kmldom::Type_Unknown)
496 34 : type = poKmlTmpGeometry->Type();
497 28 : else if (type != poKmlTmpGeometry->Type())
498 : {
499 8 : type = kmldom::Type_Unknown;
500 8 : break;
501 : }
502 : }
503 :
504 38 : if (type == kmldom::Type_Point)
505 10 : poOgrMultiGeometry = new OGRMultiPoint();
506 28 : else if (type == kmldom::Type_LineString)
507 8 : poOgrMultiGeometry = new OGRMultiLineString();
508 20 : else if (type == kmldom::Type_Polygon)
509 8 : poOgrMultiGeometry = new OGRMultiPolygon();
510 : else
511 12 : poOgrMultiGeometry = new OGRGeometryCollection ();
512 :
513 100 : for ( i = 0; i < nGeom; i++ ) {
514 62 : poKmlTmpGeometry = poKmlMultiGeometry->get_geometry_array_at ( i );
515 62 : poOgrTmpGeometry = kml2geom_rec ( poKmlTmpGeometry, poOgrSRS );
516 :
517 62 : poOgrMultiGeometry->addGeometryDirectly ( poOgrTmpGeometry );
518 : }
519 38 : poOgrGeometry = poOgrMultiGeometry;
520 : break;
521 : }
522 : default:
523 : break;
524 : }
525 :
526 882 : if (poOgrGeometry)
527 882 : poOgrGeometry->assignSpatialReference(poOgrSRS);
528 :
529 882 : return poOgrGeometry;
530 : }
531 :
532 : /******************************************************************************
533 : main function to read a kml geometry and translate to ogr
534 :
535 : Args:
536 : poKmlGeometry pointer to the kml geometry to translate
537 : poOgrSRS pointer to the spatial ref to set on the geometry
538 :
539 : Returns:
540 : pointer to the new ogr geometry object
541 :
542 : ******************************************************************************/
543 :
544 534 : OGRGeometry *kml2geom (
545 : GeometryPtr poKmlGeometry,
546 : OGRSpatialReference *poOgrSRS)
547 :
548 : {
549 :
550 : /***** get the geometry *****/
551 :
552 534 : OGRGeometry *poOgrGeometry = kml2geom_rec (poKmlGeometry, poOgrSRS);
553 :
554 : /***** split the geometry at the dateline? *****/
555 :
556 534 : const char *pszWrap = CPLGetConfigOption ( "LIBKML_WRAPDATELINE", "no" );
557 534 : if (CSLTestBoolean(pszWrap)) {
558 :
559 0 : char **papszTransformOptions = NULL;
560 : papszTransformOptions = CSLAddString( papszTransformOptions,
561 0 : "WRAPDATELINE=YES");
562 :
563 : /***** transform *****/
564 :
565 : OGRGeometry *poOgrDstGeometry =
566 : OGRGeometryFactory::transformWithOptions(poOgrGeometry,
567 : NULL,
568 0 : papszTransformOptions);
569 :
570 : /***** replace the original geom *****/
571 :
572 0 : if (poOgrDstGeometry) {
573 0 : delete poOgrGeometry;
574 0 : poOgrGeometry = poOgrDstGeometry;
575 : }
576 :
577 0 : CSLDestroy(papszTransformOptions);
578 : }
579 :
580 534 : return poOgrGeometry;
581 : }
|