Transform arcs more accurately

Segment approximation for arcs leaves small "indents" where the rounded
edges of two segments don't quite meet.

This gives closer approximation by calculating the inner and outer joint
points based on the radius, eliminating the indents.
This commit is contained in:
Seth Hillbrand 2021-06-11 12:34:57 -07:00
parent 096e342386
commit a04d6401c1
1 changed files with 33 additions and 8 deletions

View File

@ -354,21 +354,46 @@ void TransformArcToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aStart, wxPoi
{ {
SHAPE_ARC arc( aStart, aMid, aEnd, aWidth ); SHAPE_ARC arc( aStart, aMid, aEnd, aWidth );
SHAPE_LINE_CHAIN arcSpine = arc.ConvertToPolyline( aError ); SHAPE_LINE_CHAIN arcSpine = arc.ConvertToPolyline( aError );
int radial_offset = ( aWidth + 1 ) / 2;
/// We start by making rounded ends on the arc
TransformCircleToPolygon( aCornerBuffer,
wxPoint( arcSpine.GetPoint( 0 ).x, arcSpine.GetPoint( 0 ).y ), radial_offset, aError,
aErrorLoc );
TransformCircleToPolygon( aCornerBuffer,
wxPoint( arcSpine.GetPoint( -1 ).x, arcSpine.GetPoint( -1 ).y ), radial_offset, aError,
aErrorLoc );
if( aErrorLoc == ERROR_OUTSIDE ) if( aErrorLoc == ERROR_OUTSIDE )
aWidth += 2 * aError; radial_offset += aError;
else else
aWidth -= 2 * aError; radial_offset -= aError;
for( int ii = 0; ii < arcSpine.GetSegmentCount(); ++ii ) if( radial_offset < 0 )
radial_offset = 0;
std::vector<VECTOR2I> outside_pts;
SHAPE_POLY_SET polyshape;
polyshape.NewOutline();
VECTOR2I center = arc.GetCenter();
int radius = ( arc.GetP0() - center ).EuclideanNorm();
for( std::size_t ii = 0; ii < arcSpine.GetPointCount(); ++ii )
{ {
SEG seg = arcSpine.GetSegment( ii ); VECTOR2I offset = arcSpine.GetPoint( ii ) - center;
// Note that the error here is only for the rounded ends; we still need to shrink or polyshape.Append( offset.Resize( radius - radial_offset ) + center );
// expand the width above for the segments themselves. outside_pts.emplace_back( offset.Resize( radius + radial_offset ) + center );
TransformOvalToPolygon( aCornerBuffer, (wxPoint) seg.A, (wxPoint) seg.B, aWidth, aError,
aErrorLoc );
} }
for( auto it = outside_pts.rbegin(); it != outside_pts.rend(); ++it )
polyshape.Append( *it );
aCornerBuffer.Append( polyshape );
} }