Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #7120 from nyalldawson/opts
Optimise geometry conversion to/from geos
  • Loading branch information
m-kuhn committed May 31, 2018
2 parents 25f4794 + 3aa4968 commit 497abfe
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 26 deletions.
2 changes: 2 additions & 0 deletions python/core/auto_generated/geometry/qgslinestring.sip.in
Expand Up @@ -89,6 +89,8 @@ Returns the specified point from inside the line string.





double zAt( int index ) const;
%Docstring
Returns the z-coordinate of the specified node in the line string.
Expand Down
68 changes: 42 additions & 26 deletions src/core/geometry/qgsgeos.cpp
Expand Up @@ -1205,35 +1205,29 @@ std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring( const GEOSGeometry
const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit.ctxt, geos );
unsigned int nPoints;
GEOSCoordSeq_getSize_r( geosinit.ctxt, cs, &nPoints );
QVector< double > xOut;
xOut.reserve( nPoints );
QVector< double > yOut;
yOut.reserve( nPoints );
QVector< double > xOut( nPoints );
QVector< double > yOut( nPoints );
QVector< double > zOut;
if ( hasZ )
zOut.reserve( nPoints );
zOut.resize( nPoints );
QVector< double > mOut;
if ( hasM )
mOut.reserve( nPoints );
double x = 0;
double y = 0;
double z = 0;
double m = 0;
mOut.resize( nPoints );
double *x = xOut.data();
double *y = yOut.data();
double *z = zOut.data();
double *m = mOut.data();
for ( unsigned int i = 0; i < nPoints; ++i )
{
GEOSCoordSeq_getX_r( geosinit.ctxt, cs, i, &x );
xOut << x;
GEOSCoordSeq_getY_r( geosinit.ctxt, cs, i, &y );
yOut << y;
GEOSCoordSeq_getX_r( geosinit.ctxt, cs, i, x++ );
GEOSCoordSeq_getY_r( geosinit.ctxt, cs, i, y++ );
if ( hasZ )
{
GEOSCoordSeq_getZ_r( geosinit.ctxt, cs, i, &z );
zOut << z;
GEOSCoordSeq_getZ_r( geosinit.ctxt, cs, i, z++ );
}
if ( hasM )
{
GEOSCoordSeq_getOrdinate_r( geosinit.ctxt, cs, i, 3, &m );
mOut << m;
GEOSCoordSeq_getOrdinate_r( geosinit.ctxt, cs, i, 3, m++ );
}
}
std::unique_ptr< QgsLineString > line( new QgsLineString( xOut, yOut, zOut, mOut ) );
Expand Down Expand Up @@ -1769,35 +1763,57 @@ GEOSCoordSequence *QgsGeos::createCoordinateSequence( const QgsCurve *curve, dou
QgsDebugMsg( QStringLiteral( "GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
return nullptr;
}

const double *xData = line->xData();
const double *yData = line->yData();
const double *zData = hasZ ? line->zData() : nullptr;
const double *mData = hasM ? line->mData() : nullptr;

if ( precision > 0. )
{
for ( int i = 0; i < numOutPoints; ++i )
{
GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, std::round( line->xAt( i % numPoints ) / precision ) * precision );
GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, std::round( line->yAt( i % numPoints ) / precision ) * precision );
if ( i >= numPoints )
{
// start reading back from start of line
xData = line->xData();
yData = line->yData();
zData = hasZ ? line->zData() : nullptr;
mData = hasM ? line->mData() : nullptr;
}
GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, std::round( *xData++ / precision ) * precision );
GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, std::round( *yData++ / precision ) * precision );
if ( hasZ )
{
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, std::round( line->zAt( i % numPoints ) / precision ) * precision );
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, std::round( *zData++ / precision ) * precision );
}
if ( hasM )
{
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, line->mAt( i % numPoints ) );
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, line->mAt( *mData++ ) );
}
}
}
else
{
for ( int i = 0; i < numOutPoints; ++i )
{
GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, line->xAt( i % numPoints ) );
GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, line->yAt( i % numPoints ) );
if ( i >= numPoints )
{
// start reading back from start of line
xData = line->xData();
yData = line->yData();
zData = hasZ ? line->zData() : nullptr;
mData = hasM ? line->mData() : nullptr;
}
GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, *xData++ );
GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, *yData++ );
if ( hasZ )
{
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, line->zAt( i % numPoints ) );
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, *zData++ );
}
if ( hasM )
{
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, line->mAt( i % numPoints ) );
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, *mData++ );
}
}
}
Expand Down
16 changes: 16 additions & 0 deletions src/core/geometry/qgslinestring.cpp
Expand Up @@ -560,6 +560,22 @@ const double *QgsLineString::yData() const
return mY.constData();
}

const double *QgsLineString::zData() const
{
if ( mZ.empty() )
return nullptr;
else
return mZ.constData();
}

const double *QgsLineString::mData() const
{
if ( mM.empty() )
return nullptr;
else
return mM.constData();
}

double QgsLineString::zAt( int index ) const
{
if ( index >= 0 && index < mZ.size() )
Expand Down
20 changes: 20 additions & 0 deletions src/core/geometry/qgslinestring.h
Expand Up @@ -112,6 +112,26 @@ class CORE_EXPORT QgsLineString: public QgsCurve
*/
const double *yData() const SIP_SKIP;

/**
* Returns a const pointer to the z vertex data, or a nullptr if the linestring does
* not have z values.
* \note Not available in Python bindings
* \see xData()
* \see yData()
* \since QGIS 3.2
*/
const double *zData() const SIP_SKIP;

/**
* Returns a const pointer to the m vertex data, or a nullptr if the linestring does
* not have m values.
* \note Not available in Python bindings
* \see xData()
* \see yData()
* \since QGIS 3.2
*/
const double *mData() const SIP_SKIP;

/**
* Returns the z-coordinate of the specified node in the line string.
* \param index index of node, where the first node in the line is 0
Expand Down
13 changes: 13 additions & 0 deletions tests/src/core/testqgsgeometry.cpp
Expand Up @@ -2796,6 +2796,19 @@ void TestQgsGeometry::lineString()
QCOMPARE( fromArray8.zAt( 2 ), 23.0 );
QCOMPARE( fromArray8.mAt( 2 ), 33.0 );

QCOMPARE( *fromArray8.xData(), 1.0 );
QCOMPARE( *( fromArray8.xData() + 1 ), 2.0 );
QCOMPARE( *( fromArray8.xData() + 2 ), 3.0 );
QCOMPARE( *fromArray8.yData(), 11.0 );
QCOMPARE( *( fromArray8.yData() + 1 ), 12.0 );
QCOMPARE( *( fromArray8.yData() + 2 ), 13.0 );
QCOMPARE( *fromArray8.zData(), 21.0 );
QCOMPARE( *( fromArray8.zData() + 1 ), 22.0 );
QCOMPARE( *( fromArray8.zData() + 2 ), 23.0 );
QCOMPARE( *fromArray8.mData(), 31.0 );
QCOMPARE( *( fromArray8.mData() + 1 ), 32.0 );
QCOMPARE( *( fromArray8.mData() + 2 ), 33.0 );

// from QList<QgsPointXY>
QgsLineString fromPtsA = QgsLineString( QVector< QgsPoint >() );
QVERIFY( fromPtsA.isEmpty() );
Expand Down

0 comments on commit 497abfe

Please sign in to comment.