QgsCircle QgsCircle::from3Points( const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double epsilon ) { QgsPoint p1, p2, p3; if ( !isPerpendicular( pt1, pt2, pt3, epsilon ) ) { p1 = pt1; p2 = pt2; p3 = pt3; } else if ( !isPerpendicular( pt1, pt3, pt2, epsilon ) ) { p1 = pt1; p2 = pt3; p3 = pt2; } else if ( !isPerpendicular( pt2, pt1, pt3, epsilon ) ) { p1 = pt2; p2 = pt1; p3 = pt3; } else if ( !isPerpendicular( pt2, pt3, pt1, epsilon ) ) { p1 = pt2; p2 = pt3; p3 = pt1; } else if ( !isPerpendicular( pt3, pt2, pt1, epsilon ) ) { p1 = pt3; p2 = pt2; p3 = pt1; } else if ( !isPerpendicular( pt3, pt1, pt2, epsilon ) ) { p1 = pt3; p2 = pt1; p3 = pt2; } else { return QgsCircle(); } QgsPoint center = QgsPoint(); double radius = -0.0; // Paul Bourke's algorithm double yDelta_a = p2.y() - p1.y(); double xDelta_a = p2.x() - p1.x(); double yDelta_b = p3.y() - p2.y(); double xDelta_b = p3.x() - p2.x(); if ( qgsDoubleNear( xDelta_a, 0.0, epsilon ) || qgsDoubleNear( xDelta_b, 0.0, epsilon ) ) { return QgsCircle(); } double aSlope = yDelta_a / xDelta_a; double bSlope = yDelta_b / xDelta_b; if ( ( qAbs( xDelta_a ) <= epsilon ) && ( qAbs( yDelta_b ) <= epsilon ) ) { center.setX( 0.5 * ( p2.x() + p3.x() ) ); center.setY( 0.5 * ( p1.y() + p2.y() ) ); radius = center.distance( pt1 ); return QgsCircle( center, radius ); } if ( qAbs( aSlope - bSlope ) <= epsilon ) { return QgsCircle(); } center.setX( ( aSlope * bSlope * ( p1.y() - p3.y() ) + bSlope * ( p1.x() + p2.x() ) - aSlope * ( p2.x() + p3.x() ) ) / ( 2.0 * ( bSlope - aSlope ) ) ); center.setY( -1.0 * ( center.x() - ( p1.x() + p2.x() ) / 2.0 ) / aSlope + ( p1.y() + p2.y() ) / 2.0 ); radius = center.distance( p1 ); return QgsCircle( center, radius ); }
double angleBetweenLines(const Line &line) const { if (isPerpendicular(line)) return PI / 2; return atan((parameters.A * line.parameters.B - line.parameters.A * parameters.B) / (parameters.A * line.parameters.A + parameters.B * line.parameters.B)); }