When polygonizing arcs don't use synthesized center and angle.

Start, mid and end are the "real" properties and come with less
error.

Also collapses two arc polygonization routines into one.

Also fixes DRC checks to be cognizant of arc approximation error.

Fixes https://gitlab.com/kicad/code/kicad/issues/6039
This commit is contained in:
Jeff Young 2020-10-23 23:27:02 +01:00
parent b683871d93
commit 59f3fefd17
4 changed files with 28 additions and 42 deletions

View File

@ -118,8 +118,8 @@ void TransformRoundChamferedRectToPolygon( SHAPE_POLY_SET& aCornerBuffer,
* @param aError = the IU allowed for error in approximation
* @param aErrorLoc = should the approximation error be placed outside or inside the polygon?
*/
void TransformArcToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aCentre, wxPoint aStart,
double aArcAngle, int aWidth, int aError, ERROR_LOC aErrorLoc );
void TransformArcToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aStart, wxPoint aMid,
wxPoint aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc );
/**
* Function TransformRingToPolygon

View File

@ -322,39 +322,26 @@ void TransformRoundChamferedRectToPolygon( SHAPE_POLY_SET& aCornerBuffer, const
}
void TransformArcToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aCentre, wxPoint aStart,
double aArcAngle, int aWidth, int aError, ERROR_LOC aErrorLoc )
void TransformArcToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aStart, wxPoint aMid,
wxPoint aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc )
{
wxPoint arc_start, arc_end;
int dist = EuclideanNorm( aCentre - aStart );
int numSegs = GetArcToSegmentCount( dist, aError, 360.0 );
int delta = 3600 / numSegs; // rotate angle in 0.1 degree
SHAPE_ARC arc( aStart, aMid, aEnd, aWidth );
SHAPE_LINE_CHAIN arcSpine = arc.ConvertToPolyline( aError );
arc_end = arc_start = aStart;
if( aErrorLoc == ERROR_OUTSIDE )
aWidth += 2 * aError;
else
aWidth -= 2 * aError;
if( aArcAngle != 3600 )
RotatePoint( &arc_end, aCentre, -aArcAngle );
if( aArcAngle < 0 )
for( int ii = 0; ii < arcSpine.GetSegmentCount(); ++ii )
{
std::swap( arc_start, arc_end );
aArcAngle = -aArcAngle;
SEG seg = arcSpine.GetSegment( ii );
// Note that the error here is only for the rounded ends; we still need to shrink or
// expand the width above for the segments themselves.
TransformOvalToPolygon( aCornerBuffer, (wxPoint) seg.A, (wxPoint) seg.B, aWidth, aError,
aErrorLoc );
}
// Compute the ends of segments and creates poly
wxPoint curr_end = arc_start;
wxPoint curr_start = arc_start;
for( int ii = delta; ii < aArcAngle; ii += delta )
{
curr_end = arc_start;
RotatePoint( &curr_end, aCentre, -ii );
TransformOvalToPolygon( aCornerBuffer, curr_start, curr_end, aWidth, aError, aErrorLoc );
curr_start = curr_end;
}
if( curr_end != arc_end )
TransformOvalToPolygon( aCornerBuffer, curr_end, arc_end, aWidth, aError, aErrorLoc );
}

View File

@ -401,13 +401,6 @@ void PCB_SHAPE::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuf
width += 2 * aClearanceValue;
// Creating a reliable clearance shape for circles and arcs is not so easy, due to
// the error created by segment approximation.
// for a circle this is not so hard: create a polygon from a circle slightly bigger:
// thickness = width + s_error_max, and radius = initial radius + s_error_max/2
// giving a shape with a suitable internal radius and external radius
// For an arc this is more tricky: TODO
switch( m_Shape )
{
case S_CIRCLE:
@ -447,7 +440,7 @@ void PCB_SHAPE::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuf
break;
case S_ARC:
TransformArcToPolygon( aCornerBuffer, GetCenter(), GetArcStart(), m_Angle, width,
TransformArcToPolygon( aCornerBuffer, GetArcStart(), GetArcMid(), GetArcEnd(), width,
aError, aErrorLoc );
break;
@ -550,11 +543,9 @@ void TRACK::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
{
const ARC* arc = static_cast<const ARC*>( this );
int width = m_Width + ( 2 * aClearanceValue );
VECTOR2D center( arc->GetCenter() );
double angle = arc->GetAngle();
TransformArcToPolygon( aCornerBuffer, (wxPoint) center, GetStart(), angle, width,
aError, aErrorLoc );
TransformArcToPolygon( aCornerBuffer, (wxPoint) arc->GetStart(), (wxPoint) arc->GetMid(),
(wxPoint) arc->GetEnd(), width, aError, aErrorLoc );
}
break;

View File

@ -534,6 +534,14 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_I
if( !refVia->FlashLayer( aLayer ) )
halfWidth = refVia->GetDrill() / 2 + bds.GetHolePlatingThickness();
}
else if ( aRefSeg->Type() == PCB_ARC_T )
{
// We're going to do a collision with the arc "spine" using an increased
// clearance to proxy for both the clearance and the arc track width. We
// therefore need to subtract the polygonization error from the track width
// so that it is all "inside" the track.
halfWidth -= bds.m_MaxError / 2;
}
auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_CLEARANCE,
aRefSeg, zone, aLayer );