From eb292c93bb7147812539efdefbdb8c6f76344de9 Mon Sep 17 00:00:00 2001 From: lbartoletti Date: Wed, 13 Dec 2017 08:45:44 +0100 Subject: [PATCH] Apply segmentIntersection on some tools with tests. --- src/app/qgsmaptoolcircle2tangentspoint.cpp | 97 +++++----------------- src/app/qgsmaptoolcircle2tangentspoint.h | 3 - src/core/geometry/qgscircle.cpp | 14 +++- tests/src/core/testqgsgeometry.cpp | 7 ++ 4 files changed, 39 insertions(+), 82 deletions(-) diff --git a/src/app/qgsmaptoolcircle2tangentspoint.cpp b/src/app/qgsmaptoolcircle2tangentspoint.cpp index 339f67c9bc9..240d665e4f9 100644 --- a/src/app/qgsmaptoolcircle2tangentspoint.cpp +++ b/src/app/qgsmaptoolcircle2tangentspoint.cpp @@ -25,6 +25,7 @@ #include "qgslinestring.h" #include "qgsmultipolygon.h" #include "qgsspinbox.h" +#include "qgsgeometryutils.h" #include #include @@ -61,9 +62,12 @@ void QgsMapToolCircle2TangentsPoint::cadCanvasReleaseEvent( QgsMapMouseEvent *e } if ( mPoints.size() == 4 ) { - QgsPointXY ptInter = intersect( QgsPointXY( mPoints.at( 0 ) ), QgsPointXY( mPoints.at( 1 ) ), - QgsPointXY( mPoints.at( 2 ) ), QgsPointXY( mPoints.at( 3 ) ) ); - if ( ptInter == QgsPointXY() ) + bool isIntersect; + const double epsilon = 1e-8; + QgsPoint ptInter; + QgsGeometryUtils::segmentIntersection( mPoints.at( 0 ), mPoints.at( 1 ), + mPoints.at( 2 ), mPoints.at( 3 ), ptInter, isIntersect, epsilon ); + if ( !isIntersect ) { QgisApp::instance()->messageBar()->pushMessage( tr( "Error" ), tr( "Segments are parallels" ), QgsMessageBar::CRITICAL, QgisApp::instance()->messageTimeout() ); @@ -144,64 +148,6 @@ void QgsMapToolCircle2TangentsPoint::cadCanvasMoveEvent( QgsMapMouseEvent *e ) } } -QgsPointXY QgsMapToolCircle2TangentsPoint::intersect( QgsPointXY seg1_pt1, QgsPointXY seg1_pt2, QgsPointXY seg2_pt1, QgsPointXY seg2_pt2 ) -{ - /* - * Public domain function by Darel Rex Finley, 2006 - * http://alienryderflex.com/intersect/ - */ - QgsPointXY ptInter; - - double Ax = seg1_pt1.x(); - double Ay = seg1_pt1.y(); - double Bx = seg1_pt2.x(); - double By = seg1_pt2.y(); - - double Cx = seg2_pt1.x(); - double Cy = seg2_pt1.y(); - double Dx = seg2_pt2.x(); - double Dy = seg2_pt2.y(); - - if ( ( ( Ax == Bx ) && ( Ay == By ) ) || ( ( Cx == Dx ) && ( Cy == Dy ) ) ) - return ptInter; - - // (1) Translate the system so that point A is on the origin. - Bx -= Ax; - By -= Ay; - Cx -= Ax; - Cy -= Ay; - Dx -= Ax; - Dy -= Ay; - - // Discover the length of segment A-B - double distAB = sqrt( Bx * Bx + By * By ); - - // (2) Rotate the system so that point B is on the positive X axis. - double theCos = Bx / distAB; - double theSin = By / distAB; - double newX = Cx * theCos + Cy * theSin; - Cy = Cy * theCos - Cx * theSin; - Cx = newX; - newX = Dx * theCos + Dy * theSin; - Dy = Dy * theCos - Dx * theSin; - Dx = newX; - - // Fail if the lines are parallel. - if ( Cy == Dy ) - return ptInter; - - // (3) Discover the position of the intersection point along line A-B. - double ABpos = Dx + ( Cx - Dx ) * Dy / ( Dy - Cy ); - - // (4) Apply the discovered position to line A-B - // in the original coordinate system. - ptInter.setX( Ax + ABpos * theCos ); - ptInter.setY( Ay + ABpos * theSin ); - - // Success - return ptInter; -} - void QgsMapToolCircle2TangentsPoint::getPossibleCenter( ) { @@ -226,20 +172,21 @@ void QgsMapToolCircle2TangentsPoint::getPossibleCenter( ) QgsGeometry line2m = line2.offsetCurve( - mRadius, 8, QgsGeometry::JoinStyleBevel, 5 ); QgsGeometry line2p = line2.offsetCurve( + mRadius, 8, QgsGeometry::JoinStyleBevel, 5 ); - QgsPointXY p1 = intersect( line1m.asPolyline().at( 0 ), line1m.asPolyline().at( 1 ), - line2m.asPolyline().at( 0 ), line2m.asPolyline().at( 1 ) ); - QgsPointXY p2 = intersect( line1m.asPolyline().at( 0 ), line1m.asPolyline().at( 1 ), - line2p.asPolyline().at( 0 ), line2p.asPolyline().at( 1 ) ); - QgsPointXY p3 = intersect( line1p.asPolyline().at( 0 ), line1p.asPolyline().at( 1 ), - line2m.asPolyline().at( 0 ), line2m.asPolyline().at( 1 ) ); - QgsPointXY p4 = intersect( line1p.asPolyline().at( 0 ), line1p.asPolyline().at( 1 ), - line2p.asPolyline().at( 0 ), line2p.asPolyline().at( 1 ) ); - - mCenters.append( p1 ); - mCenters.append( p2 ); - mCenters.append( p3 ); - mCenters.append( p4 ); - + bool isIntersect; + const double epsilon = 1e-8; + QgsPoint inter; + QgsGeometryUtils::segmentIntersection( QgsPoint( line1m.asPolyline().at( 0 ) ), QgsPoint( line1m.asPolyline().at( 1 ) ), + QgsPoint( line2m.asPolyline().at( 0 ) ), QgsPoint( line2m.asPolyline().at( 1 ) ), inter, isIntersect, epsilon ); + mCenters.append( QgsPointXY( inter ) ); + QgsGeometryUtils::segmentIntersection( QgsPoint( line1m.asPolyline().at( 0 ) ), QgsPoint( line1m.asPolyline().at( 1 ) ), + QgsPoint( line2p.asPolyline().at( 0 ) ), QgsPoint( line2p.asPolyline().at( 1 ) ), inter, isIntersect, epsilon ); + mCenters.append( QgsPointXY( inter ) ); + QgsGeometryUtils::segmentIntersection( QgsPoint( line1p.asPolyline().at( 0 ) ), QgsPoint( line1p.asPolyline().at( 1 ) ), + QgsPoint( line2m.asPolyline().at( 0 ) ), QgsPoint( line2m.asPolyline().at( 1 ) ), inter, isIntersect, epsilon ); + mCenters.append( QgsPointXY( inter ) ); + QgsGeometryUtils::segmentIntersection( QgsPoint( line1p.asPolyline().at( 0 ) ), QgsPoint( line1p.asPolyline().at( 1 ) ), + QgsPoint( line2p.asPolyline().at( 0 ) ), QgsPoint( line2p.asPolyline().at( 1 ) ), inter, isIntersect, epsilon ); + mCenters.append( QgsPointXY( inter ) ); } } diff --git a/src/app/qgsmaptoolcircle2tangentspoint.h b/src/app/qgsmaptoolcircle2tangentspoint.h index f39f83916ce..c021150b40f 100644 --- a/src/app/qgsmaptoolcircle2tangentspoint.h +++ b/src/app/qgsmaptoolcircle2tangentspoint.h @@ -38,9 +38,6 @@ class QgsMapToolCircle2TangentsPoint: public QgsMapToolAddCircle void radiusSpinBoxChanged( int radius ); private: - //! Return the point where segments are intersected. Method from QgsGeometryUtils doesn't work for special cases used by this tool. - QgsPointXY intersect( QgsPointXY seg1_pt1, QgsPointXY seg1_pt2, QgsPointXY seg2_pt1, QgsPointXY seg2_pt2 ); - //! Compute 4 possible centers void getPossibleCenter(); diff --git a/src/core/geometry/qgscircle.cpp b/src/core/geometry/qgscircle.cpp index 2364f7568b0..a94ab5cc17d 100644 --- a/src/core/geometry/qgscircle.cpp +++ b/src/core/geometry/qgscircle.cpp @@ -182,10 +182,16 @@ QgsCircle QgsCircle::fromCenterPoint( const QgsPoint ¢er, const QgsPoint &pt QgsCircle QgsCircle::from3Tangents( const QgsPoint &pt1_tg1, const QgsPoint &pt2_tg1, const QgsPoint &pt1_tg2, const QgsPoint &pt2_tg2, const QgsPoint &pt1_tg3, const QgsPoint &pt2_tg3, double epsilon ) { QgsPoint p1, p2, p3; - bool intersection; - QgsGeometryUtils::segmentIntersection( pt1_tg1, pt2_tg1, pt1_tg2, pt2_tg2, p1, intersection, epsilon ); - QgsGeometryUtils::segmentIntersection( pt1_tg1, pt2_tg1, pt1_tg3, pt2_tg3, p2, intersection, epsilon ); - QgsGeometryUtils::segmentIntersection( pt1_tg2, pt2_tg2, pt1_tg3, pt2_tg3, p3, intersection, epsilon ); + bool isIntersect; + QgsGeometryUtils::segmentIntersection( pt1_tg1, pt2_tg1, pt1_tg2, pt2_tg2, p1, isIntersect, epsilon ); + if ( !isIntersect ) + return QgsCircle(); + QgsGeometryUtils::segmentIntersection( pt1_tg1, pt2_tg1, pt1_tg3, pt2_tg3, p2, isIntersect, epsilon ); + if ( !isIntersect ) + return QgsCircle(); + QgsGeometryUtils::segmentIntersection( pt1_tg2, pt2_tg2, pt1_tg3, pt2_tg3, p3, isIntersect, epsilon ); + if ( !isIntersect ) + return QgsCircle(); return QgsTriangle( p1, p2, p3 ).inscribedCircle(); } diff --git a/tests/src/core/testqgsgeometry.cpp b/tests/src/core/testqgsgeometry.cpp index d6e31d18881..86a60135609 100644 --- a/tests/src/core/testqgsgeometry.cpp +++ b/tests/src/core/testqgsgeometry.cpp @@ -6973,6 +6973,13 @@ void TestQgsGeometry::circle() QgsCircle circ_tgt = QgsCircle().from3Tangents( QgsPoint( 0, 0 ), QgsPoint( 0, 1 ), QgsPoint( 2, 0 ), QgsPoint( 3, 0 ), QgsPoint( 5, 0 ), QgsPoint( 0, 5 ) ); QGSCOMPARENEARPOINT( circ_tgt.center(), QgsPoint( 1.4645, 1.4645 ), 0.0001 ); QGSCOMPARENEAR( circ_tgt.radius(), 1.4645, 0.0001 ); + // with parallels + circ_tgt = QgsCircle().from3Tangents( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 1, 0 ), QgsPoint( 1, 5 ), QgsPoint( 5, 0 ), QgsPoint( 0, 5 ) ); + QVERIFY( circ_tgt.isEmpty() ); + circ_tgt = QgsCircle().from3Tangents( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 0 ), QgsPoint( 0, 5 ), QgsPoint( 1, 0 ), QgsPoint( 1, 5 ) ); + QVERIFY( circ_tgt.isEmpty() ); + circ_tgt = QgsCircle().from3Tangents( QgsPoint( 5, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 1, 0 ), QgsPoint( 1, 5 ) ); + QVERIFY( circ_tgt.isEmpty() ); // minimalCircleFrom3points QgsCircle minCircle3Points = QgsCircle().minimalCircleFrom3Points( QgsPoint( 0, 5 ), QgsPoint( 0, -5 ), QgsPoint( 1, 2 ) ); QGSCOMPARENEARPOINT( minCircle3Points.center(), QgsPoint( 0, 0 ), 0.0001 );