Skip to content

Commit 497abfe

Browse files
authoredMay 31, 2018
Merge pull request #7120 from nyalldawson/opts
Optimise geometry conversion to/from geos
2 parents 25f4794 + 3aa4968 commit 497abfe

File tree

5 files changed

+93
-26
lines changed

5 files changed

+93
-26
lines changed
 

‎python/core/auto_generated/geometry/qgslinestring.sip.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ Returns the specified point from inside the line string.
8989

9090

9191

92+
93+
9294
double zAt( int index ) const;
9395
%Docstring
9496
Returns the z-coordinate of the specified node in the line string.

‎src/core/geometry/qgsgeos.cpp

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,35 +1205,29 @@ std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring( const GEOSGeometry
12051205
const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit.ctxt, geos );
12061206
unsigned int nPoints;
12071207
GEOSCoordSeq_getSize_r( geosinit.ctxt, cs, &nPoints );
1208-
QVector< double > xOut;
1209-
xOut.reserve( nPoints );
1210-
QVector< double > yOut;
1211-
yOut.reserve( nPoints );
1208+
QVector< double > xOut( nPoints );
1209+
QVector< double > yOut( nPoints );
12121210
QVector< double > zOut;
12131211
if ( hasZ )
1214-
zOut.reserve( nPoints );
1212+
zOut.resize( nPoints );
12151213
QVector< double > mOut;
12161214
if ( hasM )
1217-
mOut.reserve( nPoints );
1218-
double x = 0;
1219-
double y = 0;
1220-
double z = 0;
1221-
double m = 0;
1215+
mOut.resize( nPoints );
1216+
double *x = xOut.data();
1217+
double *y = yOut.data();
1218+
double *z = zOut.data();
1219+
double *m = mOut.data();
12221220
for ( unsigned int i = 0; i < nPoints; ++i )
12231221
{
1224-
GEOSCoordSeq_getX_r( geosinit.ctxt, cs, i, &x );
1225-
xOut << x;
1226-
GEOSCoordSeq_getY_r( geosinit.ctxt, cs, i, &y );
1227-
yOut << y;
1222+
GEOSCoordSeq_getX_r( geosinit.ctxt, cs, i, x++ );
1223+
GEOSCoordSeq_getY_r( geosinit.ctxt, cs, i, y++ );
12281224
if ( hasZ )
12291225
{
1230-
GEOSCoordSeq_getZ_r( geosinit.ctxt, cs, i, &z );
1231-
zOut << z;
1226+
GEOSCoordSeq_getZ_r( geosinit.ctxt, cs, i, z++ );
12321227
}
12331228
if ( hasM )
12341229
{
1235-
GEOSCoordSeq_getOrdinate_r( geosinit.ctxt, cs, i, 3, &m );
1236-
mOut << m;
1230+
GEOSCoordSeq_getOrdinate_r( geosinit.ctxt, cs, i, 3, m++ );
12371231
}
12381232
}
12391233
std::unique_ptr< QgsLineString > line( new QgsLineString( xOut, yOut, zOut, mOut ) );
@@ -1769,35 +1763,57 @@ GEOSCoordSequence *QgsGeos::createCoordinateSequence( const QgsCurve *curve, dou
17691763
QgsDebugMsg( QStringLiteral( "GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
17701764
return nullptr;
17711765
}
1766+
1767+
const double *xData = line->xData();
1768+
const double *yData = line->yData();
1769+
const double *zData = hasZ ? line->zData() : nullptr;
1770+
const double *mData = hasM ? line->mData() : nullptr;
1771+
17721772
if ( precision > 0. )
17731773
{
17741774
for ( int i = 0; i < numOutPoints; ++i )
17751775
{
1776-
GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, std::round( line->xAt( i % numPoints ) / precision ) * precision );
1777-
GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, std::round( line->yAt( i % numPoints ) / precision ) * precision );
1776+
if ( i >= numPoints )
1777+
{
1778+
// start reading back from start of line
1779+
xData = line->xData();
1780+
yData = line->yData();
1781+
zData = hasZ ? line->zData() : nullptr;
1782+
mData = hasM ? line->mData() : nullptr;
1783+
}
1784+
GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, std::round( *xData++ / precision ) * precision );
1785+
GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, std::round( *yData++ / precision ) * precision );
17781786
if ( hasZ )
17791787
{
1780-
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, std::round( line->zAt( i % numPoints ) / precision ) * precision );
1788+
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, std::round( *zData++ / precision ) * precision );
17811789
}
17821790
if ( hasM )
17831791
{
1784-
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, line->mAt( i % numPoints ) );
1792+
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, line->mAt( *mData++ ) );
17851793
}
17861794
}
17871795
}
17881796
else
17891797
{
17901798
for ( int i = 0; i < numOutPoints; ++i )
17911799
{
1792-
GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, line->xAt( i % numPoints ) );
1793-
GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, line->yAt( i % numPoints ) );
1800+
if ( i >= numPoints )
1801+
{
1802+
// start reading back from start of line
1803+
xData = line->xData();
1804+
yData = line->yData();
1805+
zData = hasZ ? line->zData() : nullptr;
1806+
mData = hasM ? line->mData() : nullptr;
1807+
}
1808+
GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, *xData++ );
1809+
GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, *yData++ );
17941810
if ( hasZ )
17951811
{
1796-
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, line->zAt( i % numPoints ) );
1812+
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, *zData++ );
17971813
}
17981814
if ( hasM )
17991815
{
1800-
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, line->mAt( i % numPoints ) );
1816+
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, *mData++ );
18011817
}
18021818
}
18031819
}

‎src/core/geometry/qgslinestring.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,22 @@ const double *QgsLineString::yData() const
560560
return mY.constData();
561561
}
562562

563+
const double *QgsLineString::zData() const
564+
{
565+
if ( mZ.empty() )
566+
return nullptr;
567+
else
568+
return mZ.constData();
569+
}
570+
571+
const double *QgsLineString::mData() const
572+
{
573+
if ( mM.empty() )
574+
return nullptr;
575+
else
576+
return mM.constData();
577+
}
578+
563579
double QgsLineString::zAt( int index ) const
564580
{
565581
if ( index >= 0 && index < mZ.size() )

‎src/core/geometry/qgslinestring.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,26 @@ class CORE_EXPORT QgsLineString: public QgsCurve
112112
*/
113113
const double *yData() const SIP_SKIP;
114114

115+
/**
116+
* Returns a const pointer to the z vertex data, or a nullptr if the linestring does
117+
* not have z values.
118+
* \note Not available in Python bindings
119+
* \see xData()
120+
* \see yData()
121+
* \since QGIS 3.2
122+
*/
123+
const double *zData() const SIP_SKIP;
124+
125+
/**
126+
* Returns a const pointer to the m vertex data, or a nullptr if the linestring does
127+
* not have m values.
128+
* \note Not available in Python bindings
129+
* \see xData()
130+
* \see yData()
131+
* \since QGIS 3.2
132+
*/
133+
const double *mData() const SIP_SKIP;
134+
115135
/**
116136
* Returns the z-coordinate of the specified node in the line string.
117137
* \param index index of node, where the first node in the line is 0

‎tests/src/core/testqgsgeometry.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2796,6 +2796,19 @@ void TestQgsGeometry::lineString()
27962796
QCOMPARE( fromArray8.zAt( 2 ), 23.0 );
27972797
QCOMPARE( fromArray8.mAt( 2 ), 33.0 );
27982798

2799+
QCOMPARE( *fromArray8.xData(), 1.0 );
2800+
QCOMPARE( *( fromArray8.xData() + 1 ), 2.0 );
2801+
QCOMPARE( *( fromArray8.xData() + 2 ), 3.0 );
2802+
QCOMPARE( *fromArray8.yData(), 11.0 );
2803+
QCOMPARE( *( fromArray8.yData() + 1 ), 12.0 );
2804+
QCOMPARE( *( fromArray8.yData() + 2 ), 13.0 );
2805+
QCOMPARE( *fromArray8.zData(), 21.0 );
2806+
QCOMPARE( *( fromArray8.zData() + 1 ), 22.0 );
2807+
QCOMPARE( *( fromArray8.zData() + 2 ), 23.0 );
2808+
QCOMPARE( *fromArray8.mData(), 31.0 );
2809+
QCOMPARE( *( fromArray8.mData() + 1 ), 32.0 );
2810+
QCOMPARE( *( fromArray8.mData() + 2 ), 33.0 );
2811+
27992812
// from QList<QgsPointXY>
28002813
QgsLineString fromPtsA = QgsLineString( QVector< QgsPoint >() );
28012814
QVERIFY( fromPtsA.isEmpty() );

0 commit comments

Comments
 (0)