LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/kml - ogr2kmlgeometry.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 159 105 66.0 %
Date: 2010-01-09 Functions: 8 6 75.0 %

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

Generated by: LCOV version 1.7