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

Generated by: LCOV version 1.14