diff --git a/doc/api_break.dox b/doc/api_break.dox index f0b4bfe59ce..2b64b4c1a81 100644 --- a/doc/api_break.dox +++ b/doc/api_break.dox @@ -1465,7 +1465,8 @@ QgsGeometryUtils {#qgis_api_break_3_0_QgsGeometryUtils} - componentType enum has been renamed to ComponentType and its members were CamelCased too: VERTEX, RING and PART become Vertex, Ring and Part, respectively. - adjacentVertices was removed - use QgsAbstractGeometry.adjacentVertices instead. - +- segmentIntersection takes an optional boolean parameter "acceptImproperIntersection" returning true even if the intersection is improper. +Takes another boolean argument "isIntersection" returning if there is an intersection or not. The "inter" parameter has been renamed "intersectionPoint". QgsGPSConnectionRegistry {#qgis_api_break_3_0_QgsGPSConnectionRegistry} ------------------------ diff --git a/python/core/geometry/qgsgeometryutils.sip b/python/core/geometry/qgsgeometryutils.sip index a06115c3c3c..0ddb2498f8e 100644 --- a/python/core/geometry/qgsgeometryutils.sip +++ b/python/core/geometry/qgsgeometryutils.sip @@ -100,7 +100,7 @@ Returns the squared distance between a point and a line. :return: Whether the lines intersect %End - static bool segmentIntersection( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q1, const QgsPoint &q2, QgsPoint &inter /Out/, double tolerance ); + static bool segmentIntersection( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q1, const QgsPoint &q2, QgsPoint &intersectionPoint /Out/, bool &isIntersection /Out/, const double tolerance = 1e-8, bool acceptImproperIntersection = false ); %Docstring Compute the intersection between two segments @@ -108,10 +108,34 @@ Returns the squared distance between a point and a line. :param p2: First segment end point :param q1: Second segment start point :param q2: Second segment end point -:param inter: Output parameter, the intersection point +:param intersectionPoint: Output parameter, the intersection point +:param isIntersection: Output parameter, return true if an intersection is found :param tolerance: The tolerance to use +:param acceptImproperIntersection: By default, this method returns true only if segments have proper intersection. If set true, returns also true if segments have improper intersection (end of one segment on other segment ; continuous segments). :return: Whether the segments intersect +* Example: +\code{.py} +ret = QgsGeometryUtils.segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 1 ), QgsPoint( 1, 1 ), QgsPoint( 1, 0 ) ) +ret[0], ret[1].asWkt(), ret[2] +# Whether the segments intersect, the intersection point, is intersect +# (False, 'Point (0 0)', False) +ret = QgsGeometryUtils.segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 5 ), QgsPoint( 1, 5 ) ) +ret[0], ret[1].asWkt(), ret[2] +# (False, 'Point (0 5)', True) +ret = QgsGeometryUtils.segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 5 ), QgsPoint( 1, 5 ), acceptImproperIntersection=True ) +ret[0], ret[1].asWkt(), ret[2] +# (True, 'Point (0 5)', True) +ret = QgsGeometryUtils.segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 2 ), QgsPoint( 1, 5 ) ) +ret[0], ret[1].asWkt(), ret[2] +# (False, 'Point (0 2)', True) +ret = QgsGeometryUtils.segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 2 ), QgsPoint( 1, 5 ), acceptImproperIntersection=True ) +ret[0], ret[1].asWkt(), ret[2] +# (True, 'Point (0 2)', True) +ret = QgsGeometryUtils.segmentIntersection( QgsPoint( 0, -5 ), QgsPoint( 0, 5 ), QgsPoint( 2, 0 ), QgsPoint( -1, 0 ) ) +ret[0], ret[1].asWkt(), ret[2] +# (True, 'Point (0 0)', True) +\endcode %End static QgsPoint projPointOnSegment( const QgsPoint &p, const QgsPoint &s1, const QgsPoint &s2 ); diff --git a/src/analysis/vector/geometry_checker/qgsgeometrycheckerutils.cpp b/src/analysis/vector/geometry_checker/qgsgeometrycheckerutils.cpp index a079cedb398..621207a02c3 100644 --- a/src/analysis/vector/geometry_checker/qgsgeometrycheckerutils.cpp +++ b/src/analysis/vector/geometry_checker/qgsgeometrycheckerutils.cpp @@ -257,6 +257,7 @@ namespace QgsGeometryCheckerUtils { QList intersections; QgsPoint inter; + bool intersection = false; for ( int i = 0, n = line1->vertexCount() - 1; i < n; ++i ) { for ( int j = 0, m = line2->vertexCount() - 1; j < m; ++j ) @@ -265,7 +266,7 @@ namespace QgsGeometryCheckerUtils QgsPoint p2 = line1->vertexAt( QgsVertexId( 0, 0, i + 1 ) ); QgsPoint q1 = line2->vertexAt( QgsVertexId( 0, 0, j ) ); QgsPoint q2 = line2->vertexAt( QgsVertexId( 0, 0, j + 1 ) ); - if ( QgsGeometryUtils::segmentIntersection( p1, p2, q1, q2, inter, tol ) ) + if ( QgsGeometryUtils::segmentIntersection( p1, p2, q1, q2, inter, intersection, tol ) ) { intersections.append( inter ); } diff --git a/src/analysis/vector/geometry_checker/qgsgeometryselfintersectioncheck.cpp b/src/analysis/vector/geometry_checker/qgsgeometryselfintersectioncheck.cpp index 20a84d11fc3..81d27dc9161 100644 --- a/src/analysis/vector/geometry_checker/qgsgeometryselfintersectioncheck.cpp +++ b/src/analysis/vector/geometry_checker/qgsgeometryselfintersectioncheck.cpp @@ -114,7 +114,8 @@ void QgsGeometrySelfIntersectionCheck::fixError( QgsGeometryCheckError *error, i QgsPoint p2 = geom->vertexAt( QgsVertexId( vidx.part, vidx.ring, ( inter.segment1 + 1 ) % nVerts ) ); QgsPoint q2 = geom->vertexAt( QgsVertexId( vidx.part, vidx.ring, ( inter.segment2 + 1 ) % nVerts ) ); QgsPoint s; - if ( !QgsGeometryUtils::segmentIntersection( p1, p2, q1, q2, s, mContext->tolerance ) ) + bool intersection = false; + if ( !QgsGeometryUtils::segmentIntersection( p1, p2, q1, q2, s, intersection, mContext->tolerance ) ) { error->setObsolete(); return; diff --git a/src/app/qgsmaptoolcircle2tangentspoint.cpp b/src/app/qgsmaptoolcircle2tangentspoint.cpp index 339f67c9bc9..1fb9eaa5389 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,11 @@ 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 = false; + QgsPoint ptInter; + QgsGeometryUtils::segmentIntersection( mPoints.at( 0 ), mPoints.at( 1 ), + mPoints.at( 2 ), mPoints.at( 3 ), ptInter, isIntersect ); + if ( !isIntersect ) { QgisApp::instance()->messageBar()->pushMessage( tr( "Error" ), tr( "Segments are parallels" ), QgsMessageBar::CRITICAL, QgisApp::instance()->messageTimeout() ); @@ -144,64 +147,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 +171,20 @@ 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 = false; + 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 ); + 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 ); + 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 ); + 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 ); + mCenters.append( QgsPointXY( inter ) ); } } diff --git a/src/app/qgsmaptoolcircle2tangentspoint.h b/src/app/qgsmaptoolcircle2tangentspoint.h index 176a6ba7b09..dde59824996 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 29ba7e6150a..2d4f203579e 100644 --- a/src/core/geometry/qgscircle.cpp +++ b/src/core/geometry/qgscircle.cpp @@ -182,9 +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; - QgsGeometryUtils::segmentIntersection( pt1_tg1, pt2_tg1, pt1_tg2, pt2_tg2, p1, epsilon ); - QgsGeometryUtils::segmentIntersection( pt1_tg1, pt2_tg1, pt1_tg3, pt2_tg3, p2, epsilon ); - QgsGeometryUtils::segmentIntersection( pt1_tg2, pt2_tg2, pt1_tg3, pt2_tg3, p3, epsilon ); + bool isIntersect = false; + 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/src/core/geometry/qgsgeometryutils.cpp b/src/core/geometry/qgsgeometryutils.cpp index 5c45ea469cb..cb69d8a7603 100644 --- a/src/core/geometry/qgsgeometryutils.cpp +++ b/src/core/geometry/qgsgeometryutils.cpp @@ -251,28 +251,62 @@ bool QgsGeometryUtils::lineIntersection( const QgsPoint &p1, QgsVector v1, const return true; } -bool QgsGeometryUtils::segmentIntersection( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q1, const QgsPoint &q2, QgsPoint &inter, double tolerance ) +bool QgsGeometryUtils::segmentIntersection( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q1, const QgsPoint &q2, QgsPoint &intersectionPoint, bool &isIntersection, const double tolerance, bool acceptImproperIntersection ) { + isIntersection = false; + QgsVector v( p2.x() - p1.x(), p2.y() - p1.y() ); QgsVector w( q2.x() - q1.x(), q2.y() - q1.y() ); double vl = v.length(); double wl = w.length(); - if ( qgsDoubleNear( vl, 0, 0.000000000001 ) || qgsDoubleNear( wl, 0, 0.000000000001 ) ) + if ( qgsDoubleNear( vl, 0.0, tolerance ) || qgsDoubleNear( wl, 0.0, tolerance ) ) { return false; } v = v / vl; w = w / wl; - if ( !QgsGeometryUtils::lineIntersection( p1, v, q1, w, inter ) ) + if ( !QgsGeometryUtils::lineIntersection( p1, v, q1, w, intersectionPoint ) ) + { return false; + } - double lambdav = QgsVector( inter.x() - p1.x(), inter.y() - p1.y() ) * v; + isIntersection = true; + if ( acceptImproperIntersection ) + { + if ( ( p1 == q1 ) || ( p1 == q2 ) ) + { + intersectionPoint = p1; + return true; + } + else if ( ( p2 == q1 ) || ( p2 == q2 ) ) + { + intersectionPoint = p2; + return true; + } + + double x, y; + if ( + // intersectionPoint = p1 + qgsDoubleNear( QgsGeometryUtils::sqrDistToLine( p1.x(), p1.y(), q1.x(), q1.y(), q2.x(), q2.y(), x, y, tolerance ), 0.0, tolerance ) || + // intersectionPoint = p2 + qgsDoubleNear( QgsGeometryUtils::sqrDistToLine( p2.x(), p2.y(), q1.x(), q1.y(), q2.x(), q2.y(), x, y, tolerance ), 0.0, tolerance ) || + // intersectionPoint = q1 + qgsDoubleNear( QgsGeometryUtils::sqrDistToLine( q1.x(), q1.y(), p1.x(), p1.y(), p2.x(), p2.y(), x, y, tolerance ), 0.0, tolerance ) || + // intersectionPoint = q2 + qgsDoubleNear( QgsGeometryUtils::sqrDistToLine( q2.x(), q2.y(), p1.x(), p1.y(), p2.x(), p2.y(), x, y, tolerance ), 0.0, tolerance ) + ) + { + return true; + } + } + + double lambdav = QgsVector( intersectionPoint.x() - p1.x(), intersectionPoint.y() - p1.y() ) * v; if ( lambdav < 0. + tolerance || lambdav > vl - tolerance ) return false; - double lambdaw = QgsVector( inter.x() - q1.x(), inter.y() - q1.y() ) * w; + double lambdaw = QgsVector( intersectionPoint.x() - q1.x(), intersectionPoint.y() - q1.y() ) * w; return !( lambdaw < 0. + tolerance || lambdaw >= wl - tolerance ); } @@ -299,7 +333,8 @@ QVector QgsGeometryUtils::getSelfIntersectio QgsPoint pl = geom->vertexAt( QgsVertexId( part, ring, l ) ); QgsPoint inter; - if ( !QgsGeometryUtils::segmentIntersection( pi, pj, pk, pl, inter, tolerance ) ) continue; + bool intersection = false; + if ( !QgsGeometryUtils::segmentIntersection( pi, pj, pk, pl, inter, intersection, tolerance ) ) continue; SelfIntersection s; s.segment1 = i; diff --git a/src/core/geometry/qgsgeometryutils.h b/src/core/geometry/qgsgeometryutils.h index 9b30722d9c4..7f7bab9d902 100644 --- a/src/core/geometry/qgsgeometryutils.h +++ b/src/core/geometry/qgsgeometryutils.h @@ -106,11 +106,35 @@ class CORE_EXPORT QgsGeometryUtils * \param p2 First segment end point * \param q1 Second segment start point * \param q2 Second segment end point - * \param inter Output parameter, the intersection point + * \param intersectionPoint Output parameter, the intersection point + * \param isIntersection Output parameter, return true if an intersection is found * \param tolerance The tolerance to use + * \param acceptImproperIntersection By default, this method returns true only if segments have proper intersection. If set true, returns also true if segments have improper intersection (end of one segment on other segment ; continuous segments). * \returns Whether the segments intersect + * * Example: + * \code{.py} + * ret = QgsGeometryUtils.segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 1 ), QgsPoint( 1, 1 ), QgsPoint( 1, 0 ) ) + * ret[0], ret[1].asWkt(), ret[2] + * # Whether the segments intersect, the intersection point, is intersect + * # (False, 'Point (0 0)', False) + * ret = QgsGeometryUtils.segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 5 ), QgsPoint( 1, 5 ) ) + * ret[0], ret[1].asWkt(), ret[2] + * # (False, 'Point (0 5)', True) + * ret = QgsGeometryUtils.segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 5 ), QgsPoint( 1, 5 ), acceptImproperIntersection=True ) + * ret[0], ret[1].asWkt(), ret[2] + * # (True, 'Point (0 5)', True) + * ret = QgsGeometryUtils.segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 2 ), QgsPoint( 1, 5 ) ) + * ret[0], ret[1].asWkt(), ret[2] + * # (False, 'Point (0 2)', True) + * ret = QgsGeometryUtils.segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 2 ), QgsPoint( 1, 5 ), acceptImproperIntersection=True ) + * ret[0], ret[1].asWkt(), ret[2] + * # (True, 'Point (0 2)', True) + * ret = QgsGeometryUtils.segmentIntersection( QgsPoint( 0, -5 ), QgsPoint( 0, 5 ), QgsPoint( 2, 0 ), QgsPoint( -1, 0 ) ) + * ret[0], ret[1].asWkt(), ret[2] + * # (True, 'Point (0 0)', True) + * \endcode */ - static bool segmentIntersection( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q1, const QgsPoint &q2, QgsPoint &inter SIP_OUT, double tolerance ); + static bool segmentIntersection( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q1, const QgsPoint &q2, QgsPoint &intersectionPoint SIP_OUT, bool &isIntersection SIP_OUT, const double tolerance = 1e-8, bool acceptImproperIntersection = false ); /** * \brief Project the point on a segment diff --git a/src/core/geometry/qgstriangle.cpp b/src/core/geometry/qgstriangle.cpp index 40b6204ec97..ba88447985e 100644 --- a/src/core/geometry/qgstriangle.cpp +++ b/src/core/geometry/qgstriangle.cpp @@ -495,14 +495,15 @@ QVector QgsTriangle::bisectors( double lengthTolerance ) const QgsLineString bis3; QgsPoint incenter = inscribedCenter(); QgsPoint out; + bool intersection = false; - QgsGeometryUtils::segmentIntersection( vertexAt( 0 ), incenter, vertexAt( 1 ), vertexAt( 2 ), out, lengthTolerance ); + QgsGeometryUtils::segmentIntersection( vertexAt( 0 ), incenter, vertexAt( 1 ), vertexAt( 2 ), out, intersection, lengthTolerance ); bis1.setPoints( QgsPointSequence() << vertexAt( 0 ) << out ); - QgsGeometryUtils::segmentIntersection( vertexAt( 1 ), incenter, vertexAt( 0 ), vertexAt( 2 ), out, lengthTolerance ); + QgsGeometryUtils::segmentIntersection( vertexAt( 1 ), incenter, vertexAt( 0 ), vertexAt( 2 ), out, intersection, lengthTolerance ); bis2.setPoints( QgsPointSequence() << vertexAt( 1 ) << out ); - QgsGeometryUtils::segmentIntersection( vertexAt( 2 ), incenter, vertexAt( 0 ), vertexAt( 1 ), out, lengthTolerance ); + QgsGeometryUtils::segmentIntersection( vertexAt( 2 ), incenter, vertexAt( 0 ), vertexAt( 1 ), out, intersection, lengthTolerance ); bis3.setPoints( QgsPointSequence() << vertexAt( 2 ) << out ); bis.append( bis1 ); @@ -529,7 +530,8 @@ QgsPoint QgsTriangle::orthocenter( double lengthTolerance ) const return QgsPoint(); QVector alt = altitudes(); QgsPoint ortho; - QgsGeometryUtils::segmentIntersection( alt.at( 0 ).pointN( 0 ), alt.at( 0 ).pointN( 1 ), alt.at( 1 ).pointN( 0 ), alt.at( 1 ).pointN( 1 ), ortho, lengthTolerance ); + bool intersection; + QgsGeometryUtils::segmentIntersection( alt.at( 0 ).pointN( 0 ), alt.at( 0 ).pointN( 1 ), alt.at( 1 ).pointN( 0 ), alt.at( 1 ).pointN( 1 ), ortho, intersection, lengthTolerance ); return ortho; } diff --git a/tests/src/core/testqgsgeometry.cpp b/tests/src/core/testqgsgeometry.cpp index cd166baa682..c13773d8b3c 100644 --- a/tests/src/core/testqgsgeometry.cpp +++ b/tests/src/core/testqgsgeometry.cpp @@ -6974,6 +6974,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 ); diff --git a/tests/src/core/testqgsgeometryutils.cpp b/tests/src/core/testqgsgeometryutils.cpp index 7aa03b65185..2525c89cae7 100644 --- a/tests/src/core/testqgsgeometryutils.cpp +++ b/tests/src/core/testqgsgeometryutils.cpp @@ -54,6 +54,7 @@ class TestQgsGeometryUtils: public QObject void testCoefficients(); void testPerpendicularSegment(); void testClosestPoint(); + void testSegmentIntersection(); }; @@ -647,5 +648,154 @@ void TestQgsGeometryUtils::testClosestPoint() QGSCOMPARENEAR( pt4.m(), 1, 0.0001 ); } +void TestQgsGeometryUtils::testSegmentIntersection() +{ + const double epsilon = 1e-8; + bool intersection = false, isIntersect = false; + QgsPoint inter; + // null + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 5, 5 ), QgsPoint( 5, 5 ), QgsPoint( 1, 1 ), QgsPoint( 1, 0 ), inter, isIntersect, epsilon ); + QVERIFY( !intersection ); + QVERIFY( !isIntersect ); + QVERIFY( inter == QgsPoint() ); + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 1 ), QgsPoint( 5, 5 ), QgsPoint( 5, 5 ), inter, isIntersect, epsilon, true ); + QVERIFY( !intersection ); + QVERIFY( !isIntersect ); + QVERIFY( inter == QgsPoint() ); + // parallel + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 1 ), QgsPoint( 1, 1 ), QgsPoint( 1, 0 ), inter, isIntersect, epsilon ); + QVERIFY( !intersection ); + QVERIFY( !isIntersect ); + QVERIFY( inter == QgsPoint() ); + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 1 ), QgsPoint( 1, 1 ), QgsPoint( 1, 0 ), inter, isIntersect, epsilon, true ); + QVERIFY( !intersection ); + QVERIFY( !isIntersect ); + QVERIFY( inter == QgsPoint() ); + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 1, 1 ), QgsPoint( 0, 1 ), QgsPoint( 1, 2 ), inter, isIntersect, epsilon ); + QVERIFY( !intersection ); + QVERIFY( !isIntersect ); + QVERIFY( inter == QgsPoint() ); + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 1, 1 ), QgsPoint( -1, -1 ), inter, isIntersect, epsilon ); + QVERIFY( !intersection ); + QVERIFY( !isIntersect ); + QVERIFY( inter == QgsPoint() ); + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 1, 1 ), QgsPoint( 0, 0 ), inter, isIntersect, epsilon ); + QVERIFY( !intersection ); + QVERIFY( !isIntersect ); + QVERIFY( inter == QgsPoint() ); + // contigus + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 5 ), QgsPoint( 1, 5 ), inter, isIntersect, epsilon ); + QVERIFY( !intersection ); + QVERIFY( isIntersect ); + QVERIFY( inter == QgsPoint( 0, 5 ) ); + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 5 ), QgsPoint( 1, 5 ), inter, isIntersect, epsilon, true ); + QVERIFY( intersection ); + QVERIFY( isIntersect ); + QVERIFY( inter == QgsPoint( 0, 5 ) ); + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 5 ), QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 1, 5 ), inter, isIntersect, epsilon ); + QVERIFY( !intersection ); + QVERIFY( isIntersect ); + QVERIFY( inter == QgsPoint( 0, 5 ) ); + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 5 ), QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 1, 5 ), inter, isIntersect, epsilon, true ); + QVERIFY( intersection ); + QVERIFY( isIntersect ); + QVERIFY( inter == QgsPoint( 0, 5 ) ); + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 1, 5 ), QgsPoint( 0, 5 ), inter, isIntersect, epsilon ); + QVERIFY( !intersection ); + QVERIFY( isIntersect ); + QVERIFY( inter == QgsPoint( 0, 5 ) ); + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 1, 5 ), QgsPoint( 0, 5 ), inter, isIntersect, epsilon, true ); + QVERIFY( intersection ); + QVERIFY( isIntersect ); + QVERIFY( inter == QgsPoint( 0, 5 ) ); + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 5 ), QgsPoint( 0, 0 ), QgsPoint( 1, 5 ), QgsPoint( 0, 5 ), inter, isIntersect, epsilon ); + QVERIFY( !intersection ); + QVERIFY( isIntersect ); + QVERIFY( inter == QgsPoint( 0, 5 ) ); + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 5 ), QgsPoint( 0, 0 ), QgsPoint( 1, 5 ), QgsPoint( 0, 5 ), inter, isIntersect, epsilon, true ); + QVERIFY( intersection ); + QVERIFY( isIntersect ); + QVERIFY( inter == QgsPoint( 0, 5 ) ); + // colinear + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 5 ), QgsPoint( 0, 6 ), inter, isIntersect, epsilon ); + QVERIFY( !intersection ); + QVERIFY( !isIntersect ); + QVERIFY( inter == QgsPoint() ); + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 5 ), QgsPoint( 0, 6 ), inter, isIntersect, epsilon, true ); + QVERIFY( !intersection ); + QVERIFY( !isIntersect ); + QVERIFY( inter == QgsPoint() ); + // improper + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 2 ), QgsPoint( 1, 5 ), inter, isIntersect, epsilon ); + QVERIFY( !intersection ); + QVERIFY( isIntersect ); + QVERIFY( inter == QgsPoint( 0, 2 ) ); + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 2 ), QgsPoint( 1, 5 ), QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), inter, isIntersect, epsilon, true ); + QVERIFY( intersection ); + QVERIFY( isIntersect ); + QVERIFY( inter == QgsPoint( 0, 2 ) ); + + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 1, 5 ), QgsPoint( 0, 2 ), QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), inter, isIntersect, epsilon ); + QVERIFY( !intersection ); + QVERIFY( isIntersect ); + QVERIFY( inter == QgsPoint( 0, 2 ) ); + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 1, 5 ), QgsPoint( 0, 2 ), QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), inter, isIntersect, epsilon, true ); + QVERIFY( intersection ); + QVERIFY( isIntersect ); + QVERIFY( inter == QgsPoint( 0, 2 ) ); + + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 2 ), QgsPoint( 1, 5 ), inter, isIntersect, epsilon ); + QVERIFY( !intersection ); + QVERIFY( isIntersect ); + QVERIFY( inter == QgsPoint( 0, 2 ) ); + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 2 ), QgsPoint( 1, 5 ), inter, isIntersect, epsilon, true ); + QVERIFY( intersection ); + QVERIFY( isIntersect ); + QVERIFY( inter == QgsPoint( 0, 2 ) ); + + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 1, 5 ), QgsPoint( 0, 2 ), inter, isIntersect, epsilon ); + QVERIFY( !intersection ); + QVERIFY( isIntersect ); + QVERIFY( inter == QgsPoint( 0, 2 ) ); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 1, 5 ), QgsPoint( 0, 2 ), inter, isIntersect, epsilon, true ); + QVERIFY( intersection ); + QVERIFY( isIntersect ); + QVERIFY( inter == QgsPoint( 0, 2 ) ); + // normal + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, -5 ), QgsPoint( 0, 5 ), QgsPoint( 2, 0 ), QgsPoint( -1, 0 ), inter, isIntersect, epsilon ); + QVERIFY( intersection ); + QVERIFY( isIntersect ); + QVERIFY( inter == QgsPoint( 0, 0 ) ); + inter = QgsPoint(); + intersection = QgsGeometryUtils::segmentIntersection( QgsPoint( 0, -5 ), QgsPoint( 0, 5 ), QgsPoint( 2, 0 ), QgsPoint( -1, 0 ), inter, isIntersect, epsilon, true ); + QVERIFY( intersection ); + QVERIFY( isIntersect ); + QVERIFY( inter == QgsPoint( 0, 0 ) ); +} + QGSTEST_MAIN( TestQgsGeometryUtils ) #include "testqgsgeometryutils.moc"