LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/libkml - ogrlibkmlgeometry.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 345 404 85.4 %
Date: 2024-11-21 22:18:42 Functions: 6 8 75.0 %

          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         794 : static bool NormalizeLongLat(double &x, double &y)
      38             : {
      39         794 :     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         792 :     constexpr double EPSILON = 1e-8;
      58         792 :     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         783 :     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         320 : ElementPtr geom2kml(OGRGeometry *poOgrGeom, int extra, KmlFactory *poKmlFactory)
      96             : {
      97         320 :     if (!poOgrGeom)
      98             :     {
      99           0 :         return nullptr;
     100             :     }
     101             : 
     102             :     /***** libkml geom vars *****/
     103         640 :     CoordinatesPtr coordinates = nullptr;
     104             : 
     105             :     // This will be the return value.
     106         640 :     ElementPtr poKmlGeometry = nullptr;
     107             : 
     108             :     /***** Other vars *****/
     109         320 :     int numpoints = 0;
     110         320 :     const OGRwkbGeometryType type = poOgrGeom->getGeometryType();
     111             : 
     112         320 :     switch (type)
     113             :     {
     114          61 :         case wkbPoint:
     115             :         {
     116          61 :             const OGRPoint *poOgrPoint = poOgrGeom->toPoint();
     117          61 :             PointPtr poKmlPoint = nullptr;
     118          61 :             if (poOgrPoint->getCoordinateDimension() == 0)
     119             :             {
     120           0 :                 poKmlPoint = poKmlFactory->CreatePoint();
     121           0 :                 poKmlGeometry = poKmlPoint;
     122             :             }
     123             :             else
     124             :             {
     125          61 :                 double x = poOgrPoint->getX();
     126          61 :                 double y = poOgrPoint->getY();
     127             : 
     128          61 :                 if (!NormalizeLongLat(x, y))
     129           6 :                     return nullptr;
     130             : 
     131          55 :                 coordinates = poKmlFactory->CreateCoordinates();
     132          55 :                 coordinates->add_latlng(y, x);
     133          55 :                 poKmlPoint = poKmlFactory->CreatePoint();
     134          55 :                 poKmlGeometry = poKmlPoint;
     135          55 :                 poKmlPoint->set_coordinates(coordinates);
     136             :             }
     137             : 
     138          55 :             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             :                 bool bError;
     332             :                 {
     333          23 :                     CPLErrorStateBackuper oErrorStateBackuper;
     334          23 :                     bError = !poOgrGeom->IsValid();
     335             :                 }
     336          23 :                 if (bError)
     337             :                 {
     338           1 :                     CPLError(CE_Failure, CPLE_NotSupported, "Invalid polygon");
     339           3 :                     return nullptr;
     340             :                 }
     341             :             }
     342             : 
     343          22 :             PolygonPtr poKmlPolygon = poKmlFactory->CreatePolygon();
     344          22 :             poKmlGeometry = poKmlPolygon;
     345             : 
     346          22 :             OGRPolygon *poOgrPolygon = poOgrGeom->toPolygon();
     347             :             ElementPtr poKmlTmpGeometry =
     348          22 :                 geom2kml(poOgrPolygon->getExteriorRing(), 0, poKmlFactory);
     349          22 :             if (!poKmlTmpGeometry)
     350           1 :                 return nullptr;
     351          42 :             poKmlPolygon->set_outerboundaryis(
     352          42 :                 AsOuterBoundaryIs(poKmlTmpGeometry));
     353             : 
     354          21 :             const int nGeom = poOgrPolygon->getNumInteriorRings();
     355          22 :             for (int i = 0; i < nGeom; i++)
     356             :             {
     357           2 :                 poKmlTmpGeometry = geom2kml(poOgrPolygon->getInteriorRing(i),
     358           1 :                                             i + 1, poKmlFactory);
     359           1 :                 if (!poKmlTmpGeometry)
     360           0 :                     return nullptr;
     361           2 :                 poKmlPolygon->add_innerboundaryis(
     362           2 :                     AsInnerBoundaryIs(poKmlTmpGeometry));
     363             :             }
     364             : 
     365          21 :             break;
     366             :         }
     367          37 :         case wkbPolygon25D:
     368             :         {
     369          37 :             if (CPLTestBool(
     370          74 :                     CPLGetConfigOption("LIBKML_STRICT_COMPLIANCE", "TRUE")) &&
     371          37 :                 OGRGeometryFactory::haveGEOS())
     372             :             {
     373             :                 bool bError;
     374             :                 {
     375          37 :                     CPLErrorStateBackuper oErrorStateBackuper;
     376          37 :                     bError = !poOgrGeom->IsValid();
     377             :                 }
     378          37 :                 if (bError)
     379             :                 {
     380           1 :                     CPLError(CE_Failure, CPLE_NotSupported, "Invalid polygon");
     381           3 :                     return nullptr;
     382             :                 }
     383             :             }
     384             : 
     385          36 :             PolygonPtr poKmlPolygon = poKmlFactory->CreatePolygon();
     386          36 :             poKmlGeometry = poKmlPolygon;
     387             : 
     388          36 :             OGRPolygon *poOgrPolygon = poOgrGeom->toPolygon();
     389             :             ElementPtr poKmlTmpGeometry =
     390          36 :                 geom2kml(poOgrPolygon->getExteriorRing(), 0, poKmlFactory);
     391          36 :             if (!poKmlTmpGeometry)
     392           1 :                 return nullptr;
     393          70 :             poKmlPolygon->set_outerboundaryis(
     394          70 :                 AsOuterBoundaryIs(poKmlTmpGeometry));
     395             : 
     396          35 :             const int nGeom = poOgrPolygon->getNumInteriorRings();
     397          48 :             for (int i = 0; i < nGeom; i++)
     398             :             {
     399          26 :                 poKmlTmpGeometry = geom2kml(poOgrPolygon->getInteriorRing(i),
     400          13 :                                             i + 1, poKmlFactory);
     401          13 :                 if (!poKmlTmpGeometry)
     402           0 :                     return nullptr;
     403          26 :                 poKmlPolygon->add_innerboundaryis(
     404          26 :                     AsInnerBoundaryIs(poKmlTmpGeometry));
     405             :             }
     406             : 
     407          35 :             break;
     408             :         }
     409          54 :         case wkbMultiPoint:
     410             :         case wkbMultiLineString:
     411             :         case wkbMultiPolygon:
     412             :         case wkbGeometryCollection:
     413             :         case wkbMultiPoint25D:
     414             :         case wkbMultiLineString25D:
     415             :         case wkbMultiPolygon25D:
     416             :         case wkbGeometryCollection25D:
     417             :         {
     418             :             OGRGeometryCollection *poOgrMultiGeom =
     419          54 :                 poOgrGeom->toGeometryCollection();
     420             : 
     421          54 :             const int nGeom = poOgrMultiGeom->getNumGeometries();
     422             : 
     423          54 :             if (nGeom == 1 && CPLTestBool(CPLGetConfigOption(
     424             :                                   "LIBKML_STRICT_COMPLIANCE", "TRUE")))
     425             :             {
     426          21 :                 CPLDebug("LIBKML",
     427             :                          "Turning multiple geometry into single geometry");
     428          42 :                 poKmlGeometry = geom2kml(poOgrMultiGeom->getGeometryRef(0), -1,
     429          21 :                                          poKmlFactory);
     430          21 :                 if (!poKmlGeometry)
     431           1 :                     return nullptr;
     432             :             }
     433             :             else
     434             :             {
     435          33 :                 if (nGeom == 0 && CPLTestBool(CPLGetConfigOption(
     436             :                                       "LIBKML_STRICT_COMPLIANCE", "TRUE")))
     437             :                 {
     438           1 :                     CPLError(CE_Warning, CPLE_AppDefined,
     439             :                              "Empty multi geometry are not recommended");
     440             :                 }
     441             : 
     442             :                 MultiGeometryPtr poKmlMultiGeometry =
     443          33 :                     poKmlFactory->CreateMultiGeometry();
     444          33 :                 poKmlGeometry = poKmlMultiGeometry;
     445             : 
     446         102 :                 for (int i = 0; i < nGeom; i++)
     447             :                 {
     448             :                     ElementPtr poKmlTmpGeometry = geom2kml(
     449          70 :                         poOgrMultiGeom->getGeometryRef(i), -1, poKmlFactory);
     450          70 :                     if (!poKmlTmpGeometry)
     451           1 :                         return nullptr;
     452         138 :                     poKmlMultiGeometry->add_geometry(
     453         138 :                         AsGeometry(std::move(poKmlTmpGeometry)));
     454             :                 }
     455             :             }
     456             : 
     457          52 :             break;
     458             :         }
     459           0 :         case wkbUnknown:
     460             :         case wkbNone:
     461             :         default:
     462           0 :             break;
     463             :     }
     464             : 
     465         303 :     return poKmlGeometry;
     466             : }
     467             : 
     468             : /******************************************************************************
     469             :  Recursive function to read a kml geometry and translate to ogr.
     470             : 
     471             : Args:
     472             :             poKmlGeometry   pointer to the kml geometry to translate
     473             :             poOgrSRS        pointer to the spatial ref to set on the geometry
     474             : 
     475             : Returns:
     476             :             pointer to the new ogr geometry object
     477             : 
     478             : ******************************************************************************/
     479             : 
     480        2027 : static OGRGeometry *kml2geom_rec(const GeometryPtr &poKmlGeometry,
     481             :                                  OGRSpatialReference *poOgrSRS)
     482             : {
     483             :     /***** ogr geom vars *****/
     484        2027 :     OGRPoint *poOgrPoint = nullptr;
     485        2027 :     OGRLineString *poOgrLineString = nullptr;
     486        2027 :     OGRLinearRing *poOgrLinearRing = nullptr;
     487        2027 :     OGRPolygon *poOgrPolygon = nullptr;
     488        2027 :     OGRGeometryCollection *poOgrMultiGeometry = nullptr;
     489        2027 :     OGRGeometry *poOgrGeometry = nullptr;
     490        2027 :     OGRGeometry *poOgrTmpGeometry = nullptr;
     491             : 
     492        2027 :     switch (poKmlGeometry->Type())
     493             :     {
     494         212 :         case kmldom::Type_Point:
     495             :         {
     496         424 :             PointPtr poKmlPoint = AsPoint(poKmlGeometry);
     497         212 :             if (poKmlPoint->has_coordinates())
     498             :             {
     499         422 :                 CoordinatesPtr poKmlCoordinates = poKmlPoint->get_coordinates();
     500             :                 const size_t nCoords =
     501         211 :                     poKmlCoordinates->get_coordinates_array_size();
     502         211 :                 if (nCoords > 0)
     503             :                 {
     504             :                     const Vec3 oKmlVec =
     505         210 :                         poKmlCoordinates->get_coordinates_array_at(0);
     506             : 
     507         210 :                     if (oKmlVec.has_altitude())
     508         402 :                         poOgrPoint = new OGRPoint(oKmlVec.get_longitude(),
     509         201 :                                                   oKmlVec.get_latitude(),
     510         201 :                                                   oKmlVec.get_altitude());
     511             :                     else
     512          18 :                         poOgrPoint = new OGRPoint(oKmlVec.get_longitude(),
     513           9 :                                                   oKmlVec.get_latitude());
     514             : 
     515         210 :                     poOgrGeometry = poOgrPoint;
     516             :                 }
     517             :                 else
     518             :                 {
     519           1 :                     poOgrGeometry = new OGRPoint();
     520             :                 }
     521             :             }
     522             :             else
     523             :             {
     524           1 :                 poOgrGeometry = new OGRPoint();
     525             :             }
     526             : 
     527         212 :             break;
     528             :         }
     529         240 :         case kmldom::Type_LineString:
     530             :         {
     531         480 :             LineStringPtr poKmlLineString = AsLineString(poKmlGeometry);
     532         240 :             poOgrLineString = new OGRLineString();
     533         240 :             if (poKmlLineString->has_coordinates())
     534             :             {
     535             :                 CoordinatesPtr poKmlCoordinates =
     536         478 :                     poKmlLineString->get_coordinates();
     537             : 
     538             :                 const size_t nCoords =
     539         239 :                     poKmlCoordinates->get_coordinates_array_size();
     540        1865 :                 for (size_t i = 0; i < nCoords; i++)
     541             :                 {
     542             :                     const Vec3 oKmlVec =
     543        1626 :                         poKmlCoordinates->get_coordinates_array_at(i);
     544        1626 :                     if (oKmlVec.has_altitude())
     545        1618 :                         poOgrLineString->addPoint(oKmlVec.get_longitude(),
     546             :                                                   oKmlVec.get_latitude(),
     547             :                                                   oKmlVec.get_altitude());
     548             :                     else
     549           8 :                         poOgrLineString->addPoint(oKmlVec.get_longitude(),
     550             :                                                   oKmlVec.get_latitude());
     551             :                 }
     552             :             }
     553         240 :             poOgrGeometry = poOgrLineString;
     554             : 
     555         240 :             break;
     556             :         }
     557         799 :         case kmldom::Type_LinearRing:
     558             :         {
     559        1598 :             LinearRingPtr poKmlLinearRing = AsLinearRing(poKmlGeometry);
     560         799 :             poOgrLinearRing = new OGRLinearRing();
     561         799 :             if (poKmlLinearRing->has_coordinates())
     562             :             {
     563             :                 CoordinatesPtr poKmlCoordinates =
     564        1592 :                     poKmlLinearRing->get_coordinates();
     565             : 
     566             :                 const size_t nCoords =
     567         796 :                     poKmlCoordinates->get_coordinates_array_size();
     568       15569 :                 for (size_t i = 0; i < nCoords; i++)
     569             :                 {
     570             :                     const Vec3 oKmlVec =
     571       14773 :                         poKmlCoordinates->get_coordinates_array_at(i);
     572       14773 :                     if (oKmlVec.has_altitude())
     573       14731 :                         poOgrLinearRing->addPoint(oKmlVec.get_longitude(),
     574             :                                                   oKmlVec.get_latitude(),
     575             :                                                   oKmlVec.get_altitude());
     576             :                     else
     577          42 :                         poOgrLinearRing->addPoint(oKmlVec.get_longitude(),
     578             :                                                   oKmlVec.get_latitude());
     579             :                 }
     580             :             }
     581         799 :             poOgrGeometry = poOgrLinearRing;
     582             : 
     583         799 :             break;
     584             :         }
     585         745 :         case kmldom::Type_Polygon:
     586             :         {
     587        1490 :             PolygonPtr poKmlPolygon = AsPolygon(poKmlGeometry);
     588             : 
     589         745 :             poOgrPolygon = new OGRPolygon();
     590         745 :             if (poKmlPolygon->has_outerboundaryis())
     591             :             {
     592             :                 OuterBoundaryIsPtr poKmlOuterRing =
     593        1488 :                     poKmlPolygon->get_outerboundaryis();
     594             :                 LinearRingPtr poKmlLinearRing =
     595        1488 :                     poKmlOuterRing->get_linearring();
     596         744 :                 if (poKmlLinearRing)
     597             :                 {
     598         743 :                     poOgrTmpGeometry = kml2geom_rec(poKmlLinearRing, poOgrSRS);
     599             : 
     600         743 :                     poOgrPolygon->addRingDirectly(
     601         743 :                         (OGRLinearRing *)poOgrTmpGeometry);
     602             :                 }
     603             :             }
     604             :             const size_t nRings =
     605         745 :                 poKmlPolygon->get_innerboundaryis_array_size();
     606         799 :             for (size_t i = 0; i < nRings; i++)
     607             :             {
     608             :                 InnerBoundaryIsPtr poKmlInnerRing =
     609         108 :                     poKmlPolygon->get_innerboundaryis_array_at(i);
     610             :                 LinearRingPtr poKmlLinearRing =
     611         108 :                     poKmlInnerRing->get_linearring();
     612          54 :                 if (poKmlLinearRing)
     613             :                 {
     614          53 :                     poOgrTmpGeometry = kml2geom_rec(poKmlLinearRing, poOgrSRS);
     615             : 
     616          53 :                     poOgrPolygon->addRingDirectly(
     617          53 :                         (OGRLinearRing *)poOgrTmpGeometry);
     618             :                 }
     619             :             }
     620         745 :             poOgrGeometry = poOgrPolygon;
     621             : 
     622         745 :             break;
     623             :         }
     624          28 :         case kmldom::Type_MultiGeometry:
     625             :         {
     626             :             MultiGeometryPtr poKmlMultiGeometry =
     627          56 :                 AsMultiGeometry(poKmlGeometry);
     628          28 :             const size_t nGeom = poKmlMultiGeometry->get_geometry_array_size();
     629             : 
     630             :             // Detect subgeometry type to instantiate appropriate
     631             :             // multi geometry type.
     632          28 :             kmldom::KmlDomType type = kmldom::Type_Unknown;
     633          67 :             for (size_t i = 0; i < nGeom; i++)
     634             :             {
     635             :                 GeometryPtr poKmlTmpGeometry =
     636          44 :                     poKmlMultiGeometry->get_geometry_array_at(i);
     637          44 :                 if (type == kmldom::Type_Unknown)
     638             :                 {
     639          25 :                     type = poKmlTmpGeometry->Type();
     640             :                 }
     641          19 :                 else if (type != poKmlTmpGeometry->Type())
     642             :                 {
     643           5 :                     type = kmldom::Type_Unknown;
     644           5 :                     break;
     645             :                 }
     646             :             }
     647             : 
     648          28 :             if (type == kmldom::Type_Point)
     649           8 :                 poOgrMultiGeometry = new OGRMultiPoint();
     650          20 :             else if (type == kmldom::Type_LineString)
     651           6 :                 poOgrMultiGeometry = new OGRMultiLineString();
     652          14 :             else if (type == kmldom::Type_Polygon)
     653           6 :                 poOgrMultiGeometry = new OGRMultiPolygon();
     654             :             else
     655           8 :                 poOgrMultiGeometry = new OGRGeometryCollection();
     656             : 
     657          72 :             for (size_t i = 0; i < nGeom; i++)
     658             :             {
     659             :                 GeometryPtr poKmlTmpGeometry =
     660          88 :                     poKmlMultiGeometry->get_geometry_array_at(i);
     661          44 :                 poOgrTmpGeometry = kml2geom_rec(poKmlTmpGeometry, poOgrSRS);
     662             : 
     663          44 :                 poOgrMultiGeometry->addGeometryDirectly(poOgrTmpGeometry);
     664             :             }
     665          28 :             poOgrGeometry = poOgrMultiGeometry;
     666          28 :             break;
     667             :         }
     668           2 :         case kmldom::Type_GxTrack:
     669             :         {
     670           4 :             GxTrackPtr poKmlGxTrack = AsGxTrack(poKmlGeometry);
     671           2 :             const size_t nCoords = poKmlGxTrack->get_gx_coord_array_size();
     672           2 :             poOgrLineString = new OGRLineString();
     673          11 :             for (size_t i = 0; i < nCoords; i++)
     674             :             {
     675           9 :                 const Vec3 oKmlVec = poKmlGxTrack->get_gx_coord_array_at(i);
     676           9 :                 if (oKmlVec.has_altitude())
     677           7 :                     poOgrLineString->addPoint(oKmlVec.get_longitude(),
     678             :                                               oKmlVec.get_latitude(),
     679             :                                               oKmlVec.get_altitude());
     680             :                 else
     681           2 :                     poOgrLineString->addPoint(oKmlVec.get_longitude(),
     682             :                                               oKmlVec.get_latitude());
     683             :             }
     684           2 :             poOgrGeometry = poOgrLineString;
     685           2 :             break;
     686             :         }
     687           1 :         case kmldom::Type_GxMultiTrack:
     688             :         {
     689           2 :             GxMultiTrackPtr poKmlGxMultiTrack = AsGxMultiTrack(poKmlGeometry);
     690           1 :             const size_t nGeom = poKmlGxMultiTrack->get_gx_track_array_size();
     691           1 :             poOgrMultiGeometry = new OGRMultiLineString();
     692           2 :             for (size_t j = 0; j < nGeom; j++)
     693             :             {
     694             :                 GxTrackPtr poKmlGxTrack =
     695           2 :                     poKmlGxMultiTrack->get_gx_track_array_at(j);
     696           1 :                 const size_t nCoords = poKmlGxTrack->get_gx_coord_array_size();
     697           1 :                 poOgrLineString = new OGRLineString();
     698           3 :                 for (size_t i = 0; i < nCoords; i++)
     699             :                 {
     700           2 :                     const Vec3 oKmlVec = poKmlGxTrack->get_gx_coord_array_at(i);
     701           2 :                     if (oKmlVec.has_altitude())
     702           0 :                         poOgrLineString->addPoint(oKmlVec.get_longitude(),
     703             :                                                   oKmlVec.get_latitude(),
     704             :                                                   oKmlVec.get_altitude());
     705             :                     else
     706           2 :                         poOgrLineString->addPoint(oKmlVec.get_longitude(),
     707             :                                                   oKmlVec.get_latitude());
     708             :                 }
     709           1 :                 poOgrMultiGeometry->addGeometryDirectly(poOgrLineString);
     710             :             }
     711           1 :             poOgrGeometry = poOgrMultiGeometry;
     712           1 :             break;
     713             :         }
     714             : 
     715           0 :         default:
     716             :         {
     717           0 :             break;
     718             :         }
     719             :     }
     720             : 
     721        2027 :     if (poOgrGeometry)
     722        2027 :         poOgrGeometry->assignSpatialReference(poOgrSRS);
     723             : 
     724        2027 :     return poOgrGeometry;
     725             : }
     726             : 
     727          42 : static OGRGeometry *kml2geom_latlonbox_int(const LatLonBoxPtr &poKmlLatLonBox,
     728             :                                            OGRSpatialReference *poOgrSRS)
     729             : {
     730          84 :     if (!poKmlLatLonBox->has_north() || !poKmlLatLonBox->has_south() ||
     731          84 :         !poKmlLatLonBox->has_east() || !poKmlLatLonBox->has_west())
     732             :     {
     733           0 :         return nullptr;
     734             :     }
     735          42 :     const double north = poKmlLatLonBox->get_north();
     736          42 :     const double south = poKmlLatLonBox->get_south();
     737          42 :     const double east = poKmlLatLonBox->get_east();
     738          42 :     const double west = poKmlLatLonBox->get_west();
     739             : 
     740          42 :     OGRLinearRing *poOgrRing = new OGRLinearRing();
     741          42 :     poOgrRing->addPoint(east, north, 0.0);
     742          42 :     poOgrRing->addPoint(east, south, 0.0);
     743          42 :     poOgrRing->addPoint(west, south, 0.0);
     744          42 :     poOgrRing->addPoint(west, north, 0.0);
     745          42 :     poOgrRing->addPoint(east, north, 0.0);
     746             : 
     747          42 :     OGRPolygon *poOgrPolygon = new OGRPolygon();
     748          42 :     poOgrPolygon->addRingDirectly(poOgrRing);
     749          42 :     poOgrPolygon->assignSpatialReference(poOgrSRS);
     750             : 
     751          42 :     return poOgrPolygon;
     752             : }
     753             : 
     754             : static OGRGeometry *
     755           0 : kml2geom_latlonquad_int(const GxLatLonQuadPtr &poKmlLatLonQuad,
     756             :                         OGRSpatialReference *poOgrSRS)
     757             : {
     758           0 :     if (!poKmlLatLonQuad->has_coordinates())
     759           0 :         return nullptr;
     760             : 
     761           0 :     const CoordinatesPtr &poKmlCoordinates = poKmlLatLonQuad->get_coordinates();
     762             : 
     763           0 :     OGRLinearRing *poOgrLinearRing = new OGRLinearRing();
     764             : 
     765           0 :     size_t nCoords = poKmlCoordinates->get_coordinates_array_size();
     766           0 :     for (size_t i = 0; i < nCoords; i++)
     767             :     {
     768           0 :         Vec3 oKmlVec = poKmlCoordinates->get_coordinates_array_at(i);
     769           0 :         if (oKmlVec.has_altitude())
     770           0 :             poOgrLinearRing->addPoint(oKmlVec.get_longitude(),
     771             :                                       oKmlVec.get_latitude(),
     772             :                                       oKmlVec.get_altitude());
     773             :         else
     774           0 :             poOgrLinearRing->addPoint(oKmlVec.get_longitude(),
     775             :                                       oKmlVec.get_latitude());
     776             :     }
     777           0 :     poOgrLinearRing->closeRings();
     778             : 
     779           0 :     OGRPolygon *poOgrPolygon = new OGRPolygon();
     780           0 :     poOgrPolygon->addRingDirectly(poOgrLinearRing);
     781           0 :     poOgrPolygon->assignSpatialReference(poOgrSRS);
     782             : 
     783           0 :     return poOgrPolygon;
     784             : }
     785             : 
     786             : /******************************************************************************
     787             :  Main function to read a kml geometry and translate to ogr.
     788             : 
     789             : Args:
     790             :             poKmlGeometry   pointer to the kml geometry to translate
     791             :             poOgrSRS        pointer to the spatial ref to set on the geometry
     792             : 
     793             : Returns:
     794             :             pointer to the new ogr geometry object
     795             : 
     796             : ******************************************************************************/
     797             : 
     798        1187 : OGRGeometry *kml2geom(GeometryPtr poKmlGeometry, OGRSpatialReference *poOgrSRS)
     799             : {
     800             :     /***** Get the geometry *****/
     801             :     OGRGeometry *poOgrGeometry =
     802        1187 :         kml2geom_rec(std::move(poKmlGeometry), poOgrSRS);
     803             : 
     804             :     /***** Split the geometry at the dateline? *****/
     805        1187 :     const char *pszWrap = CPLGetConfigOption("LIBKML_WRAPDATELINE", "no");
     806        1187 :     if (!CPLTestBool(pszWrap))
     807        1187 :         return poOgrGeometry;
     808             : 
     809           0 :     char **papszTransformOptions = CSLAddString(nullptr, "WRAPDATELINE=YES");
     810             : 
     811             :     /***** Transform *****/
     812           0 :     OGRGeometry *poOgrDstGeometry = OGRGeometryFactory::transformWithOptions(
     813             :         poOgrGeometry, nullptr, papszTransformOptions);
     814             : 
     815             :     /***** Replace the original geom *****/
     816           0 :     if (poOgrDstGeometry)
     817             :     {
     818           0 :         delete poOgrGeometry;
     819           0 :         poOgrGeometry = poOgrDstGeometry;
     820             :     }
     821             : 
     822           0 :     CSLDestroy(papszTransformOptions);
     823             : 
     824           0 :     return poOgrGeometry;
     825             : }
     826             : 
     827          42 : OGRGeometry *kml2geom_latlonbox(LatLonBoxPtr poKmlLatLonBox,
     828             :                                 OGRSpatialReference *poOgrSRS)
     829             : {
     830             :     /***** Get the geometry *****/
     831             :     OGRGeometry *poOgrGeometry =
     832          42 :         kml2geom_latlonbox_int(poKmlLatLonBox, poOgrSRS);
     833             : 
     834             :     /***** Split the geometry at the dateline? *****/
     835          42 :     const char *pszWrap = CPLGetConfigOption("LIBKML_WRAPDATELINE", "no");
     836             : 
     837          42 :     if (!CPLTestBool(pszWrap))
     838          42 :         return poOgrGeometry;
     839             : 
     840           0 :     char **papszTransformOptions = CSLAddString(nullptr, "WRAPDATELINE=YES");
     841             : 
     842             :     /***** Transform *****/
     843           0 :     OGRGeometry *poOgrDstGeometry = OGRGeometryFactory::transformWithOptions(
     844             :         poOgrGeometry, nullptr, papszTransformOptions);
     845             : 
     846             :     /***** Replace the original geom *****/
     847           0 :     if (poOgrDstGeometry)
     848             :     {
     849           0 :         delete poOgrGeometry;
     850           0 :         poOgrGeometry = poOgrDstGeometry;
     851             :     }
     852             : 
     853           0 :     CSLDestroy(papszTransformOptions);
     854             : 
     855           0 :     return poOgrGeometry;
     856             : }
     857             : 
     858           0 : OGRGeometry *kml2geom_latlonquad(GxLatLonQuadPtr poKmlLatLonQuad,
     859             :                                  OGRSpatialReference *poOgrSRS)
     860             : {
     861             :     /***** Get the geometry *****/
     862             :     OGRGeometry *poOgrGeometry =
     863           0 :         kml2geom_latlonquad_int(poKmlLatLonQuad, poOgrSRS);
     864             : 
     865             :     /***** Split the geometry at the dateline? *****/
     866           0 :     const char *pszWrap = CPLGetConfigOption("LIBKML_WRAPDATELINE", "no");
     867           0 :     if (!CPLTestBool(pszWrap))
     868           0 :         return poOgrGeometry;
     869             : 
     870           0 :     char **papszTransformOptions = CSLAddString(nullptr, "WRAPDATELINE=YES");
     871             : 
     872             :     /***** Transform *****/
     873           0 :     OGRGeometry *poOgrDstGeometry = OGRGeometryFactory::transformWithOptions(
     874             :         poOgrGeometry, nullptr, papszTransformOptions);
     875             : 
     876             :     /***** Replace the original geom *****/
     877           0 :     if (poOgrDstGeometry)
     878             :     {
     879           0 :         delete poOgrGeometry;
     880           0 :         poOgrGeometry = poOgrDstGeometry;
     881             :     }
     882             : 
     883           0 :     CSLDestroy(papszTransformOptions);
     884             : 
     885           0 :     return poOgrGeometry;
     886             : }

Generated by: LCOV version 1.14