Skip to content

Commit 14324b5

Browse files
committedSep 28, 2022
Optimise QgsArcGisRestUtils::convertCompoundCurve
This method was quite slow due to numerous list resizing and temporary point construction. I've removed all this for much faster ArcGIS rest geometry conversions (at the cost of more complex code)
1 parent 9e7cebc commit 14324b5

File tree

1 file changed

+103
-17
lines changed

1 file changed

+103
-17
lines changed
 

‎src/core/providers/arcgis/qgsarcgisrestutils.cpp

Lines changed: 103 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -161,32 +161,98 @@ std::unique_ptr< QgsCompoundCurve > QgsArcGisRestUtils::convertCompoundCurve( co
161161
{
162162
// [[6,3],[5,3],{"b":[[3,2],[6,1],[2,4]]},[1,2],{"c": [[3,3],[1,4]]}]
163163
std::unique_ptr< QgsCompoundCurve > compoundCurve = std::make_unique< QgsCompoundCurve >();
164-
std::unique_ptr< QgsLineString > lineString;
164+
165+
QVector< double > lineX;
166+
QVector< double > lineY;
167+
QVector< double > lineZ;
168+
QVector< double > lineM;
169+
int maxCurveListSize = curvesList.size();
170+
lineX.resize( maxCurveListSize );
171+
lineY.resize( maxCurveListSize );
172+
173+
const bool hasZ = QgsWkbTypes::hasZ( pointType );
174+
if ( hasZ )
175+
lineZ.resize( maxCurveListSize );
176+
const bool hasM = QgsWkbTypes::hasM( pointType );
177+
if ( hasM )
178+
lineM.resize( maxCurveListSize );
179+
180+
double *outLineX = lineX.data();
181+
double *outLineY = lineY.data();
182+
double *outLineZ = lineZ.data();
183+
double *outLineM = lineM.data();
184+
int actualLineSize = 0;
185+
186+
bool xok = false;
187+
bool yok = false;
188+
189+
int curveListIndex = 0;
165190
for ( const QVariant &curveData : curvesList )
166191
{
167192
if ( curveData.type() == QVariant::List )
168193
{
169-
std::unique_ptr< QgsPoint > point( convertPoint( curveData.toList(), pointType ) );
170-
if ( !point )
171-
{
194+
const QVariantList coordList = curveData.toList();
195+
const int nCoords = coordList.size();
196+
if ( nCoords < 2 )
197+
return nullptr;
198+
199+
const double x = coordList[0].toDouble( &xok );
200+
const double y = coordList[1].toDouble( &yok );
201+
if ( !xok || !yok )
172202
return nullptr;
203+
204+
actualLineSize++;
205+
*outLineX++ = x;
206+
*outLineY++ = y;
207+
if ( hasZ )
208+
{
209+
*outLineZ++ = nCoords >= 3 ? coordList[2].toDouble() : std::numeric_limits< double >::quiet_NaN();
173210
}
174-
if ( !lineString )
175-
lineString = std::make_unique< QgsLineString >();
176211

177-
lineString->addVertex( *point );
212+
if ( hasM )
213+
{
214+
// if point has just M but not Z, then the point dimension list will only have X, Y, M, otherwise it will have X, Y, Z, M
215+
*outLineM++ = ( ( hasZ && nCoords >= 4 ) || ( !hasZ && nCoords >= 3 ) ) ? coordList[ hasZ ? 3 : 2].toDouble() : std::numeric_limits< double >::quiet_NaN();
216+
}
178217
}
179218
else if ( curveData.type() == QVariant::Map )
180219
{
181220
// The last point of the linestring is the start point of this circular string
182-
std::unique_ptr< QgsCircularString > circularString( convertCircularString( curveData.toMap(), pointType, lineString ? lineString->endPoint() : QgsPoint() ) );
221+
QgsPoint lastLineStringPoint;
222+
if ( actualLineSize > 0 )
223+
{
224+
lastLineStringPoint = QgsPoint( lineX.at( actualLineSize - 1 ),
225+
lineY.at( actualLineSize - 1 ),
226+
hasZ ? lineZ.at( actualLineSize - 1 ) : std::numeric_limits< double >::quiet_NaN(),
227+
hasM ? lineM.at( actualLineSize - 1 ) : std::numeric_limits< double >::quiet_NaN() );
228+
}
229+
std::unique_ptr< QgsCircularString > circularString( convertCircularString( curveData.toMap(), pointType, lastLineStringPoint ) );
183230
if ( !circularString )
184231
{
185232
return nullptr;
186233
}
187234

188-
if ( lineString )
189-
compoundCurve->addCurve( lineString.release() );
235+
if ( actualLineSize > 0 )
236+
{
237+
lineX.resize( actualLineSize );
238+
lineY.resize( actualLineSize );
239+
if ( hasZ )
240+
lineZ.resize( actualLineSize );
241+
if ( hasM )
242+
lineM.resize( actualLineSize );
243+
244+
compoundCurve->addCurve( new QgsLineString( lineX, lineY, lineZ, lineM ) );
245+
lineX.resize( maxCurveListSize - curveListIndex );
246+
lineY.resize( maxCurveListSize - curveListIndex );
247+
if ( hasZ )
248+
lineZ.resize( maxCurveListSize - curveListIndex );
249+
if ( hasM )
250+
lineM.resize( maxCurveListSize - curveListIndex );
251+
outLineX = lineX.data();
252+
outLineY = lineY.data();
253+
outLineZ = lineZ.data();
254+
outLineM = lineM.data();
255+
}
190256

191257
// If the previous curve had less than two points, remove it
192258
if ( compoundCurve->curveAt( compoundCurve->nCurves() - 1 )->nCoordinates() < 2 )
@@ -196,20 +262,40 @@ std::unique_ptr< QgsCompoundCurve > QgsArcGisRestUtils::convertCompoundCurve( co
196262
compoundCurve->addCurve( circularString.release() );
197263

198264
// Prepare a new line string
199-
lineString = std::make_unique< QgsLineString >();
200-
lineString->addVertex( endPointCircularString );
265+
actualLineSize = 1;
266+
*outLineX++ = endPointCircularString.x();
267+
*outLineY++ = endPointCircularString.y();
268+
if ( hasZ )
269+
*outLineZ++ = endPointCircularString.z();
270+
if ( hasM )
271+
*outLineM++ = endPointCircularString.m();
201272
}
273+
curveListIndex++;
202274
}
203275

204-
if ( lineString && lineString->numPoints() == 1 && compoundCurve->nCurves() > 0 )
276+
if ( actualLineSize == 1 && compoundCurve->nCurves() > 0 )
205277
{
206278
const QgsCurve *finalCurve = compoundCurve->curveAt( compoundCurve->nCurves() - 1 );
207-
if ( finalCurve->endPoint() == lineString->startPoint() )
208-
lineString.reset(); // redundant final curve containing a duplicate vertex
279+
const QgsPoint finalCurveEndPoint = finalCurve->endPoint();
280+
if ( qgsDoubleNear( finalCurveEndPoint.x(), lineX.at( 0 ) )
281+
&& qgsDoubleNear( finalCurveEndPoint.y(), lineY.at( 0 ) )
282+
&& ( !hasZ || qgsDoubleNear( finalCurveEndPoint.z(), lineZ.at( 0 ) ) )
283+
&& ( !hasM || qgsDoubleNear( finalCurveEndPoint.m(), lineM.at( 0 ) ) ) )
284+
{
285+
actualLineSize = 0; // redundant final curve containing a duplicate vertex
286+
}
209287
}
210288

211-
if ( lineString )
212-
compoundCurve->addCurve( lineString.release() );
289+
if ( actualLineSize > 0 )
290+
{
291+
lineX.resize( actualLineSize );
292+
lineY.resize( actualLineSize );
293+
if ( hasZ )
294+
lineZ.resize( actualLineSize );
295+
if ( hasM )
296+
lineM.resize( actualLineSize );
297+
compoundCurve->addCurve( new QgsLineString( lineX, lineY, lineZ, lineM ) );
298+
}
213299

214300
return compoundCurve;
215301
}

0 commit comments

Comments
 (0)
Please sign in to comment.