diff --git a/libs/kimath/include/convert_basic_shapes_to_polygon.h b/libs/kimath/include/convert_basic_shapes_to_polygon.h index b14daf7b79..e73a2551be 100644 --- a/libs/kimath/include/convert_basic_shapes_to_polygon.h +++ b/libs/kimath/include/convert_basic_shapes_to_polygon.h @@ -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 diff --git a/libs/kimath/src/convert_basic_shapes_to_polygon.cpp b/libs/kimath/src/convert_basic_shapes_to_polygon.cpp index 472ead2fed..f01c5a77d1 100644 --- a/libs/kimath/src/convert_basic_shapes_to_polygon.cpp +++ b/libs/kimath/src/convert_basic_shapes_to_polygon.cpp @@ -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 ); } diff --git a/pcbnew/board_items_to_polygon_shape_transform.cpp b/pcbnew/board_items_to_polygon_shape_transform.cpp index a068eabd9c..6212c7467a 100644 --- a/pcbnew/board_items_to_polygon_shape_transform.cpp +++ b/pcbnew/board_items_to_polygon_shape_transform.cpp @@ -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( 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; diff --git a/pcbnew/drc/drc_test_provider_copper_clearance.cpp b/pcbnew/drc/drc_test_provider_copper_clearance.cpp index 72d62338e8..a051bf8d32 100644 --- a/pcbnew/drc/drc_test_provider_copper_clearance.cpp +++ b/pcbnew/drc/drc_test_provider_copper_clearance.cpp @@ -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 );