LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/libkml - ogrlibkmlgeometry.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 300 373 80.4 %
Date: 2024-05-02 22:57:13 Functions: 5 7 71.4 %

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

Generated by: LCOV version 1.14