Apply segmentIntersection on some tools with tests.

This commit is contained in:
lbartoletti 2017-12-13 08:45:44 +01:00
parent 342985f162
commit eb292c93bb
4 changed files with 39 additions and 82 deletions

View File

@ -25,6 +25,7 @@
#include "qgslinestring.h"
#include "qgsmultipolygon.h"
#include "qgsspinbox.h"
#include "qgsgeometryutils.h"
#include <memory>
#include <QMouseEvent>
@ -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 ) );
}
}

View File

@ -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();

View File

@ -182,10 +182,16 @@ QgsCircle QgsCircle::fromCenterPoint( const QgsPoint &center, 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();
}

View File

@ -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 );