Skip to content

Commit 3da4413

Browse files
committed
Segmentize circular strings the same way in both directions, avoiding problems with tiny gaps/overlaps
1 parent 7732d73 commit 3da4413

File tree

1 file changed

+35
-40
lines changed

1 file changed

+35
-40
lines changed

src/core/geometry/qgscircularstring.cpp

+35-40
Original file line numberDiff line numberDiff line change
@@ -487,27 +487,32 @@ void QgsCircularString::setPoints( const QgsPointSequence &points )
487487

488488
void QgsCircularString::segmentize( const QgsPointV2& p1, const QgsPointV2& p2, const QgsPointV2& p3, QgsPointSequence &points, double tolerance, SegmentationToleranceType toleranceType ) const
489489
{
490+
bool clockwise = false;
491+
int segSide = segmentSide( p1, p3, p2 );
492+
if ( segSide == -1 )
493+
{
494+
clockwise = true;
495+
}
496+
497+
QgsPointV2 circlePoint1 = clockwise ? p3 : p1;
498+
QgsPointV2 circlePoint2 = p2;
499+
QgsPointV2 circlePoint3 = clockwise ? p1 : p3 ;
500+
490501
//adapted code from postgis
491502
double radius = 0;
492503
double centerX = 0;
493504
double centerY = 0;
494-
QgsGeometryUtils::circleCenterRadius( p1, p2, p3, radius, centerX, centerY );
495-
int segSide = segmentSide( p1, p3, p2 );
505+
QgsGeometryUtils::circleCenterRadius( circlePoint1, circlePoint2, circlePoint3, radius, centerX, centerY );
496506

497-
if ( p1 != p3 && ( radius < 0 || qgsDoubleNear( segSide, 0.0 ) ) ) //points are colinear
507+
508+
if ( circlePoint1 != circlePoint3 && ( radius < 0 || qgsDoubleNear( segSide, 0.0 ) ) ) //points are colinear
498509
{
499510
points.append( p1 );
500511
points.append( p2 );
501512
points.append( p3 );
502513
return;
503514
}
504515

505-
bool clockwise = false;
506-
if ( segSide == -1 )
507-
{
508-
clockwise = true;
509-
}
510-
511516
double increment = tolerance; //one segment per degree
512517
if ( toleranceType == QgsAbstractGeometry::MaximumDifference )
513518
{
@@ -516,27 +521,15 @@ void QgsCircularString::segmentize( const QgsPointV2& p1, const QgsPointV2& p2,
516521
}
517522

518523
//angles of pt1, pt2, pt3
519-
double a1 = atan2( p1.y() - centerY, p1.x() - centerX );
520-
double a2 = atan2( p2.y() - centerY, p2.x() - centerX );
521-
double a3 = atan2( p3.y() - centerY, p3.x() - centerX );
524+
double a1 = atan2( circlePoint1.y() - centerY, circlePoint1.x() - centerX );
525+
double a2 = atan2( circlePoint2.y() - centerY, circlePoint2.x() - centerX );
526+
double a3 = atan2( circlePoint3.y() - centerY, circlePoint3.x() - centerX );
522527

523-
if ( clockwise )
524-
{
525-
increment *= -1;
526-
/* Adjust a3 down so we can decrement from a1 to a3 cleanly */
527-
if ( a3 >= a1 )
528-
a3 -= 2.0 * M_PI;
529-
if ( a2 > a1 )
530-
a2 -= 2.0 * M_PI;
531-
}
532-
else
533-
{
534-
/* Adjust a3 up so we can increment from a1 to a3 cleanly */
535-
if ( a3 <= a1 )
536-
a3 += 2.0 * M_PI;
537-
if ( a2 < a1 )
538-
a2 += 2.0 * M_PI;
539-
}
528+
/* Adjust a3 up so we can increment from a1 to a3 cleanly */
529+
if ( a3 <= a1 )
530+
a3 += 2.0 * M_PI;
531+
if ( a2 < a1 )
532+
a2 += 2.0 * M_PI;
540533

541534
bool hasZ = is3D();
542535
bool hasM = isMeasure();
@@ -545,8 +538,9 @@ void QgsCircularString::segmentize( const QgsPointV2& p1, const QgsPointV2& p2,
545538
double z = 0;
546539
double m = 0;
547540

548-
points.append( p1 );
549-
if ( p2 != p3 && p1 != p2 ) //draw straight line segment if two points have the same position
541+
QList<QgsPointV2> stringPoints;
542+
stringPoints.insert( clockwise ? 0 : stringPoints.size(), circlePoint1 );
543+
if ( circlePoint2 != circlePoint3 && circlePoint1 != circlePoint2 ) //draw straight line segment if two points have the same position
550544
{
551545
QgsWkbTypes::Type pointWkbType = QgsWkbTypes::Point;
552546
if ( hasZ )
@@ -556,16 +550,16 @@ void QgsCircularString::segmentize( const QgsPointV2& p1, const QgsPointV2& p2,
556550

557551
//make sure the curve point p2 is part of the segmentized vertices. But only if p1 != p3
558552
bool addP2 = true;
559-
if ( qgsDoubleNear( p1.x(), p3.x() ) && qgsDoubleNear( p1.y(), p3.y() ) )
553+
if ( qgsDoubleNear( circlePoint1.x(), circlePoint3.x() ) && qgsDoubleNear( circlePoint1.y(), circlePoint3.y() ) )
560554
{
561555
addP2 = false;
562556
}
563557

564-
for ( double angle = a1 + increment; clockwise ? angle > a3 : angle < a3; angle += increment )
558+
for ( double angle = a1 + increment; angle < a3; angle += increment )
565559
{
566-
if (( addP2 && clockwise && angle < a2 ) || ( addP2 && !clockwise && angle > a2 ) )
560+
if (( addP2 && angle > a2 ) )
567561
{
568-
points.append( p2 );
562+
stringPoints.insert( clockwise ? 0 : stringPoints.size(), circlePoint2 );
569563
addP2 = false;
570564
}
571565

@@ -574,23 +568,24 @@ void QgsCircularString::segmentize( const QgsPointV2& p1, const QgsPointV2& p2,
574568

575569
if ( !hasZ && !hasM )
576570
{
577-
points.append( QgsPointV2( x, y ) );
571+
stringPoints.insert( clockwise ? 0 : stringPoints.size(), QgsPointV2( x, y ) );
578572
continue;
579573
}
580574

581575
if ( hasZ )
582576
{
583-
z = interpolateArc( angle, a1, a2, a3, p1.z(), p2.z(), p3.z() );
577+
z = interpolateArc( angle, a1, a2, a3, circlePoint1.z(), circlePoint2.z(), circlePoint3.z() );
584578
}
585579
if ( hasM )
586580
{
587-
m = interpolateArc( angle, a1, a2, a3, p1.m(), p2.m(), p3.m() );
581+
m = interpolateArc( angle, a1, a2, a3, circlePoint1.m(), circlePoint2.m(), circlePoint3.m() );
588582
}
589583

590-
points.append( QgsPointV2( pointWkbType, x, y, z, m ) );
584+
stringPoints.insert( clockwise ? 0 : stringPoints.size(), QgsPointV2( pointWkbType, x, y, z, m ) );
591585
}
592586
}
593-
points.append( p3 );
587+
stringPoints.insert( clockwise ? 0 : stringPoints.size(), circlePoint3 );
588+
points.append( stringPoints );
594589
}
595590

596591
int QgsCircularString::segmentSide( const QgsPointV2& pt1, const QgsPointV2& pt3, const QgsPointV2& pt2 ) const

0 commit comments

Comments
 (0)