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 <common.h>
|
||||||
#include <convert_basic_shapes_to_polygon.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
|
* Function TransformCircleToPolygon
|
||||||
* convert a circle to a polygon, using multiple straight lines
|
* 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 aCenter = the center of the circle
|
||||||
* @param aRadius = the radius of the circle
|
* @param aRadius = the radius of the circle
|
||||||
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
|
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
|
||||||
|
@ -397,40 +428,14 @@ void TransformRingToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
aCornerBuffer.NewOutline();
|
SHAPE_POLY_SET buffer;
|
||||||
|
|
||||||
// Draw the inner circle of the ring
|
TransformCircleToPolygon( buffer, aCentre, outer_radius, aCircleToSegmentsCount );
|
||||||
int delta = 3600 / aCircleToSegmentsCount; // rotate angle in 0.1 degree
|
|
||||||
|
|
||||||
for( int ii = 0; ii < 3600; ii += delta )
|
// Build the hole:
|
||||||
{
|
buffer.NewHole();
|
||||||
curr_point.x = inner_radius;
|
TransformCircleToPolygon( buffer.Hole( 0, 0 ), aCentre, inner_radius, aCircleToSegmentsCount );
|
||||||
curr_point.y = 0;
|
|
||||||
RotatePoint( &curr_point, ii );
|
|
||||||
curr_point += aCentre;
|
|
||||||
aCornerBuffer.Append( curr_point.x, curr_point.y );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw the last point of inner circle
|
buffer.Fracture( SHAPE_POLY_SET::PM_FAST );
|
||||||
aCornerBuffer.Append( aCentre.x + inner_radius, aCentre.y );
|
aCornerBuffer.Append( buffer );
|
||||||
|
|
||||||
// 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 );
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 )
|
void SHAPE_POLY_SET::Inflate( int aFactor, int aCircleSegmentsCount )
|
||||||
{
|
{
|
||||||
// A static table to avoid repetitive calculations of the coefficient
|
// 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,
|
void BooleanIntersection( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b,
|
||||||
POLYGON_MODE aFastMode );
|
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 );
|
void Inflate( int aFactor, int aCircleSegmentsCount );
|
||||||
|
|
||||||
///> Converts a set of polygons with holes to a singe outline with "slits"/"fractures" connecting the outer ring
|
///> Performs outline inflation/deflation, using round corners.
|
||||||
///> to the inner holes
|
///> 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
|
///> For aFastMode meaning, see function booleanOp
|
||||||
void Fracture( POLYGON_MODE aFastMode );
|
void Fracture( POLYGON_MODE aFastMode );
|
||||||
|
|
||||||
|
|
|
@ -787,11 +787,12 @@ void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
||||||
case PAD_SHAPE_CUSTOM:
|
case PAD_SHAPE_CUSTOM:
|
||||||
{
|
{
|
||||||
int clearance = KiROUND( aClearanceValue * aCorrectionFactor );
|
int clearance = KiROUND( aClearanceValue * aCorrectionFactor );
|
||||||
|
|
||||||
SHAPE_POLY_SET outline; // Will contain the corners in board coordinates
|
SHAPE_POLY_SET outline; // Will contain the corners in board coordinates
|
||||||
outline.Append( m_customShapeAsPolygon );
|
outline.Append( m_customShapeAsPolygon );
|
||||||
CustomShapeAsPolygonToBoardPosition( &outline, GetPosition(), GetOrientation() );
|
CustomShapeAsPolygonToBoardPosition( &outline, GetPosition(), GetOrientation() );
|
||||||
|
outline.Simplify( SHAPE_POLY_SET::PM_FAST );
|
||||||
outline.Inflate( clearance, aCircleToSegmentsCount );
|
outline.Inflate( clearance, aCircleToSegmentsCount );
|
||||||
|
outline.Fracture( SHAPE_POLY_SET::PM_FAST );
|
||||||
aCornerBuffer.Append( outline );
|
aCornerBuffer.Append( outline );
|
||||||
}
|
}
|
||||||
break;
|
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;
|
const int segmentToCircleCount = ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF;
|
||||||
|
|
||||||
if( aDrawInfo.m_Mask_margin.x )
|
if( aDrawInfo.m_Mask_margin.x )
|
||||||
{
|
outline.InflateWithLinkedHoles( aDrawInfo.m_Mask_margin.x,
|
||||||
SHAPE_POLY_SET clearance_outline;
|
segmentToCircleCount, SHAPE_POLY_SET::PM_FAST );
|
||||||
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 );
|
|
||||||
|
|
||||||
GRClosedPoly( aClipBox, aDC, poly->PointCount(),
|
// Draw the polygon: only one polygon is expected
|
||||||
(wxPoint*)&poly->Point( 0 ), aDrawInfo.m_ShowPadFilled, 0,
|
// However we provide a multi polygon shape drawing
|
||||||
aDrawInfo.m_Color, aDrawInfo.m_Color );
|
// ( 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 )
|
if( aDrawInfo.m_PadClearance )
|
||||||
|
|
|
@ -840,7 +840,10 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
|
||||||
SHAPE_POLY_SET outline;
|
SHAPE_POLY_SET outline;
|
||||||
outline.Append( aPad->GetCustomShapeAsPolygon() );
|
outline.Append( aPad->GetCustomShapeAsPolygon() );
|
||||||
const int segmentToCircleCount = ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF;
|
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 );
|
m_gal->DrawPolygon( outline );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -461,7 +461,11 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
|
||||||
D_PAD dummy( *pad );
|
D_PAD dummy( *pad );
|
||||||
SHAPE_POLY_SET shape;
|
SHAPE_POLY_SET shape;
|
||||||
pad->MergePrimitivesAsPolygon( &shape, 64 );
|
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.DeletePrimitivesList();
|
||||||
dummy.AddPrimitive( shape, 0 );
|
dummy.AddPrimitive( shape, 0 );
|
||||||
dummy.MergePrimitivesAsPolygon();
|
dummy.MergePrimitivesAsPolygon();
|
||||||
|
|
Loading…
Reference in New Issue