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 69 : ElementPtr geom2kml (
65 : OGRGeometry * poOgrGeom,
66 : int extra,
67 : int wkb25D,
68 : KmlFactory * poKmlFactory )
69 : {
70 : int i;
71 :
72 69 : if ( !poOgrGeom ) {
73 0 : return NULL;
74 : }
75 :
76 : /***** ogr geom vars *****/
77 :
78 69 : OGRPoint *poOgrPoint = NULL;
79 : OGRLineString *poOgrLineString;
80 : OGRPolygon *poOgrPolygon;
81 : OGRGeometryCollection *poOgrMultiGeom;
82 :
83 : /***** libkml geom vars *****/
84 :
85 69 : CoordinatesPtr coordinates;
86 69 : PointPtr poKmlPoint;
87 69 : LineStringPtr poKmlLineString;
88 69 : LinearRingPtr poKmlLinearRing;
89 69 : OuterBoundaryIsPtr poKmlOuterRing;
90 69 : InnerBoundaryIsPtr poKmlInnerRing;
91 69 : PolygonPtr poKmlPolygon;
92 69 : MultiGeometryPtr poKmlMultiGeometry;
93 :
94 69 : ElementPtr poKmlGeometry;
95 69 : ElementPtr poKmlTmpGeometry;
96 :
97 : /***** other vars *****/
98 :
99 : double x,
100 : y,
101 : z;
102 :
103 69 : int numpoints = 0;
104 : int nGeom;
105 69 : int type = poOgrGeom->getGeometryType ( );
106 :
107 69 : wkb25D = type & wkb25DBit;
108 :
109 69 : switch ( type ) {
110 :
111 : case wkbPoint:
112 :
113 12 : poOgrPoint = ( OGRPoint * ) poOgrGeom;
114 12 : if (poOgrPoint->getCoordinateDimension() == 0)
115 : {
116 0 : poKmlGeometry = poKmlPoint = poKmlFactory->CreatePoint ( );
117 : }
118 : else
119 : {
120 12 : x = poOgrPoint->getX ( );
121 12 : y = poOgrPoint->getY ( );
122 :
123 12 : if ( x > 180 )
124 0 : x -= 360;
125 :
126 12 : coordinates = poKmlFactory->CreateCoordinates ( );
127 12 : coordinates->add_latlng ( y, x );
128 12 : poKmlGeometry = poKmlPoint = poKmlFactory->CreatePoint ( );
129 12 : poKmlPoint->set_coordinates ( coordinates );
130 : }
131 :
132 12 : break;
133 :
134 : case wkbPoint25D:
135 6 : poOgrPoint = ( OGRPoint * ) poOgrGeom;
136 :
137 6 : x = poOgrPoint->getX ( );
138 6 : y = poOgrPoint->getY ( );
139 6 : z = poOgrPoint->getZ ( );
140 :
141 6 : if ( x > 180 )
142 0 : x -= 360;
143 :
144 6 : coordinates = poKmlFactory->CreateCoordinates ( );
145 6 : coordinates->add_latlngalt ( y, x, z );
146 6 : poKmlGeometry = poKmlPoint = poKmlFactory->CreatePoint ( );
147 6 : poKmlPoint->set_coordinates ( coordinates );
148 :
149 6 : break;
150 :
151 : case wkbLineString:
152 12 : poOgrLineString = ( OGRLineString * ) poOgrGeom;
153 :
154 12 : coordinates = poKmlFactory->CreateCoordinates ( );
155 :
156 12 : numpoints = poOgrLineString->getNumPoints ( );
157 12 : poOgrPoint = new OGRPoint ( );
158 :
159 36 : for ( i = 0; i < numpoints; i++ ) {
160 24 : poOgrLineString->getPoint ( i, poOgrPoint );
161 :
162 24 : x = poOgrPoint->getX ( );
163 24 : y = poOgrPoint->getY ( );
164 :
165 24 : if ( x > 180 )
166 0 : x -= 360;
167 :
168 24 : coordinates->add_latlng ( y, x );
169 : }
170 12 : delete poOgrPoint;
171 :
172 : /***** check if its a wkbLinearRing *****/
173 :
174 12 : if ( extra < 0 ) {
175 :
176 : poKmlGeometry = poKmlLineString =
177 12 : poKmlFactory->CreateLineString ( );
178 12 : poKmlLineString->set_coordinates ( coordinates );
179 :
180 12 : 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 18 : poOgrLineString = ( OGRLineString * ) poOgrGeom;
204 :
205 18 : coordinates = poKmlFactory->CreateCoordinates ( );
206 18 : poOgrPoint = new OGRPoint ( );
207 36 : numpoints = poOgrLineString->getNumPoints ( );
208 90 : for ( i = 0; i < numpoints; i++ ) {
209 72 : poOgrLineString->getPoint ( i, poOgrPoint );
210 :
211 72 : x = poOgrPoint->getX ( );
212 72 : y = poOgrPoint->getY ( );
213 72 : z = poOgrPoint->getZ ( );
214 :
215 72 : if ( x > 180 )
216 0 : x -= 360;
217 :
218 72 : coordinates->add_latlngalt ( y, x, z );
219 : }
220 18 : delete poOgrPoint;
221 :
222 : /***** check if its a wkbLinearRing *****/
223 :
224 18 : 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 18 : poKmlLinearRing = poKmlFactory->CreateLinearRing ( );
237 18 : poKmlLinearRing->set_coordinates ( coordinates );
238 :
239 18 : if ( !extra ) {
240 : poKmlGeometry = poKmlOuterRing =
241 9 : poKmlFactory->CreateOuterBoundaryIs ( );
242 9 : poKmlOuterRing->set_linearring ( poKmlLinearRing );
243 : }
244 : else {
245 : poKmlGeometry = poKmlInnerRing =
246 9 : poKmlFactory->CreateInnerBoundaryIs ( );
247 9 : poKmlInnerRing->set_linearring ( poKmlLinearRing );
248 : }
249 :
250 18 : 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 9 : poOgrPolygon = ( OGRPolygon * ) poOgrGeom;
276 :
277 9 : poKmlGeometry = poKmlPolygon = poKmlFactory->CreatePolygon ( );
278 :
279 : poKmlTmpGeometry = geom2kml ( poOgrPolygon->getExteriorRing ( ),
280 9 : 0, wkb25D, poKmlFactory );
281 : poKmlPolygon->
282 9 : set_outerboundaryis ( AsOuterBoundaryIs ( poKmlTmpGeometry ) );
283 :
284 9 : nGeom = poOgrPolygon->getNumInteriorRings ( );
285 18 : for ( i = 0; i < nGeom; i++ ) {
286 : poKmlTmpGeometry = geom2kml ( poOgrPolygon->getInteriorRing ( i ),
287 9 : i + 1, wkb25D, poKmlFactory );
288 : poKmlPolygon->
289 9 : add_innerboundaryis ( AsInnerBoundaryIs ( poKmlTmpGeometry ) );
290 : }
291 :
292 9 : 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 12 : poOgrMultiGeom = ( OGRGeometryCollection * ) poOgrGeom;
304 :
305 : poKmlGeometry = poKmlMultiGeometry =
306 12 : poKmlFactory->CreateMultiGeometry ( );
307 :
308 12 : nGeom = poOgrMultiGeom->getNumGeometries ( );
309 36 : for ( i = 0; i < nGeom; i++ ) {
310 : poKmlTmpGeometry = geom2kml ( poOgrMultiGeom->getGeometryRef ( i ),
311 24 : -1, wkb25D, poKmlFactory );
312 : poKmlMultiGeometry->
313 24 : add_geometry ( AsGeometry ( poKmlTmpGeometry ) );
314 : }
315 :
316 : break;
317 :
318 : case wkbUnknown:
319 : case wkbNone:
320 : default:
321 : break;
322 :
323 : }
324 :
325 69 : 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 441 : 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 441 : OGRGeometry *poOgrGeometry = NULL;
354 441 : OGRGeometry *poOgrTmpGeometry = NULL;
355 :
356 :
357 : /***** libkml geom vars *****/
358 :
359 441 : CoordinatesPtr poKmlCoordinates;
360 441 : PointPtr poKmlPoint;
361 441 : LineStringPtr poKmlLineString;
362 441 : LinearRingPtr poKmlLinearRing;
363 441 : OuterBoundaryIsPtr poKmlOuterRing;
364 441 : InnerBoundaryIsPtr poKmlInnerRing;
365 441 : PolygonPtr poKmlPolygon;
366 441 : MultiGeometryPtr poKmlMultiGeometry;
367 441 : GeometryPtr poKmlTmpGeometry;
368 :
369 441 : Vec3 oKmlVec;
370 :
371 : size_t nRings,
372 : nCoords,
373 : nGeom,
374 : i;
375 :
376 441 : switch ( poKmlGeometry->Type ( ) ) {
377 : case kmldom::Type_Point:
378 75 : poKmlPoint = AsPoint ( poKmlGeometry );
379 75 : if ( poKmlPoint->has_coordinates ( ) ) {
380 74 : poKmlCoordinates = poKmlPoint->get_coordinates ( );
381 74 : nCoords = poKmlCoordinates->get_coordinates_array_size ( );
382 74 : if (nCoords > 0)
383 : {
384 73 : oKmlVec = poKmlCoordinates->get_coordinates_array_at ( 0 );
385 :
386 73 : if ( oKmlVec.has_altitude ( ) )
387 : poOgrPoint = new OGRPoint ( oKmlVec.get_longitude ( ),
388 : oKmlVec.get_latitude ( ),
389 68 : oKmlVec.get_altitude ( ) );
390 : else
391 : poOgrPoint = new OGRPoint ( oKmlVec.get_longitude ( ),
392 5 : oKmlVec.get_latitude ( ) );
393 :
394 73 : poOgrGeometry = poOgrPoint;
395 : }
396 : else
397 : {
398 1 : poOgrGeometry = new OGRPoint();
399 : }
400 : }
401 : else
402 : {
403 1 : poOgrGeometry = new OGRPoint();
404 : }
405 :
406 75 : break;
407 :
408 : case kmldom::Type_LineString:
409 81 : poKmlLineString = AsLineString ( poKmlGeometry );
410 81 : poOgrLineString = new OGRLineString ( );
411 162 : if ( poKmlLineString->has_coordinates ( ) ) {
412 80 : poKmlCoordinates = poKmlLineString->get_coordinates ( );
413 :
414 80 : nCoords = poKmlCoordinates->get_coordinates_array_size ( );
415 580 : for ( i = 0; i < nCoords; i++ ) {
416 500 : oKmlVec = poKmlCoordinates->get_coordinates_array_at ( i );
417 500 : if ( oKmlVec.has_altitude ( ) )
418 : poOgrLineString->
419 : addPoint ( oKmlVec.get_longitude ( ),
420 : oKmlVec.get_latitude ( ),
421 494 : oKmlVec.get_altitude ( ) );
422 : else
423 : poOgrLineString->
424 : addPoint ( oKmlVec.get_longitude ( ),
425 6 : oKmlVec.get_latitude ( ) );
426 : }
427 : }
428 81 : poOgrGeometry = poOgrLineString;
429 :
430 81 : break;
431 : case kmldom::Type_LinearRing:
432 146 : poKmlLinearRing = AsLinearRing ( poKmlGeometry );
433 146 : poOgrLinearRing = new OGRLinearRing ( );
434 292 : if ( poKmlLinearRing->has_coordinates ( ) ) {
435 143 : poKmlCoordinates = poKmlLinearRing->get_coordinates ( );
436 :
437 143 : nCoords = poKmlCoordinates->get_coordinates_array_size ( );
438 1758 : for ( i = 0; i < nCoords; i++ ) {
439 1615 : oKmlVec = poKmlCoordinates->get_coordinates_array_at ( i );
440 1615 : if ( oKmlVec.has_altitude ( ) )
441 : poOgrLinearRing->
442 : addPoint ( oKmlVec.get_longitude ( ),
443 : oKmlVec.get_latitude ( ),
444 1578 : oKmlVec.get_altitude ( ) );
445 : else
446 : poOgrLinearRing->
447 : addPoint ( oKmlVec.get_longitude ( ),
448 37 : oKmlVec.get_latitude ( ) );
449 : }
450 : }
451 146 : poOgrGeometry = poOgrLinearRing;
452 :
453 146 : break;
454 : case kmldom::Type_Polygon:
455 120 : poKmlPolygon = AsPolygon ( poKmlGeometry );
456 :
457 120 : poOgrPolygon = new OGRPolygon ( );
458 240 : if ( poKmlPolygon->has_outerboundaryis ( ) ) {
459 :
460 119 : poKmlOuterRing = poKmlPolygon->get_outerboundaryis ( );
461 119 : poKmlLinearRing = poKmlOuterRing->get_linearring ( );
462 119 : if (poKmlLinearRing)
463 : {
464 118 : poOgrTmpGeometry = kml2geom_rec ( poKmlLinearRing, poOgrSRS );
465 :
466 : poOgrPolygon->
467 118 : addRingDirectly ( ( OGRLinearRing * ) poOgrTmpGeometry );
468 : }
469 :
470 : }
471 120 : nRings = poKmlPolygon->get_innerboundaryis_array_size ( );
472 146 : for ( i = 0; i < nRings; i++ ) {
473 26 : poKmlInnerRing = poKmlPolygon->get_innerboundaryis_array_at ( i );
474 26 : poKmlLinearRing = poKmlInnerRing->get_linearring ( );
475 26 : if (poKmlLinearRing)
476 : {
477 25 : poOgrTmpGeometry = kml2geom_rec ( poKmlLinearRing, poOgrSRS );
478 :
479 : poOgrPolygon->
480 25 : addRingDirectly ( ( OGRLinearRing * ) poOgrTmpGeometry );
481 : }
482 : }
483 120 : poOgrGeometry = poOgrPolygon;
484 :
485 120 : break;
486 : case kmldom::Type_MultiGeometry:
487 : {
488 19 : poKmlMultiGeometry = AsMultiGeometry ( poKmlGeometry );
489 19 : nGeom = poKmlMultiGeometry->get_geometry_array_size ( );
490 :
491 : /* Detect subgeometry type to instanciate appropriate Multi geometry type */
492 19 : kmldom::KmlDomType type = kmldom::Type_Unknown;
493 46 : for ( i = 0; i < nGeom; i++ ) {
494 31 : poKmlTmpGeometry = poKmlMultiGeometry->get_geometry_array_at ( i );
495 31 : if (type == kmldom::Type_Unknown)
496 17 : type = poKmlTmpGeometry->Type();
497 14 : else if (type != poKmlTmpGeometry->Type())
498 : {
499 4 : type = kmldom::Type_Unknown;
500 4 : break;
501 : }
502 : }
503 :
504 19 : if (type == kmldom::Type_Point)
505 5 : poOgrMultiGeometry = new OGRMultiPoint();
506 14 : else if (type == kmldom::Type_LineString)
507 4 : poOgrMultiGeometry = new OGRMultiLineString();
508 10 : else if (type == kmldom::Type_Polygon)
509 4 : poOgrMultiGeometry = new OGRMultiPolygon();
510 : else
511 6 : poOgrMultiGeometry = new OGRGeometryCollection ();
512 :
513 50 : for ( i = 0; i < nGeom; i++ ) {
514 31 : poKmlTmpGeometry = poKmlMultiGeometry->get_geometry_array_at ( i );
515 31 : poOgrTmpGeometry = kml2geom_rec ( poKmlTmpGeometry, poOgrSRS );
516 :
517 31 : poOgrMultiGeometry->addGeometryDirectly ( poOgrTmpGeometry );
518 : }
519 19 : poOgrGeometry = poOgrMultiGeometry;
520 : break;
521 : }
522 : default:
523 : break;
524 : }
525 :
526 441 : if (poOgrGeometry)
527 441 : poOgrGeometry->assignSpatialReference(poOgrSRS);
528 :
529 441 : 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 267 : OGRGeometry *kml2geom (
545 : GeometryPtr poKmlGeometry,
546 : OGRSpatialReference *poOgrSRS)
547 :
548 : {
549 :
550 : /***** get the geometry *****/
551 :
552 267 : OGRGeometry *poOgrGeometry = kml2geom_rec (poKmlGeometry, poOgrSRS);
553 :
554 : /***** split the geometry at the dateline? *****/
555 :
556 267 : const char *pszWrap = CPLGetConfigOption ( "LIBKML_WRAPDATELINE", "no" );
557 267 : 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 267 : return poOgrGeometry;
581 : }
|