Skip to content

Commit

Permalink
Apply segmentIntersection on some tools with tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
lbartoletti committed Dec 13, 2017
1 parent 342985f commit eb292c9
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 82 deletions.
97 changes: 22 additions & 75 deletions src/app/qgsmaptoolcircle2tangentspoint.cpp
Expand Up @@ -25,6 +25,7 @@
#include "qgslinestring.h"
#include "qgsmultipolygon.h"
#include "qgsspinbox.h"
#include "qgsgeometryutils.h"
#include <memory>
#include <QMouseEvent>

Expand Down Expand Up @@ -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() );
Expand Down Expand Up @@ -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( )
{

Expand All @@ -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 ) );
}
}

Expand Down
3 changes: 0 additions & 3 deletions src/app/qgsmaptoolcircle2tangentspoint.h
Expand Up @@ -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();

Expand Down
14 changes: 10 additions & 4 deletions src/core/geometry/qgscircle.cpp
Expand Up @@ -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();
}
Expand Down
7 changes: 7 additions & 0 deletions tests/src/core/testqgsgeometry.cpp
Expand Up @@ -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 );
Expand Down

0 comments on commit eb292c9

Please sign in to comment.