From 3aeb3c8f99a45bd3ef84470a8d697c81f1356f11 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Sat, 18 Jul 2020 12:59:57 -0700 Subject: [PATCH] =?UTF-8?q?Fix=20case=20of=20360=C2=B0=20arc=20handling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A 360° arc will have the mid point on the opposite side of the circle from both the start and end points. This will make both slopes the same, leading to a degeneracy in the calculation. We address this by noting that the center will be halfway between the midpoint and the start point. --- libs/kimath/src/trigo.cpp | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/libs/kimath/src/trigo.cpp b/libs/kimath/src/trigo.cpp index 662882e04b..3f7919d882 100644 --- a/libs/kimath/src/trigo.cpp +++ b/libs/kimath/src/trigo.cpp @@ -201,7 +201,7 @@ double ArcTangente( int dy, int dx ) } // Of course dy and dx are treated as double - return RAD2DECIDEG( atan2( (double) dy, (double) dx ) ); + return RAD2DECIDEG( std::atan2( (double) dy, (double) dx ) ); } @@ -367,22 +367,30 @@ const VECTOR2D GetArcCenter( const VECTOR2D& aStart, const VECTOR2D& aMid, const double aSlope = yDelta_21 / xDelta_21; double bSlope = yDelta_32 / xDelta_32; - // If the points are colinear, the center is at infinity, so offset - // the slope by a minimal amount - // Warning: This will induce a small error in the center location - if( yDelta_32 * xDelta_21 == yDelta_21 * xDelta_32 ) + if( ( aSlope == bSlope ) ) { - aSlope += std::numeric_limits::epsilon(); - bSlope -= std::numeric_limits::epsilon(); + if( aStart == aEnd ) + { + // This is a special case for a 360° arc. In this case, the center is halfway between + // the midpoint and either end point + center.x = ( aStart.x + aMid.x ) / 2.0; + center.y = ( aStart.y + aMid.y ) / 2.0 ; + return center; + } + else + { + // If the points are colinear, the center is at infinity, so offset + // the slope by a minimal amount + // Warning: This will induce a small error in the center location + aSlope += std::numeric_limits::epsilon(); + bSlope -= std::numeric_limits::epsilon(); + } } + // Prevent divide by zero error if( aSlope == 0.0 ) aSlope = std::numeric_limits::epsilon(); - if( bSlope == 0.0 ) - bSlope = -std::numeric_limits::epsilon(); - - center.x = ( aSlope * bSlope * ( aStart.y - aEnd.y ) + bSlope * ( aStart.x + aMid.x ) - aSlope * ( aMid.x + aEnd.x ) ) / ( 2 * ( bSlope - aSlope ) );