Custom pads: fix incorrect shape of masks when the shape is a polygon with holes and the mask margin is < 0. This is mainly the solder paste layer that shows this issue. This is due to the fact SHAPE_POLY_SET::Inflate does not work fine with polygons with linked holes. SHAPE_POLY_SET::InflateWithLinkedHoles it added to fix this issue.
Fixes: lp:1828287 https://bugs.launchpad.net/kicad/+bug/1828287
This commit is contained in:
parent
18377e0c9f
commit
c489659a20
|
@ -32,11 +32,42 @@
|
|||
#include <common.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
|
||||
/**
|
||||
* Function TransformCircleToPolygon
|
||||
* convert a circle to a polygon, using multiple straight lines
|
||||
* @param aBuffer = a SHAPE_LINE_CHAIN to store the polygon corners
|
||||
* @param aCenter = the center of the circle
|
||||
* @param aRadius = the radius of the circle
|
||||
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
|
||||
* Note: the polygon is inside the circle, so if you want to have the polygon
|
||||
* outside the circle, you should give aRadius calculated with a correction factor
|
||||
*/
|
||||
void TransformCircleToPolygon( SHAPE_LINE_CHAIN& aBuffer,
|
||||
wxPoint aCenter, int aRadius,
|
||||
int aCircleToSegmentsCount )
|
||||
{
|
||||
wxPoint corner_position;
|
||||
double delta = 3600.0 / aCircleToSegmentsCount; // rot angle in 0.1 degree
|
||||
double halfstep = delta/2; // the starting value for rot angles
|
||||
|
||||
for( int ii = 0; ii < aCircleToSegmentsCount; ii++ )
|
||||
{
|
||||
corner_position.x = aRadius;
|
||||
corner_position.y = 0;
|
||||
double angle = (ii * delta) + halfstep;
|
||||
RotatePoint( &corner_position, angle );
|
||||
corner_position += aCenter;
|
||||
aBuffer.Append( corner_position.x, corner_position.y );
|
||||
}
|
||||
|
||||
aBuffer.SetClosed( true );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function TransformCircleToPolygon
|
||||
* convert a circle to a polygon, using multiple straight lines
|
||||
* @param aCornerBuffer = a buffer to store the polygon
|
||||
* @param aCornerBuffer = a SHAPE_POLY_SET to store the polygon
|
||||
* @param aCenter = the center of the circle
|
||||
* @param aRadius = the radius of the circle
|
||||
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
|
||||
|
@ -397,40 +428,14 @@ void TransformRingToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
|||
return;
|
||||
}
|
||||
|
||||
aCornerBuffer.NewOutline();
|
||||
SHAPE_POLY_SET buffer;
|
||||
|
||||
// Draw the inner circle of the ring
|
||||
int delta = 3600 / aCircleToSegmentsCount; // rotate angle in 0.1 degree
|
||||
TransformCircleToPolygon( buffer, aCentre, outer_radius, aCircleToSegmentsCount );
|
||||
|
||||
for( int ii = 0; ii < 3600; ii += delta )
|
||||
{
|
||||
curr_point.x = inner_radius;
|
||||
curr_point.y = 0;
|
||||
RotatePoint( &curr_point, ii );
|
||||
curr_point += aCentre;
|
||||
aCornerBuffer.Append( curr_point.x, curr_point.y );
|
||||
}
|
||||
// Build the hole:
|
||||
buffer.NewHole();
|
||||
TransformCircleToPolygon( buffer.Hole( 0, 0 ), aCentre, inner_radius, aCircleToSegmentsCount );
|
||||
|
||||
// Draw the last point of inner circle
|
||||
aCornerBuffer.Append( aCentre.x + inner_radius, aCentre.y );
|
||||
|
||||
// Draw the outer circle of the ring
|
||||
// the first point creates also a segment from the inner to the outer polygon
|
||||
for( int ii = 0; ii < 3600; ii += delta )
|
||||
{
|
||||
curr_point.x = outer_radius;
|
||||
curr_point.y = 0;
|
||||
RotatePoint( &curr_point, -ii );
|
||||
curr_point += aCentre;
|
||||
aCornerBuffer.Append( curr_point.x, curr_point.y );
|
||||
}
|
||||
|
||||
// Draw the last point of outer circle
|
||||
aCornerBuffer.Append( aCentre.x + outer_radius, aCentre.y );
|
||||
|
||||
// And connect the outer polygon to the inner polygon,.
|
||||
// because a segment from inner to the outer polygon was already created,
|
||||
// the final polygon is the inner and the outer outlines connected by
|
||||
// 2 overlapping segments
|
||||
aCornerBuffer.Append( aCentre.x + inner_radius, aCentre.y );
|
||||
buffer.Fracture( SHAPE_POLY_SET::PM_FAST );
|
||||
aCornerBuffer.Append( buffer );
|
||||
}
|
||||
|
|
|
@ -544,6 +544,14 @@ void SHAPE_POLY_SET::BooleanIntersection( const SHAPE_POLY_SET& a,
|
|||
}
|
||||
|
||||
|
||||
void SHAPE_POLY_SET::InflateWithLinkedHoles( int aFactor, int aCircleSegmentsCount, POLYGON_MODE aFastMode )
|
||||
{
|
||||
Simplify( aFastMode );
|
||||
Inflate( aFactor, aCircleSegmentsCount );
|
||||
Fracture( aFastMode );
|
||||
}
|
||||
|
||||
|
||||
void SHAPE_POLY_SET::Inflate( int aFactor, int aCircleSegmentsCount )
|
||||
{
|
||||
// A static table to avoid repetitive calculations of the coefficient
|
||||
|
|
|
@ -826,11 +826,23 @@ class SHAPE_POLY_SET : public SHAPE
|
|||
void BooleanIntersection( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b,
|
||||
POLYGON_MODE aFastMode );
|
||||
|
||||
///> Performs outline inflation/deflation, using round corners.
|
||||
/** Performs outline inflation/deflation, using round corners.
|
||||
* Polygons cna have holes, but not linked holes with main outlines,
|
||||
* if aFactor < 0.
|
||||
* When aFactor is < 0 a bad shape can result from these extra-segments used to
|
||||
* link holes to main outlines
|
||||
* Use InflateWithLinkedHoles for these polygons, especially if aFactor < 0
|
||||
*/
|
||||
void Inflate( int aFactor, int aCircleSegmentsCount );
|
||||
|
||||
///> Converts a set of polygons with holes to a singe outline with "slits"/"fractures" connecting the outer ring
|
||||
///> to the inner holes
|
||||
///> Performs outline inflation/deflation, using round corners.
|
||||
///> Polygons can have holes, and/or linked holes with main outlines.
|
||||
///> The resulting polygons are laso polygons with linked holes to main outlines
|
||||
///> For aFastMode meaning, see function booleanOp
|
||||
void InflateWithLinkedHoles( int aFactor, int aCircleSegmentsCount, POLYGON_MODE aFastMode );
|
||||
|
||||
///> Converts a set of polygons with holes to a singe outline with "slits"/"fractures"
|
||||
///> connecting the outer ring to the inner holes
|
||||
///> For aFastMode meaning, see function booleanOp
|
||||
void Fracture( POLYGON_MODE aFastMode );
|
||||
|
||||
|
|
|
@ -787,11 +787,12 @@ void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
|||
case PAD_SHAPE_CUSTOM:
|
||||
{
|
||||
int clearance = KiROUND( aClearanceValue * aCorrectionFactor );
|
||||
|
||||
SHAPE_POLY_SET outline; // Will contain the corners in board coordinates
|
||||
outline.Append( m_customShapeAsPolygon );
|
||||
CustomShapeAsPolygonToBoardPosition( &outline, GetPosition(), GetOrientation() );
|
||||
outline.Simplify( SHAPE_POLY_SET::PM_FAST );
|
||||
outline.Inflate( clearance, aCircleToSegmentsCount );
|
||||
outline.Fracture( SHAPE_POLY_SET::PM_FAST );
|
||||
aCornerBuffer.Append( outline );
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -546,24 +546,19 @@ void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
|
|||
const int segmentToCircleCount = ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF;
|
||||
|
||||
if( aDrawInfo.m_Mask_margin.x )
|
||||
{
|
||||
SHAPE_POLY_SET clearance_outline;
|
||||
clearance_outline.Append( outline );
|
||||
clearance_outline.Inflate( aDrawInfo.m_Mask_margin.x, segmentToCircleCount );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw the polygon: only one polygon is expected
|
||||
// However we provide a multi polygon shape drawing
|
||||
// ( for the future or to show a non expected shape )
|
||||
for( int jj = 0; jj < outline.OutlineCount(); ++jj )
|
||||
{
|
||||
poly = &outline.Outline( jj );
|
||||
outline.InflateWithLinkedHoles( aDrawInfo.m_Mask_margin.x,
|
||||
segmentToCircleCount, SHAPE_POLY_SET::PM_FAST );
|
||||
|
||||
GRClosedPoly( aClipBox, aDC, poly->PointCount(),
|
||||
(wxPoint*)&poly->Point( 0 ), aDrawInfo.m_ShowPadFilled, 0,
|
||||
aDrawInfo.m_Color, aDrawInfo.m_Color );
|
||||
}
|
||||
// Draw the polygon: only one polygon is expected
|
||||
// However we provide a multi polygon shape drawing
|
||||
// ( can happen with CUSTOM pads and negative margins )
|
||||
for( int jj = 0; jj < outline.OutlineCount(); ++jj )
|
||||
{
|
||||
poly = &outline.Outline( jj );
|
||||
|
||||
GRClosedPoly( aClipBox, aDC, poly->PointCount(),
|
||||
(wxPoint*)&poly->Point( 0 ), aDrawInfo.m_ShowPadFilled, 0,
|
||||
aDrawInfo.m_Color, aDrawInfo.m_Color );
|
||||
}
|
||||
|
||||
if( aDrawInfo.m_PadClearance )
|
||||
|
|
|
@ -840,7 +840,10 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
|
|||
SHAPE_POLY_SET outline;
|
||||
outline.Append( aPad->GetCustomShapeAsPolygon() );
|
||||
const int segmentToCircleCount = ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF;
|
||||
outline.Inflate( custom_margin, segmentToCircleCount );
|
||||
// outline polygon can have holes linked to the main outline.
|
||||
// So use InflateWithLinkedHoles(), not Inflate() that can create
|
||||
// bad shapes if custom_margin is < 0
|
||||
outline.InflateWithLinkedHoles( custom_margin, segmentToCircleCount, SHAPE_POLY_SET::PM_FAST );
|
||||
m_gal->DrawPolygon( outline );
|
||||
}
|
||||
else
|
||||
|
|
|
@ -461,7 +461,11 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
|
|||
D_PAD dummy( *pad );
|
||||
SHAPE_POLY_SET shape;
|
||||
pad->MergePrimitivesAsPolygon( &shape, 64 );
|
||||
shape.Inflate( margin.x, ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF );
|
||||
// shape polygon can have holes linked to the main outline.
|
||||
// So use InflateWithLinkedHoles(), not Inflate() that can create
|
||||
// bad shapes if margin.x is < 0
|
||||
shape.InflateWithLinkedHoles( margin.x, ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF,
|
||||
SHAPE_POLY_SET::PM_FAST );
|
||||
dummy.DeletePrimitivesList();
|
||||
dummy.AddPrimitive( shape, 0 );
|
||||
dummy.MergePrimitivesAsPolygon();
|
||||
|
|
Loading…
Reference in New Issue