www.pudn.com > mitab.rar > ogrlinestring.cpp
/****************************************************************************** * $Id: ogrlinestring.cpp,v 1.46 2005/03/25 06:31:12 fwarmerdam Exp $ * * Project: OpenGIS Simple Features Reference Implementation * Purpose: The OGRLineString geometry class. * Author: Frank Warmerdam, warmerda@home.com * ****************************************************************************** * Copyright (c) 1999, Frank Warmerdam * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************** * * $Log: ogrlinestring.cpp,v $ * Revision 1.46 2005/03/25 06:31:12 fwarmerdam * added addSubLineString * * Revision 1.45 2005/02/22 12:38:01 fwarmerdam * rename Equal/Intersect to Equals/Intersects * * Revision 1.44 2004/02/22 10:09:16 dron * Fix compirison casting problems in Equal() method. * * Revision 1.43 2004/02/21 15:36:14 warmerda * const correctness updates for geometry: bug 289 * * Revision 1.42 2004/02/20 18:03:36 warmerda * Applied new Value() implementation to deal with duplicate points. * http://bugzilla.remotesensing.org/show_bug.cgi?id=384 * * Revision 1.41 2004/01/16 21:57:16 warmerda * fixed up EMPTY support * * Revision 1.40 2004/01/16 21:20:00 warmerda * Added EMPTY support * * Revision 1.39 2003/08/27 15:40:37 warmerda * added support for generating DB2 V7.2 compatible WKB * * Revision 1.38 2003/06/09 13:48:54 warmerda * added DB2 V7.2 byte order hack * * Revision 1.37 2003/05/28 19:16:43 warmerda * fixed up argument names and stuff for docs * * Revision 1.36 2003/03/07 21:28:56 warmerda * support 0x8000 style 3D WKB flags * * Revision 1.35 2003/01/06 17:43:13 warmerda * fixed buffer sizing problem for 3D geometries * * Revision 1.34 2003/01/06 16:18:40 warmerda * getEnvlope() crash fix if there are no points * * Revision 1.33 2002/09/11 13:47:17 warmerda * preliminary set of fixes for 3D WKB enum * * Revision 1.32 2002/08/19 14:11:35 warmerda * correct second setPoints() method properly. * * Revision 1.31 2002/08/19 03:24:51 warmerda * Fixed serious bug with 3D points in setPoints() methods. * * Revision 1.30 2002/07/15 13:31:07 warmerda * patch from Graeme for exportToWkb() with swapping code * * Revision 1.29 2002/05/02 19:45:36 warmerda * added flattenTo2D() method * * Revision 1.28 2002/04/17 21:43:09 warmerda * Free z array in descructor. * * Revision 1.27 2002/04/08 17:50:09 warmerda * Ensure Equal operator tests first vertex too. * * Revision 1.26 2002/03/05 14:25:14 warmerda * expand tabs * * Revision 1.25 2002/02/22 22:24:08 warmerda * clarify setPoints code * * Revision 1.24 2001/11/14 14:44:06 warmerda * fixed problem with WKT translation * * Revision 1.23 2001/11/01 17:20:33 warmerda * added DISABLE_OGRGEOM_TRANSFORM macro * * Revision 1.22 2001/11/01 17:01:28 warmerda * pass output buffer into OGRMakeWktCoordinate * * Revision 1.21 2001/09/21 16:24:20 warmerda * added transform() and transformTo() methods * * Revision 1.20 2001/07/19 18:25:07 warmerda * expanded tabs * * Revision 1.19 2001/07/18 05:03:05 warmerda * added CPL_CVSID * * Revision 1.18 2001/05/24 18:06:06 warmerda * fixed comment * * Revision 1.17 2001/01/19 21:10:47 warmerda * replaced tabs * * Revision 1.16 2000/01/26 21:20:47 warmerda * fixed crash assigning 2D points when already 3D * * Revision 1.15 1999/12/23 14:47:16 warmerda * improved 2D/3D handling to avoid 3D unless padfZ != 0.0 * * Revision 1.14 1999/11/18 19:02:19 warmerda * expanded tabs * * Revision 1.13 1999/11/17 19:38:22 warmerda * Further performance tweaks to exportToWkt(). * * Revision 1.12 1999/11/04 18:31:32 warmerda * Improved efficiency of exportToWkt() for large line strings. * * Revision 1.11 1999/09/13 14:34:07 warmerda * updated to use wkbZ of 0x8000 instead of 0x80000000 * * Revision 1.10 1999/09/13 02:27:33 warmerda * incorporated limited 2.5d support * * Revision 1.9 1999/07/27 00:48:11 warmerda * Added Equal() support * * Revision 1.8 1999/07/06 21:36:47 warmerda * tenatively added getEnvelope() and Intersect() * * Revision 1.7 1999/06/25 20:44:43 warmerda * implemented assignSpatialReference, carry properly * * Revision 1.6 1999/05/31 20:43:34 warmerda * added empty(), and another setPoints() * * Revision 1.5 1999/05/31 15:01:59 warmerda * OGRCurve now an abstract base class with essentially no implementation. * Everything moved down to OGRLineString where it belongs. Also documented * classes. * * Revision 1.4 1999/05/23 05:34:40 warmerda * added support for clone(), multipolygons and geometry collections * * Revision 1.3 1999/05/20 14:35:44 warmerda * added support for well known text format * * Revision 1.2 1999/03/30 21:21:43 warmerda * added linearring/polygon support * * Revision 1.1 1999/03/29 21:21:10 warmerda * New * */ #include "ogr_geometry.h" #include "ogr_p.h" #includeCPL_CVSID("$Id: ogrlinestring.cpp,v 1.46 2005/03/25 06:31:12 fwarmerdam Exp $"); /************************************************************************/ /* OGRLineString() */ /************************************************************************/ /** * Create an empty line string. */ OGRLineString::OGRLineString() { nPointCount = 0; paoPoints = NULL; padfZ = NULL; } /************************************************************************/ /* ~OGRLineString() */ /************************************************************************/ OGRLineString::~OGRLineString() { if( paoPoints != NULL ) OGRFree( paoPoints ); if( padfZ != NULL ) OGRFree( padfZ ); } /************************************************************************/ /* getGeometryType() */ /************************************************************************/ OGRwkbGeometryType OGRLineString::getGeometryType() const { if( getCoordinateDimension() == 3 ) return wkbLineString25D; else return wkbLineString; } /************************************************************************/ /* flattenTo2D() */ /************************************************************************/ void OGRLineString::flattenTo2D() { Make2D(); } /************************************************************************/ /* getGeometryName() */ /************************************************************************/ const char * OGRLineString::getGeometryName() const { return "LINESTRING"; } /************************************************************************/ /* clone() */ /************************************************************************/ OGRGeometry *OGRLineString::clone() const { OGRLineString *poNewLineString; poNewLineString = new OGRLineString(); poNewLineString->assignSpatialReference( getSpatialReference() ); poNewLineString->setPoints( nPointCount, paoPoints, padfZ ); // notdef: not 3D return poNewLineString; } /************************************************************************/ /* empty() */ /************************************************************************/ void OGRLineString::empty() { setNumPoints( 0 ); } /************************************************************************/ /* getDimension() */ /************************************************************************/ int OGRLineString::getDimension() const { return 1; } /************************************************************************/ /* getCoordinateDimension() */ /************************************************************************/ int OGRLineString::getCoordinateDimension() const { if( padfZ != NULL ) return 3; else return 2; } /************************************************************************/ /* WkbSize() */ /* */ /* Return the size of this object in well known binary */ /* representation including the byte order, and type information. */ /************************************************************************/ int OGRLineString::WkbSize() const { return 5 + 4 + 8 * nPointCount * getCoordinateDimension(); } /************************************************************************/ /* Make2D() */ /************************************************************************/ void OGRLineString::Make2D() { if( padfZ != NULL ) { OGRFree( padfZ ); padfZ = NULL; } } /************************************************************************/ /* Make3D() */ /************************************************************************/ void OGRLineString::Make3D() { if( padfZ == NULL ) { if( nPointCount == 0 ) padfZ = (double *) OGRCalloc(sizeof(double),1); else padfZ = (double *) OGRCalloc(sizeof(double),nPointCount); } } /************************************************************************/ /* getPoint() */ /************************************************************************/ /** * Fetch a point in line string. * * This method relates to the SFCOM ILineString::get_Point() method. * * @param i the vertex to fetch, from 0 to getNumPoints()-1. * @param poPoint a point to initialize with the fetched point. */ void OGRLineString::getPoint( int i, OGRPoint * poPoint ) const { assert( i >= 0 ); assert( i < nPointCount ); assert( poPoint != NULL ); poPoint->setX( paoPoints[i].x ); poPoint->setY( paoPoints[i].y ); if( getCoordinateDimension() == 3 ) poPoint->setZ( padfZ[i] ); } /************************************************************************/ /* getZ() */ /************************************************************************/ double OGRLineString::getZ( int i ) const { if( padfZ != NULL && i >= 0 && i < nPointCount ) return( padfZ[i] ); else return 0.0; } /************************************************************************/ /* setNumPoints() */ /************************************************************************/ /** * Set number of points in geometry. * * This method primary exists to preset the number of points in a linestring * geometry before setPoint() is used to assign them to avoid reallocating * the array larger with each call to addPoint(). * * This method has no SFCOM analog. * * @param nNewPointCount the new number of points for geometry. */ void OGRLineString::setNumPoints( int nNewPointCount ) { if( nNewPointCount == 0 ) { OGRFree( paoPoints ); paoPoints = NULL; OGRFree( padfZ ); padfZ = NULL; nPointCount = 0; return; } if( nNewPointCount > nPointCount ) { paoPoints = (OGRRawPoint *) OGRRealloc(paoPoints, sizeof(OGRRawPoint) * nNewPointCount); assert( paoPoints != NULL ); memset( paoPoints + nPointCount, 0, sizeof(OGRRawPoint) * (nNewPointCount - nPointCount) ); if( getCoordinateDimension() == 3 ) { padfZ = (double *) OGRRealloc( padfZ, sizeof(double)*nNewPointCount ); memset( padfZ + nPointCount, 0, sizeof(double) * (nNewPointCount - nPointCount) ); } } nPointCount = nNewPointCount; } /************************************************************************/ /* setPoint() */ /************************************************************************/ /** * Set the location of a vertex in line string. * * If iPoint is larger than the number of necessary the number of existing * points in the line string, the point count will be increased to * accomodate the request. * * There is no SFCOM analog to this method. * * @param iPoint the index of the vertex to assign (zero based). * @param poPoint the value to assign to the vertex. */ void OGRLineString::setPoint( int iPoint, OGRPoint * poPoint ) { setPoint( iPoint, poPoint->getX(), poPoint->getY(), poPoint->getZ() ); } /************************************************************************/ /* setPoint() */ /************************************************************************/ /** * Set the location of a vertex in line string. * * If iPoint is larger than the number of necessary the number of existing * points in the line string, the point count will be increased to * accomodate the request. * * There is no SFCOM analog to this method. * * @param iPoint the index of the vertex to assign (zero based). * @param xIn input X coordinate to assign. * @param yIn input Y coordinate to assign. * @param zIn input Z coordinate to assign (defaults to zero). */ void OGRLineString::setPoint( int iPoint, double xIn, double yIn, double zIn ) { if( iPoint >= nPointCount ) setNumPoints( iPoint+1 ); paoPoints[iPoint].x = xIn; paoPoints[iPoint].y = yIn; if( zIn != 0.0 ) { Make3D(); padfZ[iPoint] = zIn; } else if( getCoordinateDimension() == 3 ) { padfZ[iPoint] = 0.0; } } /************************************************************************/ /* addPoint() */ /************************************************************************/ /** * Add a point to a line string. * * The vertex count of the line string is increased by one, and assigned from * the passed location value. * * There is no SFCOM analog to this method. * * @param poPoint the point to assign to the new vertex. */ void OGRLineString::addPoint( OGRPoint * poPoint ) { setPoint( nPointCount, poPoint->getX(), poPoint->getY(), poPoint->getZ() ); } /************************************************************************/ /* addPoint() */ /************************************************************************/ /** * Add a point to a line string. * * The vertex count of the line string is increased by one, and assigned from * the passed location value. * * There is no SFCOM analog to this method. * * @param x the X coordinate to assign to the new point. * @param y the Y coordinate to assign to the new point. * @param z the Z coordinate to assign to the new point (defaults to zero). */ void OGRLineString::addPoint( double x, double y, double z ) { setPoint( nPointCount, x, y, z ); } /************************************************************************/ /* setPoints() */ /************************************************************************/ /** * Assign all points in a line string. * * This method clears any existing points assigned to this line string, * and assigns a whole new set. It is the most efficient way of assigning * the value of a line string. * * There is no SFCOM analog to this method. * * @param nPointsIn number of points being passed in paoPointsIn * @param paoPointsIn list of points being assigned. * @param padfZ the Z values that go with the points (optional, may be NULL). */ void OGRLineString::setPoints( int nPointsIn, OGRRawPoint * paoPointsIn, double * padfZ ) { setNumPoints( nPointsIn ); memcpy( paoPoints, paoPointsIn, sizeof(OGRRawPoint) * nPointsIn); /* -------------------------------------------------------------------- */ /* Check 2D/3D. */ /* -------------------------------------------------------------------- */ if( padfZ != NULL ) { int i, bIs3D = FALSE; for( i = 0; i < nPointsIn && !bIs3D; i++ ) { if( padfZ[i] != 0.0 ) bIs3D = TRUE; } if( !bIs3D ) padfZ = NULL; } if( padfZ == NULL ) { if( this->padfZ != NULL ) Make2D(); } else { Make3D(); memcpy( this->padfZ, padfZ, sizeof(double) * nPointsIn ); } } /************************************************************************/ /* setPoints() */ /************************************************************************/ /** * Assign all points in a line string. * * This method clear any existing points assigned to this line string, * and assigns a whole new set. * * There is no SFCOM analog to this method. * * @param nPointsIn number of points being passed in padfX and padfY. * @param padfX list of X coordinates of points being assigned. * @param padfY list of Y coordinates of points being assigned. * @param padfZ list of Z coordinates of points being assigned (defaults to * NULL for 2D objects). */ void OGRLineString::setPoints( int nPointsIn, double * padfX, double * padfY, double * padfZ ) { int i; /* -------------------------------------------------------------------- */ /* Check 2D/3D. */ /* -------------------------------------------------------------------- */ if( padfZ != NULL ) { int bIs3D = FALSE; for( i = 0; i < nPointsIn && !bIs3D; i++ ) { if( padfZ[i] != 0.0 ) bIs3D = TRUE; } if( !bIs3D ) padfZ = NULL; } if( padfZ == NULL ) Make2D(); else Make3D(); /* -------------------------------------------------------------------- */ /* Assign values. */ /* -------------------------------------------------------------------- */ setNumPoints( nPointsIn ); for( i = 0; i < nPointsIn; i++ ) { paoPoints[i].x = padfX[i]; paoPoints[i].y = padfY[i]; } if( this->padfZ != NULL ) memcpy( this->padfZ, padfZ, sizeof(double) * nPointsIn ); } /************************************************************************/ /* addSubLineString() */ /************************************************************************/ /** * Add a segment of another linestring to this one. * * Adds the request range of vertices to the end of this line string * in an efficient manner. If the nStartVertex is larger than the * nEndVertex then the vertices will be reversed as they are copied. * * @param poOtherLine the other OGRLineString. * @param nStartVertex the first vertex to copy, defaults to 0 to start * with the first vertex in the other linestring. * @param nEndVertex the last vertex to copy, defaults to -1 indicating * the last vertex of the other line string. */ void OGRLineString::addSubLineString( const OGRLineString *poOtherLine, int nStartVertex, int nEndVertex ) { /* -------------------------------------------------------------------- */ /* Do a bit of argument defaulting and validation. */ /* -------------------------------------------------------------------- */ if( nEndVertex == -1 ) nEndVertex = poOtherLine->getNumPoints() - 1; if( nStartVertex < 0 || nEndVertex < 0 || nStartVertex >= poOtherLine->getNumPoints() || nEndVertex >= poOtherLine->getNumPoints() ) { CPLAssert( FALSE ); return; } /* -------------------------------------------------------------------- */ /* Grow this linestring to hold the additional points. */ /* -------------------------------------------------------------------- */ int nOldPoints = nPointCount; int nPointsToAdd = ABS(nEndVertex-nStartVertex) + 1; setNumPoints( nPointsToAdd + nOldPoints ); /* -------------------------------------------------------------------- */ /* Copy the x/y points - forward copies use memcpy. */ /* -------------------------------------------------------------------- */ if( nEndVertex >= nStartVertex ) { memcpy( paoPoints + nOldPoints, poOtherLine->paoPoints + nStartVertex, sizeof(OGRRawPoint) * nPointsToAdd ); if( poOtherLine->padfZ != NULL ) { Make3D(); memcpy( padfZ + nOldPoints, poOtherLine->padfZ + nStartVertex, sizeof(double) * nPointsToAdd ); } } /* -------------------------------------------------------------------- */ /* Copy the x/y points - reverse copies done double by double. */ /* -------------------------------------------------------------------- */ else { int i; for( i = 0; i < nPointsToAdd; i++ ) { paoPoints[i+nOldPoints].x = poOtherLine->paoPoints[nStartVertex-i].x; paoPoints[i+nOldPoints].y = poOtherLine->paoPoints[nStartVertex-i].y; } if( poOtherLine->padfZ != NULL ) { Make3D(); for( i = 0; i < nPointsToAdd; i++ ) { padfZ[i+nOldPoints] = poOtherLine->padfZ[nStartVertex-i]; } } } } /************************************************************************/ /* importFromWkb() */ /* */ /* Initialize from serialized stream in well known binary */ /* format. */ /************************************************************************/ OGRErr OGRLineString::importFromWkb( unsigned char * pabyData, int nSize ) { OGRwkbByteOrder eByteOrder; if( nSize < 21 && nSize != -1 ) return OGRERR_NOT_ENOUGH_DATA; /* -------------------------------------------------------------------- */ /* Get the byte order byte. */ /* -------------------------------------------------------------------- */ eByteOrder = DB2_V72_FIX_BYTE_ORDER((OGRwkbByteOrder) *pabyData); assert( eByteOrder == wkbXDR || eByteOrder == wkbNDR ); /* -------------------------------------------------------------------- */ /* Get the geometry feature type. For now we assume that */ /* geometry type is between 0 and 255 so we only have to fetch */ /* one byte. */ /* -------------------------------------------------------------------- */ OGRwkbGeometryType eGeometryType; int bIs3D; if( eByteOrder == wkbNDR ) { eGeometryType = (OGRwkbGeometryType) pabyData[1]; bIs3D = pabyData[4] & 0x80 || pabyData[2] & 0x80; } else { eGeometryType = (OGRwkbGeometryType) pabyData[4]; bIs3D = pabyData[1] & 0x80 || pabyData[3] & 0x80; } CPLAssert( eGeometryType == wkbLineString ); /* -------------------------------------------------------------------- */ /* Get the vertex count. */ /* -------------------------------------------------------------------- */ int nNewNumPoints; memcpy( &nNewNumPoints, pabyData + 5, 4 ); if( OGR_SWAP( eByteOrder ) ) nNewNumPoints = CPL_SWAP32(nNewNumPoints); setNumPoints( nNewNumPoints ); if( bIs3D ) Make3D(); else Make2D(); /* -------------------------------------------------------------------- */ /* Get the vertex. */ /* -------------------------------------------------------------------- */ int i; if( bIs3D ) { for( i = 0; i < nPointCount; i++ ) { memcpy( paoPoints + i, pabyData + 9 + i*24, 16 ); memcpy( padfZ + i, pabyData + 9 + 16 + i*24, 8 ); } } else { memcpy( paoPoints, pabyData + 9, 16 * nPointCount ); } /* -------------------------------------------------------------------- */ /* Byte swap if needed. */ /* -------------------------------------------------------------------- */ if( OGR_SWAP( eByteOrder ) ) { for( i = 0; i < nPointCount; i++ ) { CPL_SWAPDOUBLE( &(paoPoints[i].x) ); CPL_SWAPDOUBLE( &(paoPoints[i].y) ); } if( bIs3D ) { for( i = 0; i < nPointCount; i++ ) { CPL_SWAPDOUBLE( padfZ + i ); } } } return OGRERR_NONE; } /************************************************************************/ /* exportToWkb() */ /* */ /* Build a well known binary representation of this object. */ /************************************************************************/ OGRErr OGRLineString::exportToWkb( OGRwkbByteOrder eByteOrder, unsigned char * pabyData ) const { /* -------------------------------------------------------------------- */ /* Set the byte order. */ /* -------------------------------------------------------------------- */ pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER((unsigned char) eByteOrder); /* -------------------------------------------------------------------- */ /* Set the geometry feature type. */ /* -------------------------------------------------------------------- */ GUInt32 nGType = getGeometryType(); if( eByteOrder == wkbNDR ) nGType = CPL_LSBWORD32( nGType ); else nGType = CPL_MSBWORD32( nGType ); memcpy( pabyData + 1, &nGType, 4 ); /* -------------------------------------------------------------------- */ /* Copy in the data count. */ /* -------------------------------------------------------------------- */ memcpy( pabyData+5, &nPointCount, 4 ); /* -------------------------------------------------------------------- */ /* Copy in the raw data. */ /* -------------------------------------------------------------------- */ int i; if( getCoordinateDimension() == 3 ) { for( i = 0; i < nPointCount; i++ ) { memcpy( pabyData + 9 + 24*i, paoPoints+i, 16 ); memcpy( pabyData + 9 + 16 + 24*i, padfZ+i, 8 ); } } else memcpy( pabyData+9, paoPoints, 16 * nPointCount ); /* -------------------------------------------------------------------- */ /* Swap if needed. */ /* -------------------------------------------------------------------- */ if( OGR_SWAP( eByteOrder ) ) { int nCount; nCount = CPL_SWAP32( nPointCount ); memcpy( pabyData+5, &nCount, 4 ); for( i = getCoordinateDimension() * nPointCount - 1; i >= 0; i-- ) { CPL_SWAP64PTR( pabyData + 9 + 8 * i ); } } return OGRERR_NONE; } /************************************************************************/ /* importFromWkt() */ /* */ /* Instantiate from well known text format. Currently this is */ /* `LINESTRING ( x y, x y, ...)', */ /************************************************************************/ OGRErr OGRLineString::importFromWkt( char ** ppszInput ) { char szToken[OGR_WKT_TOKEN_MAX]; const char *pszInput = *ppszInput; if( paoPoints != NULL ) { nPointCount = 0; CPLFree( paoPoints ); paoPoints = NULL; CPLFree( padfZ ); padfZ = NULL; } /* -------------------------------------------------------------------- */ /* Read and verify the ``LINESTRING'' keyword token. */ /* -------------------------------------------------------------------- */ pszInput = OGRWktReadToken( pszInput, szToken ); if( !EQUAL(szToken,getGeometryName()) ) return OGRERR_CORRUPT_DATA; /* -------------------------------------------------------------------- */ /* Check for EMPTY ... but treat like a point at 0,0. */ /* -------------------------------------------------------------------- */ const char *pszPreScan; pszPreScan = OGRWktReadToken( pszInput, szToken ); if( !EQUAL(szToken,"(") ) return OGRERR_CORRUPT_DATA; pszPreScan = OGRWktReadToken( pszPreScan, szToken ); if( EQUAL(szToken,"EMPTY") ) { pszPreScan = OGRWktReadToken( pszPreScan, szToken ); *ppszInput = (char *) pszPreScan; if( !EQUAL(szToken,")") ) return OGRERR_CORRUPT_DATA; else return OGRERR_NONE; } /* -------------------------------------------------------------------- */ /* Read the point list. */ /* -------------------------------------------------------------------- */ int nMaxPoint = 0; nPointCount = 0; pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoint, &nPointCount ); if( pszInput == NULL ) return OGRERR_CORRUPT_DATA; *ppszInput = (char *) pszInput; return OGRERR_NONE; } /************************************************************************/ /* exportToWkt() */ /* */ /* Translate this structure into it's well known text format */ /* equivelent. This could be made alot more CPU efficient! */ /************************************************************************/ OGRErr OGRLineString::exportToWkt( char ** ppszDstText ) const { int nMaxString = nPointCount * 20 * 3 + 20; int nRetLen = 0; /* -------------------------------------------------------------------- */ /* Handle special empty case. */ /* -------------------------------------------------------------------- */ if( nPointCount == 0 ) { *ppszDstText = CPLStrdup("LINESTRING(EMPTY)"); return OGRERR_NONE; } /* -------------------------------------------------------------------- */ /* General case. */ /* -------------------------------------------------------------------- */ *ppszDstText = (char *) VSIMalloc( nMaxString ); if( *ppszDstText == NULL ) return OGRERR_NOT_ENOUGH_MEMORY; sprintf( *ppszDstText, "%s (", getGeometryName() ); for( int i = 0; i < nPointCount; i++ ) { if( nMaxString <= (int) strlen(*ppszDstText+nRetLen) + 32 + nRetLen ) { CPLDebug( "OGR", "OGRLineString::exportToWkt() ... buffer overflow.\n" "nMaxString=%d, strlen(*ppszDstText) = %d, i=%d\n" "*ppszDstText = %s", nMaxString, strlen(*ppszDstText), i, *ppszDstText ); VSIFree( *ppszDstText ); *ppszDstText = NULL; return OGRERR_NOT_ENOUGH_MEMORY; } if( i > 0 ) strcat( *ppszDstText + nRetLen, "," ); nRetLen += strlen(*ppszDstText + nRetLen); if( getCoordinateDimension() == 3 ) OGRMakeWktCoordinate( *ppszDstText + nRetLen, paoPoints[i].x, paoPoints[i].y, padfZ[i] ); else OGRMakeWktCoordinate( *ppszDstText + nRetLen, paoPoints[i].x, paoPoints[i].y, 0.0 ); nRetLen += strlen(*ppszDstText + nRetLen); } strcat( *ppszDstText+nRetLen, ")" ); return OGRERR_NONE; } /************************************************************************/ /* get_Length() */ /* */ /* For now we return a simple euclidian 2D distance. */ /************************************************************************/ double OGRLineString::get_Length() const { double dfLength = 0; int i; for( i = 0; i < nPointCount-1; i++ ) { double dfDeltaX, dfDeltaY; dfDeltaX = paoPoints[i+1].x - paoPoints[i].x; dfDeltaY = paoPoints[i+1].y - paoPoints[i].y; dfLength += sqrt(dfDeltaX*dfDeltaX + dfDeltaY*dfDeltaY); } return dfLength; } /************************************************************************/ /* StartPoint() */ /************************************************************************/ void OGRLineString::StartPoint( OGRPoint * poPoint ) const { getPoint( 0, poPoint ); } /************************************************************************/ /* EndPoint() */ /************************************************************************/ void OGRLineString::EndPoint( OGRPoint * poPoint ) const { getPoint( nPointCount-1, poPoint ); } /************************************************************************/ /* Value() */ /* */ /* Get an interpolated point at some distance along the curve. */ /************************************************************************/ void OGRLineString::Value( double dfDistance, OGRPoint * poPoint ) const { double dfLength = 0; int i; if( dfDistance < 0 ) { StartPoint( poPoint ); return; } for( i = 0; i < nPointCount-1; i++ ) { double dfDeltaX, dfDeltaY, dfSegLength; dfDeltaX = paoPoints[i+1].x - paoPoints[i].x; dfDeltaY = paoPoints[i+1].y - paoPoints[i].y; dfSegLength = sqrt(dfDeltaX*dfDeltaX + dfDeltaY*dfDeltaY); if (dfSegLength > 0) { if( (dfLength <= dfDistance) && ((dfLength + dfSegLength) >= dfDistance) ) { double dfRatio; dfRatio = (dfDistance - dfLength) / dfSegLength; poPoint->setX( paoPoints[i].x * (1 - dfRatio) + paoPoints[i+1].x * dfRatio ); poPoint->setY( paoPoints[i].y * (1 - dfRatio) + paoPoints[i+1].y * dfRatio ); if( getCoordinateDimension() == 3 ) poPoint->setZ( padfZ[i] * (1 - dfRatio) + padfZ[i] * dfRatio ); return; } dfLength += dfSegLength; } } EndPoint( poPoint ); } /************************************************************************/ /* getEnvelope() */ /************************************************************************/ void OGRLineString::getEnvelope( OGREnvelope * psEnvelope ) const { double dfMinX, dfMinY, dfMaxX, dfMaxY; if( nPointCount == 0 ) return; dfMinX = dfMaxX = paoPoints[0].x; dfMinY = dfMaxY = paoPoints[0].y; for( int iPoint = 1; iPoint < nPointCount; iPoint++ ) { if( dfMaxX < paoPoints[iPoint].x ) dfMaxX = paoPoints[iPoint].x; if( dfMaxY < paoPoints[iPoint].y ) dfMaxY = paoPoints[iPoint].y; if( dfMinX > paoPoints[iPoint].x ) dfMinX = paoPoints[iPoint].x; if( dfMinY > paoPoints[iPoint].y ) dfMinY = paoPoints[iPoint].y; } psEnvelope->MinX = dfMinX; psEnvelope->MaxX = dfMaxX; psEnvelope->MinY = dfMinY; psEnvelope->MaxY = dfMaxY; } /************************************************************************/ /* Equals() */ /************************************************************************/ OGRBoolean OGRLineString::Equals( OGRGeometry * poOther ) const { OGRLineString *poOLine = (OGRLineString *) poOther; if( poOLine == this ) return TRUE; if( poOther->getGeometryType() != getGeometryType() ) return FALSE; // we should eventually test the SRS. if( getNumPoints() != poOLine->getNumPoints() ) return FALSE; for( int iPoint = 0; iPoint < getNumPoints(); iPoint++ ) { if( getX(iPoint) != poOLine->getX(iPoint) || getY(iPoint) != poOLine->getY(iPoint) || getZ(iPoint) != poOLine->getZ(iPoint) ) return FALSE; } return TRUE; } /************************************************************************/ /* transform() */ /************************************************************************/ OGRErr OGRLineString::transform( OGRCoordinateTransformation *poCT ) { #ifdef DISABLE_OGRGEOM_TRANSFORM return OGRERR_FAILURE; #else double *xyz; int i; /* -------------------------------------------------------------------- */ /* Because we don't want to partially transform this geometry */ /* (if some points fail after some have succeeded) we will */ /* instead make a copy of the points to operate on. */ /* -------------------------------------------------------------------- */ xyz = (double *) CPLMalloc(sizeof(double) * nPointCount * 3); if( xyz == NULL ) return OGRERR_NOT_ENOUGH_MEMORY; for( i = 0; i < nPointCount; i++ ) { xyz[i ] = paoPoints[i].x; xyz[i+nPointCount] = paoPoints[i].y; if( padfZ ) xyz[i+nPointCount*2] = padfZ[i]; else xyz[i+nPointCount*2] = 0.0; } /* -------------------------------------------------------------------- */ /* Transform and reapply. */ /* -------------------------------------------------------------------- */ if( !poCT->Transform( nPointCount, xyz, xyz + nPointCount, xyz+nPointCount*2 ) ) { CPLFree( xyz ); return OGRERR_FAILURE; } else { setPoints( nPointCount, xyz, xyz+nPointCount, xyz+nPointCount*2 ); CPLFree( xyz ); assignSpatialReference( poCT->GetTargetCS() ); return OGRERR_NONE; } #endif }