Merge pull request #7120 from nyalldawson/opts

Optimise geometry conversion to/from geos
This commit is contained in:
Matthias Kuhn 2018-05-31 11:30:40 +02:00 committed by GitHub
commit 497abfe797
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 93 additions and 26 deletions

View File

@ -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.

View File

@ -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 ) );
@ -1769,19 +1763,33 @@ 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++ ) );
}
}
}
@ -1789,15 +1797,23 @@ GEOSCoordSequence *QgsGeos::createCoordinateSequence( const QgsCurve *curve, dou
{
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++ );
}
}
}

View File

@ -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() )

View File

@ -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

View File

@ -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() );