Fix case of 360° arc handling

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.
This commit is contained in:
Seth Hillbrand 2020-07-18 12:59:57 -07:00
parent 69d75b90b1
commit 3aeb3c8f99
1 changed files with 19 additions and 11 deletions

View File

@ -201,7 +201,7 @@ double ArcTangente( int dy, int dx )
} }
// Of course dy and dx are treated as double // 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 aSlope = yDelta_21 / xDelta_21;
double bSlope = yDelta_32 / xDelta_32; double bSlope = yDelta_32 / xDelta_32;
// If the points are colinear, the center is at infinity, so offset if( ( aSlope == bSlope ) )
// 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 )
{ {
aSlope += std::numeric_limits<double>::epsilon(); if( aStart == aEnd )
bSlope -= std::numeric_limits<double>::epsilon(); {
// 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<double>::epsilon();
bSlope -= std::numeric_limits<double>::epsilon();
}
} }
// Prevent divide by zero error
if( aSlope == 0.0 ) if( aSlope == 0.0 )
aSlope = std::numeric_limits<double>::epsilon(); aSlope = std::numeric_limits<double>::epsilon();
if( bSlope == 0.0 )
bSlope = -std::numeric_limits<double>::epsilon();
center.x = ( aSlope * bSlope * ( aStart.y - aEnd.y ) + center.x = ( aSlope * bSlope * ( aStart.y - aEnd.y ) +
bSlope * ( aStart.x + aMid.x ) - bSlope * ( aStart.x + aMid.x ) -
aSlope * ( aMid.x + aEnd.x ) ) / ( 2 * ( bSlope - aSlope ) ); aSlope * ( aMid.x + aEnd.x ) ) / ( 2 * ( bSlope - aSlope ) );