ultimatepp/bazaar/plugin/gdal/ogr/ogrlinestring.cpp
cxl 23ff1e7e82 .gdal moved to bazaar
git-svn-id: svn://ultimatepp.org/upp/trunk@9273 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2015-12-07 13:36:24 +00:00

2020 lines
66 KiB
C++

/******************************************************************************
* $Id: ogrlinestring.cpp 29330 2015-06-14 12:11:11Z rouault $
*
* Project: OpenGIS Simple Features Reference Implementation
* Purpose: The OGRSimpleCurve and OGRLineString geometry classes.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
* Copyright (c) 2008-2014, Even Rouault <even dot rouault at mines-paris dot org>
*
* 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.
****************************************************************************/
#include "ogr_geometry.h"
#include "ogr_p.h"
#include <assert.h>
#include "ogr_geos.h"
CPL_CVSID("$Id: ogrlinestring.cpp 29330 2015-06-14 12:11:11Z rouault $");
/************************************************************************/
/* OGRSimpleCurve() */
/************************************************************************/
OGRSimpleCurve::OGRSimpleCurve()
{
nPointCount = 0;
paoPoints = NULL;
padfZ = NULL;
}
/************************************************************************/
/* ~OGRSimpleCurve() */
/************************************************************************/
OGRSimpleCurve::~OGRSimpleCurve()
{
if( paoPoints != NULL )
OGRFree( paoPoints );
if( padfZ != NULL )
OGRFree( padfZ );
}
/************************************************************************/
/* flattenTo2D() */
/************************************************************************/
void OGRSimpleCurve::flattenTo2D()
{
Make2D();
}
/************************************************************************/
/* clone() */
/************************************************************************/
OGRGeometry *OGRSimpleCurve::clone() const
{
OGRLineString *poNewLineString;
poNewLineString = (OGRLineString*)
OGRGeometryFactory::createGeometry(getGeometryType());
poNewLineString->assignSpatialReference( getSpatialReference() );
poNewLineString->setPoints( nPointCount, paoPoints, padfZ );
poNewLineString->setCoordinateDimension( getCoordinateDimension() );
return poNewLineString;
}
/************************************************************************/
/* empty() */
/************************************************************************/
void OGRSimpleCurve::empty()
{
setNumPoints( 0 );
}
/************************************************************************/
/* setCoordinateDimension() */
/************************************************************************/
void OGRSimpleCurve::setCoordinateDimension( int nNewDimension )
{
nCoordDimension = nNewDimension;
if( nNewDimension == 2 )
Make2D();
else if( nNewDimension == 3 )
Make3D();
}
/************************************************************************/
/* WkbSize() */
/* */
/* Return the size of this object in well known binary */
/* representation including the byte order, and type information. */
/************************************************************************/
int OGRSimpleCurve::WkbSize() const
{
return 5 + 4 + 8 * nPointCount * getCoordinateDimension();
}
/************************************************************************/
/* Make2D() */
/************************************************************************/
void OGRSimpleCurve::Make2D()
{
if( padfZ != NULL )
{
OGRFree( padfZ );
padfZ = NULL;
}
nCoordDimension = 2;
}
/************************************************************************/
/* Make3D() */
/************************************************************************/
void OGRSimpleCurve::Make3D()
{
if( padfZ == NULL )
{
if( nPointCount == 0 )
padfZ = (double *) OGRCalloc(sizeof(double),1);
else
padfZ = (double *) OGRCalloc(sizeof(double),nPointCount);
}
nCoordDimension = 3;
}
/************************************************************************/
/* getPoint() */
/************************************************************************/
/**
* \brief 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 OGRSimpleCurve::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 && padfZ != NULL )
poPoint->setZ( padfZ[i] );
}
/**
* \fn int OGRSimpleCurve::getNumPoints() const;
*
* \brief Fetch vertex count.
*
* Returns the number of vertices in the line string.
*
* @return vertex count.
*/
/**
* \fn double OGRSimpleCurve::getX( int iVertex ) const;
*
* \brief Get X at vertex.
*
* Returns the X value at the indicated vertex. If iVertex is out of range a
* crash may occur, no internal range checking is performed.
*
* @param iVertex the vertex to return, between 0 and getNumPoints()-1.
*
* @return X value.
*/
/**
* \fn double OGRSimpleCurve::getY( int iVertex ) const;
*
* \brief Get Y at vertex.
*
* Returns the Y value at the indicated vertex. If iVertex is out of range a
* crash may occur, no internal range checking is performed.
*
* @param iVertex the vertex to return, between 0 and getNumPoints()-1.
*
* @return X value.
*/
/************************************************************************/
/* getZ() */
/************************************************************************/
/**
* \brief Get Z at vertex.
*
* Returns the Z (elevation) value at the indicated vertex. If no Z
* value is available, 0.0 is returned. If iVertex is out of range a
* crash may occur, no internal range checking is performed.
*
* @param iVertex the vertex to return, between 0 and getNumPoints()-1.
*
* @return Z value.
*/
double OGRSimpleCurve::getZ( int iVertex ) const
{
if( padfZ != NULL && iVertex >= 0 && iVertex < nPointCount
&& nCoordDimension >= 3 )
return( padfZ[iVertex] );
else
return 0.0;
}
/************************************************************************/
/* setNumPoints() */
/************************************************************************/
/**
* \brief 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 OGRSimpleCurve::setNumPoints( int nNewPointCount, int bZeroizeNewContent )
{
if( nNewPointCount == 0 )
{
OGRFree( paoPoints );
paoPoints = NULL;
OGRFree( padfZ );
padfZ = NULL;
nPointCount = 0;
return;
}
if( nNewPointCount > nPointCount )
{
OGRRawPoint* paoNewPoints = (OGRRawPoint *)
VSIRealloc(paoPoints, sizeof(OGRRawPoint) * nNewPointCount);
if (paoNewPoints == NULL)
{
CPLError(CE_Failure, CPLE_OutOfMemory,
"Could not allocate array for %d points", nNewPointCount);
return;
}
paoPoints = paoNewPoints;
if( bZeroizeNewContent )
memset( paoPoints + nPointCount,
0, sizeof(OGRRawPoint) * (nNewPointCount - nPointCount) );
if( getCoordinateDimension() == 3 )
{
double* padfNewZ = (double *)
VSIRealloc( padfZ, sizeof(double)*nNewPointCount );
if (padfNewZ == NULL)
{
CPLError(CE_Failure, CPLE_OutOfMemory,
"Could not allocate array for %d points", nNewPointCount);
return;
}
padfZ = padfNewZ;
if( bZeroizeNewContent )
memset( padfZ + nPointCount, 0,
sizeof(double) * (nNewPointCount - nPointCount) );
}
}
nPointCount = nNewPointCount;
}
/************************************************************************/
/* setPoint() */
/************************************************************************/
/**
* \brief 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
* accommodate 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 OGRSimpleCurve::setPoint( int iPoint, OGRPoint * poPoint )
{
if (poPoint->getCoordinateDimension() < 3)
setPoint( iPoint, poPoint->getX(), poPoint->getY() );
else
setPoint( iPoint, poPoint->getX(), poPoint->getY(), poPoint->getZ() );
}
/************************************************************************/
/* setPoint() */
/************************************************************************/
/**
* \brief 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
* accommodate 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 OGRSimpleCurve::setPoint( int iPoint, double xIn, double yIn, double zIn )
{
if( getCoordinateDimension() == 2 )
Make3D();
if( iPoint >= nPointCount )
{
setNumPoints( iPoint+1 );
if (nPointCount < iPoint + 1)
return;
}
paoPoints[iPoint].x = xIn;
paoPoints[iPoint].y = yIn;
if( zIn != 0.0 )
{
Make3D();
padfZ[iPoint] = zIn;
}
else if( getCoordinateDimension() == 3 )
{
padfZ[iPoint] = 0.0;
}
}
void OGRSimpleCurve::setPoint( int iPoint, double xIn, double yIn )
{
if( iPoint >= nPointCount )
{
setNumPoints( iPoint+1 );
if (nPointCount < iPoint + 1)
return;
}
paoPoints[iPoint].x = xIn;
paoPoints[iPoint].y = yIn;
}
/************************************************************************/
/* setZ() */
/************************************************************************/
void OGRSimpleCurve::setZ( int iPoint, double zIn )
{
if( getCoordinateDimension() == 2 )
Make3D();
if( iPoint >= nPointCount )
{
setNumPoints( iPoint+1 );
if (nPointCount < iPoint + 1)
return;
}
if( padfZ )
padfZ[iPoint] = zIn;
}
/************************************************************************/
/* addPoint() */
/************************************************************************/
/**
* \brief 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 OGRSimpleCurve::addPoint( OGRPoint * poPoint )
{
if ( poPoint->getCoordinateDimension() < 3 )
setPoint( nPointCount, poPoint->getX(), poPoint->getY() );
else
setPoint( nPointCount, poPoint->getX(), poPoint->getY(), poPoint->getZ() );
}
/************************************************************************/
/* addPoint() */
/************************************************************************/
/**
* \brief 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 OGRSimpleCurve::addPoint( double x, double y, double z )
{
setPoint( nPointCount, x, y, z );
}
void OGRSimpleCurve::addPoint( double x, double y )
{
setPoint( nPointCount, x, y );
}
/************************************************************************/
/* setPoints() */
/************************************************************************/
/**
* \brief 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 OGRSimpleCurve::setPoints( int nPointsIn, OGRRawPoint * paoPointsIn,
double * padfZ )
{
setNumPoints( nPointsIn, FALSE );
if (nPointCount < nPointsIn)
return;
memcpy( paoPoints, paoPointsIn, sizeof(OGRRawPoint) * nPointsIn);
/* -------------------------------------------------------------------- */
/* Check 2D/3D. */
/* -------------------------------------------------------------------- */
if( padfZ == NULL && getCoordinateDimension() > 2 )
{
Make2D();
}
else if( padfZ )
{
Make3D();
memcpy( this->padfZ, padfZ, sizeof(double) * nPointsIn );
}
}
/************************************************************************/
/* setPoints() */
/************************************************************************/
/**
* \brief 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 OGRSimpleCurve::setPoints( int nPointsIn, double * padfX, double * padfY,
double * padfZ )
{
int i;
/* -------------------------------------------------------------------- */
/* Check 2D/3D. */
/* -------------------------------------------------------------------- */
if( padfZ == NULL )
Make2D();
else
Make3D();
/* -------------------------------------------------------------------- */
/* Assign values. */
/* -------------------------------------------------------------------- */
setNumPoints( nPointsIn, FALSE );
if (nPointCount < nPointsIn)
return;
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 );
}
/************************************************************************/
/* getPoints() */
/************************************************************************/
/**
* \brief Returns all points of line string.
*
* This method copies all points into user list. This list must be at
* least sizeof(OGRRawPoint) * OGRGeometry::getNumPoints() byte in size.
* It also copies all Z coordinates.
*
* There is no SFCOM analog to this method.
*
* @param paoPointsOut a buffer into which the points is written.
* @param padfZ the Z values that go with the points (optional, may be NULL).
*/
void OGRSimpleCurve::getPoints( OGRRawPoint * paoPointsOut, double * padfZ ) const
{
if ( ! paoPointsOut )
return;
memcpy( paoPointsOut, paoPoints, sizeof(OGRRawPoint) * nPointCount );
/* -------------------------------------------------------------------- */
/* Check 2D/3D. */
/* -------------------------------------------------------------------- */
if( padfZ )
{
if ( this->padfZ )
memcpy( padfZ, this->padfZ, sizeof(double) * nPointCount );
else
memset( padfZ, 0, sizeof(double) * nPointCount );
}
}
/************************************************************************/
/* getPoints() */
/************************************************************************/
/**
* \brief Returns all points of line string.
*
* This method copies all points into user arrays. The user provides the
* stride between 2 consecutives elements of the array.
*
* On some CPU architectures, care must be taken so that the arrays are properly aligned.
*
* There is no SFCOM analog to this method.
*
* @param pabyX a buffer of at least (sizeof(double) * nXStride * nPointCount) bytes, may be NULL.
* @param nXStride the number of bytes between 2 elements of pabyX.
* @param pabyY a buffer of at least (sizeof(double) * nYStride * nPointCount) bytes, may be NULL.
* @param nYStride the number of bytes between 2 elements of pabyY.
* @param pabyZ a buffer of at last size (sizeof(double) * nZStride * nPointCount) bytes, may be NULL.
* @param nZStride the number of bytes between 2 elements of pabyZ.
*
* @since OGR 1.9.0
*/
void OGRSimpleCurve::getPoints( void* pabyX, int nXStride,
void* pabyY, int nYStride,
void* pabyZ, int nZStride) const
{
int i;
if (pabyX != NULL && nXStride == 0)
return;
if (pabyY != NULL && nYStride == 0)
return;
if (pabyZ != NULL && nZStride == 0)
return;
if (nXStride == 2 * sizeof(double) &&
nYStride == 2 * sizeof(double) &&
(char*)pabyY == (char*)pabyX + sizeof(double) &&
(pabyZ == NULL || nZStride == sizeof(double)))
{
getPoints((OGRRawPoint *)pabyX, (double*)pabyZ);
return;
}
for(i=0;i<nPointCount;i++)
{
if (pabyX) *(double*)((char*)pabyX + i * nXStride) = paoPoints[i].x;
if (pabyY) *(double*)((char*)pabyY + i * nYStride) = paoPoints[i].y;
}
if (pabyZ)
{
for(i=0;i<nPointCount;i++)
{
*(double*)((char*)pabyZ + i * nZStride) = (padfZ) ? padfZ[i] : 0.0;
}
}
}
/************************************************************************/
/* reversePoints() */
/************************************************************************/
/**
* \brief Reverse point order.
*
* This method updates the points in this line string in place
* reversing the point ordering (first for last, etc).
*/
void OGRSimpleCurve::reversePoints()
{
int i;
for( i = 0; i < nPointCount/2; i++ )
{
OGRRawPoint sPointTemp = paoPoints[i];
paoPoints[i] = paoPoints[nPointCount-i-1];
paoPoints[nPointCount-i-1] = sPointTemp;
if( padfZ )
{
double dfZTemp = padfZ[i];
padfZ[i] = padfZ[nPointCount-i-1];
padfZ[nPointCount-i-1] = dfZTemp;
}
}
}
/************************************************************************/
/* addSubLineString() */
/************************************************************************/
/**
* \brief 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 OGRSimpleCurve::addSubLineString( const OGRLineString *poOtherLine,
int nStartVertex, int nEndVertex )
{
int nOtherLineNumPoints = poOtherLine->getNumPoints();
if (nOtherLineNumPoints == 0)
return;
/* -------------------------------------------------------------------- */
/* Do a bit of argument defaulting and validation. */
/* -------------------------------------------------------------------- */
if( nEndVertex == -1 )
nEndVertex = nOtherLineNumPoints - 1;
if( nStartVertex < 0 || nEndVertex < 0
|| nStartVertex >= nOtherLineNumPoints
|| nEndVertex >= nOtherLineNumPoints )
{
CPLAssert( FALSE );
return;
}
/* -------------------------------------------------------------------- */
/* Grow this linestring to hold the additional points. */
/* -------------------------------------------------------------------- */
int nOldPoints = nPointCount;
int nPointsToAdd = ABS(nEndVertex-nStartVertex) + 1;
setNumPoints( nPointsToAdd + nOldPoints, FALSE );
if (nPointCount < nPointsToAdd + nOldPoints)
return;
/* -------------------------------------------------------------------- */
/* 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 OGRSimpleCurve::importFromWkb( unsigned char * pabyData,
int nSize,
OGRwkbVariant eWkbVariant )
{
OGRwkbByteOrder eByteOrder;
int nDataOffset = 0;
int nNewNumPoints = 0;
OGRErr eErr = importPreambuleOfCollectionFromWkb( pabyData,
nSize,
nDataOffset,
eByteOrder,
16,
nNewNumPoints,
eWkbVariant );
if( eErr >= 0 )
return eErr;
/* Check if the wkb stream buffer is big enough to store
* fetched number of points.
* 16 or 24 - size of point structure
*/
int nPointSize = (getCoordinateDimension() == 3 ? 24 : 16);
if (nNewNumPoints < 0 || nNewNumPoints > INT_MAX / nPointSize)
return OGRERR_CORRUPT_DATA;
int nBufferMinSize = nPointSize * nNewNumPoints;
if( nSize != -1 && nBufferMinSize > nSize )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Length of input WKB is too small" );
return OGRERR_NOT_ENOUGH_DATA;
}
setNumPoints( nNewNumPoints, FALSE );
if (nPointCount < nNewNumPoints)
return OGRERR_FAILURE;
/* -------------------------------------------------------------------- */
/* Get the vertex. */
/* -------------------------------------------------------------------- */
int i = 0;
if( getCoordinateDimension() == 3 )
{
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( getCoordinateDimension() == 3 )
{
for( i = 0; i < nPointCount; i++ )
{
CPL_SWAPDOUBLE( padfZ + i );
}
}
}
return OGRERR_NONE;
}
/************************************************************************/
/* exportToWkb() */
/* */
/* Build a well known binary representation of this object. */
/************************************************************************/
OGRErr OGRSimpleCurve::exportToWkb( OGRwkbByteOrder eByteOrder,
unsigned char * pabyData,
OGRwkbVariant eWkbVariant ) const
{
/* -------------------------------------------------------------------- */
/* Set the byte order. */
/* -------------------------------------------------------------------- */
pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER((unsigned char) eByteOrder);
/* -------------------------------------------------------------------- */
/* Set the geometry feature type. */
/* -------------------------------------------------------------------- */
GUInt32 nGType = getGeometryType();
if ( eWkbVariant == wkbVariantIso )
nGType = getIsoGeometryType();
else if( eWkbVariant == wkbVariantPostGIS1 && wkbHasZ((OGRwkbGeometryType)nGType) )
nGType = (OGRwkbGeometryType)(wkbFlatten(nGType) | wkb25DBitInternalUse); /* yes we explicitly set wkb25DBit */
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 OGRSimpleCurve::importFromWkt( char ** ppszInput )
{
int bHasZ = FALSE, bHasM = FALSE;
OGRErr eErr = importPreambuleFromWkt(ppszInput, &bHasZ, &bHasM);
if( eErr >= 0 )
return eErr;
const char *pszInput = *ppszInput;
/* -------------------------------------------------------------------- */
/* Read the point list. */
/* -------------------------------------------------------------------- */
nPointCount = 0;
int nMaxPoints = 0;
pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoints,
&nPointCount );
if( pszInput == NULL )
return OGRERR_CORRUPT_DATA;
*ppszInput = (char *) pszInput;
if( padfZ == NULL )
nCoordDimension = 2;
else
{
/* Ignore Z array when we have a LINESTRING M */
if (bHasM && !bHasZ)
{
nCoordDimension = 2;
CPLFree(padfZ);
padfZ = NULL;
}
else
nCoordDimension = 3;
}
return OGRERR_NONE;
}
/************************************************************************/
/* importFromWKTListOnly() */
/* */
/* Instantiate from "(x y, x y, ...)" */
/************************************************************************/
OGRErr OGRSimpleCurve::importFromWKTListOnly( char ** ppszInput, int bHasZ, int bHasM,
OGRRawPoint*& paoPointsIn, int& nMaxPointsIn,
double*& padfZIn )
{
const char *pszInput = *ppszInput;
/* -------------------------------------------------------------------- */
/* Read the point list. */
/* -------------------------------------------------------------------- */
int nPointCountRead = 0;
pszInput = OGRWktReadPoints( pszInput, &paoPointsIn, &padfZIn, &nMaxPointsIn,
&nPointCountRead );
if( pszInput == NULL )
return OGRERR_CORRUPT_DATA;
*ppszInput = (char *) pszInput;
/* Ignore Z array when we have a POLYGON M */
if (bHasM && !bHasZ)
setPoints( nPointCountRead, paoPointsIn, NULL );
else
setPoints( nPointCountRead, paoPointsIn, padfZIn );
return OGRERR_NONE;
}
/************************************************************************/
/* exportToWkt() */
/* */
/* Translate this structure into it's well known text format */
/* equivelent. This could be made alot more CPU efficient! */
/************************************************************************/
OGRErr OGRSimpleCurve::exportToWkt( char ** ppszDstText,
OGRwkbVariant eWkbVariant ) const
{
int nMaxString = nPointCount * 40 * 3 + 25;
int nRetLen = 0;
/* -------------------------------------------------------------------- */
/* Handle special empty case. */
/* -------------------------------------------------------------------- */
if( IsEmpty() )
{
CPLString osEmpty;
if( getCoordinateDimension() == 3 && eWkbVariant == wkbVariantIso )
osEmpty.Printf("%s Z EMPTY",getGeometryName());
else
osEmpty.Printf("%s EMPTY",getGeometryName());
*ppszDstText = CPLStrdup(osEmpty);
return OGRERR_NONE;
}
/* -------------------------------------------------------------------- */
/* General case. */
/* -------------------------------------------------------------------- */
*ppszDstText = (char *) VSIMalloc( nMaxString );
if( *ppszDstText == NULL )
return OGRERR_NOT_ENOUGH_MEMORY;
if( getCoordinateDimension() == 3 && eWkbVariant == wkbVariantIso )
sprintf( *ppszDstText, "%s Z (", getGeometryName() );
else
sprintf( *ppszDstText, "%s (", getGeometryName() );
for( int i = 0; i < nPointCount; i++ )
{
if( nMaxString <= (int) strlen(*ppszDstText+nRetLen) + 32 + nRetLen )
{
CPLDebug( "OGR",
"OGRSimpleCurve::exportToWkt() ... buffer overflow.\n"
"nMaxString=%d, strlen(*ppszDstText) = %d, i=%d\n"
"*ppszDstText = %s",
nMaxString, (int) 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],
nCoordDimension );
else
OGRMakeWktCoordinate( *ppszDstText + nRetLen,
paoPoints[i].x,
paoPoints[i].y,
0.0,
nCoordDimension );
nRetLen += strlen(*ppszDstText + nRetLen);
}
strcat( *ppszDstText+nRetLen, ")" );
return OGRERR_NONE;
}
/************************************************************************/
/* get_Length() */
/* */
/* For now we return a simple euclidian 2D distance. */
/************************************************************************/
double OGRSimpleCurve::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 OGRSimpleCurve::StartPoint( OGRPoint * poPoint ) const
{
getPoint( 0, poPoint );
}
/************************************************************************/
/* EndPoint() */
/************************************************************************/
void OGRSimpleCurve::EndPoint( OGRPoint * poPoint ) const
{
getPoint( nPointCount-1, poPoint );
}
/************************************************************************/
/* Value() */
/* */
/* Get an interpolated point at some distance along the curve. */
/************************************************************************/
void OGRSimpleCurve::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+1] * dfRatio );
return;
}
dfLength += dfSegLength;
}
}
EndPoint( poPoint );
}
/************************************************************************/
/* Project() */
/* */
/* Return distance of point projected on line from origin of this line */
/************************************************************************/
/**
* \brief Project point on linestring.
*
* The input point projeted on linestring. This is the shortest distance
* from point to the linestring. The distance from begin of linestring to
* the point projection returned.
*
* This method is built on the GEOS library (GEOS >= 3.2.0), check it for the
* definition of the geometry operation.
* If OGR is built without the GEOS library, this method will always return -1,
* issuing a CPLE_NotSupported error.
*
* @return a distance from the begin of the linestring to the projected point.
*
* @since OGR 1.11.0
*/
/* GEOS >= 3.2.0 for project capabilty */
#if defined(HAVE_GEOS)
#if GEOS_VERSION_MAJOR > 3 || (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR >= 2)
#define HAVE_GEOS_PROJECT
#endif
#endif
double OGRSimpleCurve::Project(const OGRPoint *poPoint) const
{
double dfResult = -1;
#ifndef HAVE_GEOS_PROJECT
CPLError(CE_Failure, CPLE_NotSupported,
"GEOS support not enabled.");
return dfResult;
#else
GEOSGeom hThisGeosGeom = NULL;
GEOSGeom hPointGeosGeom = NULL;
GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
hThisGeosGeom = exportToGEOS(hGEOSCtxt);
hPointGeosGeom = poPoint->exportToGEOS(hGEOSCtxt);
if (hThisGeosGeom != NULL && hPointGeosGeom != NULL)
{
dfResult = GEOSProject_r(hGEOSCtxt, hThisGeosGeom, hPointGeosGeom);
}
GEOSGeom_destroy_r(hGEOSCtxt, hThisGeosGeom);
GEOSGeom_destroy_r(hGEOSCtxt, hPointGeosGeom);
freeGEOSContext(hGEOSCtxt);
return dfResult;
#endif /* HAVE_GEOS */
}
/************************************************************************/
/* getSubLine() */
/* */
/* Extracts a portion of this OGRLineString into a new OGRLineString */
/************************************************************************/
/**
* \brief Get the portion of linestring.
*
* The portion of the linestring extracted to new one. The input distances
* (maybe present as ratio of length of linestring) set begin and end of
* extracted portion.
*
* @param dfDistanceFrom The distance from the origin of linestring, where the subline should begins
* @param dfDistanceTo The distance from the origin of linestring, where the subline should ends
* @param bAsRatio The flag indicating that distances are the ratio of the linestring length.
*
* @return a newly allocated linestring now owned by the caller, or NULL on failure.
*
* @since OGR 1.11.0
*/
OGRLineString* OGRSimpleCurve::getSubLine(double dfDistanceFrom, double dfDistanceTo, int bAsRatio) const
{
OGRLineString *poNewLineString;
double dfLength = 0;
int i;
poNewLineString = new OGRLineString();
poNewLineString->assignSpatialReference(getSpatialReference());
//poNewLineString->setPoints(nPointCount, paoPoints, padfZ);
poNewLineString->setCoordinateDimension(getCoordinateDimension());
double dfLen = get_Length();
if (bAsRatio == TRUE)
{
//convert to real distance
dfDistanceFrom *= dfLen;
dfDistanceTo *= dfLen;
}
if (dfDistanceFrom < 0)
dfDistanceFrom = 0;
if (dfDistanceTo > dfLen)
dfDistanceTo = dfLen;
if ( dfDistanceFrom > dfDistanceTo || dfDistanceFrom >= dfLen)
{
CPLError(CE_Failure, CPLE_IllegalArg, "Input distances are invalid.");
return NULL;
}
//get first point
if (dfDistanceFrom == 0)
{
if (getCoordinateDimension() == 3)
poNewLineString->addPoint(paoPoints[0].x, paoPoints[0].y, padfZ[0]);
else
poNewLineString->addPoint(paoPoints[0].x, paoPoints[0].y);
i = 0;
}
else
{
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);
double dfX, dfY, dfRatio;
if (dfSegLength > 0)
{
if ((dfLength <= dfDistanceFrom) && ((dfLength + dfSegLength) >=
dfDistanceFrom))
{
dfRatio = (dfDistanceFrom - dfLength) / dfSegLength;
dfX = paoPoints[i].x * (1 - dfRatio)
+ paoPoints[i + 1].x * dfRatio;
dfY = paoPoints[i].y * (1 - dfRatio)
+ paoPoints[i + 1].y * dfRatio;
if (getCoordinateDimension() == 3)
{
poNewLineString->addPoint(dfX, dfY, padfZ[i] * (1 - dfRatio)
+ padfZ[i+1] * dfRatio);
}
else
{
poNewLineString->addPoint(dfX, dfY);
}
//check if dfDistanceTo is in same segment
if ((dfLength <= dfDistanceTo) && ((dfLength + dfSegLength) >=
dfDistanceTo))
{
dfRatio = (dfDistanceTo - dfLength) / dfSegLength;
dfX = paoPoints[i].x * (1 - dfRatio)
+ paoPoints[i + 1].x * dfRatio;
dfY = paoPoints[i].y * (1 - dfRatio)
+ paoPoints[i + 1].y * dfRatio;
if (getCoordinateDimension() == 3)
{
poNewLineString->addPoint(dfX, dfY, padfZ[i] * (1 - dfRatio)
+ padfZ[i + 1] * dfRatio);
}
else
{
poNewLineString->addPoint(dfX, dfY);
}
if (poNewLineString->getNumPoints() < 2)
{
delete poNewLineString;
poNewLineString = NULL;
}
return poNewLineString;
}
i++;
dfLength += dfSegLength;
break;
}
dfLength += dfSegLength;
}
}
}
//add points
for (; i < nPointCount - 1; i++)
{
double dfDeltaX, dfDeltaY, dfSegLength;
if (getCoordinateDimension() == 3)
poNewLineString->addPoint(paoPoints[i].x, paoPoints[i].y, padfZ[i]);
else
poNewLineString->addPoint(paoPoints[i].x, paoPoints[i].y);
dfDeltaX = paoPoints[i + 1].x - paoPoints[i].x;
dfDeltaY = paoPoints[i + 1].y - paoPoints[i].y;
dfSegLength = sqrt(dfDeltaX*dfDeltaX + dfDeltaY*dfDeltaY);
double dfX, dfY, dfRatio;
if (dfSegLength > 0)
{
if ((dfLength <= dfDistanceTo) && ((dfLength + dfSegLength) >=
dfDistanceTo))
{
dfRatio = (dfDistanceTo - dfLength) / dfSegLength;
dfX = paoPoints[i].x * (1 - dfRatio)
+ paoPoints[i + 1].x * dfRatio;
dfY = paoPoints[i].y * (1 - dfRatio)
+ paoPoints[i + 1].y * dfRatio;
if (getCoordinateDimension() == 3)
poNewLineString->addPoint(dfX, dfY, padfZ[i] * (1 - dfRatio)
+ padfZ[i + 1] * dfRatio);
else
poNewLineString->addPoint(dfX, dfY);
return poNewLineString;
}
dfLength += dfSegLength;
}
}
if (getCoordinateDimension() == 3)
poNewLineString->addPoint(paoPoints[nPointCount - 1].x, paoPoints[nPointCount - 1].y, padfZ[nPointCount - 1]);
else
poNewLineString->addPoint(paoPoints[nPointCount - 1].x, paoPoints[nPointCount - 1].y);
if (poNewLineString->getNumPoints() < 2)
{
delete poNewLineString;
poNewLineString = NULL;
}
return poNewLineString;
}
/************************************************************************/
/* getEnvelope() */
/************************************************************************/
void OGRSimpleCurve::getEnvelope( OGREnvelope * psEnvelope ) const
{
double dfMinX, dfMinY, dfMaxX, dfMaxY;
if( IsEmpty() )
{
psEnvelope->MinX = 0;
psEnvelope->MaxX = 0;
psEnvelope->MinY = 0;
psEnvelope->MaxY = 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;
}
/************************************************************************/
/* getEnvelope() */
/************************************************************************/
void OGRSimpleCurve::getEnvelope( OGREnvelope3D * psEnvelope ) const
{
getEnvelope((OGREnvelope*)psEnvelope);
double dfMinZ, dfMaxZ;
if( IsEmpty() || padfZ == NULL )
{
psEnvelope->MinZ = 0;
psEnvelope->MaxZ = 0;
return;
}
dfMinZ = dfMaxZ = padfZ[0];
for( int iPoint = 1; iPoint < nPointCount; iPoint++ )
{
if( dfMinZ > padfZ[iPoint] )
dfMinZ = padfZ[iPoint];
if( dfMaxZ < padfZ[iPoint] )
dfMaxZ = padfZ[iPoint];
}
psEnvelope->MinZ = dfMinZ;
psEnvelope->MaxZ = dfMaxZ;
}
/************************************************************************/
/* Equals() */
/************************************************************************/
OGRBoolean OGRSimpleCurve::Equals( OGRGeometry * poOther ) const
{
OGRLineString *poOLine = (OGRLineString *) poOther;
if( poOLine == this )
return TRUE;
if( poOther->getGeometryType() != getGeometryType() )
return FALSE;
if( IsEmpty() && poOther->IsEmpty() )
return TRUE;
// 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 OGRSimpleCurve::transform( OGRCoordinateTransformation *poCT )
{
#ifdef DISABLE_OGRGEOM_TRANSFORM
return OGRERR_FAILURE;
#else
double *xyz;
int *pabSuccess;
int i, j;
/* -------------------------------------------------------------------- */
/* Make a copy of the points to operate on, so as to be able to */
/* keep only valid reprojected points if partial reprojection enabled */
/* or keeping intact the original geometry if only full reprojection */
/* allowed. */
/* -------------------------------------------------------------------- */
xyz = (double *) VSIMalloc(sizeof(double) * nPointCount * 3);
pabSuccess = (int *) VSICalloc(sizeof(int), nPointCount);
if( xyz == NULL || pabSuccess == NULL )
{
VSIFree(xyz);
VSIFree(pabSuccess);
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. */
/* -------------------------------------------------------------------- */
poCT->TransformEx( nPointCount, xyz, xyz + nPointCount,
xyz+nPointCount*2, pabSuccess );
const char* pszEnablePartialReprojection = NULL;
for( i = 0, j = 0; i < nPointCount; i++ )
{
if (pabSuccess[i])
{
xyz[j] = xyz[i];
xyz[j+nPointCount] = xyz[i+nPointCount];
xyz[j+2*nPointCount] = xyz[i+2*nPointCount];
j ++;
}
else
{
if (pszEnablePartialReprojection == NULL)
pszEnablePartialReprojection =
CPLGetConfigOption("OGR_ENABLE_PARTIAL_REPROJECTION", NULL);
if (pszEnablePartialReprojection == NULL)
{
static int bHasWarned = FALSE;
if (!bHasWarned)
{
/* Check that there is at least one valid reprojected point */
/* and issue an error giving an hint to use OGR_ENABLE_PARTIAL_REPROJECTION */
int bHasOneValidPoint = (j != 0);
for( ; i < nPointCount && !bHasOneValidPoint; i++ )
{
if (pabSuccess[i])
bHasOneValidPoint = TRUE;
}
if (bHasOneValidPoint)
{
bHasWarned = TRUE;
CPLError(CE_Failure, CPLE_AppDefined,
"Full reprojection failed, but partial is possible if you define "
"OGR_ENABLE_PARTIAL_REPROJECTION configuration option to TRUE");
}
}
CPLFree( xyz );
CPLFree( pabSuccess );
return OGRERR_FAILURE;
}
else if (!CSLTestBoolean(pszEnablePartialReprojection))
{
CPLFree( xyz );
CPLFree( pabSuccess );
return OGRERR_FAILURE;
}
}
}
if (j == 0 && nPointCount != 0)
{
CPLFree( xyz );
CPLFree( pabSuccess );
return OGRERR_FAILURE;
}
setPoints( j, xyz, xyz+nPointCount,
( padfZ ) ? xyz+nPointCount*2 : NULL);
CPLFree( xyz );
CPLFree( pabSuccess );
assignSpatialReference( poCT->GetTargetCS() );
return OGRERR_NONE;
#endif
}
/************************************************************************/
/* IsEmpty() */
/************************************************************************/
OGRBoolean OGRSimpleCurve::IsEmpty( ) const
{
return (nPointCount == 0);
}
/************************************************************************/
/* OGRSimpleCurve::segmentize() */
/************************************************************************/
void OGRSimpleCurve::segmentize( double dfMaxLength )
{
if (dfMaxLength <= 0)
{
CPLError(CE_Failure, CPLE_AppDefined,
"dfMaxLength must be strictly positive");
return;
}
if( nPointCount < 2 )
return;
/* So as to make sure that the same line followed in both directions */
/* result in the same segmentized line */
if ( paoPoints[0].x < paoPoints[nPointCount - 1].x ||
(paoPoints[0].x == paoPoints[nPointCount - 1].x &&
paoPoints[0].y < paoPoints[nPointCount - 1].y) )
{
reversePoints();
segmentize(dfMaxLength);
reversePoints();
}
int i;
OGRRawPoint* paoNewPoints = NULL;
double* padfNewZ = NULL;
int nNewPointCount = 0;
double dfSquareMaxLength = dfMaxLength * dfMaxLength;
const int nCoordinateDimension = getCoordinateDimension();
for( i = 0; i < nPointCount; i++ )
{
paoNewPoints = (OGRRawPoint *)
OGRRealloc(paoNewPoints, sizeof(OGRRawPoint) * (nNewPointCount + 1));
paoNewPoints[nNewPointCount] = paoPoints[i];
if( nCoordinateDimension == 3 )
{
padfNewZ = (double *)
OGRRealloc(padfNewZ, sizeof(double) * (nNewPointCount + 1));
padfNewZ[nNewPointCount] = padfZ[i];
}
nNewPointCount++;
if (i == nPointCount - 1)
break;
double dfX = paoPoints[i+1].x - paoPoints[i].x;
double dfY = paoPoints[i+1].y - paoPoints[i].y;
double dfSquareDist = dfX * dfX + dfY * dfY;
if (dfSquareDist > dfSquareMaxLength)
{
int nIntermediatePoints = (int)floor(sqrt(dfSquareDist / dfSquareMaxLength));
int j;
paoNewPoints = (OGRRawPoint *)
OGRRealloc(paoNewPoints, sizeof(OGRRawPoint) * (nNewPointCount + nIntermediatePoints));
if( nCoordinateDimension == 3 )
{
padfNewZ = (double *)
OGRRealloc(padfNewZ, sizeof(double) * (nNewPointCount + nIntermediatePoints));
}
for(j=1;j<=nIntermediatePoints;j++)
{
paoNewPoints[nNewPointCount + j - 1].x = paoPoints[i].x + j * dfX / (nIntermediatePoints + 1);
paoNewPoints[nNewPointCount + j - 1].y = paoPoints[i].y + j * dfY / (nIntermediatePoints + 1);
if( nCoordinateDimension == 3 )
{
/* No interpolation */
padfNewZ[nNewPointCount + j - 1] = padfZ[i];
}
}
nNewPointCount += nIntermediatePoints;
}
}
OGRFree(paoPoints);
paoPoints = paoNewPoints;
nPointCount = nNewPointCount;
if( nCoordinateDimension == 3 )
{
OGRFree(padfZ);
padfZ = padfNewZ;
}
}
/************************************************************************/
/* swapXY() */
/************************************************************************/
void OGRSimpleCurve::swapXY()
{
int i;
for( i = 0; i < nPointCount; i++ )
{
double dfTemp = paoPoints[i].x;
paoPoints[i].x = paoPoints[i].y;
paoPoints[i].y = dfTemp;
}
}
/************************************************************************/
/* OGRSimpleCurvePointIterator */
/************************************************************************/
class OGRSimpleCurvePointIterator: public OGRPointIterator
{
const OGRSimpleCurve* poSC;
int iCurPoint;
public:
OGRSimpleCurvePointIterator(const OGRSimpleCurve* poSC) : poSC(poSC), iCurPoint(0) {}
virtual OGRBoolean getNextPoint(OGRPoint* p);
};
/************************************************************************/
/* getNextPoint() */
/************************************************************************/
OGRBoolean OGRSimpleCurvePointIterator::getNextPoint(OGRPoint* p)
{
if( iCurPoint >= poSC->getNumPoints() )
return FALSE;
poSC->getPoint(iCurPoint, p);
iCurPoint ++;
return TRUE;
}
/************************************************************************/
/* getPointIterator() */
/************************************************************************/
OGRPointIterator* OGRSimpleCurve::getPointIterator() const
{
return new OGRSimpleCurvePointIterator(this);
}
/************************************************************************/
/* OGRLineString() */
/************************************************************************/
/**
* \brief Create an empty line string.
*/
OGRLineString::OGRLineString()
{
}
/************************************************************************/
/* ~OGRLineString() */
/************************************************************************/
OGRLineString::~OGRLineString()
{
}
/************************************************************************/
/* getGeometryType() */
/************************************************************************/
OGRwkbGeometryType OGRLineString::getGeometryType() const
{
if( nCoordDimension == 3 )
return wkbLineString25D;
else
return wkbLineString;
}
/************************************************************************/
/* getGeometryName() */
/************************************************************************/
const char * OGRLineString::getGeometryName() const
{
return "LINESTRING";
}
/************************************************************************/
/* curveToLine() */
/************************************************************************/
OGRLineString* OGRLineString::CurveToLine(CPL_UNUSED double dfMaxAngleStepSizeDegrees,
CPL_UNUSED const char* const* papszOptions) const
{
return (OGRLineString*)clone();
}
/************************************************************************/
/* get_LinearArea() */
/************************************************************************/
/**
* \brief Compute area of ring / closed linestring.
*
* The area is computed according to Green's Theorem:
*
* Area is "Sum(x(i)*(y(i+1) - y(i-1)))/2" for i = 0 to pointCount-1,
* assuming the last point is a duplicate of the first.
*
* @return computed area.
*/
double OGRSimpleCurve::get_LinearArea() const
{
double dfAreaSum;
int i;
if( nPointCount < 2 )
return 0;
dfAreaSum = paoPoints[0].x * (paoPoints[1].y - paoPoints[nPointCount-1].y);
for( i = 1; i < nPointCount-1; i++ )
{
dfAreaSum += paoPoints[i].x * (paoPoints[i+1].y - paoPoints[i-1].y);
}
dfAreaSum += paoPoints[nPointCount-1].x * (paoPoints[0].y - paoPoints[nPointCount-2].y);
return 0.5 * fabs(dfAreaSum);
}
/************************************************************************/
/* getCurveGeometry() */
/************************************************************************/
OGRGeometry* OGRLineString::getCurveGeometry(const char* const* papszOptions) const
{
return OGRGeometryFactory::curveFromLineString(this, papszOptions);
}
/************************************************************************/
/* TransferMembersAndDestroy() */
/************************************************************************/
OGRLineString* OGRLineString::TransferMembersAndDestroy(
OGRLineString* poSrc,
OGRLineString* poDst)
{
poDst->setCoordinateDimension(poSrc->getCoordinateDimension());
poDst->assignSpatialReference(poSrc->getSpatialReference());
poDst->nPointCount = poSrc->nPointCount;
poDst->paoPoints = poSrc->paoPoints;
poDst->padfZ = poSrc->padfZ;
poSrc->nPointCount = 0;
poSrc->paoPoints = NULL;
poSrc->padfZ = NULL;
delete poSrc;
return poDst;
}
/************************************************************************/
/* CastToLinearRing() */
/************************************************************************/
/**
* \brief Cast to linear ring.
*
* The passed in geometry is consumed and a new one returned (or NULL in case
* of failure)
*
* @param poLS the input geometry - ownership is passed to the method.
* @return new geometry.
*/
OGRLinearRing* OGRLineString::CastToLinearRing(OGRLineString* poLS)
{
if( poLS->nPointCount < 2 || !poLS->get_IsClosed() )
{
CPLError(CE_Failure, CPLE_AppDefined, "Cannot convert non-closed linestring to linearring");
delete poLS;
return NULL;
}
return (OGRLinearRing*)TransferMembersAndDestroy(poLS, new OGRLinearRing());
}
/************************************************************************/
/* GetCasterToLineString() */
/************************************************************************/
OGRCurveCasterToLineString OGRLineString::GetCasterToLineString() const {
return (OGRCurveCasterToLineString) OGRGeometry::CastToIdentity;
}
/************************************************************************/
/* GetCasterToLinearRing() */
/************************************************************************/
OGRCurveCasterToLinearRing OGRLineString::GetCasterToLinearRing() const {
return (OGRCurveCasterToLinearRing) OGRLineString::CastToLinearRing;
}
/************************************************************************/
/* get_Area() */
/************************************************************************/
double OGRLineString::get_Area() const
{
return get_LinearArea();
}
/************************************************************************/
/* get_AreaOfCurveSegments() */
/************************************************************************/
double OGRLineString::get_AreaOfCurveSegments() const
{
return 0;
}