Skip to content

Commit

Permalink
Merge pull request #7120 from nyalldawson/opts
Browse files Browse the repository at this point in the history
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
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ Returns the specified point from inside the line string.








double zAt( int index ) const; double zAt( int index ) const;
%Docstring %Docstring
Returns the z-coordinate of the specified node in the line string. 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
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -1205,35 +1205,29 @@ std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring( const GEOSGeometry
const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit.ctxt, geos ); const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit.ctxt, geos );
unsigned int nPoints; unsigned int nPoints;
GEOSCoordSeq_getSize_r( geosinit.ctxt, cs, &nPoints ); GEOSCoordSeq_getSize_r( geosinit.ctxt, cs, &nPoints );
QVector< double > xOut; QVector< double > xOut( nPoints );
xOut.reserve( nPoints ); QVector< double > yOut( nPoints );
QVector< double > yOut;
yOut.reserve( nPoints );
QVector< double > zOut; QVector< double > zOut;
if ( hasZ ) if ( hasZ )
zOut.reserve( nPoints ); zOut.resize( nPoints );
QVector< double > mOut; QVector< double > mOut;
if ( hasM ) if ( hasM )
mOut.reserve( nPoints ); mOut.resize( nPoints );
double x = 0; double *x = xOut.data();
double y = 0; double *y = yOut.data();
double z = 0; double *z = zOut.data();
double m = 0; double *m = mOut.data();
for ( unsigned int i = 0; i < nPoints; ++i ) for ( unsigned int i = 0; i < nPoints; ++i )
{ {
GEOSCoordSeq_getX_r( geosinit.ctxt, cs, i, &x ); GEOSCoordSeq_getX_r( geosinit.ctxt, cs, i, x++ );
xOut << x; GEOSCoordSeq_getY_r( geosinit.ctxt, cs, i, y++ );
GEOSCoordSeq_getY_r( geosinit.ctxt, cs, i, &y );
yOut << y;
if ( hasZ ) if ( hasZ )
{ {
GEOSCoordSeq_getZ_r( geosinit.ctxt, cs, i, &z ); GEOSCoordSeq_getZ_r( geosinit.ctxt, cs, i, z++ );
zOut << z;
} }
if ( hasM ) if ( hasM )
{ {
GEOSCoordSeq_getOrdinate_r( geosinit.ctxt, cs, i, 3, &m ); GEOSCoordSeq_getOrdinate_r( geosinit.ctxt, cs, i, 3, m++ );
mOut << m;
} }
} }
std::unique_ptr< QgsLineString > line( new QgsLineString( xOut, yOut, zOut, mOut ) ); 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 ) ); QgsDebugMsg( QStringLiteral( "GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
return nullptr; 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. ) if ( precision > 0. )
{ {
for ( int i = 0; i < numOutPoints; ++i ) for ( int i = 0; i < numOutPoints; ++i )
{ {
GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, std::round( line->xAt( i % numPoints ) / precision ) * precision ); if ( i >= numPoints )
GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, std::round( line->yAt( i % numPoints ) / precision ) * precision ); {
// 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 ) 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 ) 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 else
{ {
for ( int i = 0; i < numOutPoints; ++i ) for ( int i = 0; i < numOutPoints; ++i )
{ {
GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, line->xAt( i % numPoints ) ); if ( i >= numPoints )
GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, line->yAt( 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 ) 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 ) 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
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -560,6 +560,22 @@ const double *QgsLineString::yData() const
return mY.constData(); 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 double QgsLineString::zAt( int index ) const
{ {
if ( index >= 0 && index < mZ.size() ) if ( index >= 0 && index < mZ.size() )
Expand Down
20 changes: 20 additions & 0 deletions src/core/geometry/qgslinestring.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -112,6 +112,26 @@ class CORE_EXPORT QgsLineString: public QgsCurve
*/ */
const double *yData() const SIP_SKIP; 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. * 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 * \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
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2796,6 +2796,19 @@ void TestQgsGeometry::lineString()
QCOMPARE( fromArray8.zAt( 2 ), 23.0 ); QCOMPARE( fromArray8.zAt( 2 ), 23.0 );
QCOMPARE( fromArray8.mAt( 2 ), 33.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> // from QList<QgsPointXY>
QgsLineString fromPtsA = QgsLineString( QVector< QgsPoint >() ); QgsLineString fromPtsA = QgsLineString( QVector< QgsPoint >() );
QVERIFY( fromPtsA.isEmpty() ); QVERIFY( fromPtsA.isEmpty() );
Expand Down

0 comments on commit 497abfe

Please sign in to comment.