LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/kml - ogr2kmlgeometry.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 105 141 74.5 %
Date: 2024-04-27 17:22:41 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  KML Driver
       4             :  * Purpose:  Implementation of OGR -> KML geometries writer.
       5             :  * Author:   Christopher Condit, condit@sdsc.edu
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2006, Christopher Condit
       9             :  * Copyright (c) 2007-2010, 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 "cpl_port.h"
      31             : #include "ogr_api.h"
      32             : 
      33             : #include <stddef.h>
      34             : #include <stdio.h>
      35             : #include <string.h>
      36             : #include <algorithm>
      37             : 
      38             : #include "cpl_conv.h"
      39             : #include "cpl_error.h"
      40             : #include "cpl_minixml.h"
      41             : #include "ogr_core.h"
      42             : #include "ogr_geometry.h"
      43             : #include "ogr_p.h"
      44             : 
      45             : constexpr double EPSILON = 1e-8;
      46             : 
      47             : /************************************************************************/
      48             : /*                        MakeKMLCoordinate()                           */
      49             : /************************************************************************/
      50             : 
      51         270 : static void MakeKMLCoordinate(char *pszTarget, size_t nTargetLen, double x,
      52             :                               double y, double z, bool b3D)
      53             : 
      54             : {
      55         270 :     if (y < -90 || y > 90)
      56             :     {
      57           0 :         if (y > 90 && y < 90 + EPSILON)
      58             :         {
      59           0 :             y = 90;
      60             :         }
      61           0 :         else if (y > -90 - EPSILON && y < -90)
      62             :         {
      63           0 :             y = -90;
      64             :         }
      65             :         else
      66             :         {
      67             :             static bool bFirstWarning = true;
      68           0 :             if (bFirstWarning)
      69             :             {
      70           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
      71             :                          "Latitude %f is invalid. Valid range is [-90,90]. "
      72             :                          "This warning will not be issued any more",
      73             :                          y);
      74           0 :                 bFirstWarning = false;
      75             :             }
      76             :         }
      77             :     }
      78             : 
      79         270 :     if (x < -180 || x > 180)
      80             :     {
      81           0 :         if (x > 180 && x < 180 + EPSILON)
      82             :         {
      83           0 :             x = 180;
      84             :         }
      85           0 :         else if (x > -180 - EPSILON && x < -180)
      86             :         {
      87           0 :             x = -180;
      88             :         }
      89             :         else
      90             :         {
      91             :             static bool bFirstWarning = true;
      92           0 :             if (bFirstWarning)
      93             :             {
      94           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
      95             :                          "Longitude %f has been modified to fit into "
      96             :                          "range [-180,180]. This warning will not be "
      97             :                          "issued any more",
      98             :                          x);
      99           0 :                 bFirstWarning = false;
     100             :             }
     101             : 
     102             :             // Trash drastically non-sensical values.
     103           0 :             if (x > 1.0e6 || x < -1.0e6 || CPLIsNan(x))
     104             :             {
     105             :                 static bool bFirstWarning2 = true;
     106           0 :                 if (bFirstWarning2)
     107             :                 {
     108           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     109             :                              "Longitude %lf is unreasonable.  Setting to 0."
     110             :                              "This warning will not be issued any more",
     111             :                              x);
     112           0 :                     bFirstWarning2 = false;
     113             :                 }
     114           0 :                 x = 0.0;
     115             :             }
     116             : 
     117           0 :             if (x > 180)
     118           0 :                 x -= (static_cast<int>((x + 180) / 360) * 360);
     119           0 :             else if (x < -180)
     120           0 :                 x += (static_cast<int>(180 - x) / 360) * 360;
     121             :         }
     122             :     }
     123             : 
     124         270 :     OGRMakeWktCoordinate(pszTarget, x, y, z, b3D ? 3 : 2);
     125        3842 :     while (*pszTarget != '\0')
     126             :     {
     127        3572 :         if (*pszTarget == ' ')
     128         346 :             *pszTarget = ',';
     129        3572 :         pszTarget++;
     130        3572 :         nTargetLen--;
     131             :     }
     132             : 
     133         270 :     CPL_IGNORE_RET_VAL(nTargetLen);
     134             : 
     135             : #if 0
     136             :     if( !b3D )
     137             :     {
     138             :         if( x == static_cast<int>(x) && y == static_cast<int>(y) )
     139             :             snprintf( pszTarget, nTargetLen, "%d,%d",
     140             :                       static_cast<int>(x), static_cast<int>(y) );
     141             :         else if( fabs(x) < 370 && fabs(y) < 370 )
     142             :             CPLsnprintf( pszTarget, nTargetLen, "%.16g,%.16g", x, y );
     143             :         else if( fabs(x) > 100000000.0 || fabs(y) > 100000000.0 )
     144             :             CPLsnprintf( pszTarget, nTargetLen, "%.16g,%.16g", x, y );
     145             :         else
     146             :             CPLsnprintf( pszTarget, nTargetLen, "%.3f,%.3f", x, y );
     147             :     }
     148             :     else
     149             :     {
     150             :         if( x == static_cast<int>(x) &&
     151             :             y == static_cast<int>(y) &&
     152             :             z == static_cast<int>(z) )
     153             :             snprintf( pszTarget, nTargetLen, "%d,%d,%d",
     154             :                       static_cast<int>(x), static_cast<int>(y),
     155             :                       static_cast<int>(z) );
     156             :         else if( fabs(x) < 370 && fabs(y) < 370 )
     157             :             CPLsnprintf( pszTarget, nTargetLen, "%.16g,%.16g,%.16g", x, y, z );
     158             :         else if( fabs(x) > 100000000.0 || fabs(y) > 100000000.0
     159             :                  || fabs(z) > 100000000.0 )
     160             :             CPLsnprintf( pszTarget, nTargetLen, "%.16g,%.16g,%.16g", x, y, z );
     161             :         else
     162             :             CPLsnprintf( pszTarget, nTargetLen, "%.3f,%.3f,%.3f", x, y, z );
     163             :     }
     164             : #endif
     165         270 : }
     166             : 
     167             : /************************************************************************/
     168             : /*                            _GrowBuffer()                             */
     169             : /************************************************************************/
     170             : 
     171         842 : static void _GrowBuffer(size_t nNeeded, char **ppszText, size_t *pnMaxLength)
     172             : 
     173             : {
     174         842 :     if (nNeeded + 1 >= *pnMaxLength)
     175             :     {
     176         359 :         *pnMaxLength = std::max(*pnMaxLength * 2, nNeeded + 1);
     177         359 :         *ppszText = static_cast<char *>(CPLRealloc(*ppszText, *pnMaxLength));
     178             :     }
     179         842 : }
     180             : 
     181             : /************************************************************************/
     182             : /*                            AppendString()                            */
     183             : /************************************************************************/
     184             : 
     185         410 : static void AppendString(char **ppszText, size_t *pnLength, size_t *pnMaxLength,
     186             :                          const char *pszTextToAppend)
     187             : 
     188             : {
     189         410 :     _GrowBuffer(*pnLength + strlen(pszTextToAppend) + 1, ppszText, pnMaxLength);
     190             : 
     191         410 :     strcat(*ppszText + *pnLength, pszTextToAppend);
     192         410 :     *pnLength += strlen(*ppszText + *pnLength);
     193         410 : }
     194             : 
     195             : /************************************************************************/
     196             : /*                        AppendCoordinateList()                        */
     197             : /************************************************************************/
     198             : 
     199          81 : static void AppendCoordinateList(OGRLineString *poLine, char **ppszText,
     200             :                                  size_t *pnLength, size_t *pnMaxLength)
     201             : 
     202             : {
     203          81 :     char szCoordinate[256] = {0};
     204          81 :     const bool b3D = CPL_TO_BOOL(wkbHasZ(poLine->getGeometryType()));
     205             : 
     206          81 :     *pnLength += strlen(*ppszText + *pnLength);
     207          81 :     _GrowBuffer(*pnLength + 20, ppszText, pnMaxLength);
     208             : 
     209          81 :     strcat(*ppszText + *pnLength, "<coordinates>");
     210          81 :     *pnLength += strlen(*ppszText + *pnLength);
     211             : 
     212         322 :     for (int iPoint = 0; iPoint < poLine->getNumPoints(); iPoint++)
     213             :     {
     214         241 :         MakeKMLCoordinate(szCoordinate, sizeof(szCoordinate),
     215             :                           poLine->getX(iPoint), poLine->getY(iPoint),
     216             :                           poLine->getZ(iPoint), b3D);
     217         241 :         _GrowBuffer(*pnLength + strlen(szCoordinate) + 1, ppszText,
     218             :                     pnMaxLength);
     219             : 
     220         241 :         if (iPoint != 0)
     221         160 :             strcat(*ppszText + *pnLength, " ");
     222             : 
     223         241 :         strcat(*ppszText + *pnLength, szCoordinate);
     224         241 :         *pnLength += strlen(*ppszText + *pnLength);
     225             :     }
     226             : 
     227          81 :     _GrowBuffer(*pnLength + 20, ppszText, pnMaxLength);
     228          81 :     strcat(*ppszText + *pnLength, "</coordinates>");
     229          81 :     *pnLength += strlen(*ppszText + *pnLength);
     230          81 : }
     231             : 
     232             : /************************************************************************/
     233             : /*                       OGR2KMLGeometryAppend()                        */
     234             : /************************************************************************/
     235             : 
     236         159 : static bool OGR2KMLGeometryAppend(OGRGeometry *poGeometry, char **ppszText,
     237             :                                   size_t *pnLength, size_t *pnMaxLength,
     238             :                                   char *szAltitudeMode)
     239             : 
     240             : {
     241             :     /* -------------------------------------------------------------------- */
     242             :     /*      2D Point                                                        */
     243             :     /* -------------------------------------------------------------------- */
     244         159 :     if (poGeometry->getGeometryType() == wkbPoint)
     245             :     {
     246          18 :         OGRPoint *poPoint = poGeometry->toPoint();
     247             : 
     248          18 :         if (poPoint->getCoordinateDimension() == 0)
     249             :         {
     250           0 :             _GrowBuffer(*pnLength + 10, ppszText, pnMaxLength);
     251           0 :             strcat(*ppszText + *pnLength, "<Point/>");
     252           0 :             *pnLength += strlen(*ppszText + *pnLength);
     253             :         }
     254             :         else
     255             :         {
     256          18 :             char szCoordinate[256] = {0};
     257          18 :             MakeKMLCoordinate(szCoordinate, sizeof(szCoordinate),
     258             :                               poPoint->getX(), poPoint->getY(), 0.0, false);
     259             : 
     260          18 :             _GrowBuffer(*pnLength + strlen(szCoordinate) + 60, ppszText,
     261             :                         pnMaxLength);
     262             : 
     263          18 :             snprintf(*ppszText + *pnLength, *pnMaxLength - *pnLength,
     264             :                      "<Point><coordinates>%s</coordinates></Point>",
     265             :                      szCoordinate);
     266             : 
     267          18 :             *pnLength += strlen(*ppszText + *pnLength);
     268             :         }
     269             :     }
     270             :     /* -------------------------------------------------------------------- */
     271             :     /*      3D Point                                                        */
     272             :     /* -------------------------------------------------------------------- */
     273         141 :     else if (poGeometry->getGeometryType() == wkbPoint25D)
     274             :     {
     275          11 :         char szCoordinate[256] = {0};
     276          11 :         OGRPoint *poPoint = poGeometry->toPoint();
     277             : 
     278          11 :         MakeKMLCoordinate(szCoordinate, sizeof(szCoordinate), poPoint->getX(),
     279             :                           poPoint->getY(), poPoint->getZ(), true);
     280             : 
     281          11 :         if (nullptr == szAltitudeMode)
     282             :         {
     283           0 :             _GrowBuffer(*pnLength + strlen(szCoordinate) + 70, ppszText,
     284             :                         pnMaxLength);
     285             : 
     286           0 :             snprintf(*ppszText + *pnLength, *pnMaxLength - *pnLength,
     287             :                      "<Point><coordinates>%s</coordinates></Point>",
     288             :                      szCoordinate);
     289             :         }
     290             :         else
     291             :         {
     292          11 :             _GrowBuffer(*pnLength + strlen(szCoordinate) +
     293          11 :                             strlen(szAltitudeMode) + 70,
     294             :                         ppszText, pnMaxLength);
     295             : 
     296          11 :             snprintf(*ppszText + *pnLength, *pnMaxLength - *pnLength,
     297             :                      "<Point>%s<coordinates>%s</coordinates></Point>",
     298             :                      szAltitudeMode, szCoordinate);
     299             :         }
     300             : 
     301          11 :         *pnLength += strlen(*ppszText + *pnLength);
     302             :     }
     303             :     /* -------------------------------------------------------------------- */
     304             :     /*      LineString and LinearRing                                       */
     305             :     /* -------------------------------------------------------------------- */
     306         198 :     else if (poGeometry->getGeometryType() == wkbLineString ||
     307          68 :              poGeometry->getGeometryType() == wkbLineString25D)
     308             :     {
     309          81 :         const bool bRing = EQUAL(poGeometry->getGeometryName(), "LINEARRING");
     310             : 
     311          81 :         if (bRing)
     312          24 :             AppendString(ppszText, pnLength, pnMaxLength, "<LinearRing>");
     313             :         else
     314          57 :             AppendString(ppszText, pnLength, pnMaxLength, "<LineString>");
     315             : 
     316          81 :         if (nullptr != szAltitudeMode)
     317             :         {
     318          81 :             AppendString(ppszText, pnLength, pnMaxLength, szAltitudeMode);
     319             :         }
     320             : 
     321          81 :         AppendCoordinateList(poGeometry->toLineString(), ppszText, pnLength,
     322             :                              pnMaxLength);
     323             : 
     324          81 :         if (bRing)
     325          24 :             AppendString(ppszText, pnLength, pnMaxLength, "</LinearRing>");
     326             :         else
     327          57 :             AppendString(ppszText, pnLength, pnMaxLength, "</LineString>");
     328             :     }
     329             : 
     330             :     /* -------------------------------------------------------------------- */
     331             :     /*      Polygon                                                         */
     332             :     /* -------------------------------------------------------------------- */
     333          86 :     else if (poGeometry->getGeometryType() == wkbPolygon ||
     334          37 :              poGeometry->getGeometryType() == wkbPolygon25D)
     335             :     {
     336          21 :         OGRPolygon *poPolygon = poGeometry->toPolygon();
     337             : 
     338          21 :         AppendString(ppszText, pnLength, pnMaxLength, "<Polygon>");
     339             : 
     340          21 :         if (nullptr != szAltitudeMode)
     341             :         {
     342          21 :             AppendString(ppszText, pnLength, pnMaxLength, szAltitudeMode);
     343             :         }
     344             : 
     345          21 :         if (poPolygon->getExteriorRing() != nullptr)
     346             :         {
     347          21 :             AppendString(ppszText, pnLength, pnMaxLength, "<outerBoundaryIs>");
     348             : 
     349          21 :             if (!OGR2KMLGeometryAppend(poPolygon->getExteriorRing(), ppszText,
     350             :                                        pnLength, pnMaxLength, szAltitudeMode))
     351             :             {
     352           0 :                 return false;
     353             :             }
     354          21 :             AppendString(ppszText, pnLength, pnMaxLength, "</outerBoundaryIs>");
     355             :         }
     356             : 
     357          24 :         for (int iRing = 0; iRing < poPolygon->getNumInteriorRings(); iRing++)
     358             :         {
     359           3 :             OGRLinearRing *poRing = poPolygon->getInteriorRing(iRing);
     360             : 
     361           3 :             AppendString(ppszText, pnLength, pnMaxLength, "<innerBoundaryIs>");
     362             : 
     363           3 :             if (!OGR2KMLGeometryAppend(poRing, ppszText, pnLength, pnMaxLength,
     364             :                                        szAltitudeMode))
     365             :             {
     366           0 :                 return false;
     367             :             }
     368           3 :             AppendString(ppszText, pnLength, pnMaxLength, "</innerBoundaryIs>");
     369             :         }
     370             : 
     371          21 :         AppendString(ppszText, pnLength, pnMaxLength, "</Polygon>");
     372             :     }
     373             : 
     374             :     /* -------------------------------------------------------------------- */
     375             :     /*      MultiPolygon                                                    */
     376             :     /* -------------------------------------------------------------------- */
     377          28 :     else if (wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPolygon ||
     378          21 :              wkbFlatten(poGeometry->getGeometryType()) == wkbMultiLineString ||
     379          56 :              wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPoint ||
     380           7 :              wkbFlatten(poGeometry->getGeometryType()) == wkbGeometryCollection)
     381             :     {
     382          28 :         OGRGeometryCollection *poGC = poGeometry->toGeometryCollection();
     383             : 
     384          28 :         AppendString(ppszText, pnLength, pnMaxLength, "<MultiGeometry>");
     385             : 
     386             :         // XXX - mloskot
     387             :         // if (NULL != szAltitudeMode)
     388             :         //{
     389             :         //    AppendString( ppszText, pnLength, pnMaxLength, szAltitudeMode);
     390             :         //}
     391             : 
     392          72 :         for (auto &&poMember : poGC)
     393             :         {
     394          44 :             if (!OGR2KMLGeometryAppend(poMember, ppszText, pnLength,
     395             :                                        pnMaxLength, szAltitudeMode))
     396             :             {
     397           0 :                 return false;
     398             :             }
     399             :         }
     400             : 
     401          28 :         AppendString(ppszText, pnLength, pnMaxLength, "</MultiGeometry>");
     402             :     }
     403             :     else
     404             :     {
     405           0 :         return false;
     406             :     }
     407             : 
     408         159 :     return true;
     409             : }
     410             : 
     411             : /************************************************************************/
     412             : /*                   OGR_G_ExportEnvelopeToKMLTree()                    */
     413             : /*                                                                      */
     414             : /*      Export the envelope of a geometry as a KML:Box.                 */
     415             : /************************************************************************/
     416             : 
     417             : #if 0
     418             : CPLXMLNode* OGR_G_ExportEnvelopeToKMLTree( OGRGeometryH hGeometry )
     419             : {
     420             :     VALIDATE_POINTER1( hGeometry, "OGR_G_ExportEnvelopeToKMLTree", NULL );
     421             : 
     422             :     OGREnvelope sEnvelope;
     423             : 
     424             :     memset( &sEnvelope, 0, sizeof(sEnvelope) );
     425             :     ((OGRGeometry*)(hGeometry))->getEnvelope( &sEnvelope );
     426             : 
     427             :     if( sEnvelope.MinX == 0 && sEnvelope.MaxX == 0
     428             :         && sEnvelope.MaxX == 0 && sEnvelope.MaxY == 0 )
     429             :     {
     430             :         /* There is apparently a special way of representing a null box
     431             :            geometry ... we should use it here eventually. */
     432             : 
     433             :         return NULL;
     434             :     }
     435             : 
     436             :     CPLXMLNode* psBox = CPLCreateXMLNode( NULL, CXT_Element, "Box" );
     437             : 
     438             : /* -------------------------------------------------------------------- */
     439             : /*      Add minxy coordinate.                                           */
     440             : /* -------------------------------------------------------------------- */
     441             :     CPLXMLNode* psCoord = CPLCreateXMLNode( psBox, CXT_Element, "coord" );
     442             : 
     443             :     char szCoordinate[256] = { 0 };
     444             :     MakeKMLCoordinate( szCoordinate, sEnvelope.MinX, sEnvelope.MinY, 0.0,
     445             :                        false );
     446             :     char* pszY = strstr(szCoordinate,",") + 1;
     447             :     pszY[-1] = '\0';
     448             : 
     449             :     CPLCreateXMLElementAndValue( psCoord, "X", szCoordinate );
     450             :     CPLCreateXMLElementAndValue( psCoord, "Y", pszY );
     451             : 
     452             : /* -------------------------------------------------------------------- */
     453             : /*      Add maxxy coordinate.                                           */
     454             : /* -------------------------------------------------------------------- */
     455             :     psCoord = CPLCreateXMLNode( psBox, CXT_Element, "coord" );
     456             : 
     457             :     MakeKMLCoordinate( szCoordinate, sEnvelope.MaxX, sEnvelope.MaxY, 0.0,
     458             :                        false );
     459             :     pszY = strstr(szCoordinate,",") + 1;
     460             :     pszY[-1] = '\0';
     461             : 
     462             :     CPLCreateXMLElementAndValue( psCoord, "X", szCoordinate );
     463             :     CPLCreateXMLElementAndValue( psCoord, "Y", pszY );
     464             : 
     465             :     return psBox;
     466             : }
     467             : #endif
     468             : 
     469             : /************************************************************************/
     470             : /*                         OGR_G_ExportToKML()                          */
     471             : /************************************************************************/
     472             : 
     473             : /**
     474             :  * \brief Convert a geometry into KML format.
     475             :  *
     476             :  * The returned string should be freed with CPLFree() when no longer required.
     477             :  *
     478             :  * This method is the same as the C++ method OGRGeometry::exportToKML().
     479             :  *
     480             :  * @param hGeometry handle to the geometry.
     481             :  * @param pszAltitudeMode value to write in altitudeMode element, or NULL.
     482             :  * @return A KML fragment or NULL in case of error.
     483             :  */
     484             : 
     485          91 : char *OGR_G_ExportToKML(OGRGeometryH hGeometry, const char *pszAltitudeMode)
     486             : {
     487             :     char szAltitudeMode[128];
     488             : 
     489             :     // TODO - mloskot: Should we use VALIDATE_POINTER1 here?
     490          91 :     if (hGeometry == nullptr)
     491           0 :         return CPLStrdup("");
     492             : 
     493          91 :     size_t nMaxLength = 1;
     494          91 :     char *pszText = static_cast<char *>(CPLMalloc(nMaxLength));
     495          91 :     pszText[0] = '\0';
     496             : 
     497          91 :     if (nullptr != pszAltitudeMode && strlen(pszAltitudeMode) < 128 - (29 + 1))
     498             :     {
     499           0 :         snprintf(szAltitudeMode, sizeof(szAltitudeMode),
     500             :                  "<altitudeMode>%s</altitudeMode>", pszAltitudeMode);
     501             :     }
     502             :     else
     503             :     {
     504          91 :         szAltitudeMode[0] = 0;
     505             :     }
     506             : 
     507          91 :     size_t nLength = 0;
     508          91 :     if (!OGR2KMLGeometryAppend(OGRGeometry::FromHandle(hGeometry), &pszText,
     509             :                                &nLength, &nMaxLength, szAltitudeMode))
     510             :     {
     511           0 :         CPLFree(pszText);
     512           0 :         return nullptr;
     513             :     }
     514             : 
     515          91 :     return pszText;
     516             : }
     517             : 
     518             : /************************************************************************/
     519             : /*                       OGR_G_ExportToKMLTree()                        */
     520             : /************************************************************************/
     521             : 
     522             : #if 0
     523             : CPLXMLNode *OGR_G_ExportToKMLTree( OGRGeometryH hGeometry )
     524             : {
     525             :     // TODO - mloskot: If passed geometry is null the pszText is non-null,
     526             :     // so the condition below is false.
     527             :     char *pszText = OGR_G_ExportToKML( hGeometry, NULL );
     528             :     if( pszText == NULL )
     529             :         return NULL;
     530             : 
     531             :     CPLXMLNode *psTree = CPLParseXMLString( pszText );
     532             : 
     533             :     CPLFree( pszText );
     534             : 
     535             :     return psTree;
     536             : }
     537             : #endif

Generated by: LCOV version 1.14