Skip to content

Commit ab58413

Browse files
committedApr 2, 2017
Move private arc segmentization routines to QgsGeometryUtils
1 parent d0a36d3 commit ab58413

File tree

5 files changed

+164
-150
lines changed

5 files changed

+164
-150
lines changed
 

‎python/core/geometry/qgsgeometryutils.sip

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ class QgsGeometryUtils
5252

5353
static double circleTangentDirection( const QgsPointV2& tangentPoint, const QgsPointV2& cp1, const QgsPointV2& cp2, const QgsPointV2& cp3 );
5454

55+
static void segmentizeArc( const QgsPointV2 &p1, const QgsPointV2 &p2, const QgsPointV2 &p3, QList<QgsPointV2> &points /Out/, double tolerance = M_PI_2 / 90, QgsAbstractGeometry::SegmentationToleranceType toleranceType = QgsAbstractGeometry::MaximumAngle, bool hasZ = false, bool hasM = false );
56+
57+
static int segmentSide( const QgsPointV2 &pt1, const QgsPointV2 &pt3, const QgsPointV2 &pt2 );
58+
59+
static double interpolateArcValue( double angle, double a1, double a2, double a3, double zm1, double zm2, double zm3 );
60+
5561
static double normalizedAngle( double angle );
5662

5763
static double lineAngle( double x1, double y1, double x2, double y2 );

‎src/core/geometry/qgscircularstring.cpp

Lines changed: 2 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ QgsLineString *QgsCircularString::curveToLine( double tolerance, SegmentationTol
355355

356356
for ( int i = 0; i < ( nPoints - 2 ) ; i += 2 )
357357
{
358-
segmentize( pointN( i ), pointN( i + 1 ), pointN( i + 2 ), points, tolerance, toleranceType );
358+
QgsGeometryUtils::segmentizeArc( pointN( i ), pointN( i + 1 ), pointN( i + 2 ), points, tolerance, toleranceType, is3D(), isMeasure() );
359359
}
360360

361361
line->setPoints( points );
@@ -485,150 +485,6 @@ void QgsCircularString::setPoints( const QgsPointSequence &points )
485485
}
486486
}
487487

488-
void QgsCircularString::segmentize( const QgsPointV2 &p1, const QgsPointV2 &p2, const QgsPointV2 &p3, QgsPointSequence &points, double tolerance, SegmentationToleranceType toleranceType ) const
489-
{
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-
501-
//adapted code from postgis
502-
double radius = 0;
503-
double centerX = 0;
504-
double centerY = 0;
505-
QgsGeometryUtils::circleCenterRadius( circlePoint1, circlePoint2, circlePoint3, radius, centerX, centerY );
506-
507-
508-
if ( circlePoint1 != circlePoint3 && ( radius < 0 || qgsDoubleNear( segSide, 0.0 ) ) ) //points are colinear
509-
{
510-
points.append( p1 );
511-
points.append( p2 );
512-
points.append( p3 );
513-
return;
514-
}
515-
516-
double increment = tolerance; //one segment per degree
517-
if ( toleranceType == QgsAbstractGeometry::MaximumDifference )
518-
{
519-
double halfAngle = acos( -tolerance / radius + 1 );
520-
increment = 2 * halfAngle;
521-
}
522-
523-
//angles of pt1, pt2, pt3
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 );
527-
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;
533-
534-
bool hasZ = is3D();
535-
bool hasM = isMeasure();
536-
537-
double x, y;
538-
double z = 0;
539-
double m = 0;
540-
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
544-
{
545-
QgsWkbTypes::Type pointWkbType = QgsWkbTypes::Point;
546-
if ( hasZ )
547-
pointWkbType = QgsWkbTypes::addZ( pointWkbType );
548-
if ( hasM )
549-
pointWkbType = QgsWkbTypes::addM( pointWkbType );
550-
551-
//make sure the curve point p2 is part of the segmentized vertices. But only if p1 != p3
552-
bool addP2 = true;
553-
if ( qgsDoubleNear( circlePoint1.x(), circlePoint3.x() ) && qgsDoubleNear( circlePoint1.y(), circlePoint3.y() ) )
554-
{
555-
addP2 = false;
556-
}
557-
558-
for ( double angle = a1 + increment; angle < a3; angle += increment )
559-
{
560-
if ( ( addP2 && angle > a2 ) )
561-
{
562-
stringPoints.insert( clockwise ? 0 : stringPoints.size(), circlePoint2 );
563-
addP2 = false;
564-
}
565-
566-
x = centerX + radius * cos( angle );
567-
y = centerY + radius * sin( angle );
568-
569-
if ( !hasZ && !hasM )
570-
{
571-
stringPoints.insert( clockwise ? 0 : stringPoints.size(), QgsPointV2( x, y ) );
572-
continue;
573-
}
574-
575-
if ( hasZ )
576-
{
577-
z = interpolateArc( angle, a1, a2, a3, circlePoint1.z(), circlePoint2.z(), circlePoint3.z() );
578-
}
579-
if ( hasM )
580-
{
581-
m = interpolateArc( angle, a1, a2, a3, circlePoint1.m(), circlePoint2.m(), circlePoint3.m() );
582-
}
583-
584-
stringPoints.insert( clockwise ? 0 : stringPoints.size(), QgsPointV2( pointWkbType, x, y, z, m ) );
585-
}
586-
}
587-
stringPoints.insert( clockwise ? 0 : stringPoints.size(), circlePoint3 );
588-
points.append( stringPoints );
589-
}
590-
591-
int QgsCircularString::segmentSide( const QgsPointV2 &pt1, const QgsPointV2 &pt3, const QgsPointV2 &pt2 ) const
592-
{
593-
double side = ( ( pt2.x() - pt1.x() ) * ( pt3.y() - pt1.y() ) - ( pt3.x() - pt1.x() ) * ( pt2.y() - pt1.y() ) );
594-
if ( side == 0.0 )
595-
{
596-
return 0;
597-
}
598-
else
599-
{
600-
if ( side < 0 )
601-
{
602-
return -1;
603-
}
604-
if ( side > 0 )
605-
{
606-
return 1;
607-
}
608-
return 0;
609-
}
610-
}
611-
612-
double QgsCircularString::interpolateArc( double angle, double a1, double a2, double a3, double zm1, double zm2, double zm3 ) const
613-
{
614-
/* Counter-clockwise sweep */
615-
if ( a1 < a2 )
616-
{
617-
if ( angle <= a2 )
618-
return zm1 + ( zm2 - zm1 ) * ( angle - a1 ) / ( a2 - a1 );
619-
else
620-
return zm2 + ( zm3 - zm2 ) * ( angle - a2 ) / ( a3 - a2 );
621-
}
622-
/* Clockwise sweep */
623-
else
624-
{
625-
if ( angle >= a2 )
626-
return zm1 + ( zm2 - zm1 ) * ( a1 - angle ) / ( a1 - a2 );
627-
else
628-
return zm2 + ( zm3 - zm2 ) * ( a2 - angle ) / ( a2 - a3 );
629-
}
630-
}
631-
632488
void QgsCircularString::draw( QPainter &p ) const
633489
{
634490
QPainterPath path;
@@ -697,7 +553,7 @@ void QgsCircularString::addToPainterPath( QPainterPath &path ) const
697553
for ( int i = 0; i < ( nPoints - 2 ) ; i += 2 )
698554
{
699555
QgsPointSequence pt;
700-
segmentize( QgsPointV2( mX[i], mY[i] ), QgsPointV2( mX[i + 1], mY[i + 1] ), QgsPointV2( mX[i + 2], mY[i + 2] ), pt );
556+
QgsGeometryUtils::segmentizeArc( QgsPointV2( mX[i], mY[i] ), QgsPointV2( mX[i + 1], mY[i + 1] ), QgsPointV2( mX[i + 2], mY[i + 2] ), pt );
701557
for ( int j = 1; j < pt.size(); ++j )
702558
{
703559
path.lineTo( pt.at( j ).x(), pt.at( j ).y() );

‎src/core/geometry/qgscircularstring.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,6 @@ class CORE_EXPORT QgsCircularString: public QgsCurve
145145
QVector<double> mZ;
146146
QVector<double> mM;
147147

148-
//helper methods for curveToLine
149-
void segmentize( const QgsPointV2 &p1, const QgsPointV2 &p2, const QgsPointV2 &p3, QgsPointSequence &points, double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const;
150-
int segmentSide( const QgsPointV2 &pt1, const QgsPointV2 &pt3, const QgsPointV2 &pt2 ) const;
151-
double interpolateArc( double angle, double a1, double a2, double a3, double zm1, double zm2, double zm3 ) const;
152148
static void arcTo( QPainterPath &path, QPointF pt1, QPointF pt2, QPointF pt3 );
153149
//bounding box of a single segment
154150
static QgsRectangle segmentBoundingBox( const QgsPointV2 &pt1, const QgsPointV2 &pt2, const QgsPointV2 &pt3 );

‎src/core/geometry/qgsgeometryutils.cpp

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,146 @@ double QgsGeometryUtils::circleTangentDirection( const QgsPointV2 &tangentPoint,
595595
}
596596
}
597597

598+
void QgsGeometryUtils::segmentizeArc( const QgsPointV2 &p1, const QgsPointV2 &p2, const QgsPointV2 &p3, QgsPointSequence &points, double tolerance, QgsAbstractGeometry::SegmentationToleranceType toleranceType, bool hasZ, bool hasM )
599+
{
600+
bool clockwise = false;
601+
int segSide = segmentSide( p1, p3, p2 );
602+
if ( segSide == -1 )
603+
{
604+
clockwise = true;
605+
}
606+
607+
QgsPointV2 circlePoint1 = clockwise ? p3 : p1;
608+
QgsPointV2 circlePoint2 = p2;
609+
QgsPointV2 circlePoint3 = clockwise ? p1 : p3 ;
610+
611+
//adapted code from postgis
612+
double radius = 0;
613+
double centerX = 0;
614+
double centerY = 0;
615+
circleCenterRadius( circlePoint1, circlePoint2, circlePoint3, radius, centerX, centerY );
616+
617+
if ( circlePoint1 != circlePoint3 && ( radius < 0 || qgsDoubleNear( segSide, 0.0 ) ) ) //points are colinear
618+
{
619+
points.append( p1 );
620+
points.append( p2 );
621+
points.append( p3 );
622+
return;
623+
}
624+
625+
double increment = tolerance; //one segment per degree
626+
if ( toleranceType == QgsAbstractGeometry::MaximumDifference )
627+
{
628+
double halfAngle = acos( -tolerance / radius + 1 );
629+
increment = 2 * halfAngle;
630+
}
631+
632+
//angles of pt1, pt2, pt3
633+
double a1 = atan2( circlePoint1.y() - centerY, circlePoint1.x() - centerX );
634+
double a2 = atan2( circlePoint2.y() - centerY, circlePoint2.x() - centerX );
635+
double a3 = atan2( circlePoint3.y() - centerY, circlePoint3.x() - centerX );
636+
637+
/* Adjust a3 up so we can increment from a1 to a3 cleanly */
638+
if ( a3 <= a1 )
639+
a3 += 2.0 * M_PI;
640+
if ( a2 < a1 )
641+
a2 += 2.0 * M_PI;
642+
643+
double x, y;
644+
double z = 0;
645+
double m = 0;
646+
647+
QList<QgsPointV2> stringPoints;
648+
stringPoints.insert( clockwise ? 0 : stringPoints.size(), circlePoint1 );
649+
if ( circlePoint2 != circlePoint3 && circlePoint1 != circlePoint2 ) //draw straight line segment if two points have the same position
650+
{
651+
QgsWkbTypes::Type pointWkbType = QgsWkbTypes::Point;
652+
if ( hasZ )
653+
pointWkbType = QgsWkbTypes::addZ( pointWkbType );
654+
if ( hasM )
655+
pointWkbType = QgsWkbTypes::addM( pointWkbType );
656+
657+
//make sure the curve point p2 is part of the segmentized vertices. But only if p1 != p3
658+
bool addP2 = true;
659+
if ( qgsDoubleNear( circlePoint1.x(), circlePoint3.x() ) && qgsDoubleNear( circlePoint1.y(), circlePoint3.y() ) )
660+
{
661+
addP2 = false;
662+
}
663+
664+
for ( double angle = a1 + increment; angle < a3; angle += increment )
665+
{
666+
if ( ( addP2 && angle > a2 ) )
667+
{
668+
stringPoints.insert( clockwise ? 0 : stringPoints.size(), circlePoint2 );
669+
addP2 = false;
670+
}
671+
672+
x = centerX + radius * cos( angle );
673+
y = centerY + radius * sin( angle );
674+
675+
if ( !hasZ && !hasM )
676+
{
677+
stringPoints.insert( clockwise ? 0 : stringPoints.size(), QgsPointV2( x, y ) );
678+
continue;
679+
}
680+
681+
if ( hasZ )
682+
{
683+
z = interpolateArcValue( angle, a1, a2, a3, circlePoint1.z(), circlePoint2.z(), circlePoint3.z() );
684+
}
685+
if ( hasM )
686+
{
687+
m = interpolateArcValue( angle, a1, a2, a3, circlePoint1.m(), circlePoint2.m(), circlePoint3.m() );
688+
}
689+
690+
stringPoints.insert( clockwise ? 0 : stringPoints.size(), QgsPointV2( pointWkbType, x, y, z, m ) );
691+
}
692+
}
693+
stringPoints.insert( clockwise ? 0 : stringPoints.size(), circlePoint3 );
694+
points.append( stringPoints );
695+
}
696+
697+
int QgsGeometryUtils::segmentSide( const QgsPointV2 &pt1, const QgsPointV2 &pt3, const QgsPointV2 &pt2 )
698+
{
699+
double side = ( ( pt2.x() - pt1.x() ) * ( pt3.y() - pt1.y() ) - ( pt3.x() - pt1.x() ) * ( pt2.y() - pt1.y() ) );
700+
if ( side == 0.0 )
701+
{
702+
return 0;
703+
}
704+
else
705+
{
706+
if ( side < 0 )
707+
{
708+
return -1;
709+
}
710+
if ( side > 0 )
711+
{
712+
return 1;
713+
}
714+
return 0;
715+
}
716+
}
717+
718+
double QgsGeometryUtils::interpolateArcValue( double angle, double a1, double a2, double a3, double zm1, double zm2, double zm3 )
719+
{
720+
/* Counter-clockwise sweep */
721+
if ( a1 < a2 )
722+
{
723+
if ( angle <= a2 )
724+
return zm1 + ( zm2 - zm1 ) * ( angle - a1 ) / ( a2 - a1 );
725+
else
726+
return zm2 + ( zm3 - zm2 ) * ( angle - a2 ) / ( a3 - a2 );
727+
}
728+
/* Clockwise sweep */
729+
else
730+
{
731+
if ( angle >= a2 )
732+
return zm1 + ( zm2 - zm1 ) * ( a1 - angle ) / ( a1 - a2 );
733+
else
734+
return zm2 + ( zm3 - zm2 ) * ( a2 - angle ) / ( a2 - a3 );
735+
}
736+
}
737+
598738
QgsPointSequence QgsGeometryUtils::pointsFromWKT( const QString &wktCoordinateList, bool is3D, bool isMeasure )
599739
{
600740
int dim = 2 + is3D + isMeasure;

‎src/core/geometry/qgsgeometryutils.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,22 @@ class CORE_EXPORT QgsGeometryUtils
171171
//! Calculates the direction angle of a circle tangent (clockwise from north in radians)
172172
static double circleTangentDirection( const QgsPointV2 &tangentPoint, const QgsPointV2 &cp1, const QgsPointV2 &cp2, const QgsPointV2 &cp3 );
173173

174+
/** Convert circular arc defined by p1, p2, p3 (p1/p3 being start resp. end point, p2 lies on the arc) into a sequence of points.
175+
* @note added in 3.0
176+
*/
177+
static void segmentizeArc( const QgsPointV2 &p1, const QgsPointV2 &p2, const QgsPointV2 &p3, QgsPointSequence &points, double tolerance = M_PI_2 / 90, QgsAbstractGeometry::SegmentationToleranceType toleranceType = QgsAbstractGeometry::MaximumAngle, bool hasZ = false, bool hasM = false );
178+
179+
/** For line defined by points pt1 and pt3, find out on which side of the line is point pt3.
180+
* Returns -1 if pt3 on the left side, 1 if pt3 is on the right side or 0 if pt3 lies on the line.
181+
* @note added in 3.0
182+
*/
183+
static int segmentSide( const QgsPointV2 &pt1, const QgsPointV2 &pt3, const QgsPointV2 &pt2 );
184+
185+
/** Interpolate a value at given angle on circular arc given values (zm1, zm2, zm3) at three different angles (a1, a2, a3).
186+
* @note added in 3.0
187+
*/
188+
static double interpolateArcValue( double angle, double a1, double a2, double a3, double zm1, double zm2, double zm3 );
189+
174190
/** Returns a list of points contained in a WKT string.
175191
* @note not available in Python bindings
176192
*/

0 commit comments

Comments
 (0)
Please sign in to comment.