Fix incorrect calculation in TransformCircleToPolygon(), only noticeable

when the allowed aError is (unusually) large.
This commit is contained in:
jean-pierre charras 2021-06-28 18:51:37 +02:00
parent fa49b54f93
commit bcb5618315
3 changed files with 29 additions and 13 deletions

View File

@ -55,11 +55,14 @@ enum ERROR_LOC { ERROR_OUTSIDE, ERROR_INSIDE };
int GetArcToSegmentCount( int aRadius, int aErrorMax, double aArcAngleDegree );
/**
* @return the max error when approximating a circle by segments
* @param aRadius is the radius of the circle
* @return the radius diffence of the circle defined by segments inside the circle
* and the radius of the circle tangent to the middle of segments (defined by
* segments outside this circle)
* @param aInnerCircleRadius is the radius of the circle tangent to the middle
* of segments
* @param aSegCount is the seg count to approximate the circle
*/
int GetCircleToSegmentError( int aRadius, int aSegCount );
int CircleToEndSegmentDeltaRadius( int aInnerCircleRadius, int aSegCount );
/**
* When creating polygons to create a clearance polygonal area, the polygon must

View File

@ -56,8 +56,11 @@ void TransformCircleToPolygon( SHAPE_LINE_CHAIN& aCornerBuffer, wxPoint aCenter,
if( aErrorLoc == ERROR_OUTSIDE )
{
int actual_error = GetCircleToSegmentError( radius, numSegs );
radius += GetCircleToPolyCorrection( actual_error );
// The outer radius should be radius+aError
// Recalculate the actual approx error, as it can be smaller than aError
// because numSegs is clamped to a minimal value
int actual_delta_radius = CircleToEndSegmentDeltaRadius( radius, numSegs );
radius += GetCircleToPolyCorrection( actual_delta_radius );
}
for( int angle = 0; angle < 3600; angle += delta )
@ -90,7 +93,13 @@ void TransformCircleToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aCenter, i
int radius = aRadius;
if( aErrorLoc == ERROR_OUTSIDE )
radius += GetCircleToPolyCorrection( aError );
{
// The outer radius should be radius+aError
// Recalculate the actual approx error, as it can be smaller than aError
// because numSegs is clamped to a minimal value
int actual_delta_radius = CircleToEndSegmentDeltaRadius( radius, numSegs );
radius += GetCircleToPolyCorrection( actual_delta_radius );
}
aCornerBuffer.NewOutline();

View File

@ -64,18 +64,22 @@ int GetArcToSegmentCount( int aRadius, int aErrorMax, double aArcAngleDegree )
}
int GetCircleToSegmentError( int aRadius, int aSegCount )
int CircleToEndSegmentDeltaRadius( int aRadius, int aSegCount )
{
// This is similar to the "inverse" of GetArcToSegmentCount()
// The minimal seg count is 2, giving error = aRadius
// The minimal seg count is 3, otherwise we cannot calculate the result
// in practice, the min count is clamped to 8 in kicad
if( aSegCount <= 2 )
return aRadius;
aSegCount = 3;
// The angle between the center of the segment and one end of the segment
// when the circle is approximated by aSegCount segments
double alpha = M_PI / aSegCount;
int error = KiROUND( aRadius * ( 1.0 - cos( alpha) ) );
return error;
// aRadius is the radius of the circle tangent to the middle of each segment
// and aRadius/cos(aplha) is the radius of the circle defined by seg ends
int delta = KiROUND( aRadius * ( 1/cos(alpha) - 1 ) );
return delta;
}
// When creating polygons to create a clearance polygonal area, the polygon must