KiCad PCB EDA Suite
ZONE_FILLER Class Reference

#include <zone_filler.h>

Public Member Functions

 ZONE_FILLER (BOARD *aBoard, COMMIT *aCommit)
 
 ~ZONE_FILLER ()
 
void SetProgressReporter (PROGRESS_REPORTER *aReporter)
 
bool Fill (std::vector< ZONE * > &aZones, bool aCheck=false, wxWindow *aParent=nullptr)
 Fills the given list of zones. More...
 
bool IsDebug () const
 

Private Member Functions

void addKnockout (PAD *aPad, PCB_LAYER_ID aLayer, int aGap, SHAPE_POLY_SET &aHoles)
 Add a knockout for a pad. More...
 
void addKnockout (BOARD_ITEM *aItem, PCB_LAYER_ID aLayer, int aGap, bool aIgnoreLineWidth, SHAPE_POLY_SET &aHoles)
 Add a knockout for a graphic item. More...
 
void addHoleKnockout (PAD *aPad, int aGap, SHAPE_POLY_SET &aHoles)
 Add a knockout for a pad's hole. More...
 
void knockoutThermalReliefs (const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aFill)
 Removes thermal reliefs from the shape for any pads connected to the zone. More...
 
void buildCopperItemClearances (const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aHoles)
 Removes clearance from the shape for copper items which share the zone's layer but are not connected to it. More...
 
void subtractHigherPriorityZones (const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aRawFill)
 Removes the outlines of higher-proirity zones with the same net. More...
 
bool computeRawFilledArea (const ZONE *aZone, PCB_LAYER_ID aLayer, PCB_LAYER_ID aDebugLayer, const SHAPE_POLY_SET &aSmoothedOutline, const SHAPE_POLY_SET &aMaxExtents, SHAPE_POLY_SET &aRawPolys)
 Function computeRawFilledArea Add non copper areas polygons (pads and tracks with clearance) to a filled copper area used in BuildFilledSolidAreasPolygons when calculating filled areas in a zone Non copper areas are pads and track and their clearance area The filled copper area must be computed before BuildFilledSolidAreasPolygons() call this function just after creating the filled copper area polygon (without clearance areas. More...
 
void buildThermalSpokes (const ZONE *aZone, PCB_LAYER_ID aLayer, std::deque< SHAPE_LINE_CHAIN > &aSpokes)
 Function buildThermalSpokes Constructs a list of all thermal spokes for the given zone. More...
 
bool fillSingleZone (ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aRawPolys, SHAPE_POLY_SET &aFinalPolys)
 Build the filled solid areas polygons from zone outlines (stored in m_Poly) The solid areas can be more than one on copper layers, and do not have holes ( holes are linked by overlapping segments to the main outline) in order to have drawable (and plottable) filled polygons. More...
 
bool addHatchFillTypeOnZone (const ZONE *aZone, PCB_LAYER_ID aLayer, PCB_LAYER_ID aDebugLayer, SHAPE_POLY_SET &aRawPolys)
 for zones having the ZONE_FILL_MODE::ZONE_FILL_MODE::HATCH_PATTERN, create a grid pattern in filled areas of aZone, giving to the filled polygons a fill style like a grid More...
 

Private Attributes

BOARDm_board
 
SHAPE_POLY_SET m_boardOutline
 
bool m_brdOutlinesValid
 
COMMITm_commit
 
PROGRESS_REPORTERm_progressReporter
 
int m_maxError
 
int m_worstClearance
 
bool m_debugZoneFiller
 

Detailed Description

Definition at line 39 of file zone_filler.h.

Constructor & Destructor Documentation

◆ ZONE_FILLER()

ZONE_FILLER::ZONE_FILLER ( BOARD aBoard,
COMMIT aCommit 
)

Definition at line 53 of file zone_filler.cpp.

53  :
54  m_board( aBoard ),
55  m_brdOutlinesValid( false ),
56  m_commit( aCommit ),
57  m_progressReporter( nullptr ),
58  m_maxError( ARC_HIGH_DEF ),
59  m_worstClearance( 0 )
60 {
61  // To enable add "DebugZoneFiller=1" to kicad_advanced settings file.
63 }
PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:127
BOARD * m_board
Definition: zone_filler.h:123
COMMIT * m_commit
Definition: zone_filler.h:126
bool m_debugZoneFiller
Definition: zone_filler.h:132
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
bool m_brdOutlinesValid
Definition: zone_filler.h:125
bool m_DebugZoneFiller
A mode that dumps the various stages of a F_Cu fill into In1_Cu through In9_Cu.
int m_worstClearance
Definition: zone_filler.h:130

References ADVANCED_CFG::GetCfg(), m_debugZoneFiller, and ADVANCED_CFG::m_DebugZoneFiller.

◆ ~ZONE_FILLER()

ZONE_FILLER::~ZONE_FILLER ( )

Definition at line 66 of file zone_filler.cpp.

67 {
68 }

Member Function Documentation

◆ addHatchFillTypeOnZone()

bool ZONE_FILLER::addHatchFillTypeOnZone ( const ZONE aZone,
PCB_LAYER_ID  aLayer,
PCB_LAYER_ID  aDebugLayer,
SHAPE_POLY_SET aRawPolys 
)
private

for zones having the ZONE_FILL_MODE::ZONE_FILL_MODE::HATCH_PATTERN, create a grid pattern in filled areas of aZone, giving to the filled polygons a fill style like a grid

Parameters
aZoneis the zone to modify
aRawPolysA reference to a SHAPE_POLY_SET buffer containing the initial filled areas, and after adding the grid pattern, the modified filled areas with holes

Definition at line 1402 of file zone_filler.cpp.

1404 {
1405  // Build grid:
1406 
1407  // obviously line thickness must be > zone min thickness.
1408  // It can happens if a board file was edited by hand by a python script
1409  // Use 1 micron margin to be *sure* there is no issue in Gerber files
1410  // (Gbr file unit = 1 or 10 nm) due to some truncation in coordinates or calculations
1411  // This margin also avoid problems due to rounding coordinates in next calculations
1412  // that can create incorrect polygons
1413  int thickness = std::max( aZone->GetHatchThickness(),
1414  aZone->GetMinThickness() + Millimeter2iu( 0.001 ) );
1415 
1416  int linethickness = thickness - aZone->GetMinThickness();
1417  int gridsize = thickness + aZone->GetHatchGap();
1418  double orientation = aZone->GetHatchOrientation();
1419 
1420  SHAPE_POLY_SET filledPolys = aRawPolys;
1421  // Use a area that contains the rotated bbox by orientation,
1422  // and after rotate the result by -orientation.
1423  if( orientation != 0.0 )
1424  filledPolys.Rotate( M_PI / 180.0 * orientation, VECTOR2I( 0, 0 ) );
1425 
1426  BOX2I bbox = filledPolys.BBox( 0 );
1427 
1428  // Build hole shape
1429  // the hole size is aZone->GetHatchGap(), but because the outline thickness
1430  // is aZone->GetMinThickness(), the hole shape size must be larger
1431  SHAPE_LINE_CHAIN hole_base;
1432  int hole_size = aZone->GetHatchGap() + aZone->GetMinThickness();
1433  VECTOR2I corner( 0, 0 );;
1434  hole_base.Append( corner );
1435  corner.x += hole_size;
1436  hole_base.Append( corner );
1437  corner.y += hole_size;
1438  hole_base.Append( corner );
1439  corner.x = 0;
1440  hole_base.Append( corner );
1441  hole_base.SetClosed( true );
1442 
1443  // Calculate minimal area of a grid hole.
1444  // All holes smaller than a threshold will be removed
1445  double minimal_hole_area = hole_base.Area() * aZone->GetHatchHoleMinArea();
1446 
1447  // Now convert this hole to a smoothed shape:
1448  if( aZone->GetHatchSmoothingLevel() > 0 )
1449  {
1450  // the actual size of chamfer, or rounded corner radius is the half size
1451  // of the HatchFillTypeGap scaled by aZone->GetHatchSmoothingValue()
1452  // aZone->GetHatchSmoothingValue() = 1.0 is the max value for the chamfer or the
1453  // radius of corner (radius = half size of the hole)
1454  int smooth_value = KiROUND( aZone->GetHatchGap()
1455  * aZone->GetHatchSmoothingValue() / 2 );
1456 
1457  // Minimal optimization:
1458  // make smoothing only for reasonable smooth values, to avoid a lot of useless segments
1459  // and if the smooth value is small, use chamfer even if fillet is requested
1460  #define SMOOTH_MIN_VAL_MM 0.02
1461  #define SMOOTH_SMALL_VAL_MM 0.04
1462 
1463  if( smooth_value > Millimeter2iu( SMOOTH_MIN_VAL_MM ) )
1464  {
1465  SHAPE_POLY_SET smooth_hole;
1466  smooth_hole.AddOutline( hole_base );
1467  int smooth_level = aZone->GetHatchSmoothingLevel();
1468 
1469  if( smooth_value < Millimeter2iu( SMOOTH_SMALL_VAL_MM ) && smooth_level > 1 )
1470  smooth_level = 1;
1471 
1472  // Use a larger smooth_value to compensate the outline tickness
1473  // (chamfer is not visible is smooth value < outline thickess)
1474  smooth_value += aZone->GetMinThickness() / 2;
1475 
1476  // smooth_value cannot be bigger than the half size oh the hole:
1477  smooth_value = std::min( smooth_value, aZone->GetHatchGap() / 2 );
1478 
1479  // the error to approximate a circle by segments when smoothing corners by a arc
1480  int error_max = std::max( Millimeter2iu( 0.01 ), smooth_value / 20 );
1481 
1482  switch( smooth_level )
1483  {
1484  case 1:
1485  // Chamfer() uses the distance from a corner to create a end point
1486  // for the chamfer.
1487  hole_base = smooth_hole.Chamfer( smooth_value ).Outline( 0 );
1488  break;
1489 
1490  default:
1491  if( aZone->GetHatchSmoothingLevel() > 2 )
1492  error_max /= 2; // Force better smoothing
1493 
1494  hole_base = smooth_hole.Fillet( smooth_value, error_max ).Outline( 0 );
1495  break;
1496 
1497  case 0:
1498  break;
1499  };
1500  }
1501  }
1502 
1503  // Build holes
1504  SHAPE_POLY_SET holes;
1505 
1506  for( int xx = 0; ; xx++ )
1507  {
1508  int xpos = xx * gridsize;
1509 
1510  if( xpos > bbox.GetWidth() )
1511  break;
1512 
1513  for( int yy = 0; ; yy++ )
1514  {
1515  int ypos = yy * gridsize;
1516 
1517  if( ypos > bbox.GetHeight() )
1518  break;
1519 
1520  // Generate hole
1521  SHAPE_LINE_CHAIN hole( hole_base );
1522  hole.Move( VECTOR2I( xpos, ypos ) );
1523  holes.AddOutline( hole );
1524  }
1525  }
1526 
1527  holes.Move( bbox.GetPosition() );
1528 
1529  if( orientation != 0.0 )
1530  holes.Rotate( -M_PI/180.0 * orientation, VECTOR2I( 0,0 ) );
1531 
1532  DUMP_POLYS_TO_COPPER_LAYER( holes, In10_Cu, "hatch-holes" );
1533 
1534  int outline_margin = aZone->GetMinThickness() * 1.1;
1535 
1536  // Using GetHatchThickness() can look more consistent than GetMinThickness().
1537  if( aZone->GetHatchBorderAlgorithm() && aZone->GetHatchThickness() > outline_margin )
1538  outline_margin = aZone->GetHatchThickness();
1539 
1540  // The fill has already been deflated to ensure GetMinThickness() so we just have to
1541  // account for anything beyond that.
1542  SHAPE_POLY_SET deflatedFilledPolys = aRawPolys;
1543  deflatedFilledPolys.Deflate( outline_margin - aZone->GetMinThickness(), 16 );
1544  holes.BooleanIntersection( deflatedFilledPolys, SHAPE_POLY_SET::PM_FAST );
1545  DUMP_POLYS_TO_COPPER_LAYER( holes, In11_Cu, "fill-clipped-hatch-holes" );
1546 
1547  SHAPE_POLY_SET deflatedOutline = *aZone->Outline();
1548  deflatedOutline.Deflate( outline_margin, 16 );
1549  holes.BooleanIntersection( deflatedOutline, SHAPE_POLY_SET::PM_FAST );
1550  DUMP_POLYS_TO_COPPER_LAYER( holes, In12_Cu, "outline-clipped-hatch-holes" );
1551 
1552  if( aZone->GetNetCode() != 0 )
1553  {
1554  // Vias and pads connected to the zone must not be allowed to become isolated inside
1555  // one of the holes. Effectively this means their copper outline needs to be expanded
1556  // to be at least as wide as the gap so that it is guaranteed to touch at least one
1557  // edge.
1558  EDA_RECT zone_boundingbox = aZone->GetCachedBoundingBox();
1559  SHAPE_POLY_SET aprons;
1560  int min_apron_radius = ( aZone->GetHatchGap() * 10 ) / 19;
1561 
1562  for( PCB_TRACK* track : m_board->Tracks() )
1563  {
1564  if( track->Type() == PCB_VIA_T )
1565  {
1566  PCB_VIA* via = static_cast<PCB_VIA*>( track );
1567 
1568  if( via->GetNetCode() == aZone->GetNetCode()
1569  && via->IsOnLayer( aLayer )
1570  && via->GetBoundingBox().Intersects( zone_boundingbox ) )
1571  {
1572  int r = std::max( min_apron_radius,
1573  via->GetDrillValue() / 2 + outline_margin );
1574 
1575  TransformCircleToPolygon( aprons, via->GetPosition(), r, ARC_HIGH_DEF,
1576  ERROR_OUTSIDE );
1577  }
1578  }
1579  }
1580 
1581  for( FOOTPRINT* footprint : m_board->Footprints() )
1582  {
1583  for( PAD* pad : footprint->Pads() )
1584  {
1585  if( pad->GetNetCode() == aZone->GetNetCode()
1586  && pad->IsOnLayer( aLayer )
1587  && pad->GetBoundingBox().Intersects( zone_boundingbox ) )
1588  {
1589  // What we want is to bulk up the pad shape so that the narrowest bit of
1590  // copper between the hole and the apron edge is at least outline_margin
1591  // wide (and that the apron itself meets min_apron_radius. But that would
1592  // take a lot of code and math, and the following approximation is close
1593  // enough.
1594  int pad_width = std::min( pad->GetSize().x, pad->GetSize().y );
1595  int slot_width = std::min( pad->GetDrillSize().x, pad->GetDrillSize().y );
1596  int min_annular_ring_width = ( pad_width - slot_width ) / 2;
1597  int clearance = std::max( min_apron_radius - pad_width / 2,
1598  outline_margin - min_annular_ring_width );
1599 
1600  clearance = std::max( 0, clearance - linethickness / 2 );
1601  pad->TransformShapeWithClearanceToPolygon( aprons, aLayer, clearance,
1602  ARC_HIGH_DEF, ERROR_OUTSIDE );
1603  }
1604  }
1605  }
1606 
1607  holes.BooleanSubtract( aprons, SHAPE_POLY_SET::PM_FAST );
1608  }
1609  DUMP_POLYS_TO_COPPER_LAYER( holes, In13_Cu, "pad-via-clipped-hatch-holes" );
1610 
1611  // Now filter truncated holes to avoid small holes in pattern
1612  // It happens for holes near the zone outline
1613  for( int ii = 0; ii < holes.OutlineCount(); )
1614  {
1615  double area = holes.Outline( ii ).Area();
1616 
1617  if( area < minimal_hole_area ) // The current hole is too small: remove it
1618  holes.DeletePolygon( ii );
1619  else
1620  ++ii;
1621  }
1622 
1623  // create grid. Use SHAPE_POLY_SET::PM_STRICTLY_SIMPLE to
1624  // generate strictly simple polygons needed by Gerber files and Fracture()
1625  aRawPolys.BooleanSubtract( aRawPolys, holes, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
1626  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In14_Cu, "after-hatching" );
1627 
1628  return true;
1629 }
#define DUMP_POLYS_TO_COPPER_LAYER(a, b, c)
int GetHatchGap() const
Definition: zone.h:256
int OutlineCount() const
Return the number of vertices in a given outline/hole.
int GetHatchThickness() const
Definition: zone.h:253
BOARD * m_board
Definition: zone_filler.h:123
SHAPE_POLY_SET * Outline()
Definition: zone.h:320
#define SMOOTH_MIN_VAL_MM
double GetHatchSmoothingValue() const
Definition: zone.h:265
void Rotate(double aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
SHAPE_POLY_SET Fillet(int aRadius, int aErrorMax)
Return a filleted version of the polygon set.
double Area(bool aAbsolute=true) const
Return the area of this chain.
VECTOR2< int > VECTOR2I
Definition: vector2d.h:623
#define SMOOTH_SMALL_VAL_MM
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
void DeletePolygon(int aIdx)
double GetHatchHoleMinArea() const
Definition: zone.h:268
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int GetMinThickness() const
Definition: zone.h:244
void Move(const VECTOR2I &aVector) override
int GetHatchSmoothingLevel() const
Definition: zone.h:262
const EDA_RECT GetCachedBoundingBox() const
ONLY TO BE USED BY CLIENTS WHICH SET UP THE CACHE!
Definition: zone.h:145
Represent a set of closed polygons.
SHAPE_LINE_CHAIN & Outline(int aIndex)
coord_type GetWidth() const
Definition: box2.h:180
FOOTPRINTS & Footprints()
Definition: board.h:233
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aCornerBuffer, const wxPoint &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void Deflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
E_SERIE r
Definition: eserie.cpp:41
void BooleanIntersection(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset union between a and b, store the result in it self For aFastMode meaning,...
const Vec & GetPosition() const
Definition: box2.h:177
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new hole to the given outline (default: last) and returns its index.
double GetHatchOrientation() const
Definition: zone.h:259
int GetHatchBorderAlgorithm() const
Definition: zone.h:271
SHAPE_POLY_SET Chamfer(int aDistance)
Return a chamfered version of the polygon set.
Represent a polyline (an zero-thickness chain of connected line segments).
Handle the component boundary box.
Definition: eda_rect.h:42
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
coord_type GetHeight() const
Definition: box2.h:181
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
Definition: pad.h:57
static constexpr int Millimeter2iu(double mm)
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
TRACKS & Tracks()
Definition: board.h:230

References SHAPE_POLY_SET::AddOutline(), SHAPE_LINE_CHAIN::Append(), SHAPE_LINE_CHAIN::Area(), SHAPE_POLY_SET::BBox(), SHAPE_POLY_SET::BooleanIntersection(), SHAPE_POLY_SET::BooleanSubtract(), SHAPE_POLY_SET::Chamfer(), SHAPE_POLY_SET::Deflate(), SHAPE_POLY_SET::DeletePolygon(), DUMP_POLYS_TO_COPPER_LAYER, ERROR_OUTSIDE, SHAPE_POLY_SET::Fillet(), BOARD::Footprints(), ZONE::GetCachedBoundingBox(), ZONE::GetHatchBorderAlgorithm(), ZONE::GetHatchGap(), ZONE::GetHatchHoleMinArea(), ZONE::GetHatchOrientation(), ZONE::GetHatchSmoothingLevel(), ZONE::GetHatchSmoothingValue(), ZONE::GetHatchThickness(), BOX2< Vec >::GetHeight(), ZONE::GetMinThickness(), BOARD_CONNECTED_ITEM::GetNetCode(), BOX2< Vec >::GetPosition(), BOX2< Vec >::GetWidth(), In10_Cu, In11_Cu, In12_Cu, In13_Cu, In14_Cu, KiROUND(), m_board, Millimeter2iu(), SHAPE_LINE_CHAIN::Move(), SHAPE_POLY_SET::Move(), ZONE::Outline(), SHAPE_POLY_SET::Outline(), SHAPE_POLY_SET::OutlineCount(), pad, PCB_VIA_T, SHAPE_POLY_SET::PM_FAST, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE, r, SHAPE_POLY_SET::Rotate(), SHAPE_LINE_CHAIN::SetClosed(), SMOOTH_MIN_VAL_MM, SMOOTH_SMALL_VAL_MM, BOARD::Tracks(), TransformCircleToPolygon(), via, VECTOR2< T >::x, and VECTOR2< T >::y.

Referenced by computeRawFilledArea(), and fillSingleZone().

◆ addHoleKnockout()

void ZONE_FILLER::addHoleKnockout ( PAD aPad,
int  aGap,
SHAPE_POLY_SET aHoles 
)
private

Add a knockout for a pad's hole.

Definition at line 564 of file zone_filler.cpp.

565 {
566  // Note: drill size represents finish size, which means the actual hole size is the plating
567  // thickness larger.
568  if( aPad->GetAttribute() == PAD_ATTRIB::PTH )
570 
572 }
bool TransformHoleWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, int aInflateValue, int aError, ERROR_LOC aErrorLoc) const
Build the corner list of the polygonal drill shape in the board coordinate system.
int GetHolePlatingThickness() const
Pad & via drills are finish size.
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:590
Plated through hole pad.
PAD_ATTRIB GetAttribute() const
Definition: pad.h:371
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:36

References ERROR_OUTSIDE, PAD::GetAttribute(), BOARD_ITEM::GetBoard(), BOARD::GetDesignSettings(), BOARD_DESIGN_SETTINGS::GetHolePlatingThickness(), m_maxError, PTH, and PAD::TransformHoleWithClearanceToPolygon().

Referenced by buildCopperItemClearances().

◆ addKnockout() [1/2]

void ZONE_FILLER::addKnockout ( PAD aPad,
PCB_LAYER_ID  aLayer,
int  aGap,
SHAPE_POLY_SET aHoles 
)
private

Add a knockout for a pad.

The knockout is 'aGap' larger than the pad (which might be either the thermal clearance or the electrical clearance).

Definition at line 531 of file zone_filler.cpp.

532 {
533  if( aPad->GetShape() == PAD_SHAPE::CUSTOM )
534  {
535  SHAPE_POLY_SET poly;
536  aPad->TransformShapeWithClearanceToPolygon( poly, aLayer, aGap, m_maxError,
537  ERROR_OUTSIDE );
538 
539  // the pad shape in zone can be its convex hull or the shape itself
541  {
542  std::vector<wxPoint> convex_hull;
543  BuildConvexHull( convex_hull, poly );
544 
545  aHoles.NewOutline();
546 
547  for( const wxPoint& pt : convex_hull )
548  aHoles.Append( pt );
549  }
550  else
551  aHoles.Append( poly );
552  }
553  else
554  {
555  aPad->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_maxError,
556  ERROR_OUTSIDE );
557  }
558 }
Represent a set of closed polygons.
PAD_SHAPE GetShape() const
Definition: pad.h:170
int NewOutline()
Creates a new hole in a given outline.
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, PCB_LAYER_ID aLayer, int aClearanceValue, int aMaxError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
CUST_PAD_SHAPE_IN_ZONE GetCustomShapeInZoneOpt() const
Definition: pad.h:188
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...
void BuildConvexHull(std::vector< wxPoint > &aResult, const std::vector< wxPoint > &aPoly)
Calculate the convex hull of a list of points in counter-clockwise order.
Definition: convex_hull.cpp:87

References SHAPE_POLY_SET::Append(), BuildConvexHull(), CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL, CUSTOM, ERROR_OUTSIDE, PAD::GetCustomShapeInZoneOpt(), PAD::GetShape(), m_maxError, SHAPE_POLY_SET::NewOutline(), and PAD::TransformShapeWithClearanceToPolygon().

Referenced by buildCopperItemClearances(), and knockoutThermalReliefs().

◆ addKnockout() [2/2]

void ZONE_FILLER::addKnockout ( BOARD_ITEM aItem,
PCB_LAYER_ID  aLayer,
int  aGap,
bool  aIgnoreLineWidth,
SHAPE_POLY_SET aHoles 
)
private

Add a knockout for a graphic item.

The knockout is 'aGap' larger than the item (which might be either the electrical clearance or the board edge clearance).

Definition at line 579 of file zone_filler.cpp.

581 {
582  switch( aItem->Type() )
583  {
584  case PCB_SHAPE_T:
585  case PCB_TEXT_T:
586  case PCB_FP_SHAPE_T:
587  aItem->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_maxError,
588  ERROR_OUTSIDE, aIgnoreLineWidth );
589  break;
590 
591  case PCB_FP_TEXT_T:
592  {
593  FP_TEXT* text = static_cast<FP_TEXT*>( aItem );
594 
595  if( text->IsVisible() )
596  {
597  text->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_maxError,
598  ERROR_OUTSIDE, aIgnoreLineWidth );
599  }
600  }
601  break;
602 
603  default:
604  break;
605  }
606 }
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
class PCB_TEXT, text on a layer
Definition: typeinfo.h:91
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:93
virtual void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, PCB_LAYER_ID aLayer, int aClearanceValue, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const
Convert the item shape to a closed polygon.
Definition: board_item.cpp:142
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:90
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113

References ERROR_OUTSIDE, m_maxError, PCB_FP_SHAPE_T, PCB_FP_TEXT_T, PCB_SHAPE_T, PCB_TEXT_T, text, BOARD_ITEM::TransformShapeWithClearanceToPolygon(), and EDA_ITEM::Type().

◆ buildCopperItemClearances()

void ZONE_FILLER::buildCopperItemClearances ( const ZONE aZone,
PCB_LAYER_ID  aLayer,
SHAPE_POLY_SET aHoles 
)
private

Removes clearance from the shape for copper items which share the zone's layer but are not connected to it.

Definition at line 658 of file zone_filler.cpp.

660 {
661  long ticker = 0;
662 
663  auto checkForCancel =
664  [&ticker]( PROGRESS_REPORTER* aReporter ) -> bool
665  {
666  return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
667  };
668 
669  // A small extra clearance to be sure actual track clearances are not smaller than
670  // requested clearance due to many approximations in calculations, like arc to segment
671  // approx, rounding issues, etc.
672  int extra_margin = Millimeter2iu( ADVANCED_CFG::GetCfg().m_ExtraClearance );
673 
675  int zone_clearance = aZone->GetLocalClearance();
676  EDA_RECT zone_boundingbox = aZone->GetCachedBoundingBox();
677 
678  // Items outside the zone bounding box are skipped, so it needs to be inflated by the
679  // largest clearance value found in the netclasses and rules
680  zone_boundingbox.Inflate( m_worstClearance + extra_margin );
681 
682  auto evalRulesForItems =
683  [&bds]( DRC_CONSTRAINT_T aConstraint, const BOARD_ITEM* a, const BOARD_ITEM* b,
684  PCB_LAYER_ID aEvalLayer ) -> int
685  {
686  auto c = bds.m_DRCEngine->EvalRules( aConstraint, a, b, aEvalLayer );
687  return c.Value().Min();
688  };
689 
690  // Add non-connected pad clearances
691  //
692  auto knockoutPadClearance =
693  [&]( PAD* aPad )
694  {
695  if( aPad->GetBoundingBox().Intersects( zone_boundingbox ) )
696  {
697  int gap = 0;
698  bool knockoutHoleClearance = true;
699 
700  if( aPad->GetNetCode() > 0 && aPad->GetNetCode() == aZone->GetNetCode() )
701  {
702  // For pads having the same netcode as the zone, the net and hole
703  // clearances have no meanings.
704  // So just knock out the greater of the zone's local clearance and
705  // thermal relief.
706  gap = std::max( zone_clearance, aZone->GetThermalReliefGap( aPad ) );
707  knockoutHoleClearance = false;
708  }
709  else
710  {
711  gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aPad, aLayer );
712  }
713 
714  gap += extra_margin;
715 
716  if( aPad->FlashLayer( aLayer ) )
717  addKnockout( aPad, aLayer, gap, aHoles );
718  else if( aPad->GetDrillSize().x > 0 )
719  addHoleKnockout( aPad, gap, aHoles );
720 
721  if( knockoutHoleClearance && aPad->GetDrillSize().x > 0 )
722  {
723  gap = evalRulesForItems( HOLE_CLEARANCE_CONSTRAINT, aZone, aPad, aLayer );
724  gap += extra_margin;
725 
726  addHoleKnockout( aPad, gap, aHoles );
727  }
728  }
729  };
730 
731  for( FOOTPRINT* footprint : m_board->Footprints() )
732  {
733  for( PAD* pad : footprint->Pads() )
734  {
735  if( checkForCancel( m_progressReporter ) )
736  return;
737 
738  if( pad->GetNetCode() != aZone->GetNetCode()
739  || pad->GetNetCode() <= 0
740  || aZone->GetPadConnection( pad ) == ZONE_CONNECTION::NONE )
741  {
742  knockoutPadClearance( pad );
743  }
744  }
745  }
746 
747  // Add non-connected track clearances
748  //
749  auto knockoutTrackClearance =
750  [&]( PCB_TRACK* aTrack )
751  {
752  if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
753  {
754  if( aTrack->Type() == PCB_VIA_T )
755  {
756  PCB_VIA* via = static_cast<PCB_VIA*>( aTrack );
757  int gap = 0;
758  bool checkHoleClearance = true;
759 
760  if( via->GetNetCode() > 0 && via->GetNetCode() == aZone->GetNetCode() )
761  {
762  // For pads having the same netcode as the zone, the net and hole
763  // clearances have no meanings.
764  // So just knock out the zone's local clearance.
765  gap = zone_clearance;
766  checkHoleClearance = false;
767  }
768  else
769  {
770  gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aTrack, aLayer );
771  }
772 
773  if( via->FlashLayer( aLayer ) )
774  {
775  via->TransformShapeWithClearanceToPolygon( aHoles, aLayer,
776  gap + extra_margin,
778  }
779 
780  if( checkHoleClearance )
781  {
782  gap = std::max( gap, evalRulesForItems( HOLE_CLEARANCE_CONSTRAINT,
783  aZone, via, aLayer ) );
784  }
785 
786  int radius = via->GetDrillValue() / 2 + bds.GetHolePlatingThickness();
787 
788  TransformCircleToPolygon( aHoles, via->GetPosition(),
789  radius + gap + extra_margin,
791  }
792  else
793  {
794  int gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aTrack, aLayer );
795 
796  aTrack->TransformShapeWithClearanceToPolygon( aHoles, aLayer,
797  gap + extra_margin,
799  }
800  }
801  };
802 
803  for( PCB_TRACK* track : m_board->Tracks() )
804  {
805  if( !track->IsOnLayer( aLayer ) )
806  continue;
807 
808  if( track->GetNetCode() == aZone->GetNetCode() && ( aZone->GetNetCode() != 0) )
809  continue;
810 
811  if( checkForCancel( m_progressReporter ) )
812  return;
813 
814  knockoutTrackClearance( track );
815  }
816 
817  // Add graphic item clearances. They are by definition unconnected, and have no clearance
818  // definitions of their own.
819  //
820  auto knockoutGraphicClearance =
821  [&]( BOARD_ITEM* aItem )
822  {
823  // A item on the Edge_Cuts or Margin is always seen as on any layer:
824  if( aItem->IsOnLayer( aLayer )
825  || aItem->IsOnLayer( Edge_Cuts )
826  || aItem->IsOnLayer( Margin ) )
827  {
828  if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
829  {
830  bool ignoreLineWidths = false;
831  int gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aItem, aLayer );
832 
833  if( aItem->IsOnLayer( Edge_Cuts ) )
834  {
835  gap = std::max( gap, evalRulesForItems( EDGE_CLEARANCE_CONSTRAINT,
836  aZone, aItem, Edge_Cuts ) );
837 
838  ignoreLineWidths = true;
839  gap = std::max( gap, bds.GetDRCEpsilon() );
840  }
841 
842  if( aItem->IsOnLayer( Margin ) )
843  {
844  gap = std::max( gap, evalRulesForItems( EDGE_CLEARANCE_CONSTRAINT,
845  aZone, aItem, Margin ) );
846  }
847 
848  addKnockout( aItem, aLayer, gap, ignoreLineWidths, aHoles );
849  }
850  }
851  };
852 
853  for( FOOTPRINT* footprint : m_board->Footprints() )
854  {
855  bool skipFootprint = false;
856 
857  knockoutGraphicClearance( &footprint->Reference() );
858  knockoutGraphicClearance( &footprint->Value() );
859 
860  // Don't knock out holes in zones that share a net
861  // with a nettie footprint
862  if( footprint->IsNetTie() )
863  {
864  for( PAD* pad : footprint->Pads() )
865  {
866  if( aZone->GetNetCode() == pad->GetNetCode() )
867  {
868  skipFootprint = true;
869  break;
870  }
871  }
872  }
873 
874  if( skipFootprint )
875  continue;
876 
877  for( BOARD_ITEM* item : footprint->GraphicalItems() )
878  {
879  if( checkForCancel( m_progressReporter ) )
880  return;
881 
882  knockoutGraphicClearance( item );
883  }
884  }
885 
886  for( BOARD_ITEM* item : m_board->Drawings() )
887  {
888  if( checkForCancel( m_progressReporter ) )
889  return;
890 
891  knockoutGraphicClearance( item );
892  }
893 
894  // Add non-connected zone clearances
895  //
896  auto knockoutZoneClearance =
897  [&]( ZONE* aKnockout )
898  {
899  // If the zones share no common layers
900  if( !aKnockout->GetLayerSet().test( aLayer ) )
901  return;
902 
903  if( aKnockout->GetCachedBoundingBox().Intersects( zone_boundingbox ) )
904  {
905  if( aKnockout->GetIsRuleArea() )
906  {
907  // Keepouts use outline with no clearance
908  aKnockout->TransformSmoothedOutlineToPolygon( aHoles, 0, nullptr );
909  }
910  else if( bds.m_ZoneFillVersion == 5 )
911  {
912  // 5.x used outline with clearance
913  int gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aKnockout,
914  aLayer );
915 
916  aKnockout->TransformSmoothedOutlineToPolygon( aHoles, gap, nullptr );
917  }
918  else
919  {
920  // 6.0 uses filled areas with clearance
921  int gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aKnockout,
922  aLayer );
923 
924  SHAPE_POLY_SET poly;
925  aKnockout->TransformShapeWithClearanceToPolygon( poly, aLayer, gap,
926  m_maxError,
927  ERROR_OUTSIDE );
928  aHoles.Append( poly );
929  }
930  }
931  };
932 
933  for( ZONE* otherZone : m_board->Zones() )
934  {
935  if( checkForCancel( m_progressReporter ) )
936  return;
937 
938  if( otherZone->GetNetCode() != aZone->GetNetCode()
939  && otherZone->GetPriority() > aZone->GetPriority() )
940  {
941  knockoutZoneClearance( otherZone );
942  }
943  else if( otherZone->GetIsRuleArea() && otherZone->GetDoNotAllowCopperPour() )
944  {
945  knockoutZoneClearance( otherZone );
946  }
947  }
948 
949  for( FOOTPRINT* footprint : m_board->Footprints() )
950  {
951  for( ZONE* otherZone : footprint->Zones() )
952  {
953  if( checkForCancel( m_progressReporter ) )
954  return;
955 
956  if( otherZone->GetNetCode() != aZone->GetNetCode()
957  && otherZone->GetPriority() > aZone->GetPriority() )
958  {
959  knockoutZoneClearance( otherZone );
960  }
961  else if( otherZone->GetIsRuleArea() && otherZone->GetDoNotAllowCopperPour() )
962  {
963  knockoutZoneClearance( otherZone );
964  }
965  }
966  }
967 
969 }
int m_ZoneFillVersion
Option to select different fill algorithms.
PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:127
ZONES & Zones()
Definition: board.h:239
unsigned GetPriority() const
Definition: zone.h:122
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:49
BOARD * m_board
Definition: zone_filler.h:123
A progress reporter interface for use in multi-threaded environments.
int GetHolePlatingThickness() const
Pad & via drills are finish size.
void addHoleKnockout(PAD *aPad, int aGap, SHAPE_POLY_SET &aHoles)
Add a knockout for a pad's hole.
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:590
int GetThermalReliefGap() const
Definition: zone.h:191
DRC_CONSTRAINT_T
Definition: drc_rule.h:41
const EDA_RECT GetCachedBoundingBox() const
ONLY TO BE USED BY CLIENTS WHICH SET UP THE CACHE!
Definition: zone.h:145
Represent a set of closed polygons.
int GetLocalClearance(wxString *aSource) const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
Definition: zone.cpp:498
FOOTPRINTS & Footprints()
Definition: board.h:233
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aCornerBuffer, const wxPoint &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void addKnockout(PAD *aPad, PCB_LAYER_ID aLayer, int aGap, SHAPE_POLY_SET &aHoles)
Add a knockout for a pad.
void Simplify(POLYGON_MODE aFastMode)
Handle a list of polygons defining a copper zone.
Definition: zone.h:56
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
Handle the component boundary box.
Definition: eda_rect.h:42
Pads are not covered.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
ZONE_CONNECTION GetPadConnection(PAD *aPad, wxString *aSource=nullptr) const
Definition: zone.cpp:778
Definition: pad.h:57
static constexpr int Millimeter2iu(double mm)
DRAWINGS & Drawings()
Definition: board.h:236
TRACKS & Tracks()
Definition: board.h:230
std::shared_ptr< DRC_ENGINE > m_DRCEngine
int m_worstClearance
Definition: zone_filler.h:130
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Inflate the rectangle horizontally by dx and vertically by dy.
Definition: eda_rect.cpp:364
Container for design settings for a BOARD object.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...

References addHoleKnockout(), addKnockout(), SHAPE_POLY_SET::Append(), CLEARANCE_CONSTRAINT, BOARD::Drawings(), EDGE_CLEARANCE_CONSTRAINT, Edge_Cuts, ERROR_OUTSIDE, BOARD::Footprints(), ZONE::GetCachedBoundingBox(), ADVANCED_CFG::GetCfg(), BOARD::GetDesignSettings(), BOARD_DESIGN_SETTINGS::GetDRCEpsilon(), BOARD_DESIGN_SETTINGS::GetHolePlatingThickness(), ZONE::GetLocalClearance(), BOARD_CONNECTED_ITEM::GetNetCode(), ZONE::GetPadConnection(), ZONE::GetPriority(), ZONE::GetThermalReliefGap(), HOLE_CLEARANCE_CONSTRAINT, EDA_RECT::Inflate(), m_board, BOARD_DESIGN_SETTINGS::m_DRCEngine, m_maxError, m_progressReporter, m_worstClearance, BOARD_DESIGN_SETTINGS::m_ZoneFillVersion, Margin, Millimeter2iu(), NONE, pad, PCB_VIA_T, SHAPE_POLY_SET::PM_FAST, SHAPE_POLY_SET::Simplify(), BOARD::Tracks(), TransformCircleToPolygon(), via, and BOARD::Zones().

Referenced by computeRawFilledArea().

◆ buildThermalSpokes()

void ZONE_FILLER::buildThermalSpokes ( const ZONE aZone,
PCB_LAYER_ID  aLayer,
std::deque< SHAPE_LINE_CHAIN > &  aSpokes 
)
private

Function buildThermalSpokes Constructs a list of all thermal spokes for the given zone.

Function buildThermalSpokes.

Definition at line 1284 of file zone_filler.cpp.

1286 {
1287  auto zoneBB = aZone->GetCachedBoundingBox();
1288  int zone_clearance = aZone->GetLocalClearance();
1289  int biggest_clearance = m_board->GetDesignSettings().GetBiggestClearanceValue();
1290  biggest_clearance = std::max( biggest_clearance, zone_clearance );
1291  zoneBB.Inflate( biggest_clearance );
1292 
1293  // Is a point on the boundary of the polygon inside or outside? This small epsilon lets
1294  // us avoid the question.
1295  int epsilon = KiROUND( IU_PER_MM * 0.04 ); // about 1.5 mil
1296 
1297  for( FOOTPRINT* footprint : m_board->Footprints() )
1298  {
1299  for( PAD* pad : footprint->Pads() )
1300  {
1301  if( !hasThermalConnection( pad, aZone ) )
1302  continue;
1303 
1304  // We currently only connect to pads, not pad holes
1305  if( !pad->IsOnLayer( aLayer ) )
1306  continue;
1307 
1308  int thermalReliefGap = aZone->GetThermalReliefGap( pad );
1309 
1310  // Calculate thermal bridge half width
1311  int spoke_w = aZone->GetThermalReliefSpokeWidth( pad );
1312  // Avoid spoke_w bigger than the smaller pad size, because
1313  // it is not possible to create stubs bigger than the pad.
1314  // Possible refinement: have a separate size for vertical and horizontal stubs
1315  spoke_w = std::min( spoke_w, pad->GetSize().x );
1316  spoke_w = std::min( spoke_w, pad->GetSize().y );
1317 
1318  // Cannot create stubs having a width < zone min thickness
1319  if( spoke_w < aZone->GetMinThickness() )
1320  continue;
1321 
1322  int spoke_half_w = spoke_w / 2;
1323 
1324  // Quick test here to possibly save us some work
1325  BOX2I itemBB = pad->GetBoundingBox();
1326  itemBB.Inflate( thermalReliefGap + epsilon );
1327 
1328  if( !( itemBB.Intersects( zoneBB ) ) )
1329  continue;
1330 
1331  // Thermal spokes consist of segments from the pad center to points just outside
1332  // the thermal relief.
1333  //
1334  // We use the bounding-box to lay out the spokes, but for this to work the
1335  // bounding box has to be built at the same rotation as the spokes.
1336  // We have to use a dummy pad to avoid dirtying the cached shapes
1337  wxPoint shapePos = pad->ShapePos();
1338  double padAngle = pad->GetOrientation();
1339  PAD dummy_pad( *pad );
1340  dummy_pad.SetOrientation( 0.0 );
1341 
1342  // Spokes are from center of pad, not from hole
1343  dummy_pad.SetPosition( -pad->GetOffset() );
1344 
1345  BOX2I reliefBB = dummy_pad.GetBoundingBox();
1346  reliefBB.Inflate( thermalReliefGap + epsilon );
1347 
1348  // For circle pads, the thermal spoke orientation is 45 deg
1349  if( pad->GetShape() == PAD_SHAPE::CIRCLE )
1350  padAngle = s_RoundPadThermalSpokeAngle;
1351 
1352  for( int i = 0; i < 4; i++ )
1353  {
1354  SHAPE_LINE_CHAIN spoke;
1355  switch( i )
1356  {
1357  case 0: // lower stub
1358  spoke.Append( +spoke_half_w, -spoke_half_w );
1359  spoke.Append( -spoke_half_w, -spoke_half_w );
1360  spoke.Append( -spoke_half_w, reliefBB.GetBottom() );
1361  spoke.Append( 0, reliefBB.GetBottom() ); // test pt
1362  spoke.Append( +spoke_half_w, reliefBB.GetBottom() );
1363  break;
1364 
1365  case 1: // upper stub
1366  spoke.Append( +spoke_half_w, spoke_half_w );
1367  spoke.Append( -spoke_half_w, spoke_half_w );
1368  spoke.Append( -spoke_half_w, reliefBB.GetTop() );
1369  spoke.Append( 0, reliefBB.GetTop() ); // test pt
1370  spoke.Append( +spoke_half_w, reliefBB.GetTop() );
1371  break;
1372 
1373  case 2: // right stub
1374  spoke.Append( -spoke_half_w, spoke_half_w );
1375  spoke.Append( -spoke_half_w, -spoke_half_w );
1376  spoke.Append( reliefBB.GetRight(), -spoke_half_w );
1377  spoke.Append( reliefBB.GetRight(), 0 ); // test pt
1378  spoke.Append( reliefBB.GetRight(), spoke_half_w );
1379  break;
1380 
1381  case 3: // left stub
1382  spoke.Append( spoke_half_w, spoke_half_w );
1383  spoke.Append( spoke_half_w, -spoke_half_w );
1384  spoke.Append( reliefBB.GetLeft(), -spoke_half_w );
1385  spoke.Append( reliefBB.GetLeft(), 0 ); // test pt
1386  spoke.Append( reliefBB.GetLeft(), spoke_half_w );
1387  break;
1388  }
1389 
1390  spoke.Rotate( -DECIDEG2RAD( padAngle ) );
1391  spoke.Move( shapePos );
1392 
1393  spoke.SetClosed( true );
1394  spoke.GenerateBBoxCache();
1395  aSpokesList.push_back( std::move( spoke ) );
1396  }
1397  }
1398  }
1399 }
BOARD * m_board
Definition: zone_filler.h:123
coord_type GetTop() const
Definition: box2.h:187
static constexpr double IU_PER_MM
Mock up a conversion function.
void Move(const VECTOR2I &aVector) override
static const double s_RoundPadThermalSpokeAngle
Definition: zone_filler.cpp:50
coord_type GetRight() const
Definition: box2.h:182
coord_type GetBottom() const
Definition: box2.h:183
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:590
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
int GetThermalReliefGap() const
Definition: zone.h:191
bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:217
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
const EDA_RECT GetCachedBoundingBox() const
ONLY TO BE USED BY CLIENTS WHICH SET UP THE CACHE!
Definition: zone.h:145
int GetLocalClearance(wxString *aSource) const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
Definition: zone.cpp:498
FOOTPRINTS & Footprints()
Definition: board.h:233
void Rotate(double aAngle, const VECTOR2I &aCenter=VECTOR2I(0, 0)) override
Rotate all vertices by a given angle.
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:281
Represent a polyline (an zero-thickness chain of connected line segments).
double DECIDEG2RAD(double deg)
Definition: trigo.h:233
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
void GenerateBBoxCache() const
int GetThermalReliefSpokeWidth() const
Definition: zone.h:202
coord_type GetLeft() const
Definition: box2.h:186
Definition: pad.h:57
bool hasThermalConnection(PAD *pad, const ZONE *aZone)
Return true if the given pad has a thermal connection with the given zone.

References SHAPE_LINE_CHAIN::Append(), CIRCLE, DECIDEG2RAD(), BOARD::Footprints(), SHAPE_LINE_CHAIN::GenerateBBoxCache(), BOARD_DESIGN_SETTINGS::GetBiggestClearanceValue(), BOX2< Vec >::GetBottom(), PAD::GetBoundingBox(), ZONE::GetCachedBoundingBox(), BOARD::GetDesignSettings(), BOX2< Vec >::GetLeft(), ZONE::GetLocalClearance(), BOX2< Vec >::GetRight(), ZONE::GetThermalReliefGap(), ZONE::GetThermalReliefSpokeWidth(), BOX2< Vec >::GetTop(), hasThermalConnection(), BOX2< Vec >::Inflate(), BOX2< Vec >::Intersects(), IU_PER_MM, KiROUND(), m_board, SHAPE_LINE_CHAIN::Move(), pad, SHAPE_LINE_CHAIN::Rotate(), s_RoundPadThermalSpokeAngle, SHAPE_LINE_CHAIN::SetClosed(), PAD::SetOrientation(), and PAD::SetPosition().

Referenced by computeRawFilledArea().

◆ computeRawFilledArea()

bool ZONE_FILLER::computeRawFilledArea ( const ZONE aZone,
PCB_LAYER_ID  aLayer,
PCB_LAYER_ID  aDebugLayer,
const SHAPE_POLY_SET aSmoothedOutline,
const SHAPE_POLY_SET aMaxExtents,
SHAPE_POLY_SET aRawPolys 
)
private

Function computeRawFilledArea Add non copper areas polygons (pads and tracks with clearance) to a filled copper area used in BuildFilledSolidAreasPolygons when calculating filled areas in a zone Non copper areas are pads and track and their clearance area The filled copper area must be computed before BuildFilledSolidAreasPolygons() call this function just after creating the filled copper area polygon (without clearance areas.

1 - Creates the main zone outline using a correction to shrink the resulting area by m_ZoneMinThickness / 2.

Parameters
aPcbthe current board

The result is areas with a margin of m_ZoneMinThickness / 2 so that when drawing outline with segments having a thickness of m_ZoneMinThickness the outlines will match exactly the initial outlines 2 - Knocks out thermal reliefs around thermally-connected pads 3 - Builds a set of thermal spoke for the whole zone 4 - Knocks out unconnected copper items, deleting any affected spokes 5 - Removes unconnected copper islands, deleting any affected spokes 6 - Adds in the remaining spokes

Definition at line 1039 of file zone_filler.cpp.

1044 {
1046 
1047  // Features which are min_width should survive pruning; features that are *less* than
1048  // min_width should not. Therefore we subtract epsilon from the min_width when
1049  // deflating/inflating.
1050  int half_min_width = aZone->GetMinThickness() / 2;
1051  int epsilon = Millimeter2iu( 0.001 );
1052  int numSegs = GetArcToSegmentCount( half_min_width, m_maxError, 360.0 );
1053 
1054  // Solid polygons are deflated and inflated during calculations. Deflating doesn't cause
1055  // issues, but inflate is tricky as it can create excessively long and narrow spikes for
1056  // acute angles.
1057  // ALLOW_ACUTE_CORNERS cannot be used due to the spike problem.
1058  // CHAMFER_ACUTE_CORNERS is tempting, but can still produce spikes in some unusual
1059  // circumstances (https://gitlab.com/kicad/code/kicad/-/issues/5581).
1060  // It's unclear if ROUND_ACUTE_CORNERS would have the same issues, but is currently avoided
1061  // as a "less-safe" option.
1062  // ROUND_ALL_CORNERS produces the uniformly nicest shapes, but also a lot of segments.
1063  // CHAMFER_ALL_CORNERS improves the segment count.
1066 
1067  std::deque<SHAPE_LINE_CHAIN> thermalSpokes;
1068  SHAPE_POLY_SET clearanceHoles;
1069 
1070  aRawPolys = aSmoothedOutline;
1071  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In1_Cu, "smoothed-outline" );
1072 
1074  return false;
1075 
1076  knockoutThermalReliefs( aZone, aLayer, aRawPolys );
1077  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In2_Cu, "minus-thermal-reliefs" );
1078 
1080  return false;
1081 
1082  buildCopperItemClearances( aZone, aLayer, clearanceHoles );
1083  DUMP_POLYS_TO_COPPER_LAYER( clearanceHoles, In3_Cu, "clearance-holes" );
1084 
1086  return false;
1087 
1088  buildThermalSpokes( aZone, aLayer, thermalSpokes );
1089 
1091  return false;
1092 
1093  // Create a temporary zone that we can hit-test spoke-ends against. It's only temporary
1094  // because the "real" subtract-clearance-holes has to be done after the spokes are added.
1095  static const bool USE_BBOX_CACHES = true;
1096  SHAPE_POLY_SET testAreas = aRawPolys;
1097  testAreas.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );
1098  DUMP_POLYS_TO_COPPER_LAYER( testAreas, In4_Cu, "minus-clearance-holes" );
1099 
1100  // Prune features that don't meet minimum-width criteria
1101  if( half_min_width - epsilon > epsilon )
1102  {
1103  testAreas.Deflate( half_min_width - epsilon, numSegs, fastCornerStrategy );
1104  DUMP_POLYS_TO_COPPER_LAYER( testAreas, In5_Cu, "spoke-test-deflated" );
1105 
1106  testAreas.Inflate( half_min_width - epsilon, numSegs, fastCornerStrategy );
1107  DUMP_POLYS_TO_COPPER_LAYER( testAreas, In6_Cu, "spoke-test-reinflated" );
1108  }
1109 
1111  return false;
1112 
1113  // Spoke-end-testing is hugely expensive so we generate cached bounding-boxes to speed
1114  // things up a bit.
1115  testAreas.BuildBBoxCaches();
1116  int interval = 0;
1117 
1118  SHAPE_POLY_SET debugSpokes;
1119 
1120  for( const SHAPE_LINE_CHAIN& spoke : thermalSpokes )
1121  {
1122  const VECTOR2I& testPt = spoke.CPoint( 3 );
1123 
1124  // Hit-test against zone body
1125  if( testAreas.Contains( testPt, -1, 1, USE_BBOX_CACHES ) )
1126  {
1127  if( m_debugZoneFiller )
1128  debugSpokes.AddOutline( spoke );
1129 
1130  aRawPolys.AddOutline( spoke );
1131  continue;
1132  }
1133 
1134  if( interval++ > 400 )
1135  {
1137  return false;
1138 
1139  interval = 0;
1140  }
1141 
1142  // Hit-test against other spokes
1143  for( const SHAPE_LINE_CHAIN& other : thermalSpokes )
1144  {
1145  if( &other != &spoke && other.PointInside( testPt, 1, USE_BBOX_CACHES ) )
1146  {
1147  if( m_debugZoneFiller )
1148  debugSpokes.AddOutline( spoke );
1149 
1150  aRawPolys.AddOutline( spoke );
1151  break;
1152  }
1153  }
1154  }
1155 
1156  DUMP_POLYS_TO_COPPER_LAYER( debugSpokes, In7_Cu, "spokes" );
1157 
1159  return false;
1160 
1161  aRawPolys.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );
1162  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In8_Cu, "after-spoke-trimming" );
1163 
1164  // Prune features that don't meet minimum-width criteria
1165  if( half_min_width - epsilon > epsilon )
1166  aRawPolys.Deflate( half_min_width - epsilon, numSegs, cornerStrategy );
1167 
1168  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In9_Cu, "deflated" );
1169 
1171  return false;
1172 
1173  // Now remove the non filled areas due to the hatch pattern
1174  if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
1175  {
1176  if( !addHatchFillTypeOnZone( aZone, aLayer, aDebugLayer, aRawPolys ) )
1177  return false;
1178  }
1179 
1181  return false;
1182 
1183  // Re-inflate after pruning of areas that don't meet minimum-width criteria
1184  if( aZone->GetFilledPolysUseThickness() )
1185  {
1186  // If we're stroking the zone with a min_width stroke then this will naturally inflate
1187  // the zone by half_min_width
1188  }
1189  else if( half_min_width - epsilon > epsilon )
1190  {
1191  aRawPolys.Inflate( half_min_width - epsilon, numSegs, cornerStrategy );
1192  }
1193 
1194  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In15_Cu, "after-reinflating" );
1195 
1196  // Ensure additive changes (thermal stubs and particularly inflating acute corners) do not
1197  // add copper outside the zone boundary or inside the clearance holes
1198  aRawPolys.BooleanIntersection( aMaxExtents, SHAPE_POLY_SET::PM_FAST );
1199  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In16_Cu, "after-trim-to-outline" );
1200  aRawPolys.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );
1201  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In17_Cu, "after-trim-to-clearance-holes" );
1202 
1203  // Lastly give any same-net but higher-priority zones control over their own area.
1204  subtractHigherPriorityZones( aZone, aLayer, aRawPolys );
1205  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In18_Cu, "minus-higher-priority-zones" );
1206 
1207  aRawPolys.Fracture( SHAPE_POLY_SET::PM_FAST );
1208  return true;
1209 }
#define DUMP_POLYS_TO_COPPER_LAYER(a, b, c)
All angles are chamfered.
PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:127
BOARD * m_board
Definition: zone_filler.h:123
CORNER_STRATEGY
< define how inflate transform build inflated polygon
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:590
ZONE_FILL_MODE GetFillMode() const
Definition: zone.h:181
void BuildBBoxCaches() const
Construct BBoxCaches for Contains(), below.
void buildCopperItemClearances(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aHoles)
Removes clearance from the shape for copper items which share the zone's layer but are not connected ...
int GetMinThickness() const
Definition: zone.h:244
Represent a set of closed polygons.
void Deflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
bool addHatchFillTypeOnZone(const ZONE *aZone, PCB_LAYER_ID aLayer, PCB_LAYER_ID aDebugLayer, SHAPE_POLY_SET &aRawPolys)
for zones having the ZONE_FILL_MODE::ZONE_FILL_MODE::HATCH_PATTERN, create a grid pattern in filled a...
void BooleanIntersection(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset union between a and b, store the result in it self For aFastMode meaning,...
void Fracture(POLYGON_MODE aFastMode)
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
void Inflate(int aAmount, int aCircleSegCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
Perform outline inflation/deflation.
void knockoutThermalReliefs(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aFill)
Removes thermal reliefs from the shape for any pads connected to the zone.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new hole to the given outline (default: last) and returns its index.
Represent a polyline (an zero-thickness chain of connected line segments).
bool m_debugZoneFiller
Definition: zone_filler.h:132
void subtractHigherPriorityZones(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aRawFill)
Removes the outlines of higher-proirity zones with the same net.
virtual bool IsCancelled() const =0
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
static constexpr int Millimeter2iu(double mm)
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
void buildThermalSpokes(const ZONE *aZone, PCB_LAYER_ID aLayer, std::deque< SHAPE_LINE_CHAIN > &aSpokes)
Function buildThermalSpokes Constructs a list of all thermal spokes for the given zone.
bool GetFilledPolysUseThickness() const
Definition: zone.h:689

References addHatchFillTypeOnZone(), SHAPE_POLY_SET::AddOutline(), SHAPE_POLY_SET::BooleanIntersection(), SHAPE_POLY_SET::BooleanSubtract(), SHAPE_POLY_SET::BuildBBoxCaches(), buildCopperItemClearances(), buildThermalSpokes(), SHAPE_POLY_SET::CHAMFER_ALL_CORNERS, SHAPE_POLY_SET::Contains(), SHAPE_POLY_SET::Deflate(), DUMP_POLYS_TO_COPPER_LAYER, SHAPE_POLY_SET::Fracture(), GetArcToSegmentCount(), BOARD::GetDesignSettings(), ZONE::GetFilledPolysUseThickness(), ZONE::GetFillMode(), ZONE::GetMinThickness(), HATCH_PATTERN, In15_Cu, In16_Cu, In17_Cu, In18_Cu, In1_Cu, In2_Cu, In3_Cu, In4_Cu, In5_Cu, In6_Cu, In7_Cu, In8_Cu, In9_Cu, SHAPE_POLY_SET::Inflate(), PROGRESS_REPORTER::IsCancelled(), knockoutThermalReliefs(), m_board, m_debugZoneFiller, m_maxError, BOARD_DESIGN_SETTINGS::m_MaxError, m_progressReporter, Millimeter2iu(), SHAPE_POLY_SET::PM_FAST, SHAPE_POLY_SET::ROUND_ALL_CORNERS, and subtractHigherPriorityZones().

Referenced by fillSingleZone().

◆ Fill()

bool ZONE_FILLER::Fill ( std::vector< ZONE * > &  aZones,
bool  aCheck = false,
wxWindow *  aParent = nullptr 
)

Fills the given list of zones.

Invalidates connectivity - it is up to the caller to obtain a lock on the connectivity data before calling Fill to prevent access to stale data by other coroutines (for example, ratsnest redraw). This will generally be required if a UI-based progress reporter has been installed.

Definition at line 78 of file zone_filler.cpp.

79 {
80  std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
81  std::vector<CN_ZONE_ISOLATED_ISLAND_LIST> islandsList;
82 
83  std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
84 
85  // Rebuild just in case. This really needs to be reliable.
86  connectivity->Clear();
87  connectivity->Build( m_board, m_progressReporter );
88 
90 
92 
93  if( m_progressReporter )
94  {
95  m_progressReporter->Report( aCheck ? _( "Checking zone fills..." )
96  : _( "Building zone fills..." ) );
97  m_progressReporter->SetMaxProgress( aZones.size() );
99  }
100 
101  // The board outlines is used to clip solid areas inside the board (when outlines are valid)
104 
105  // Update and cache zone bounding boxes and pad effective shapes so that we don't have to
106  // make them thread-safe.
107  for( ZONE* zone : m_board->Zones() )
108  {
109  zone->CacheBoundingBox();
110  m_worstClearance = std::max( m_worstClearance, zone->GetLocalClearance() );
111  }
112 
113  for( FOOTPRINT* footprint : m_board->Footprints() )
114  {
115  for( PAD* pad : footprint->Pads() )
116  {
117  if( pad->IsDirty() )
118  {
119  pad->BuildEffectiveShapes( UNDEFINED_LAYER );
120  pad->BuildEffectivePolygon();
121  }
122 
123  m_worstClearance = std::max( m_worstClearance, pad->GetLocalClearance() );
124  }
125 
126  for( ZONE* zone : footprint->Zones() )
127  {
128  zone->CacheBoundingBox();
129  m_worstClearance = std::max( m_worstClearance, zone->GetLocalClearance() );
130  }
131 
132  // Rules may depend on insideCourtyard() or other expressions
133  footprint->BuildPolyCourtyards();
134  }
135 
136  // Sort by priority to reduce deferrals waiting on higher priority zones.
137  std::sort( aZones.begin(), aZones.end(),
138  []( const ZONE* lhs, const ZONE* rhs )
139  {
140  return lhs->GetPriority() > rhs->GetPriority();
141  } );
142 
143  for( ZONE* zone : aZones )
144  {
145  // Rule areas are not filled
146  if( zone->GetIsRuleArea() )
147  continue;
148 
149  if( m_commit )
150  m_commit->Modify( zone );
151 
152  // calculate the hash value for filled areas. it will be used later
153  // to know if the current filled areas are up to date
154  for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
155  {
156  zone->BuildHashValue( layer );
157 
158  // Add the zone to the list of zones to test or refill
159  toFill.emplace_back( std::make_pair( zone, layer ) );
160  }
161 
162  islandsList.emplace_back( CN_ZONE_ISOLATED_ISLAND_LIST( zone ) );
163 
164  // Remove existing fill first to prevent drawing invalid polygons
165  // on some platforms
166  zone->UnFill();
167 
168  zone->SetFillVersion( bds.m_ZoneFillVersion );
169  }
170 
171  size_t cores = std::thread::hardware_concurrency();
172  std::atomic<size_t> nextItem;
173 
174  auto check_fill_dependency =
175  [&]( ZONE* aZone, PCB_LAYER_ID aLayer, ZONE* aOtherZone ) -> bool
176  {
177  // Check to see if we have to knock-out the filled areas of a higher-priority
178  // zone. If so we have to wait until said zone is filled before we can fill.
179 
180  // If the other zone is already filled then we're good-to-go
181  if( aOtherZone->GetFillFlag( aLayer ) )
182  return false;
183 
184  // Even if keepouts exclude copper pours the exclusion is by outline, not by
185  // filled area, so we're good-to-go here too.
186  if( aOtherZone->GetIsRuleArea() )
187  return false;
188 
189  // If the zones share no common layers
190  if( !aOtherZone->GetLayerSet().test( aLayer ) )
191  return false;
192 
193  if( aOtherZone->GetPriority() <= aZone->GetPriority() )
194  return false;
195 
196  // Same-net zones always use outline to produce predictable results
197  if( aOtherZone->GetNetCode() == aZone->GetNetCode() )
198  return false;
199 
200  // A higher priority zone is found: if we intersect and it's not filled yet
201  // then we have to wait.
202  EDA_RECT inflatedBBox = aZone->GetCachedBoundingBox();
203  inflatedBBox.Inflate( m_worstClearance );
204 
205  return inflatedBBox.Intersects( aOtherZone->GetCachedBoundingBox() );
206  };
207 
208  auto fill_lambda =
209  [&]( PROGRESS_REPORTER* aReporter )
210  {
211  size_t num = 0;
212 
213  for( size_t i = nextItem++; i < toFill.size(); i = nextItem++ )
214  {
215  PCB_LAYER_ID layer = toFill[i].second;
216  ZONE* zone = toFill[i].first;
217  bool canFill = true;
218 
219  // Check for any fill dependencies. If our zone needs to be clipped by
220  // another zone then we can't fill until that zone is filled.
221  for( ZONE* otherZone : aZones )
222  {
223  if( otherZone == zone )
224  continue;
225 
226  if( check_fill_dependency( zone, layer, otherZone ) )
227  {
228  canFill = false;
229  break;
230  }
231  }
232 
234  break;
235 
236  if( !canFill )
237  continue;
238 
239  // Now we're ready to fill.
240  SHAPE_POLY_SET rawPolys, finalPolys;
241  fillSingleZone( zone, layer, rawPolys, finalPolys );
242 
243  std::unique_lock<std::mutex> zoneLock( zone->GetLock() );
244 
245  zone->SetRawPolysList( layer, rawPolys );
246  zone->SetFilledPolysList( layer, finalPolys );
247  zone->SetFillFlag( layer, true );
248 
249  if( m_progressReporter )
251 
252  num++;
253  }
254 
255  return num;
256  };
257 
258  while( !toFill.empty() )
259  {
260  size_t parallelThreadCount = std::min( cores, toFill.size() );
261  std::vector<std::future<size_t>> returns( parallelThreadCount );
262 
263  nextItem = 0;
264 
265  if( parallelThreadCount <= 1 )
266  fill_lambda( m_progressReporter );
267  else
268  {
269  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
270  returns[ii] = std::async( std::launch::async, fill_lambda, m_progressReporter );
271 
272  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
273  {
274  // Here we balance returns with a 100ms timeout to allow UI updating
275  std::future_status status;
276  do
277  {
278  if( m_progressReporter )
280 
281  status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) );
282  } while( status != std::future_status::ready );
283  }
284  }
285 
286  alg::delete_if( toFill, [&]( const std::pair<ZONE*, PCB_LAYER_ID> pair ) -> bool
287  {
288  return pair.first->GetFillFlag( pair.second );
289  } );
290 
292  break;
293  }
294 
295  // Now update the connectivity to check for copper islands
296  if( m_progressReporter )
297  {
299  return false;
300 
302  m_progressReporter->Report( _( "Removing isolated copper islands..." ) );
304  }
305 
306  connectivity->SetProgressReporter( m_progressReporter );
307  connectivity->FindIsolatedCopperIslands( islandsList );
308  connectivity->SetProgressReporter( nullptr );
309 
311  return false;
312 
313  for( ZONE* zone : aZones )
314  {
315  // Keepout zones are not filled
316  if( zone->GetIsRuleArea() )
317  continue;
318 
319  zone->SetIsFilled( true );
320  }
321 
322  // Now remove insulated copper islands
323  for( CN_ZONE_ISOLATED_ISLAND_LIST& zone : islandsList )
324  {
325  for( PCB_LAYER_ID layer : zone.m_zone->GetLayerSet().Seq() )
326  {
328  continue;
329 
330  if( !zone.m_islands.count( layer ) )
331  continue;
332 
333  std::vector<int>& islands = zone.m_islands.at( layer );
334 
335  // The list of polygons to delete must be explored from last to first in list,
336  // to allow deleting a polygon from list without breaking the remaining of the list
337  std::sort( islands.begin(), islands.end(), std::greater<int>() );
338 
339  SHAPE_POLY_SET poly = zone.m_zone->GetFilledPolysList( layer );
340  long long int minArea = zone.m_zone->GetMinIslandArea();
341  ISLAND_REMOVAL_MODE mode = zone.m_zone->GetIslandRemovalMode();
342 
343  for( int idx : islands )
344  {
345  SHAPE_LINE_CHAIN& outline = poly.Outline( idx );
346 
347  if( mode == ISLAND_REMOVAL_MODE::ALWAYS )
348  poly.DeletePolygon( idx );
349  else if ( mode == ISLAND_REMOVAL_MODE::AREA && outline.Area() < minArea )
350  poly.DeletePolygon( idx );
351  else
352  zone.m_zone->SetIsIsland( layer, idx );
353  }
354 
355  zone.m_zone->SetFilledPolysList( layer, poly );
356  zone.m_zone->CalculateFilledArea();
357 
359  return false;
360  }
361  }
362 
363  // Now remove islands outside the board edge
364  for( ZONE* zone : aZones )
365  {
366  LSET zoneCopperLayers = zone->GetLayerSet() & LSET::AllCuMask( MAX_CU_LAYERS );
367 
368  for( PCB_LAYER_ID layer : zoneCopperLayers.Seq() )
369  {
371  continue;
372 
373  SHAPE_POLY_SET poly = zone->GetFilledPolysList( layer );
374 
375  for( int ii = poly.OutlineCount() - 1; ii >= 0; ii-- )
376  {
377  std::vector<SHAPE_LINE_CHAIN>& island = poly.Polygon( ii );
378 
379  if( island.empty() || !m_boardOutline.Contains( island.front().CPoint( 0 ) ) )
380  poly.DeletePolygon( ii );
381  }
382 
383  zone->SetFilledPolysList( layer, poly );
384  zone->CalculateFilledArea();
385 
387  return false;
388  }
389  }
390 
391  if( aCheck )
392  {
393  bool outOfDate = false;
394 
395  for( ZONE* zone : aZones )
396  {
397  // Keepout zones are not filled
398  if( zone->GetIsRuleArea() )
399  continue;
400 
401  for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
402  {
403  MD5_HASH was = zone->GetHashValue( layer );
404  zone->CacheTriangulation( layer );
405  zone->BuildHashValue( layer );
406  MD5_HASH is = zone->GetHashValue( layer );
407 
408  if( is != was )
409  outOfDate = true;
410  }
411  }
412 
413  if( outOfDate )
414  {
415  KIDIALOG dlg( aParent, _( "Zone fills are out-of-date. Refill?" ),
416  _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
417  dlg.SetOKCancelLabels( _( "Refill" ), _( "Continue without Refill" ) );
418  dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
419 
420  if( dlg.ShowModal() == wxID_CANCEL )
421  return false;
422  }
423  }
424 
425  if( m_progressReporter )
426  {
428  m_progressReporter->Report( _( "Performing polygon fills..." ) );
429  m_progressReporter->SetMaxProgress( islandsList.size() );
430  }
431 
432  nextItem = 0;
433 
434  auto tri_lambda =
435  [&]( PROGRESS_REPORTER* aReporter ) -> size_t
436  {
437  size_t num = 0;
438 
439  for( size_t i = nextItem++; i < islandsList.size(); i = nextItem++ )
440  {
441  islandsList[i].m_zone->CacheTriangulation();
442  num++;
443 
444  if( m_progressReporter )
445  {
447 
449  break;
450  }
451  }
452 
453  return num;
454  };
455 
456  size_t parallelThreadCount = std::min( cores, islandsList.size() );
457  std::vector<std::future<size_t>> returns( parallelThreadCount );
458 
459  if( parallelThreadCount <= 1 )
460  tri_lambda( m_progressReporter );
461  else
462  {
463  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
464  returns[ii] = std::async( std::launch::async, tri_lambda, m_progressReporter );
465 
466  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
467  {
468  // Here we balance returns with a 100ms timeout to allow UI updating
469  std::future_status status;
470  do
471  {
472  if( m_progressReporter )
473  {
475 
477  break;
478  }
479 
480  status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) );
481  } while( status != std::future_status::ready );
482  }
483  }
484 
485  if( m_progressReporter )
486  {
488  return false;
489 
492  }
493 
494  return true;
495 }
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:750
int m_ZoneFillVersion
Option to select different fill algorithms.
COMMIT & Modify(EDA_ITEM *aItem)
Create an undo entry for an item that has been already modified.
Definition: commit.h:103
virtual void SetMaxProgress(int aMaxProgress)=0
Fix the value that gives the 100 percent progress bar length (inside the current virtual zone).
void CacheTriangulation(PCB_LAYER_ID aLayer=UNDEFINED_LAYER)
Create a list of triangles that "fill" the solid areas used for instance to draw these solid areas on...
Definition: zone.cpp:1112
int OutlineCount() const
Return the number of vertices in a given outline/hole.
virtual void Report(const wxString &aMessage)=0
Display aMessage in the progress bar dialog.
PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:127
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
Definition: board.cpp:1880
ZONES & Zones()
Definition: board.h:239
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: confirm.h:45
unsigned GetPriority() const
Definition: zone.h:122
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:733
BOARD * m_board
Definition: zone_filler.h:123
A progress reporter interface for use in multi-threaded environments.
bool Contains(PCB_LAYER_ID aLayer)
See if the layer set contains a PCB layer.
Definition: layer_ids.h:575
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.cpp:295
const SHAPE_POLY_SET & GetFilledPolysList(PCB_LAYER_ID aLayer) const
Definition: zone.h:635
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
double Area(bool aAbsolute=true) const
Return the area of this chain.
MD5_HASH GetHashValue(PCB_LAYER_ID aLayer)
Definition: zone.cpp:386
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:411
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:590
virtual void AdvanceProgress()=0
Increment the progress bar length (inside the current virtual zone).
void DeletePolygon(int aIdx)
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:504
#define MAX_CU_LAYERS
Definition: layer_ids.h:147
COMMIT * m_commit
Definition: zone_filler.h:126
virtual void AdvancePhase()=0
Use the next available virtual zone of the dialog progress bar.
const EDA_RECT GetCachedBoundingBox() const
ONLY TO BE USED BY CLIENTS WHICH SET UP THE CACHE!
Definition: zone.h:145
Represent a set of closed polygons.
FOOTPRINTS & Footprints()
Definition: board.h:233
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:344
static LSET InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
Definition: lset.cpp:710
#define _(s)
Handle a list of polygons defining a copper zone.
Definition: zone.h:56
void SetIsFilled(bool isFilled)
Definition: zone.h:235
void SetFilledPolysList(PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPolysList)
Set the list of filled polygons.
Definition: zone.h:650
void BuildHashValue(PCB_LAYER_ID aLayer)
Build the hash value of m_FilledPolysList, and store it internally in m_filledPolysHash.
Definition: zone.cpp:395
void SetIsIsland(PCB_LAYER_ID aLayer, int aPolyIdx)
Definition: zone.h:672
const ISLAND_REMOVAL_MODE GetIslandRemovalMode() const
Definition: zone.h:749
Represent a polyline (an zero-thickness chain of connected line segments).
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
ISLAND_REMOVAL_MODE
Whether or not to remove isolated islands from a zone.
Definition: zone_settings.h:54
bool m_debugZoneFiller
Definition: zone_filler.h:132
Handle the component boundary box.
Definition: eda_rect.h:42
void SetFillFlag(PCB_LAYER_ID aLayer, bool aFlag)
Definition: zone.h:232
bool Intersects(const EDA_RECT &aRect) const
Test for a common area between rectangles.
Definition: eda_rect.cpp:150
std::mutex & GetLock()
Definition: zone.h:222
SHAPE_POLY_SET m_boardOutline
Definition: zone_filler.h:124
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual bool IsCancelled() const =0
long long int GetMinIslandArea() const
Definition: zone.h:753
bool fillSingleZone(ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aRawPolys, SHAPE_POLY_SET &aFinalPolys)
Build the filled solid areas polygons from zone outlines (stored in m_Poly) The solid areas can be mo...
bool m_brdOutlinesValid
Definition: zone_filler.h:125
double CalculateFilledArea()
Compute the area currently occupied by the zone fill.
Definition: zone.cpp:1267
POLYGON & Polygon(int aIndex)
void SetRawPolysList(PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPolysList)
Set the list of filled polygons.
Definition: zone.h:658
Definition: pad.h:57
void delete_if(_Container &__c, _Function &&__f)
Deletes all values from __c for which __f returns true.
Definition: kicad_algo.h:173
A structure used for calculating isolated islands on a given zone across all its layers.
int m_worstClearance
Definition: zone_filler.h:130
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Inflate the rectangle horizontally by dx and vertically by dy.
Definition: eda_rect.cpp:364
Container for design settings for a BOARD object.

References _, PROGRESS_REPORTER::AdvancePhase(), PROGRESS_REPORTER::AdvanceProgress(), LSET::AllCuMask(), ALWAYS, AREA, SHAPE_LINE_CHAIN::Area(), LSET::Contains(), SHAPE_POLY_SET::Contains(), alg::delete_if(), SHAPE_POLY_SET::DeletePolygon(), KIDIALOG::DoNotShowCheckbox(), fillSingleZone(), BOARD::Footprints(), BOARD_DESIGN_SETTINGS::GetBiggestClearanceValue(), BOARD::GetBoardPolygonOutlines(), ZONE::GetCachedBoundingBox(), BOARD::GetConnectivity(), BOARD::GetDesignSettings(), ZONE::GetLock(), BOARD_CONNECTED_ITEM::GetNetCode(), ZONE::GetPriority(), EDA_RECT::Inflate(), LSET::InternalCuMask(), EDA_RECT::Intersects(), PROGRESS_REPORTER::IsCancelled(), PROGRESS_REPORTER::KeepRefreshing(), m_board, m_boardOutline, m_brdOutlinesValid, m_commit, m_debugZoneFiller, m_progressReporter, m_worstClearance, BOARD_DESIGN_SETTINGS::m_ZoneFillVersion, MAX_CU_LAYERS, COMMIT::Modify(), SHAPE_POLY_SET::OutlineCount(), pad, SHAPE_POLY_SET::Polygon(), SHAPE_POLY_SET::RemoveAllContours(), PROGRESS_REPORTER::Report(), LSET::Seq(), ZONE::SetFilledPolysList(), ZONE::SetFillFlag(), PROGRESS_REPORTER::SetMaxProgress(), KIDIALOG::SetOKCancelLabels(), ZONE::SetRawPolysList(), KIDIALOG::ShowModal(), UNDEFINED_LAYER, and BOARD::Zones().

Referenced by ZONE_FILLER_TOOL::CheckAllZones(), PCB_EDIT_FRAME::Edit_Zone_Params(), ZONE_FILLER_TOOL::FillAllZones(), KI_TEST::FillZones(), and ZONE_FILLER_TOOL::ZoneFill().

◆ fillSingleZone()

bool ZONE_FILLER::fillSingleZone ( ZONE aZone,
PCB_LAYER_ID  aLayer,
SHAPE_POLY_SET aRawPolys,
SHAPE_POLY_SET aFinalPolys 
)
private

Build the filled solid areas polygons from zone outlines (stored in m_Poly) The solid areas can be more than one on copper layers, and do not have holes ( holes are linked by overlapping segments to the main outline) in order to have drawable (and plottable) filled polygons.

Returns
true if OK, false if the solid polygons cannot be built
Parameters
aZoneis the zone to fill
aRawPolysA reference to a SHAPE_POLY_SET buffer to store filled solid areas polygons (with holes)
aFinalPolysA reference to a SHAPE_POLY_SET buffer to store polygons with no holes (holes are linked to main outline by overlapping segments, and these polygons are shrunk by aZone->GetMinThickness() / 2 to be drawn with a outline thickness = aZone->GetMinThickness() aFinalPolys are polygons that will be drawn on screen and plotted

Definition at line 1217 of file zone_filler.cpp.

1219 {
1220  SHAPE_POLY_SET* boardOutline = m_brdOutlinesValid ? &m_boardOutline : nullptr;
1221  SHAPE_POLY_SET maxExtents;
1222  SHAPE_POLY_SET smoothedPoly;
1223  PCB_LAYER_ID debugLayer = UNDEFINED_LAYER;
1224 
1225  if( m_debugZoneFiller && LSET::InternalCuMask().Contains( aLayer ) )
1226  {
1227  debugLayer = aLayer;
1228  aLayer = F_Cu;
1229  }
1230 
1231  if ( !aZone->BuildSmoothedPoly( maxExtents, aLayer, boardOutline, &smoothedPoly ) )
1232  return false;
1233 
1235  return false;
1236 
1237  if( aZone->IsOnCopperLayer() )
1238  {
1239  if( computeRawFilledArea( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aRawPolys ) )
1240  aZone->SetNeedRefill( false );
1241 
1242  aFinalPolys = aRawPolys;
1243  }
1244  else
1245  {
1246  // Features which are min_width should survive pruning; features that are *less* than
1247  // min_width should not. Therefore we subtract epsilon from the min_width when
1248  // deflating/inflating.
1249  int half_min_width = aZone->GetMinThickness() / 2;
1250  int epsilon = Millimeter2iu( 0.001 );
1251  int numSegs = GetArcToSegmentCount( half_min_width, m_maxError, 360.0 );
1252 
1253  smoothedPoly.Deflate( half_min_width - epsilon, numSegs );
1254 
1255  // Remove the non filled areas due to the hatch pattern
1256  if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
1257  addHatchFillTypeOnZone( aZone, aLayer, debugLayer, smoothedPoly );
1258 
1259  // Re-inflate after pruning of areas that don't meet minimum-width criteria
1260  if( aZone->GetFilledPolysUseThickness() )
1261  {
1262  // If we're stroking the zone with a min_width stroke then this will naturally
1263  // inflate the zone by half_min_width
1264  }
1265  else if( half_min_width - epsilon > epsilon )
1266  {
1267  smoothedPoly.Inflate( half_min_width - epsilon, numSegs );
1268  }
1269 
1270  aRawPolys = smoothedPoly;
1271  aFinalPolys = smoothedPoly;
1272 
1274  aZone->SetNeedRefill( false );
1275  }
1276 
1277  return true;
1278 }
PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:127
bool BuildSmoothedPoly(SHAPE_POLY_SET &aSmoothedPoly, PCB_LAYER_ID aLayer, SHAPE_POLY_SET *aBoardOutline, SHAPE_POLY_SET *aSmoothedPolyWithApron=nullptr) const
Definition: zone.cpp:1169
ZONE_FILL_MODE GetFillMode() const
Definition: zone.h:181
int GetMinThickness() const
Definition: zone.h:244
Represent a set of closed polygons.
void Deflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
static LSET InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
Definition: lset.cpp:710
bool addHatchFillTypeOnZone(const ZONE *aZone, PCB_LAYER_ID aLayer, PCB_LAYER_ID aDebugLayer, SHAPE_POLY_SET &aRawPolys)
for zones having the ZONE_FILL_MODE::ZONE_FILL_MODE::HATCH_PATTERN, create a grid pattern in filled a...
void Fracture(POLYGON_MODE aFastMode)
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
void Inflate(int aAmount, int aCircleSegCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
Perform outline inflation/deflation.
bool computeRawFilledArea(const ZONE *aZone, PCB_LAYER_ID aLayer, PCB_LAYER_ID aDebugLayer, const SHAPE_POLY_SET &aSmoothedOutline, const SHAPE_POLY_SET &aMaxExtents, SHAPE_POLY_SET &aRawPolys)
Function computeRawFilledArea Add non copper areas polygons (pads and tracks with clearance) to a fil...
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
bool m_debugZoneFiller
Definition: zone_filler.h:132
Definition: layer_ids.h:71
bool IsOnCopperLayer() const override
Definition: zone.cpp:228
SHAPE_POLY_SET m_boardOutline
Definition: zone_filler.h:124
virtual bool IsCancelled() const =0
bool m_brdOutlinesValid
Definition: zone_filler.h:125
void SetNeedRefill(bool aNeedRefill)
Definition: zone.h:238
static constexpr int Millimeter2iu(double mm)
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
bool GetFilledPolysUseThickness() const
Definition: zone.h:689

References addHatchFillTypeOnZone(), ZONE::BuildSmoothedPoly(), computeRawFilledArea(), SHAPE_POLY_SET::Deflate(), F_Cu, SHAPE_POLY_SET::Fracture(), GetArcToSegmentCount(), ZONE::GetFilledPolysUseThickness(), ZONE::GetFillMode(), ZONE::GetMinThickness(), HATCH_PATTERN, SHAPE_POLY_SET::Inflate(), LSET::InternalCuMask(), PROGRESS_REPORTER::IsCancelled(), ZONE::IsOnCopperLayer(), m_boardOutline, m_brdOutlinesValid, m_debugZoneFiller, m_maxError, m_progressReporter, Millimeter2iu(), SHAPE_POLY_SET::PM_STRICTLY_SIMPLE, ZONE::SetNeedRefill(), and UNDEFINED_LAYER.

Referenced by Fill().

◆ IsDebug()

bool ZONE_FILLER::IsDebug ( ) const
inline

Definition at line 55 of file zone_filler.h.

55 { return m_debugZoneFiller; }
bool m_debugZoneFiller
Definition: zone_filler.h:132

References m_debugZoneFiller.

Referenced by ZONE_FILLER_TOOL::FillAllZones().

◆ knockoutThermalReliefs()

void ZONE_FILLER::knockoutThermalReliefs ( const ZONE aZone,
PCB_LAYER_ID  aLayer,
SHAPE_POLY_SET aFill 
)
private

Removes thermal reliefs from the shape for any pads connected to the zone.

Does NOT add in spokes, which must be done later.

Definition at line 613 of file zone_filler.cpp.

615 {
616  SHAPE_POLY_SET holes;
617 
618  for( FOOTPRINT* footprint : m_board->Footprints() )
619  {
620  for( PAD* pad : footprint->Pads() )
621  {
622  if( !hasThermalConnection( pad, aZone ) )
623  continue;
624 
625  int gap = aZone->GetThermalReliefGap( pad );
626 
627  // If the pad is flashed to the current layer, or is on the same layer and shares a netcode, then
628  // we need to knock out the thermal relief.
629  if( pad->FlashLayer( aLayer ) || ( pad->IsOnLayer( aLayer ) && pad->GetNetCode() == aZone->GetNetCode() ) )
630  {
631  addKnockout( pad, aLayer, gap, holes );
632  }
633  else
634  {
635  // If the pad isn't on the current layer but has a hole, knock out a thermal relief
636  // for the hole.
637  if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
638  continue;
639 
640  // Note: drill size represents finish size, which means the actual holes size is
641  // the plating thickness larger.
642  if( pad->GetAttribute() == PAD_ATTRIB::PTH )
643  gap += pad->GetBoard()->GetDesignSettings().GetHolePlatingThickness();
644 
645  pad->TransformHoleWithClearanceToPolygon( holes, gap, m_maxError, ERROR_OUTSIDE );
646  }
647  }
648  }
649 
651 }
BOARD * m_board
Definition: zone_filler.h:123
Plated through hole pad.
int GetThermalReliefGap() const
Definition: zone.h:191
Represent a set of closed polygons.
FOOTPRINTS & Footprints()
Definition: board.h:233
void addKnockout(PAD *aPad, PCB_LAYER_ID aLayer, int aGap, SHAPE_POLY_SET &aHoles)
Add a knockout for a pad.
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
Definition: pad.h:57
bool hasThermalConnection(PAD *pad, const ZONE *aZone)
Return true if the given pad has a thermal connection with the given zone.

References addKnockout(), SHAPE_POLY_SET::BooleanSubtract(), ERROR_OUTSIDE, BOARD::Footprints(), BOARD_CONNECTED_ITEM::GetNetCode(), ZONE::GetThermalReliefGap(), hasThermalConnection(), m_board, m_maxError, pad, SHAPE_POLY_SET::PM_FAST, and PTH.

Referenced by computeRawFilledArea().

◆ SetProgressReporter()

void ZONE_FILLER::SetProgressReporter ( PROGRESS_REPORTER aReporter)

Definition at line 71 of file zone_filler.cpp.

72 {
73  m_progressReporter = aReporter;
74  wxASSERT_MSG( m_commit, "ZONE_FILLER must have a valid commit to call SetProgressReporter" );
75 }
PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:127
COMMIT * m_commit
Definition: zone_filler.h:126

References m_commit, and m_progressReporter.

Referenced by ZONE_FILLER_TOOL::CheckAllZones(), PCB_EDIT_FRAME::Edit_Zone_Params(), ZONE_FILLER_TOOL::FillAllZones(), and ZONE_FILLER_TOOL::ZoneFill().

◆ subtractHigherPriorityZones()

void ZONE_FILLER::subtractHigherPriorityZones ( const ZONE aZone,
PCB_LAYER_ID  aLayer,
SHAPE_POLY_SET aRawFill 
)
private

Removes the outlines of higher-proirity zones with the same net.

These zones should be in charge of the fill parameters within their own outlines.

Definition at line 976 of file zone_filler.cpp.

978 {
979  auto knockoutZoneOutline =
980  [&]( ZONE* aKnockout )
981  {
982  // If the zones share no common layers
983  if( !aKnockout->GetLayerSet().test( aLayer ) )
984  return;
985 
986  if( aKnockout->GetCachedBoundingBox().Intersects( aZone->GetCachedBoundingBox() ) )
987  {
988  aRawFill.BooleanSubtract( *aKnockout->Outline(), SHAPE_POLY_SET::PM_FAST );
989  }
990  };
991 
992  for( ZONE* otherZone : m_board->Zones() )
993  {
994  if( otherZone->GetNetCode() == aZone->GetNetCode()
995  && otherZone->GetPriority() > aZone->GetPriority() )
996  {
997  knockoutZoneOutline( otherZone );
998  }
999  }
1000 
1001  for( FOOTPRINT* footprint : m_board->Footprints() )
1002  {
1003  for( ZONE* otherZone : footprint->Zones() )
1004  {
1005  if( otherZone->GetNetCode() == aZone->GetNetCode()
1006  && otherZone->GetPriority() > aZone->GetPriority() )
1007  {
1008  knockoutZoneOutline( otherZone );
1009  }
1010  }
1011  }
1012 }
ZONES & Zones()
Definition: board.h:239
unsigned GetPriority() const
Definition: zone.h:122
BOARD * m_board
Definition: zone_filler.h:123
const EDA_RECT GetCachedBoundingBox() const
ONLY TO BE USED BY CLIENTS WHICH SET UP THE CACHE!
Definition: zone.h:145
FOOTPRINTS & Footprints()
Definition: board.h:233
Handle a list of polygons defining a copper zone.
Definition: zone.h:56
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.

References SHAPE_POLY_SET::BooleanSubtract(), BOARD::Footprints(), ZONE::GetCachedBoundingBox(), BOARD_CONNECTED_ITEM::GetNetCode(), ZONE::GetPriority(), m_board, SHAPE_POLY_SET::PM_FAST, and BOARD::Zones().

Referenced by computeRawFilledArea().

Member Data Documentation

◆ m_board

◆ m_boardOutline

SHAPE_POLY_SET ZONE_FILLER::m_boardOutline
private

Definition at line 124 of file zone_filler.h.

Referenced by Fill(), and fillSingleZone().

◆ m_brdOutlinesValid

bool ZONE_FILLER::m_brdOutlinesValid
private

Definition at line 125 of file zone_filler.h.

Referenced by Fill(), and fillSingleZone().

◆ m_commit

COMMIT* ZONE_FILLER::m_commit
private

Definition at line 126 of file zone_filler.h.

Referenced by Fill(), and SetProgressReporter().

◆ m_debugZoneFiller

bool ZONE_FILLER::m_debugZoneFiller
private

Definition at line 132 of file zone_filler.h.

Referenced by computeRawFilledArea(), Fill(), fillSingleZone(), IsDebug(), and ZONE_FILLER().

◆ m_maxError

int ZONE_FILLER::m_maxError
private

◆ m_progressReporter

PROGRESS_REPORTER* ZONE_FILLER::m_progressReporter
private

◆ m_worstClearance

int ZONE_FILLER::m_worstClearance
private

Definition at line 130 of file zone_filler.h.

Referenced by buildCopperItemClearances(), and Fill().


The documentation for this class was generated from the following files: