Skip to content

Commit 8783fe2

Browse files
committed
Don't store QgsLineStringV2 coordinates in QPolygonF
This stores coordinates as qreal, which on some platforms is float, and not suitable for accurate geometry storage.
1 parent 9cfbba1 commit 8783fe2

File tree

2 files changed

+102
-51
lines changed

2 files changed

+102
-51
lines changed

src/core/geometry/qgslinestringv2.cpp

Lines changed: 99 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ QgsLineStringV2 *QgsLineStringV2::clone() const
4040

4141
void QgsLineStringV2::clear()
4242
{
43-
mCoords.clear();
43+
mX.clear();
44+
mY.clear();
4445
mZ.clear();
4546
mM.clear();
4647
mWkbType = QgsWKBTypes::Unknown;
@@ -149,12 +150,12 @@ QString QgsLineStringV2::asJSON( int precision ) const
149150
double QgsLineStringV2::length() const
150151
{
151152
double length = 0;
152-
int size = mCoords.size();
153+
int size = mX.size();
153154
double dx, dy;
154155
for ( int i = 1; i < size; ++i )
155156
{
156-
dx = mCoords[i].x() - mCoords[ i - 1 ].x();
157-
dy = mCoords[i].y() - mCoords[ i - 1 ].y();
157+
dx = mX.at( i ) - mX.at( i - 1 );
158+
dy = mY.at( i ) - mY.at( i - 1 );
158159
length += sqrt( dx * dx + dy * dy );
159160
}
160161
return length;
@@ -185,17 +186,18 @@ QgsLineStringV2* QgsLineStringV2::curveToLine() const
185186

186187
int QgsLineStringV2::numPoints() const
187188
{
188-
return mCoords.size();
189+
return mX.size();
189190
}
190191

191192
QgsPointV2 QgsLineStringV2::pointN( int i ) const
192193
{
193-
if ( mCoords.size() <= i )
194+
if ( mX.size() <= i )
194195
{
195196
return QgsPointV2();
196197
}
197198

198-
const QPointF& pt = mCoords.at( i );
199+
double x = mX.at( i );
200+
double y = mY.at( i );
199201
double z = 0;
200202
double m = 0;
201203

@@ -223,7 +225,7 @@ QgsPointV2 QgsLineStringV2::pointN( int i ) const
223225
{
224226
t = QgsWKBTypes::PointM;
225227
}
226-
return QgsPointV2( t, pt.x(), pt.y(), z, m );
228+
return QgsPointV2( t, x, y, z, m );
227229
}
228230

229231
void QgsLineStringV2::points( QList<QgsPointV2>& pts ) const
@@ -241,7 +243,8 @@ void QgsLineStringV2::setPoints( const QList<QgsPointV2>& points )
241243
if ( points.size() < 1 )
242244
{
243245
mWkbType = QgsWKBTypes::Unknown;
244-
mCoords.clear();
246+
mX.clear();
247+
mY.clear();
245248
mZ.clear();
246249
mM.clear();
247250
return;
@@ -254,7 +257,8 @@ void QgsLineStringV2::setPoints( const QList<QgsPointV2>& points )
254257

255258
setZMTypeFromSubGeometry( &firstPt, QgsWKBTypes::LineString );
256259

257-
mCoords.resize( points.size() );
260+
mX.resize( points.size() );
261+
mY.resize( points.size() );
258262
if ( hasZ )
259263
{
260264
mZ.resize( points.size() );
@@ -274,15 +278,15 @@ void QgsLineStringV2::setPoints( const QList<QgsPointV2>& points )
274278

275279
for ( int i = 0; i < points.size(); ++i )
276280
{
277-
mCoords[i].rx() = points[i].x();
278-
mCoords[i].ry() = points[i].y();
281+
mX[i] = points.at( i ).x();
282+
mY[i] = points.at( i ).y();
279283
if ( hasZ )
280284
{
281-
mZ[i] = points[i].z();
285+
mZ[i] = points.at( i ).z();
282286
}
283287
if ( hasM )
284288
{
285-
mM[i] = points[i].m();
289+
mM[i] = points.at( i ).m();
286290
}
287291
}
288292
}
@@ -299,14 +303,15 @@ void QgsLineStringV2::append( const QgsLineStringV2* line )
299303
setZMTypeFromSubGeometry( line, QgsWKBTypes::LineString );
300304
}
301305

302-
mCoords += line->mCoords;
306+
mX += line->mX;
307+
mY += line->mY;
303308
mZ += line->mZ;
304309
mM += line->mM;
305310
}
306311

307312
void QgsLineStringV2::draw( QPainter& p ) const
308313
{
309-
p.drawPolyline( mCoords );
314+
p.drawPolyline( qPolygonF() );
310315
}
311316

312317
void QgsLineStringV2::addToPainterPath( QPainterPath& path ) const
@@ -317,39 +322,73 @@ void QgsLineStringV2::addToPainterPath( QPainterPath& path ) const
317322
return;
318323
}
319324

320-
if ( path.isEmpty() || path.currentPosition() != mCoords[0] )
325+
if ( path.isEmpty() || path.currentPosition() != QPointF( mX.at( 0 ), mY.at( 0 ) ) )
321326
{
322-
path.moveTo( mCoords[0] );
327+
path.moveTo( mX.at( 0 ), mY.at( 0 ) );
323328
}
324329

325330
for ( int i = 1; i < nPoints; ++i )
326331
{
327-
path.lineTo( mCoords[i] );
332+
path.lineTo( mX.at( i ), mY.at( i ) );
328333
}
329334
}
330335

331336
void QgsLineStringV2::drawAsPolygon( QPainter& p ) const
332337
{
333-
p.drawPolygon( mCoords );
338+
p.drawPolygon( qPolygonF() );
339+
}
340+
341+
QPolygonF QgsLineStringV2::qPolygonF() const
342+
{
343+
QPolygonF points;
344+
for ( int i = 0; i < mX.count(); ++i )
345+
{
346+
points << QPointF( mX.at( i ), mY.at( i ) );
347+
}
348+
return points;
334349
}
335350

336351
void QgsLineStringV2::transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d )
337352
{
338-
ct.transformPolygon( mCoords, d );
353+
double* zArray = mZ.data();
354+
355+
bool hasZ = is3D();
356+
int nPoints = numPoints();
357+
if ( !hasZ )
358+
{
359+
zArray = new double[nPoints];
360+
for ( int i = 0; i < nPoints; ++i )
361+
{
362+
zArray[i] = 0;
363+
}
364+
}
365+
ct.transformCoords( nPoints, mX.data(), mY.data(), zArray, d );
366+
if ( !hasZ )
367+
{
368+
delete[] zArray;
369+
}
370+
339371
}
340372

341373
void QgsLineStringV2::transform( const QTransform& t )
342374
{
343-
mCoords = t.map( mCoords );
375+
int nPoints = numPoints();
376+
for ( int i = 0; i < nPoints; ++i )
377+
{
378+
qreal x, y;
379+
t.map( mX.at( i ), mY.at( i ), &x, &y );
380+
mX[i] = x; mY[i] = y;
381+
}
344382
}
345383

346384
bool QgsLineStringV2::insertVertex( const QgsVertexId& position, const QgsPointV2& vertex )
347385
{
348-
if ( position.vertex < 0 || position.vertex > mCoords.size() )
386+
if ( position.vertex < 0 || position.vertex > mX.size() )
349387
{
350388
return false;
351389
}
352-
mCoords.insert( position.vertex, QPointF( vertex.x(), vertex.y() ) );
390+
mX.insert( position.vertex, vertex.x() );
391+
mY.insert( position.vertex, vertex.y() );
353392
if ( is3D() )
354393
{
355394
mZ.insert( position.vertex, vertex.z() );
@@ -364,12 +403,12 @@ bool QgsLineStringV2::insertVertex( const QgsVertexId& position, const QgsPointV
364403

365404
bool QgsLineStringV2::moveVertex( const QgsVertexId& position, const QgsPointV2& newPos )
366405
{
367-
if ( position.vertex < 0 || position.vertex >= mCoords.size() )
406+
if ( position.vertex < 0 || position.vertex >= mX.size() )
368407
{
369408
return false;
370409
}
371-
mCoords[position.vertex].rx() = newPos.x();
372-
mCoords[position.vertex].ry() = newPos.y();
410+
mX[position.vertex] = newPos.x();
411+
mY[position.vertex] = newPos.y();
373412
if ( is3D() && newPos.is3D() )
374413
{
375414
mZ[position.vertex] = newPos.z();
@@ -384,12 +423,13 @@ bool QgsLineStringV2::moveVertex( const QgsVertexId& position, const QgsPointV2&
384423

385424
bool QgsLineStringV2::deleteVertex( const QgsVertexId& position )
386425
{
387-
if ( position.vertex >= mCoords.size() || position.vertex < 0 )
426+
if ( position.vertex >= mX.size() || position.vertex < 0 )
388427
{
389428
return false;
390429
}
391430

392-
mCoords.remove( position.vertex );
431+
mX.remove( position.vertex );
432+
mY.remove( position.vertex );
393433
if ( is3D() )
394434
{
395435
mZ.remove( position.vertex );
@@ -409,7 +449,8 @@ void QgsLineStringV2::addVertex( const QgsPointV2& pt )
409449
setZMTypeFromSubGeometry( &pt, QgsWKBTypes::LineString );
410450
}
411451

412-
mCoords.append( QPointF( pt.x(), pt.y() ) );
452+
mX.append( pt.x() );
453+
mY.append( pt.y() );
413454
if ( is3D() )
414455
{
415456
mZ.append( pt.z() );
@@ -427,20 +468,22 @@ double QgsLineStringV2::closestSegment( const QgsPointV2& pt, QgsPointV2& segmen
427468
double testDist = 0;
428469
double segmentPtX, segmentPtY;
429470

430-
int size = mCoords.size();
471+
int size = mX.size();
431472
for ( int i = 1; i < size; ++i )
432473
{
433-
const QPointF& prev = mCoords.at( i - 1 );
434-
const QPointF& currentPt = mCoords.at( i );
435-
testDist = QgsGeometryUtils::sqrDistToLine( pt.x(), pt.y(), prev.x(), prev.y(), currentPt.x(), currentPt.y(), segmentPtX, segmentPtY, epsilon );
474+
double prevX = mX.at( i - 1 );
475+
double prevY = mY.at( i - 1 );
476+
double currentX = mX.at( i );
477+
double currentY = mY.at( i );
478+
testDist = QgsGeometryUtils::sqrDistToLine( pt.x(), pt.y(), prevX, prevY, currentX, currentY, segmentPtX, segmentPtY, epsilon );
436479
if ( testDist < sqrDist )
437480
{
438481
sqrDist = testDist;
439482
segmentPt.setX( segmentPtX );
440483
segmentPt.setY( segmentPtY );
441484
if ( leftOf )
442485
{
443-
*leftOf = ( QgsGeometryUtils::leftOfLine( segmentPtX, segmentPtY, prev.x(), prev.y(), pt.x(), pt.y() ) < 0 );
486+
*leftOf = ( QgsGeometryUtils::leftOfLine( segmentPtX, segmentPtY, prevX, prevY, pt.x(), pt.y() ) < 0 );
444487
}
445488
vertexAfter.part = 0; vertexAfter.ring = 0; vertexAfter.vertex = i;
446489
}
@@ -464,7 +507,7 @@ void QgsLineStringV2::sumUpArea( double& sum ) const
464507
int maxIndex = numPoints() - 1;
465508
for ( int i = 0; i < maxIndex; ++i )
466509
{
467-
sum += 0.5 * ( mCoords[i].x() * mCoords[i+1].y() - mCoords[i].y() * mCoords[i+1].x() );
510+
sum += 0.5 * ( mX.at( i ) * mY.at( i + 1 ) - mY.at( i ) * mX.at( i + 1 ) );
468511
}
469512
}
470513

@@ -474,13 +517,14 @@ void QgsLineStringV2::importVerticesFromWkb( const QgsConstWkbPtr& wkb )
474517
bool hasM = isMeasure();
475518
int nVertices = 0;
476519
wkb >> nVertices;
477-
mCoords.resize( nVertices );
520+
mX.resize( nVertices );
521+
mY.resize( nVertices );
478522
hasZ ? mZ.resize( nVertices ) : mZ.clear();
479523
hasM ? mM.resize( nVertices ) : mM.clear();
480524
for ( int i = 0; i < nVertices; ++i )
481525
{
482-
wkb >> mCoords[i].rx();
483-
wkb >> mCoords[i].ry();
526+
wkb >> mX[i];
527+
wkb >> mY[i];
484528
if ( hasZ )
485529
{
486530
wkb >> mZ[i];
@@ -507,28 +551,34 @@ double QgsLineStringV2::vertexAngle( const QgsVertexId& vertex ) const
507551
{
508552
if ( isClosed() )
509553
{
510-
QPointF previous = mCoords[numPoints() - 1 ];
511-
QPointF current = mCoords[0];
512-
QPointF after = mCoords[1];
513-
return QgsGeometryUtils::averageAngle( previous.x(), previous.y(), current.x(), current.y(), after.x(), after.y() );
554+
double previousX = mX.at( numPoints() - 1 );
555+
double previousY = mY.at( numPoints() - 1 );
556+
double currentX = mX.at( 0 );
557+
double currentY = mY.at( 0 );
558+
double afterX = mX.at( 1 );
559+
double afterY = mY.at( 1 );
560+
return QgsGeometryUtils::averageAngle( previousX, previousY, currentX, currentY, afterX, afterY );
514561
}
515562
else if ( vertex.vertex == 0 )
516563
{
517-
return QgsGeometryUtils::linePerpendicularAngle( mCoords[0].x(), mCoords[0].y(), mCoords[1].x(), mCoords[1].y() );
564+
return QgsGeometryUtils::linePerpendicularAngle( mX.at( 0 ), mY.at( 0 ), mX.at( 1 ), mY.at( 1 ) );
518565
}
519566
else
520567
{
521568
int a = numPoints() - 2;
522569
int b = numPoints() - 1;
523-
return QgsGeometryUtils::linePerpendicularAngle( mCoords[a].x(), mCoords[a].y(), mCoords[b].x(), mCoords[b].y() );
570+
return QgsGeometryUtils::linePerpendicularAngle( mX.at( a ), mY.at( a ), mX.at( b ), mY.at( b ) );
524571
}
525572
}
526573
else
527574
{
528-
QPointF previous = mCoords[vertex.vertex - 1 ];
529-
QPointF current = mCoords[vertex.vertex];
530-
QPointF after = mCoords[vertex.vertex + 1];
531-
return QgsGeometryUtils::averageAngle( previous.x(), previous.y(), current.x(), current.y(), after.x(), after.y() );
575+
double previousX = mX.at( vertex.vertex - 1 );
576+
double previousY = mY.at( vertex.vertex - 1 );
577+
double currentX = mX.at( vertex.vertex );
578+
double currentY = mY.at( vertex.vertex );
579+
double afterX = mX.at( vertex.vertex + 1 );
580+
double afterY = mY.at( vertex.vertex + 1 );
581+
return QgsGeometryUtils::averageAngle( previousX, previousY, currentX, currentY, afterX, afterY );
532582
}
533583
}
534584

src/core/geometry/qgslinestringv2.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class CORE_EXPORT QgsLineStringV2: public QgsCurveV2
7575
void addToPainterPath( QPainterPath& path ) const override;
7676
void drawAsPolygon( QPainter& p ) const override;
7777

78-
const QPolygonF& qPolygonF() const { return mCoords; }
78+
QPolygonF qPolygonF() const;
7979

8080
virtual bool insertVertex( const QgsVertexId& position, const QgsPointV2& vertex ) override;
8181
virtual bool moveVertex( const QgsVertexId& position, const QgsPointV2& newPos ) override;
@@ -99,7 +99,8 @@ class CORE_EXPORT QgsLineStringV2: public QgsCurveV2
9999
virtual bool addMValue( double mValue = 0 ) override;
100100

101101
private:
102-
QPolygonF mCoords;
102+
QVector<double> mX;
103+
QVector<double> mY;
103104
QVector<double> mZ;
104105
QVector<double> mM;
105106

0 commit comments

Comments
 (0)