convert_basic_shapes_to_polygon: some enhancements:

- allows setting a minimal seg count for circles and rounded end segments.
- When using ERROR_OUTSIDE, ensure the arc correction is the actual value
needed by the segment count, not the max value allowed
This commit is contained in:
jean-pierre charras 2021-07-05 17:40:26 +02:00
parent f524d9bec2
commit 515669284a
2 changed files with 30 additions and 8 deletions

View File

@ -56,9 +56,11 @@ enum RECT_CHAMFER_POSITIONS : int
* @param aRadius is the radius of the circle. * @param aRadius is the radius of the circle.
* @param aError is the internal units allowed for error approximation. * @param aError is the internal units allowed for error approximation.
* @param aErrorLoc determines if the approximation error be placed outside or inside the polygon. * @param aErrorLoc determines if the approximation error be placed outside or inside the polygon.
* @param aMinSegCount is the min count of segments to approximate.
* Default = 0 to do not force a min count.
*/ */
void TransformCircleToPolygon( SHAPE_LINE_CHAIN& aCornerBuffer, wxPoint aCenter, int aRadius, void TransformCircleToPolygon( SHAPE_LINE_CHAIN& aCornerBuffer, wxPoint aCenter, int aRadius,
int aError, ERROR_LOC aErrorLoc ); int aError, ERROR_LOC aErrorLoc, int aMinSegCount = 0 );
/** /**
* Convert a circle to a polygon, using multiple straight lines. * Convert a circle to a polygon, using multiple straight lines.
@ -68,9 +70,11 @@ void TransformCircleToPolygon( SHAPE_LINE_CHAIN& aCornerBuffer, wxPoint aCenter,
* @param aRadius is the radius of the circle. * @param aRadius is the radius of the circle.
* @param aError is the internal units allowed for error in approximation. * @param aError is the internal units allowed for error in approximation.
* @param aErrorLoc determines if the approximation error be placed outside or inside the polygon. * @param aErrorLoc determines if the approximation error be placed outside or inside the polygon.
* @param aMinSegCount is the min count of segments to approximate.
* Default = 0 to do not force a min count.
*/ */
void TransformCircleToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aCenter, int aRadius, void TransformCircleToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aCenter, int aRadius,
int aError, ERROR_LOC aErrorLoc ); int aError, ERROR_LOC aErrorLoc, int aMinSegCount = 0 );
/** /**
@ -87,9 +91,11 @@ void TransformCircleToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aCenter, i
* @param aWidth is the width of the segment. * @param aWidth is the width of the segment.
* @param aError is the internal units allowed for error in approximation. * @param aError is the internal units allowed for error in approximation.
* @param aErrorLoc determines if the approximation error be placed outside or inside the polygon. * @param aErrorLoc determines if the approximation error be placed outside or inside the polygon.
* @param aMinSegCount is the min count of segments to approximate.
* Default = 0 to do not force a min count.
*/ */
void TransformOvalToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aStart, wxPoint aEnd, void TransformOvalToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aStart, wxPoint aEnd,
int aWidth, int aError, ERROR_LOC aErrorLoc ); int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount = 0 );
/** /**

View File

@ -39,10 +39,11 @@
void TransformCircleToPolygon( SHAPE_LINE_CHAIN& aCornerBuffer, wxPoint aCenter, int aRadius, void TransformCircleToPolygon( SHAPE_LINE_CHAIN& aCornerBuffer, wxPoint aCenter, int aRadius,
int aError, ERROR_LOC aErrorLoc ) int aError, ERROR_LOC aErrorLoc, int aMinSegCount )
{ {
wxPoint corner_position; wxPoint corner_position;
int numSegs = GetArcToSegmentCount( aRadius, aError, 360.0 ); int numSegs = GetArcToSegmentCount( aRadius, aError, 360.0 );
numSegs = std::max( aMinSegCount, numSegs );
// The shape will be built with a even number of segs. Reason: the horizontal // The shape will be built with a even number of segs. Reason: the horizontal
// diameter begins and ends to points on the actual circle, or circle // diameter begins and ends to points on the actual circle, or circle
@ -77,10 +78,11 @@ void TransformCircleToPolygon( SHAPE_LINE_CHAIN& aCornerBuffer, wxPoint aCenter,
void TransformCircleToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aCenter, int aRadius, void TransformCircleToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aCenter, int aRadius,
int aError, ERROR_LOC aErrorLoc ) int aError, ERROR_LOC aErrorLoc, int aMinSegCount )
{ {
wxPoint corner_position; wxPoint corner_position;
int numSegs = GetArcToSegmentCount( aRadius, aError, 360.0 ); int numSegs = GetArcToSegmentCount( aRadius, aError, 360.0 );
numSegs = std::max( aMinSegCount, numSegs);
// The shape will be built with a even number of segs. Reason: the horizontal // The shape will be built with a even number of segs. Reason: the horizontal
// diameter begins and ends to points on the actual circle, or circle // diameter begins and ends to points on the actual circle, or circle
@ -121,7 +123,7 @@ void TransformCircleToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aCenter, i
void TransformOvalToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aStart, wxPoint aEnd, void TransformOvalToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aStart, wxPoint aEnd,
int aWidth, int aError, ERROR_LOC aErrorLoc ) int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount )
{ {
// To build the polygonal shape outside the actual shape, we use a bigger // To build the polygonal shape outside the actual shape, we use a bigger
// radius to build rounded ends. // radius to build rounded ends.
@ -130,11 +132,19 @@ void TransformOvalToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aStart, wxPo
// of the segment. // of the segment.
int radius = aWidth / 2; int radius = aWidth / 2;
int numSegs = GetArcToSegmentCount( radius, aError, 360.0 ); int numSegs = GetArcToSegmentCount( radius, aError, 360.0 );
numSegs = std::max( aMinSegCount, numSegs );
int delta = 3600 / numSegs; // rotate angle in 0.1 degree int delta = 3600 / numSegs; // rotate angle in 0.1 degree
int correction = GetCircleToPolyCorrection( aError );
if( aErrorLoc == ERROR_OUTSIDE ) if( aErrorLoc == ERROR_OUTSIDE )
{
// 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 );
int correction = GetCircleToPolyCorrection( actual_delta_radius );
radius += correction; radius += correction;
}
// end point is the coordinate relative to aStart // end point is the coordinate relative to aStart
wxPoint endp = aEnd - aStart; wxPoint endp = aEnd - aStart;
@ -248,7 +258,13 @@ void TransformRoundRectToPolygon( SHAPE_POLY_SET& aCornerBuffer, const wxSize& a
int radius = aCornerRadius; int radius = aCornerRadius;
if( aErrorLoc == ERROR_OUTSIDE ) 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 );
}
auto genArc = auto genArc =
[&]( const wxPoint& aCenter, int aStart, int aEnd ) [&]( const wxPoint& aCenter, int aStart, int aEnd )