Allow squared inflation and inflate Eagle Zones
Sometimes we want to inflate a polygon without adding rounded edges.
This add the option using the jtMiter setting.
This is used in the Eagle parser to expand the Eagle zones for KiCad.
Eagle Zones are drawn on the polygon edge, so they extend out from the
outline. KiCad zones are drawn inside the polygon. We need to both
increase the zone size and decrease the minimum pen width to account for
this.
Fixes: lp:1817312
* https://bugs.launchpad.net/kicad/+bug/1817312
(cherry picked from commit 490c805319
)
This commit is contained in:
parent
94e5b36279
commit
6f34f95c52
|
@ -552,7 +552,7 @@ void SHAPE_POLY_SET::InflateWithLinkedHoles( int aFactor, int aCircleSegmentsCou
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SHAPE_POLY_SET::Inflate( int aFactor, int aCircleSegmentsCount )
|
void SHAPE_POLY_SET::Inflate( int aFactor, int aCircleSegmentsCount, bool aPreseveCorners )
|
||||||
{
|
{
|
||||||
// A static table to avoid repetitive calculations of the coefficient
|
// A static table to avoid repetitive calculations of the coefficient
|
||||||
// 1.0 - cos( M_PI/aCircleSegmentsCount)
|
// 1.0 - cos( M_PI/aCircleSegmentsCount)
|
||||||
|
@ -562,10 +562,14 @@ void SHAPE_POLY_SET::Inflate( int aFactor, int aCircleSegmentsCount )
|
||||||
|
|
||||||
ClipperOffset c;
|
ClipperOffset c;
|
||||||
|
|
||||||
|
// N.B. using jtSquare here does not create square corners. They end up mitered by
|
||||||
|
// aFactor. Setting jtMiter and forcing the limit to be aFactor creates sharp corners.
|
||||||
|
JoinType type = aPreseveCorners ? jtMiter : jtRound;
|
||||||
|
|
||||||
for( const POLYGON& poly : m_polys )
|
for( const POLYGON& poly : m_polys )
|
||||||
{
|
{
|
||||||
for( size_t i = 0; i < poly.size(); i++ )
|
for( size_t i = 0; i < poly.size(); i++ )
|
||||||
c.AddPath( poly[i].convertToClipper( i == 0 ), jtRound, etClosedPolygon );
|
c.AddPath( poly[i].convertToClipper( i == 0 ), type, etClosedPolygon );
|
||||||
}
|
}
|
||||||
|
|
||||||
PolyTree solution;
|
PolyTree solution;
|
||||||
|
@ -591,6 +595,7 @@ void SHAPE_POLY_SET::Inflate( int aFactor, int aCircleSegmentsCount )
|
||||||
coeff = arc_tolerance_factor[aCircleSegmentsCount];
|
coeff = arc_tolerance_factor[aCircleSegmentsCount];
|
||||||
|
|
||||||
c.ArcTolerance = std::abs( aFactor ) * coeff;
|
c.ArcTolerance = std::abs( aFactor ) * coeff;
|
||||||
|
c.MiterLimit = std::abs( aFactor );
|
||||||
|
|
||||||
c.Execute( solution, aFactor );
|
c.Execute( solution, aFactor );
|
||||||
|
|
||||||
|
|
|
@ -826,14 +826,24 @@ 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.
|
/**
|
||||||
* Polygons cna have holes, but not linked holes with main outlines,
|
* Performs outline inflation/deflation, using (optionally) round corners.
|
||||||
|
* Polygons can have holes, but not linked holes with main outlines,
|
||||||
* if aFactor < 0.
|
* if aFactor < 0.
|
||||||
* When aFactor is < 0 a bad shape can result from these extra-segments used to
|
* When aFactor is < 0 a bad shape can result from these extra-segments used to
|
||||||
* link holes to main outlines
|
* link holes to main outlines
|
||||||
* Use InflateWithLinkedHoles for these polygons, especially if aFactor < 0
|
* Use InflateWithLinkedHoles for these polygons, especially if aFactor < 0
|
||||||
|
*
|
||||||
|
* @param aFactor - number of units to offset edges
|
||||||
|
* @param aCircleSegmentsCount - number of segments per 360° to use in curve approx
|
||||||
|
* @param aPreseveCorners - If true, use square joints to keep angles preserved
|
||||||
*/
|
*/
|
||||||
void Inflate( int aFactor, int aCircleSegmentsCount );
|
void Inflate( int aFactor, int aCircleSegmentsCount, bool aPreseveCorners = false );
|
||||||
|
|
||||||
|
void Inflate( int aFactor, bool aPreseveCorners )
|
||||||
|
{
|
||||||
|
Inflate( aFactor, 32, aPreseveCorners );
|
||||||
|
}
|
||||||
|
|
||||||
///> Performs outline inflation/deflation, using round corners.
|
///> Performs outline inflation/deflation, using round corners.
|
||||||
///> Polygons can have holes, and/or linked holes with main outlines.
|
///> Polygons can have holes, and/or linked holes with main outlines.
|
||||||
|
|
|
@ -1135,12 +1135,15 @@ ZONE_CONTAINER* EAGLE_PLUGIN::loadPolygon( wxXmlNode* aPolyNode )
|
||||||
|
|
||||||
vertices.push_back( vertices[0] );
|
vertices.push_back( vertices[0] );
|
||||||
|
|
||||||
|
SHAPE_POLY_SET polygon;
|
||||||
|
polygon.NewOutline();
|
||||||
|
|
||||||
for( size_t i = 0; i < vertices.size() - 1; i++ )
|
for( size_t i = 0; i < vertices.size() - 1; i++ )
|
||||||
{
|
{
|
||||||
EVERTEX v1 = vertices[i];
|
EVERTEX v1 = vertices[i];
|
||||||
|
|
||||||
// Append the corner
|
// Append the corner
|
||||||
zone->AppendCorner( wxPoint( kicad_x( v1.x ), kicad_y( v1.y ) ), -1 );
|
polygon.Append( kicad_x( v1.x ), kicad_y( v1.y ) );
|
||||||
|
|
||||||
if( v1.curve )
|
if( v1.curve )
|
||||||
{
|
{
|
||||||
|
@ -1164,14 +1167,22 @@ ZONE_CONTAINER* EAGLE_PLUGIN::loadPolygon( wxXmlNode* aPolyNode )
|
||||||
fabs( a - end_angle ) > fabs( delta_angle );
|
fabs( a - end_angle ) > fabs( delta_angle );
|
||||||
a -= delta_angle )
|
a -= delta_angle )
|
||||||
{
|
{
|
||||||
zone->AppendCorner(
|
polygon.Append( KiROUND( radius * cos( a ) ) + center.x,
|
||||||
wxPoint( KiROUND( radius * cos( a ) ),
|
KiROUND( radius * sin( a ) ) + center.y );
|
||||||
KiROUND( radius * sin( a ) ) ) + center,
|
|
||||||
-1 );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Eagle traces the zone such that half of the pen width is outside the polygon.
|
||||||
|
// We trace the zone such that the copper is completely inside.
|
||||||
|
if( p.width.ToPcbUnits() > 0 )
|
||||||
|
{
|
||||||
|
polygon.Inflate( p.width.ToPcbUnits() / 2, true );
|
||||||
|
polygon.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
|
||||||
|
}
|
||||||
|
|
||||||
|
zone->AddPolygon( polygon.COutline( 0 ) );
|
||||||
|
|
||||||
// If the pour is a cutout it needs to be set to a keepout
|
// If the pour is a cutout it needs to be set to a keepout
|
||||||
if( p.pour == EPOLYGON::CUTOUT )
|
if( p.pour == EPOLYGON::CUTOUT )
|
||||||
{
|
{
|
||||||
|
@ -1187,13 +1198,13 @@ ZONE_CONTAINER* EAGLE_PLUGIN::loadPolygon( wxXmlNode* aPolyNode )
|
||||||
zone->SetHatch( ZONE_CONTAINER::DIAGONAL_EDGE, zone->GetDefaultHatchPitch(), true );
|
zone->SetHatch( ZONE_CONTAINER::DIAGONAL_EDGE, zone->GetDefaultHatchPitch(), true );
|
||||||
|
|
||||||
// clearances, etc.
|
// clearances, etc.
|
||||||
zone->SetArcSegmentCount( ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF ); // @todo: should be a constructor default?
|
zone->SetArcSegmentCount( ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF );
|
||||||
zone->SetMinThickness( std::max<int>(
|
|
||||||
ZONE_THICKNESS_MIN_VALUE_MIL*IU_PER_MILS, p.width.ToPcbUnits() ) );
|
// We divide the thickness by half because we are tracing _inside_ the zone outline
|
||||||
|
// This means the radius of curvature will be twice the size for an equivalent EAGLE zone
|
||||||
|
zone->SetMinThickness(
|
||||||
|
std::max<int>( ZONE_THICKNESS_MIN_VALUE_MIL * IU_PER_MILS, p.width.ToPcbUnits() / 2 ) );
|
||||||
|
|
||||||
// FIXME: KiCad zones have very rounded corners compared to eagle.
|
|
||||||
// This means that isolation amounts that work well in eagle
|
|
||||||
// tend to make copper intrude in soldermask free areas around pads.
|
|
||||||
if( p.isolate )
|
if( p.isolate )
|
||||||
zone->SetZoneClearance( p.isolate->ToPcbUnits() );
|
zone->SetZoneClearance( p.isolate->ToPcbUnits() );
|
||||||
else
|
else
|
||||||
|
@ -1709,8 +1720,6 @@ void EAGLE_PLUGIN::packagePolygon( MODULE* aModule, wxXmlNode* aTree ) const
|
||||||
dwg->SetTimeStamp( EagleTimeStamp( aTree ) );
|
dwg->SetTimeStamp( EagleTimeStamp( aTree ) );
|
||||||
|
|
||||||
std::vector<wxPoint> pts;
|
std::vector<wxPoint> pts;
|
||||||
// TODO: I think there's no way to know a priori the number of children in wxXmlNode :()
|
|
||||||
// pts.reserve( aTree.size() );
|
|
||||||
|
|
||||||
// Get the first vertex and iterate
|
// Get the first vertex and iterate
|
||||||
wxXmlNode* vertex = aTree->GetChildren();
|
wxXmlNode* vertex = aTree->GetChildren();
|
||||||
|
|
Loading…
Reference in New Issue