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)
 
void InstallNewProgressReporter (wxWindow *aParent, const wxString &aTitle, int aNumPhases)
 
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 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
 
std::unique_ptr< WX_PROGRESS_REPORTERm_uniqueReporter
 
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 54 of file zone_filler.cpp.

54  :
55  m_board( aBoard ),
56  m_brdOutlinesValid( false ),
57  m_commit( aCommit ),
58  m_progressReporter( nullptr ),
59  m_maxError( ARC_HIGH_DEF ),
60  m_worstClearance( 0 )
61 {
62  // To enable add "DebugZoneFiller=1" to kicad_advanced settings file.
64 }
PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:126
BOARD * m_board
Definition: zone_filler.h:122
COMMIT * m_commit
Definition: zone_filler.h:125
bool m_debugZoneFiller
Definition: zone_filler.h:133
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
bool m_brdOutlinesValid
Definition: zone_filler.h:124
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:131

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

◆ ~ZONE_FILLER()

ZONE_FILLER::~ZONE_FILLER ( )

Definition at line 67 of file zone_filler.cpp.

68 {
69 }

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 1383 of file zone_filler.cpp.

1385 {
1386  // Build grid:
1387 
1388  // obviously line thickness must be > zone min thickness.
1389  // It can happens if a board file was edited by hand by a python script
1390  // Use 1 micron margin to be *sure* there is no issue in Gerber files
1391  // (Gbr file unit = 1 or 10 nm) due to some truncation in coordinates or calculations
1392  // This margin also avoid problems due to rounding coordinates in next calculations
1393  // that can create incorrect polygons
1394  int thickness = std::max( aZone->GetHatchThickness(),
1395  aZone->GetMinThickness() + Millimeter2iu( 0.001 ) );
1396 
1397  int linethickness = thickness - aZone->GetMinThickness();
1398  int gridsize = thickness + aZone->GetHatchGap();
1399  double orientation = aZone->GetHatchOrientation();
1400 
1401  SHAPE_POLY_SET filledPolys = aRawPolys;
1402  // Use a area that contains the rotated bbox by orientation,
1403  // and after rotate the result by -orientation.
1404  if( orientation != 0.0 )
1405  filledPolys.Rotate( M_PI / 180.0 * orientation, VECTOR2I( 0, 0 ) );
1406 
1407  BOX2I bbox = filledPolys.BBox( 0 );
1408 
1409  // Build hole shape
1410  // the hole size is aZone->GetHatchGap(), but because the outline thickness
1411  // is aZone->GetMinThickness(), the hole shape size must be larger
1412  SHAPE_LINE_CHAIN hole_base;
1413  int hole_size = aZone->GetHatchGap() + aZone->GetMinThickness();
1414  VECTOR2I corner( 0, 0 );;
1415  hole_base.Append( corner );
1416  corner.x += hole_size;
1417  hole_base.Append( corner );
1418  corner.y += hole_size;
1419  hole_base.Append( corner );
1420  corner.x = 0;
1421  hole_base.Append( corner );
1422  hole_base.SetClosed( true );
1423 
1424  // Calculate minimal area of a grid hole.
1425  // All holes smaller than a threshold will be removed
1426  double minimal_hole_area = hole_base.Area() * aZone->GetHatchHoleMinArea();
1427 
1428  // Now convert this hole to a smoothed shape:
1429  if( aZone->GetHatchSmoothingLevel() > 0 )
1430  {
1431  // the actual size of chamfer, or rounded corner radius is the half size
1432  // of the HatchFillTypeGap scaled by aZone->GetHatchSmoothingValue()
1433  // aZone->GetHatchSmoothingValue() = 1.0 is the max value for the chamfer or the
1434  // radius of corner (radius = half size of the hole)
1435  int smooth_value = KiROUND( aZone->GetHatchGap()
1436  * aZone->GetHatchSmoothingValue() / 2 );
1437 
1438  // Minimal optimization:
1439  // make smoothing only for reasonable smooth values, to avoid a lot of useless segments
1440  // and if the smooth value is small, use chamfer even if fillet is requested
1441  #define SMOOTH_MIN_VAL_MM 0.02
1442  #define SMOOTH_SMALL_VAL_MM 0.04
1443 
1444  if( smooth_value > Millimeter2iu( SMOOTH_MIN_VAL_MM ) )
1445  {
1446  SHAPE_POLY_SET smooth_hole;
1447  smooth_hole.AddOutline( hole_base );
1448  int smooth_level = aZone->GetHatchSmoothingLevel();
1449 
1450  if( smooth_value < Millimeter2iu( SMOOTH_SMALL_VAL_MM ) && smooth_level > 1 )
1451  smooth_level = 1;
1452 
1453  // Use a larger smooth_value to compensate the outline tickness
1454  // (chamfer is not visible is smooth value < outline thickess)
1455  smooth_value += aZone->GetMinThickness() / 2;
1456 
1457  // smooth_value cannot be bigger than the half size oh the hole:
1458  smooth_value = std::min( smooth_value, aZone->GetHatchGap() / 2 );
1459 
1460  // the error to approximate a circle by segments when smoothing corners by a arc
1461  int error_max = std::max( Millimeter2iu( 0.01 ), smooth_value / 20 );
1462 
1463  switch( smooth_level )
1464  {
1465  case 1:
1466  // Chamfer() uses the distance from a corner to create a end point
1467  // for the chamfer.
1468  hole_base = smooth_hole.Chamfer( smooth_value ).Outline( 0 );
1469  break;
1470 
1471  default:
1472  if( aZone->GetHatchSmoothingLevel() > 2 )
1473  error_max /= 2; // Force better smoothing
1474 
1475  hole_base = smooth_hole.Fillet( smooth_value, error_max ).Outline( 0 );
1476  break;
1477 
1478  case 0:
1479  break;
1480  };
1481  }
1482  }
1483 
1484  // Build holes
1485  SHAPE_POLY_SET holes;
1486 
1487  for( int xx = 0; ; xx++ )
1488  {
1489  int xpos = xx * gridsize;
1490 
1491  if( xpos > bbox.GetWidth() )
1492  break;
1493 
1494  for( int yy = 0; ; yy++ )
1495  {
1496  int ypos = yy * gridsize;
1497 
1498  if( ypos > bbox.GetHeight() )
1499  break;
1500 
1501  // Generate hole
1502  SHAPE_LINE_CHAIN hole( hole_base );
1503  hole.Move( VECTOR2I( xpos, ypos ) );
1504  holes.AddOutline( hole );
1505  }
1506  }
1507 
1508  holes.Move( bbox.GetPosition() );
1509 
1510  if( orientation != 0.0 )
1511  holes.Rotate( -M_PI/180.0 * orientation, VECTOR2I( 0,0 ) );
1512 
1513  DUMP_POLYS_TO_COPPER_LAYER( holes, In10_Cu, "hatch-holes" );
1514 
1515  int outline_margin = aZone->GetMinThickness() * 1.1;
1516 
1517  // Using GetHatchThickness() can look more consistent than GetMinThickness().
1518  if( aZone->GetHatchBorderAlgorithm() && aZone->GetHatchThickness() > outline_margin )
1519  outline_margin = aZone->GetHatchThickness();
1520 
1521  // The fill has already been deflated to ensure GetMinThickness() so we just have to
1522  // account for anything beyond that.
1523  SHAPE_POLY_SET deflatedFilledPolys = aRawPolys;
1524  deflatedFilledPolys.Deflate( outline_margin - aZone->GetMinThickness(), 16 );
1525  holes.BooleanIntersection( deflatedFilledPolys, SHAPE_POLY_SET::PM_FAST );
1526  DUMP_POLYS_TO_COPPER_LAYER( holes, In11_Cu, "fill-clipped-hatch-holes" );
1527 
1528  SHAPE_POLY_SET deflatedOutline = *aZone->Outline();
1529  deflatedOutline.Deflate( outline_margin, 16 );
1530  holes.BooleanIntersection( deflatedOutline, SHAPE_POLY_SET::PM_FAST );
1531  DUMP_POLYS_TO_COPPER_LAYER( holes, In12_Cu, "outline-clipped-hatch-holes" );
1532 
1533  if( aZone->GetNetCode() != 0 )
1534  {
1535  // Vias and pads connected to the zone must not be allowed to become isolated inside
1536  // one of the holes. Effectively this means their copper outline needs to be expanded
1537  // to be at least as wide as the gap so that it is guaranteed to touch at least one
1538  // edge.
1539  EDA_RECT zone_boundingbox = aZone->GetCachedBoundingBox();
1540  SHAPE_POLY_SET aprons;
1541  int min_apron_radius = ( aZone->GetHatchGap() * 10 ) / 19;
1542 
1543  for( PCB_TRACK* track : m_board->Tracks() )
1544  {
1545  if( track->Type() == PCB_VIA_T )
1546  {
1547  PCB_VIA* via = static_cast<PCB_VIA*>( track );
1548 
1549  if( via->GetNetCode() == aZone->GetNetCode()
1550  && via->IsOnLayer( aLayer )
1551  && via->GetBoundingBox().Intersects( zone_boundingbox ) )
1552  {
1553  int r = std::max( min_apron_radius,
1554  via->GetDrillValue() / 2 + outline_margin );
1555 
1556  TransformCircleToPolygon( aprons, via->GetPosition(), r, ARC_HIGH_DEF,
1557  ERROR_OUTSIDE );
1558  }
1559  }
1560  }
1561 
1562  for( FOOTPRINT* footprint : m_board->Footprints() )
1563  {
1564  for( PAD* pad : footprint->Pads() )
1565  {
1566  if( pad->GetNetCode() == aZone->GetNetCode()
1567  && pad->IsOnLayer( aLayer )
1568  && pad->GetBoundingBox().Intersects( zone_boundingbox ) )
1569  {
1570  // What we want is to bulk up the pad shape so that the narrowest bit of
1571  // copper between the hole and the apron edge is at least outline_margin
1572  // wide (and that the apron itself meets min_apron_radius. But that would
1573  // take a lot of code and math, and the following approximation is close
1574  // enough.
1575  int pad_width = std::min( pad->GetSize().x, pad->GetSize().y );
1576  int slot_width = std::min( pad->GetDrillSize().x, pad->GetDrillSize().y );
1577  int min_annular_ring_width = ( pad_width - slot_width ) / 2;
1578  int clearance = std::max( min_apron_radius - pad_width / 2,
1579  outline_margin - min_annular_ring_width );
1580 
1581  clearance = std::max( 0, clearance - linethickness / 2 );
1582  pad->TransformShapeWithClearanceToPolygon( aprons, aLayer, clearance,
1583  ARC_HIGH_DEF, ERROR_OUTSIDE );
1584  }
1585  }
1586  }
1587 
1588  holes.BooleanSubtract( aprons, SHAPE_POLY_SET::PM_FAST );
1589  }
1590  DUMP_POLYS_TO_COPPER_LAYER( holes, In13_Cu, "pad-via-clipped-hatch-holes" );
1591 
1592  // Now filter truncated holes to avoid small holes in pattern
1593  // It happens for holes near the zone outline
1594  for( int ii = 0; ii < holes.OutlineCount(); )
1595  {
1596  double area = holes.Outline( ii ).Area();
1597 
1598  if( area < minimal_hole_area ) // The current hole is too small: remove it
1599  holes.DeletePolygon( ii );
1600  else
1601  ++ii;
1602  }
1603 
1604  // create grid. Use SHAPE_POLY_SET::PM_STRICTLY_SIMPLE to
1605  // generate strictly simple polygons needed by Gerber files and Fracture()
1606  aRawPolys.BooleanSubtract( aRawPolys, holes, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
1607  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In14_Cu, "after-hatching" );
1608 
1609  return true;
1610 }
#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:122
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)
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, 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().

◆ 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 542 of file zone_filler.cpp.

543 {
544  if( aPad->GetShape() == PAD_SHAPE::CUSTOM )
545  {
546  SHAPE_POLY_SET poly;
547  aPad->TransformShapeWithClearanceToPolygon( poly, aLayer, aGap, m_maxError,
548  ERROR_OUTSIDE );
549 
550  // the pad shape in zone can be its convex hull or the shape itself
552  {
553  std::vector<wxPoint> convex_hull;
554  BuildConvexHull( convex_hull, poly );
555 
556  aHoles.NewOutline();
557 
558  for( const wxPoint& pt : convex_hull )
559  aHoles.Append( pt );
560  }
561  else
562  aHoles.Append( poly );
563  }
564  else
565  {
566  aPad->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_maxError,
567  ERROR_OUTSIDE );
568  }
569 }
Represent a set of closed polygons.
PAD_SHAPE GetShape() const
Definition: pad.h:166
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:184
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 576 of file zone_filler.cpp.

578 {
579  switch( aItem->Type() )
580  {
581  case PCB_SHAPE_T:
582  case PCB_TEXT_T:
583  case PCB_FP_SHAPE_T:
584  aItem->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_maxError,
585  ERROR_OUTSIDE, aIgnoreLineWidth );
586  break;
587 
588  case PCB_FP_TEXT_T:
589  {
590  FP_TEXT* text = static_cast<FP_TEXT*>( aItem );
591 
592  if( text->IsVisible() )
593  {
594  text->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_maxError,
595  ERROR_OUTSIDE, aIgnoreLineWidth );
596  }
597  }
598  break;
599 
600  default:
601  break;
602  }
603 }
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:143
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 655 of file zone_filler.cpp.

657 {
658  long ticker = 0;
659 
660  auto checkForCancel =
661  [&ticker]( PROGRESS_REPORTER* aReporter ) -> bool
662  {
663  return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
664  };
665 
666  // A small extra clearance to be sure actual track clearances are not smaller than
667  // requested clearance due to many approximations in calculations, like arc to segment
668  // approx, rounding issues, etc.
669  int extra_margin = Millimeter2iu( ADVANCED_CFG::GetCfg().m_ExtraClearance );
670 
672  int zone_clearance = aZone->GetLocalClearance();
673  EDA_RECT zone_boundingbox = aZone->GetCachedBoundingBox();
674 
675  // Items outside the zone bounding box are skipped, so it needs to be inflated by the
676  // largest clearance value found in the netclasses and rules
677  zone_boundingbox.Inflate( m_worstClearance + extra_margin );
678 
679  auto evalRulesForItems =
680  [&bds]( DRC_CONSTRAINT_T aConstraint, const BOARD_ITEM* a, const BOARD_ITEM* b,
681  PCB_LAYER_ID aEvalLayer ) -> int
682  {
683  auto c = bds.m_DRCEngine->EvalRules( aConstraint, a, b, aEvalLayer );
684  return c.Value().Min();
685  };
686 
687  // Add non-connected pad clearances
688  //
689  auto knockoutPadClearance =
690  [&]( PAD* aPad )
691  {
692  if( aPad->GetBoundingBox().Intersects( zone_boundingbox ) )
693  {
694  int gap;
695 
696  // For pads having the same netcode as the zone, the net clearance has no
697  // meaning so use the greater of the zone clearance and the thermal relief.
698  if( aPad->GetNetCode() > 0 && aPad->GetNetCode() == aZone->GetNetCode() )
699  gap = std::max( zone_clearance, aZone->GetThermalReliefGap( aPad ) );
700  else
701  gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aPad, aLayer );
702 
703  gap += extra_margin;
704 
705  // If the pad isn't on the current layer but has a hole, knock out the hole.
706  if( !aPad->FlashLayer( aLayer ) )
707  {
708  if( aPad->GetDrillSize().x == 0 && aPad->GetDrillSize().y == 0 )
709  return;
710 
711  // Note: drill size represents finish size, which means the actual hole
712  // size is the plating thickness larger.
713  if( aPad->GetAttribute() == PAD_ATTRIB::PTH )
714  gap += aPad->GetBoard()->GetDesignSettings().GetHolePlatingThickness();
715 
716  aPad->TransformHoleWithClearanceToPolygon( aHoles, gap, m_maxError,
717  ERROR_OUTSIDE );
718  }
719  else
720  {
721  addKnockout( aPad, aLayer, gap, aHoles );
722  }
723  }
724  };
725 
726  for( FOOTPRINT* footprint : m_board->Footprints() )
727  {
728  for( PAD* pad : footprint->Pads() )
729  {
730  if( checkForCancel( m_progressReporter ) )
731  return;
732 
733  if( pad->GetNetCode() != aZone->GetNetCode()
734  || pad->GetNetCode() <= 0
735  || aZone->GetPadConnection( pad ) == ZONE_CONNECTION::NONE )
736  {
737  knockoutPadClearance( pad );
738  }
739  }
740  }
741 
742  // Add non-connected track clearances
743  //
744  auto knockoutTrackClearance =
745  [&]( PCB_TRACK* aTrack )
746  {
747  if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
748  {
749  int gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aTrack, aLayer );
750 
751  gap += extra_margin;
752 
753  if( aTrack->Type() == PCB_VIA_T )
754  {
755  PCB_VIA* via = static_cast<PCB_VIA*>( aTrack );
756 
757  if( !via->FlashLayer( aLayer ) && via->GetNetCode() != aZone->GetNetCode() )
758  {
759  int radius = via->GetDrillValue() / 2 + bds.GetHolePlatingThickness();
760  TransformCircleToPolygon( aHoles, via->GetPosition(), radius + gap,
762  }
763  else
764  {
765  via->TransformShapeWithClearanceToPolygon( aHoles, aLayer, gap,
767  }
768  }
769  else
770  {
771  // Gives more clearance to arcs (the arc to area drc test is not perfect)
772  // extra_margin is not enough here
773  // This is a workaround, that can be removed when (if?) the DRC arcs
774  // issues are fixed
775  // The root cause is the fact the DRC approximates the arc shape
776  // by a segmentlist with a error = +- SHAPE_ARC::DefaultAccuracyForPCB()/2
777  // and the arc to polygons approximation also creates approximations when
778  // filling the zone
779  if( aTrack->Type() == PCB_ARC_T )
781 
782  aTrack->TransformShapeWithClearanceToPolygon( aHoles, aLayer, gap,
784  }
785  }
786  };
787 
788  for( PCB_TRACK* track : m_board->Tracks() )
789  {
790  if( !track->IsOnLayer( aLayer ) )
791  continue;
792 
793  if( track->GetNetCode() == aZone->GetNetCode() && ( aZone->GetNetCode() != 0) )
794  continue;
795 
796  if( checkForCancel( m_progressReporter ) )
797  return;
798 
799  knockoutTrackClearance( track );
800  }
801 
802  // Add graphic item clearances. They are by definition unconnected, and have no clearance
803  // definitions of their own.
804  //
805  auto knockoutGraphicClearance =
806  [&]( BOARD_ITEM* aItem )
807  {
808  // A item on the Edge_Cuts or Margin is always seen as on any layer:
809  if( aItem->IsOnLayer( aLayer )
810  || aItem->IsOnLayer( Edge_Cuts )
811  || aItem->IsOnLayer( Margin ) )
812  {
813  if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
814  {
815  int gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aItem, aLayer );
816 
817  if( aItem->IsOnLayer( Edge_Cuts ) )
818  {
819  gap = std::max( gap, evalRulesForItems( EDGE_CLEARANCE_CONSTRAINT,
820  aZone, aItem, Edge_Cuts ) );
821  }
822 
823  if( aItem->IsOnLayer( Margin ) )
824  {
825  gap = std::max( gap, evalRulesForItems( EDGE_CLEARANCE_CONSTRAINT,
826  aZone, aItem, Margin ) );
827  }
828 
829  addKnockout( aItem, aLayer, gap, aItem->IsOnLayer( Edge_Cuts ), aHoles );
830  }
831  }
832  };
833 
834  for( FOOTPRINT* footprint : m_board->Footprints() )
835  {
836  bool skipFootprint = false;
837 
838  knockoutGraphicClearance( &footprint->Reference() );
839  knockoutGraphicClearance( &footprint->Value() );
840 
841  // Don't knock out holes in zones that share a net
842  // with a nettie footprint
843  if( footprint->IsNetTie() )
844  {
845  for( PAD* pad : footprint->Pads() )
846  {
847  if( aZone->GetNetCode() == pad->GetNetCode() )
848  {
849  skipFootprint = true;
850  break;
851  }
852  }
853  }
854 
855  if( skipFootprint )
856  continue;
857 
858  for( BOARD_ITEM* item : footprint->GraphicalItems() )
859  {
860  if( checkForCancel( m_progressReporter ) )
861  return;
862 
863  knockoutGraphicClearance( item );
864  }
865  }
866 
867  for( BOARD_ITEM* item : m_board->Drawings() )
868  {
869  if( checkForCancel( m_progressReporter ) )
870  return;
871 
872  knockoutGraphicClearance( item );
873  }
874 
875  // Add non-connected zone clearances
876  //
877  auto knockoutZoneClearance =
878  [&]( ZONE* aKnockout )
879  {
880  // If the zones share no common layers
881  if( !aKnockout->GetLayerSet().test( aLayer ) )
882  return;
883 
884  if( aKnockout->GetCachedBoundingBox().Intersects( zone_boundingbox ) )
885  {
886  if( aKnockout->GetIsRuleArea() )
887  {
888  // Keepouts use outline with no clearance
889  aKnockout->TransformSmoothedOutlineToPolygon( aHoles, 0, nullptr );
890  }
891  else if( bds.m_ZoneFillVersion == 5 )
892  {
893  // 5.x used outline with clearance
894  int gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aKnockout,
895  aLayer );
896 
897  aKnockout->TransformSmoothedOutlineToPolygon( aHoles, gap, nullptr );
898  }
899  else
900  {
901  // 6.0 uses filled areas with clearance
902  int gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aKnockout,
903  aLayer );
904 
905  SHAPE_POLY_SET poly;
906  aKnockout->TransformShapeWithClearanceToPolygon( poly, aLayer, gap,
907  m_maxError,
908  ERROR_OUTSIDE );
909  aHoles.Append( poly );
910  }
911  }
912  };
913 
914  for( ZONE* otherZone : m_board->Zones() )
915  {
916  if( checkForCancel( m_progressReporter ) )
917  return;
918 
919  if( otherZone->GetNetCode() != aZone->GetNetCode()
920  && otherZone->GetPriority() > aZone->GetPriority() )
921  {
922  knockoutZoneClearance( otherZone );
923  }
924  else if( otherZone->GetIsRuleArea() && otherZone->GetDoNotAllowCopperPour() )
925  {
926  knockoutZoneClearance( otherZone );
927  }
928  }
929 
930  for( FOOTPRINT* footprint : m_board->Footprints() )
931  {
932  for( ZONE* otherZone : footprint->Zones() )
933  {
934  if( checkForCancel( m_progressReporter ) )
935  return;
936 
937  if( otherZone->GetNetCode() != aZone->GetNetCode()
938  && otherZone->GetPriority() > aZone->GetPriority() )
939  {
940  knockoutZoneClearance( otherZone );
941  }
942  else if( otherZone->GetIsRuleArea() && otherZone->GetDoNotAllowCopperPour() )
943  {
944  knockoutZoneClearance( otherZone );
945  }
946  }
947  }
948 
950 }
int m_ZoneFillVersion
Option to select different fill algorithms.
PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:126
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:80
BOARD * m_board
Definition: zone_filler.h:122
A progress reporter for use in multi-threaded environments.
int GetHolePlatingThickness() const
Pad & via drills are finish size.
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:97
static double DefaultAccuracyForPCB()
Definition: shape_arc.h:194
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:588
Plated through hole pad.
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:494
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:64
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:774
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:131
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 addKnockout(), SHAPE_POLY_SET::Append(), CLEARANCE_CONSTRAINT, SHAPE_ARC::DefaultAccuracyForPCB(), BOARD::Drawings(), EDGE_CLEARANCE_CONSTRAINT, Edge_Cuts, ERROR_OUTSIDE, BOARD::Footprints(), ZONE::GetCachedBoundingBox(), ADVANCED_CFG::GetCfg(), BOARD::GetDesignSettings(), BOARD_DESIGN_SETTINGS::GetHolePlatingThickness(), ZONE::GetLocalClearance(), BOARD_CONNECTED_ITEM::GetNetCode(), ZONE::GetPadConnection(), ZONE::GetPriority(), ZONE::GetThermalReliefGap(), 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_ARC_T, PCB_VIA_T, SHAPE_POLY_SET::PM_FAST, PTH, 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 1265 of file zone_filler.cpp.

1267 {
1268  auto zoneBB = aZone->GetCachedBoundingBox();
1269  int zone_clearance = aZone->GetLocalClearance();
1270  int biggest_clearance = m_board->GetDesignSettings().GetBiggestClearanceValue();
1271  biggest_clearance = std::max( biggest_clearance, zone_clearance );
1272  zoneBB.Inflate( biggest_clearance );
1273 
1274  // Is a point on the boundary of the polygon inside or outside? This small epsilon lets
1275  // us avoid the question.
1276  int epsilon = KiROUND( IU_PER_MM * 0.04 ); // about 1.5 mil
1277 
1278  for( FOOTPRINT* footprint : m_board->Footprints() )
1279  {
1280  for( PAD* pad : footprint->Pads() )
1281  {
1282  if( !hasThermalConnection( pad, aZone ) )
1283  continue;
1284 
1285  // We currently only connect to pads, not pad holes
1286  if( !pad->IsOnLayer( aLayer ) )
1287  continue;
1288 
1289  int thermalReliefGap = aZone->GetThermalReliefGap( pad );
1290 
1291  // Calculate thermal bridge half width
1292  int spoke_w = aZone->GetThermalReliefSpokeWidth( pad );
1293  // Avoid spoke_w bigger than the smaller pad size, because
1294  // it is not possible to create stubs bigger than the pad.
1295  // Possible refinement: have a separate size for vertical and horizontal stubs
1296  spoke_w = std::min( spoke_w, pad->GetSize().x );
1297  spoke_w = std::min( spoke_w, pad->GetSize().y );
1298 
1299  // Cannot create stubs having a width < zone min thickness
1300  if( spoke_w < aZone->GetMinThickness() )
1301  continue;
1302 
1303  int spoke_half_w = spoke_w / 2;
1304 
1305  // Quick test here to possibly save us some work
1306  BOX2I itemBB = pad->GetBoundingBox();
1307  itemBB.Inflate( thermalReliefGap + epsilon );
1308 
1309  if( !( itemBB.Intersects( zoneBB ) ) )
1310  continue;
1311 
1312  // Thermal spokes consist of segments from the pad center to points just outside
1313  // the thermal relief.
1314  //
1315  // We use the bounding-box to lay out the spokes, but for this to work the
1316  // bounding box has to be built at the same rotation as the spokes.
1317  // We have to use a dummy pad to avoid dirtying the cached shapes
1318  wxPoint shapePos = pad->ShapePos();
1319  double padAngle = pad->GetOrientation();
1320  PAD dummy_pad( *pad );
1321  dummy_pad.SetOrientation( 0.0 );
1322 
1323  // Spokes are from center of pad, not from hole
1324  dummy_pad.SetPosition( -pad->GetOffset() );
1325 
1326  BOX2I reliefBB = dummy_pad.GetBoundingBox();
1327  reliefBB.Inflate( thermalReliefGap + epsilon );
1328 
1329  // For circle pads, the thermal spoke orientation is 45 deg
1330  if( pad->GetShape() == PAD_SHAPE::CIRCLE )
1331  padAngle = s_RoundPadThermalSpokeAngle;
1332 
1333  for( int i = 0; i < 4; i++ )
1334  {
1335  SHAPE_LINE_CHAIN spoke;
1336  switch( i )
1337  {
1338  case 0: // lower stub
1339  spoke.Append( +spoke_half_w, -spoke_half_w );
1340  spoke.Append( -spoke_half_w, -spoke_half_w );
1341  spoke.Append( -spoke_half_w, reliefBB.GetBottom() );
1342  spoke.Append( 0, reliefBB.GetBottom() ); // test pt
1343  spoke.Append( +spoke_half_w, reliefBB.GetBottom() );
1344  break;
1345 
1346  case 1: // upper stub
1347  spoke.Append( +spoke_half_w, spoke_half_w );
1348  spoke.Append( -spoke_half_w, spoke_half_w );
1349  spoke.Append( -spoke_half_w, reliefBB.GetTop() );
1350  spoke.Append( 0, reliefBB.GetTop() ); // test pt
1351  spoke.Append( +spoke_half_w, reliefBB.GetTop() );
1352  break;
1353 
1354  case 2: // right stub
1355  spoke.Append( -spoke_half_w, spoke_half_w );
1356  spoke.Append( -spoke_half_w, -spoke_half_w );
1357  spoke.Append( reliefBB.GetRight(), -spoke_half_w );
1358  spoke.Append( reliefBB.GetRight(), 0 ); // test pt
1359  spoke.Append( reliefBB.GetRight(), spoke_half_w );
1360  break;
1361 
1362  case 3: // left stub
1363  spoke.Append( spoke_half_w, spoke_half_w );
1364  spoke.Append( spoke_half_w, -spoke_half_w );
1365  spoke.Append( reliefBB.GetLeft(), -spoke_half_w );
1366  spoke.Append( reliefBB.GetLeft(), 0 ); // test pt
1367  spoke.Append( reliefBB.GetLeft(), spoke_half_w );
1368  break;
1369  }
1370 
1371  spoke.Rotate( -DECIDEG2RAD( padAngle ) );
1372  spoke.Move( shapePos );
1373 
1374  spoke.SetClosed( true );
1375  spoke.GenerateBBoxCache();
1376  aSpokesList.push_back( std::move( spoke ) );
1377  }
1378  }
1379  }
1380 }
BOARD * m_board
Definition: zone_filler.h:122
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:51
coord_type GetRight() const
Definition: box2.h:182
coord_type GetBottom() const
Definition: box2.h:183
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:588
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:494
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 1020 of file zone_filler.cpp.

1025 {
1027 
1028  // Features which are min_width should survive pruning; features that are *less* than
1029  // min_width should not. Therefore we subtract epsilon from the min_width when
1030  // deflating/inflating.
1031  int half_min_width = aZone->GetMinThickness() / 2;
1032  int epsilon = Millimeter2iu( 0.001 );
1033  int numSegs = GetArcToSegmentCount( half_min_width, m_maxError, 360.0 );
1034 
1035  // Solid polygons are deflated and inflated during calculations. Deflating doesn't cause
1036  // issues, but inflate is tricky as it can create excessively long and narrow spikes for
1037  // acute angles.
1038  // ALLOW_ACUTE_CORNERS cannot be used due to the spike problem.
1039  // CHAMFER_ACUTE_CORNERS is tempting, but can still produce spikes in some unusual
1040  // circumstances (https://gitlab.com/kicad/code/kicad/-/issues/5581).
1041  // It's unclear if ROUND_ACUTE_CORNERS would have the same issues, but is currently avoided
1042  // as a "less-safe" option.
1043  // ROUND_ALL_CORNERS produces the uniformly nicest shapes, but also a lot of segments.
1044  // CHAMFER_ALL_CORNERS improves the segment count.
1047 
1048  std::deque<SHAPE_LINE_CHAIN> thermalSpokes;
1049  SHAPE_POLY_SET clearanceHoles;
1050 
1051  aRawPolys = aSmoothedOutline;
1052  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In1_Cu, "smoothed-outline" );
1053 
1055  return false;
1056 
1057  knockoutThermalReliefs( aZone, aLayer, aRawPolys );
1058  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In2_Cu, "minus-thermal-reliefs" );
1059 
1061  return false;
1062 
1063  buildCopperItemClearances( aZone, aLayer, clearanceHoles );
1064  DUMP_POLYS_TO_COPPER_LAYER( clearanceHoles, In3_Cu, "clearance-holes" );
1065 
1067  return false;
1068 
1069  buildThermalSpokes( aZone, aLayer, thermalSpokes );
1070 
1072  return false;
1073 
1074  // Create a temporary zone that we can hit-test spoke-ends against. It's only temporary
1075  // because the "real" subtract-clearance-holes has to be done after the spokes are added.
1076  static const bool USE_BBOX_CACHES = true;
1077  SHAPE_POLY_SET testAreas = aRawPolys;
1078  testAreas.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );
1079  DUMP_POLYS_TO_COPPER_LAYER( testAreas, In4_Cu, "minus-clearance-holes" );
1080 
1081  // Prune features that don't meet minimum-width criteria
1082  if( half_min_width - epsilon > epsilon )
1083  {
1084  testAreas.Deflate( half_min_width - epsilon, numSegs, fastCornerStrategy );
1085  DUMP_POLYS_TO_COPPER_LAYER( testAreas, In5_Cu, "spoke-test-deflated" );
1086 
1087  testAreas.Inflate( half_min_width - epsilon, numSegs, fastCornerStrategy );
1088  DUMP_POLYS_TO_COPPER_LAYER( testAreas, In6_Cu, "spoke-test-reinflated" );
1089  }
1090 
1092  return false;
1093 
1094  // Spoke-end-testing is hugely expensive so we generate cached bounding-boxes to speed
1095  // things up a bit.
1096  testAreas.BuildBBoxCaches();
1097  int interval = 0;
1098 
1099  SHAPE_POLY_SET debugSpokes;
1100 
1101  for( const SHAPE_LINE_CHAIN& spoke : thermalSpokes )
1102  {
1103  const VECTOR2I& testPt = spoke.CPoint( 3 );
1104 
1105  // Hit-test against zone body
1106  if( testAreas.Contains( testPt, -1, 1, USE_BBOX_CACHES ) )
1107  {
1108  if( m_debugZoneFiller )
1109  debugSpokes.AddOutline( spoke );
1110 
1111  aRawPolys.AddOutline( spoke );
1112  continue;
1113  }
1114 
1115  if( interval++ > 400 )
1116  {
1118  return false;
1119 
1120  interval = 0;
1121  }
1122 
1123  // Hit-test against other spokes
1124  for( const SHAPE_LINE_CHAIN& other : thermalSpokes )
1125  {
1126  if( &other != &spoke && other.PointInside( testPt, 1, USE_BBOX_CACHES ) )
1127  {
1128  if( m_debugZoneFiller )
1129  debugSpokes.AddOutline( spoke );
1130 
1131  aRawPolys.AddOutline( spoke );
1132  break;
1133  }
1134  }
1135  }
1136 
1137  DUMP_POLYS_TO_COPPER_LAYER( debugSpokes, In7_Cu, "spokes" );
1138 
1140  return false;
1141 
1142  aRawPolys.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );
1143  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In8_Cu, "after-spoke-trimming" );
1144 
1145  // Prune features that don't meet minimum-width criteria
1146  if( half_min_width - epsilon > epsilon )
1147  aRawPolys.Deflate( half_min_width - epsilon, numSegs, cornerStrategy );
1148 
1149  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In9_Cu, "deflated" );
1150 
1152  return false;
1153 
1154  // Now remove the non filled areas due to the hatch pattern
1155  if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
1156  {
1157  if( !addHatchFillTypeOnZone( aZone, aLayer, aDebugLayer, aRawPolys ) )
1158  return false;
1159  }
1160 
1162  return false;
1163 
1164  // Re-inflate after pruning of areas that don't meet minimum-width criteria
1165  if( aZone->GetFilledPolysUseThickness() )
1166  {
1167  // If we're stroking the zone with a min_width stroke then this will naturally inflate
1168  // the zone by half_min_width
1169  }
1170  else if( half_min_width - epsilon > epsilon )
1171  {
1172  aRawPolys.Inflate( half_min_width - epsilon, numSegs, cornerStrategy );
1173  }
1174 
1175  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In15_Cu, "after-reinflating" );
1176 
1177  // Ensure additive changes (thermal stubs and particularly inflating acute corners) do not
1178  // add copper outside the zone boundary or inside the clearance holes
1179  aRawPolys.BooleanIntersection( aMaxExtents, SHAPE_POLY_SET::PM_FAST );
1180  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In16_Cu, "after-trim-to-outline" );
1181  aRawPolys.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );
1182  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In17_Cu, "after-trim-to-clearance-holes" );
1183 
1184  // Lastly give any same-net but higher-priority zones control over their own area.
1185  subtractHigherPriorityZones( aZone, aLayer, aRawPolys );
1186  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In18_Cu, "minus-higher-priority-zones" );
1187 
1188  aRawPolys.Fracture( SHAPE_POLY_SET::PM_FAST );
1189  return true;
1190 }
#define DUMP_POLYS_TO_COPPER_LAYER(a, b, c)
All angles are chamfered.
PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:126
BOARD * m_board
Definition: zone_filler.h:122
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:588
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 ...
bool IsCancelled() const
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:133
void subtractHigherPriorityZones(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aRawFill)
Removes the outlines of higher-proirity zones with the same net.
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 87 of file zone_filler.cpp.

88 {
89  std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
90  std::vector<CN_ZONE_ISOLATED_ISLAND_LIST> islandsList;
91 
92  std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
93 
94  // Rebuild just in case. This really needs to be reliable.
95  connectivity->Clear();
96  connectivity->Build( m_board, m_progressReporter );
97 
99 
101 
102  if( m_progressReporter )
103  {
104  m_progressReporter->Report( aCheck ? _( "Checking zone fills..." )
105  : _( "Building zone fills..." ) );
106  m_progressReporter->SetMaxProgress( aZones.size() );
108  }
109 
110  // The board outlines is used to clip solid areas inside the board (when outlines are valid)
113 
114  // Update and cache zone bounding boxes and pad effective shapes so that we don't have to
115  // make them thread-safe.
116  for( ZONE* zone : m_board->Zones() )
117  {
118  zone->CacheBoundingBox();
119  m_worstClearance = std::max( m_worstClearance, zone->GetLocalClearance() );
120  }
121 
122  for( FOOTPRINT* footprint : m_board->Footprints() )
123  {
124  for( PAD* pad : footprint->Pads() )
125  {
126  if( pad->IsDirty() )
127  {
128  pad->BuildEffectiveShapes( UNDEFINED_LAYER );
129  pad->BuildEffectivePolygon();
130  }
131 
132  m_worstClearance = std::max( m_worstClearance, pad->GetLocalClearance() );
133  }
134 
135  for( ZONE* zone : footprint->Zones() )
136  {
137  zone->CacheBoundingBox();
138  m_worstClearance = std::max( m_worstClearance, zone->GetLocalClearance() );
139  }
140 
141  // Rules may depend on insideCourtyard() or other expressions
142  footprint->BuildPolyCourtyards();
143  }
144 
145  // Sort by priority to reduce deferrals waiting on higher priority zones.
146  std::sort( aZones.begin(), aZones.end(),
147  []( const ZONE* lhs, const ZONE* rhs )
148  {
149  return lhs->GetPriority() > rhs->GetPriority();
150  } );
151 
152  for( ZONE* zone : aZones )
153  {
154  // Rule areas are not filled
155  if( zone->GetIsRuleArea() )
156  continue;
157 
158  if( m_commit )
159  m_commit->Modify( zone );
160 
161  // calculate the hash value for filled areas. it will be used later
162  // to know if the current filled areas are up to date
163  for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
164  {
165  zone->BuildHashValue( layer );
166 
167  // Add the zone to the list of zones to test or refill
168  toFill.emplace_back( std::make_pair( zone, layer ) );
169  }
170 
171  islandsList.emplace_back( CN_ZONE_ISOLATED_ISLAND_LIST( zone ) );
172 
173  // Remove existing fill first to prevent drawing invalid polygons
174  // on some platforms
175  zone->UnFill();
176 
177  zone->SetFillVersion( bds.m_ZoneFillVersion );
178  }
179 
180  size_t cores = std::thread::hardware_concurrency();
181  std::atomic<size_t> nextItem;
182 
183  auto check_fill_dependency =
184  [&]( ZONE* aZone, PCB_LAYER_ID aLayer, ZONE* aOtherZone ) -> bool
185  {
186  // Check to see if we have to knock-out the filled areas of a higher-priority
187  // zone. If so we have to wait until said zone is filled before we can fill.
188 
189  // If the other zone is already filled then we're good-to-go
190  if( aOtherZone->GetFillFlag( aLayer ) )
191  return false;
192 
193  // Even if keepouts exclude copper pours the exclusion is by outline, not by
194  // filled area, so we're good-to-go here too.
195  if( aOtherZone->GetIsRuleArea() )
196  return false;
197 
198  // If the zones share no common layers
199  if( !aOtherZone->GetLayerSet().test( aLayer ) )
200  return false;
201 
202  if( aOtherZone->GetPriority() <= aZone->GetPriority() )
203  return false;
204 
205  // Same-net zones always use outline to produce predictable results
206  if( aOtherZone->GetNetCode() == aZone->GetNetCode() )
207  return false;
208 
209  // A higher priority zone is found: if we intersect and it's not filled yet
210  // then we have to wait.
211  EDA_RECT inflatedBBox = aZone->GetCachedBoundingBox();
212  inflatedBBox.Inflate( m_worstClearance );
213 
214  return inflatedBBox.Intersects( aOtherZone->GetCachedBoundingBox() );
215  };
216 
217  auto fill_lambda =
218  [&]( PROGRESS_REPORTER* aReporter )
219  {
220  size_t num = 0;
221 
222  for( size_t i = nextItem++; i < toFill.size(); i = nextItem++ )
223  {
224  PCB_LAYER_ID layer = toFill[i].second;
225  ZONE* zone = toFill[i].first;
226  bool canFill = true;
227 
228  // Check for any fill dependencies. If our zone needs to be clipped by
229  // another zone then we can't fill until that zone is filled.
230  for( ZONE* otherZone : aZones )
231  {
232  if( otherZone == zone )
233  continue;
234 
235  if( check_fill_dependency( zone, layer, otherZone ) )
236  {
237  canFill = false;
238  break;
239  }
240  }
241 
243  break;
244 
245  if( !canFill )
246  continue;
247 
248  // Now we're ready to fill.
249  SHAPE_POLY_SET rawPolys, finalPolys;
250  fillSingleZone( zone, layer, rawPolys, finalPolys );
251 
252  std::unique_lock<std::mutex> zoneLock( zone->GetLock() );
253 
254  zone->SetRawPolysList( layer, rawPolys );
255  zone->SetFilledPolysList( layer, finalPolys );
256  zone->SetFillFlag( layer, true );
257 
258  if( m_progressReporter )
260 
261  num++;
262  }
263 
264  return num;
265  };
266 
267  while( !toFill.empty() )
268  {
269  size_t parallelThreadCount = std::min( cores, toFill.size() );
270  std::vector<std::future<size_t>> returns( parallelThreadCount );
271 
272  nextItem = 0;
273 
274  if( parallelThreadCount <= 1 )
275  fill_lambda( m_progressReporter );
276  else
277  {
278  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
279  returns[ii] = std::async( std::launch::async, fill_lambda, m_progressReporter );
280 
281  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
282  {
283  // Here we balance returns with a 100ms timeout to allow UI updating
284  std::future_status status;
285  do
286  {
287  if( m_progressReporter )
289 
290  status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) );
291  } while( status != std::future_status::ready );
292  }
293  }
294 
295  toFill.erase( std::remove_if( toFill.begin(), toFill.end(),
296  [&] ( const std::pair<ZONE*, PCB_LAYER_ID> pair ) -> bool
297  {
298  return pair.first->GetFillFlag( pair.second );
299  } ),
300  toFill.end() );
301 
303  break;
304  }
305 
306  // Now update the connectivity to check for copper islands
307  if( m_progressReporter )
308  {
310  return false;
311 
313  m_progressReporter->Report( _( "Removing isolated copper islands..." ) );
315  }
316 
317  connectivity->SetProgressReporter( m_progressReporter );
318  connectivity->FindIsolatedCopperIslands( islandsList );
319  connectivity->SetProgressReporter( nullptr );
320 
322  return false;
323 
324  for( ZONE* zone : aZones )
325  {
326  // Keepout zones are not filled
327  if( zone->GetIsRuleArea() )
328  continue;
329 
330  zone->SetIsFilled( true );
331  }
332 
333  // Now remove insulated copper islands
334  for( CN_ZONE_ISOLATED_ISLAND_LIST& zone : islandsList )
335  {
336  for( PCB_LAYER_ID layer : zone.m_zone->GetLayerSet().Seq() )
337  {
339  continue;
340 
341  if( !zone.m_islands.count( layer ) )
342  continue;
343 
344  std::vector<int>& islands = zone.m_islands.at( layer );
345 
346  // The list of polygons to delete must be explored from last to first in list,
347  // to allow deleting a polygon from list without breaking the remaining of the list
348  std::sort( islands.begin(), islands.end(), std::greater<int>() );
349 
350  SHAPE_POLY_SET poly = zone.m_zone->GetFilledPolysList( layer );
351  long long int minArea = zone.m_zone->GetMinIslandArea();
352  ISLAND_REMOVAL_MODE mode = zone.m_zone->GetIslandRemovalMode();
353 
354  for( int idx : islands )
355  {
356  SHAPE_LINE_CHAIN& outline = poly.Outline( idx );
357 
358  if( mode == ISLAND_REMOVAL_MODE::ALWAYS )
359  poly.DeletePolygon( idx );
360  else if ( mode == ISLAND_REMOVAL_MODE::AREA && outline.Area() < minArea )
361  poly.DeletePolygon( idx );
362  else
363  zone.m_zone->SetIsIsland( layer, idx );
364  }
365 
366  zone.m_zone->SetFilledPolysList( layer, poly );
367  zone.m_zone->CalculateFilledArea();
368 
370  return false;
371  }
372  }
373 
374  // Now remove islands outside the board edge
375  for( ZONE* zone : aZones )
376  {
377  LSET zoneCopperLayers = zone->GetLayerSet() & LSET::AllCuMask( MAX_CU_LAYERS );
378 
379  for( PCB_LAYER_ID layer : zoneCopperLayers.Seq() )
380  {
382  continue;
383 
384  SHAPE_POLY_SET poly = zone->GetFilledPolysList( layer );
385 
386  for( int ii = poly.OutlineCount() - 1; ii >= 0; ii-- )
387  {
388  std::vector<SHAPE_LINE_CHAIN>& island = poly.Polygon( ii );
389 
390  if( island.empty() || !m_boardOutline.Contains( island.front().CPoint( 0 ) ) )
391  poly.DeletePolygon( ii );
392  }
393 
394  zone->SetFilledPolysList( layer, poly );
395  zone->CalculateFilledArea();
396 
398  return false;
399  }
400  }
401 
402  if( aCheck )
403  {
404  bool outOfDate = false;
405 
406  for( ZONE* zone : aZones )
407  {
408  // Keepout zones are not filled
409  if( zone->GetIsRuleArea() )
410  continue;
411 
412  for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
413  {
414  MD5_HASH was = zone->GetHashValue( layer );
415  zone->CacheTriangulation( layer );
416  zone->BuildHashValue( layer );
417  MD5_HASH is = zone->GetHashValue( layer );
418 
419  if( is != was )
420  outOfDate = true;
421  }
422  }
423 
424  if( outOfDate )
425  {
426  KIDIALOG dlg( aParent, _( "Zone fills are out-of-date. Refill?" ),
427  _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
428  dlg.SetOKCancelLabels( _( "Refill" ), _( "Continue without Refill" ) );
429  dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
430 
431  if( dlg.ShowModal() == wxID_CANCEL )
432  return false;
433  }
434  }
435 
436  if( m_progressReporter )
437  {
439  m_progressReporter->Report( _( "Performing polygon fills..." ) );
440  m_progressReporter->SetMaxProgress( islandsList.size() );
441  }
442 
443  nextItem = 0;
444 
445  auto tri_lambda =
446  [&]( PROGRESS_REPORTER* aReporter ) -> size_t
447  {
448  size_t num = 0;
449 
450  for( size_t i = nextItem++; i < islandsList.size(); i = nextItem++ )
451  {
452  islandsList[i].m_zone->CacheTriangulation();
453  num++;
454 
455  if( m_progressReporter )
456  {
458 
460  break;
461  }
462  }
463 
464  return num;
465  };
466 
467  size_t parallelThreadCount = std::min( cores, islandsList.size() );
468  std::vector<std::future<size_t>> returns( parallelThreadCount );
469 
470  if( parallelThreadCount <= 1 )
471  tri_lambda( m_progressReporter );
472  else
473  {
474  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
475  returns[ii] = std::async( std::launch::async, tri_lambda, m_progressReporter );
476 
477  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
478  {
479  // Here we balance returns with a 100ms timeout to allow UI updating
480  std::future_status status;
481  do
482  {
483  if( m_progressReporter )
484  {
486 
488  break;
489  }
490 
491  status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) );
492  } while( status != std::future_status::ready );
493  }
494  }
495 
496  if( m_progressReporter )
497  {
499  return false;
500 
503  }
504 
505  return true;
506 }
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:750
virtual void AdvancePhase()
Use the next available virtual zone of the dialog progress bar.
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
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:1108
int OutlineCount() const
Return the number of vertices in a given outline/hole.
PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:126
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:1898
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:122
A progress reporter 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:573
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.cpp:291
virtual void Report(const wxString &aMessage)
Display aMessage in the progress bar dialog.
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:382
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:588
void DeletePolygon(int aIdx)
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:502
bool IsCancelled() const
#define MAX_CU_LAYERS
Definition: layer_ids.h:146
COMMIT * m_commit
Definition: zone_filler.h:125
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:391
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:64
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:133
bool KeepRefreshing(bool aWait=false)
Update the UI dialog.
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:123
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:124
double CalculateFilledArea()
Compute the area currently occupied by the zone fill.
Definition: zone.cpp:1254
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 SetMaxProgress(int aMaxProgress)
Fix the value that gives the 100 percent progress bar length (inside the current virtual zone).
void AdvanceProgress()
Increment the progress bar length (inside the current virtual zone).
A structure used for calculating isolated islands on a given zone across all its layers.
int m_worstClearance
Definition: zone_filler.h:131
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(), 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(), 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 1198 of file zone_filler.cpp.

1200 {
1201  SHAPE_POLY_SET* boardOutline = m_brdOutlinesValid ? &m_boardOutline : nullptr;
1202  SHAPE_POLY_SET maxExtents;
1203  SHAPE_POLY_SET smoothedPoly;
1204  PCB_LAYER_ID debugLayer = UNDEFINED_LAYER;
1205 
1206  if( m_debugZoneFiller && LSET::InternalCuMask().Contains( aLayer ) )
1207  {
1208  debugLayer = aLayer;
1209  aLayer = F_Cu;
1210  }
1211 
1212  if ( !aZone->BuildSmoothedPoly( maxExtents, aLayer, boardOutline, &smoothedPoly ) )
1213  return false;
1214 
1216  return false;
1217 
1218  if( aZone->IsOnCopperLayer() )
1219  {
1220  if( computeRawFilledArea( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aRawPolys ) )
1221  aZone->SetNeedRefill( false );
1222 
1223  aFinalPolys = aRawPolys;
1224  }
1225  else
1226  {
1227  // Features which are min_width should survive pruning; features that are *less* than
1228  // min_width should not. Therefore we subtract epsilon from the min_width when
1229  // deflating/inflating.
1230  int half_min_width = aZone->GetMinThickness() / 2;
1231  int epsilon = Millimeter2iu( 0.001 );
1232  int numSegs = GetArcToSegmentCount( half_min_width, m_maxError, 360.0 );
1233 
1234  smoothedPoly.Deflate( half_min_width - epsilon, numSegs );
1235 
1236  // Remove the non filled areas due to the hatch pattern
1237  if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
1238  addHatchFillTypeOnZone( aZone, aLayer, debugLayer, smoothedPoly );
1239 
1240  // Re-inflate after pruning of areas that don't meet minimum-width criteria
1241  if( aZone->GetFilledPolysUseThickness() )
1242  {
1243  // If we're stroking the zone with a min_width stroke then this will naturally
1244  // inflate the zone by half_min_width
1245  }
1246  else if( half_min_width - epsilon > epsilon )
1247  {
1248  smoothedPoly.Inflate( half_min_width - epsilon, numSegs );
1249  }
1250 
1251  aRawPolys = smoothedPoly;
1252  aFinalPolys = smoothedPoly;
1253 
1255  aZone->SetNeedRefill( false );
1256  }
1257 
1258  return true;
1259 }
PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:126
bool BuildSmoothedPoly(SHAPE_POLY_SET &aSmoothedPoly, PCB_LAYER_ID aLayer, SHAPE_POLY_SET *aBoardOutline, SHAPE_POLY_SET *aSmoothedPolyWithApron=nullptr) const
Definition: zone.cpp:1165
ZONE_FILL_MODE GetFillMode() const
Definition: zone.h:181
bool IsCancelled() const
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:64
bool m_debugZoneFiller
Definition: zone_filler.h:133
Definition: layer_ids.h:70
bool IsOnCopperLayer() const override
Definition: zone.cpp:224
SHAPE_POLY_SET m_boardOutline
Definition: zone_filler.h:123
bool m_brdOutlinesValid
Definition: zone_filler.h:124
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().

◆ InstallNewProgressReporter()

void ZONE_FILLER::InstallNewProgressReporter ( wxWindow *  aParent,
const wxString &  aTitle,
int  aNumPhases 
)

Definition at line 72 of file zone_filler.cpp.

74 {
75  m_uniqueReporter = std::make_unique<WX_PROGRESS_REPORTER>( aParent, aTitle, aNumPhases );
77 }
std::unique_ptr< WX_PROGRESS_REPORTER > m_uniqueReporter
Definition: zone_filler.h:128
void SetProgressReporter(PROGRESS_REPORTER *aReporter)
Definition: zone_filler.cpp:80

References m_uniqueReporter, and SetProgressReporter().

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

◆ IsDebug()

bool ZONE_FILLER::IsDebug ( ) const
inline

Definition at line 56 of file zone_filler.h.

56 { return m_debugZoneFiller; }
bool m_debugZoneFiller
Definition: zone_filler.h:133

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 610 of file zone_filler.cpp.

612 {
613  SHAPE_POLY_SET holes;
614 
615  for( FOOTPRINT* footprint : m_board->Footprints() )
616  {
617  for( PAD* pad : footprint->Pads() )
618  {
619  if( !hasThermalConnection( pad, aZone ) )
620  continue;
621 
622  int gap = aZone->GetThermalReliefGap( pad );
623 
624  // If the pad is flashed to the current layer, or is on the same layer and shares a netcode, then
625  // we need to knock out the thermal relief.
626  if( pad->FlashLayer( aLayer ) || ( pad->IsOnLayer( aLayer ) && pad->GetNetCode() == aZone->GetNetCode() ) )
627  {
628  addKnockout( pad, aLayer, gap, holes );
629  }
630  else
631  {
632  // If the pad isn't on the current layer but has a hole, knock out a thermal relief
633  // for the hole.
634  if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
635  continue;
636 
637  // Note: drill size represents finish size, which means the actual holes size is
638  // the plating thickness larger.
639  if( pad->GetAttribute() == PAD_ATTRIB::PTH )
640  gap += pad->GetBoard()->GetDesignSettings().GetHolePlatingThickness();
641 
642  pad->TransformHoleWithClearanceToPolygon( holes, gap, m_maxError, ERROR_OUTSIDE );
643  }
644  }
645  }
646 
648 }
BOARD * m_board
Definition: zone_filler.h:122
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 80 of file zone_filler.cpp.

81 {
82  m_progressReporter = aReporter;
83  wxASSERT_MSG( m_commit, "ZONE_FILLER must have a valid commit to call SetProgressReporter" );
84 }
PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:126
COMMIT * m_commit
Definition: zone_filler.h:125

References m_commit, and m_progressReporter.

Referenced by ZONE_FILLER_TOOL::CheckAllZones(), ZONE_FILLER_TOOL::FillAllZones(), and InstallNewProgressReporter().

◆ 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 957 of file zone_filler.cpp.

959 {
960  auto knockoutZoneOutline =
961  [&]( ZONE* aKnockout )
962  {
963  // If the zones share no common layers
964  if( !aKnockout->GetLayerSet().test( aLayer ) )
965  return;
966 
967  if( aKnockout->GetCachedBoundingBox().Intersects( aZone->GetCachedBoundingBox() ) )
968  {
969  aRawFill.BooleanSubtract( *aKnockout->Outline(), SHAPE_POLY_SET::PM_FAST );
970  }
971  };
972 
973  for( ZONE* otherZone : m_board->Zones() )
974  {
975  if( otherZone->GetNetCode() == aZone->GetNetCode()
976  && otherZone->GetPriority() > aZone->GetPriority() )
977  {
978  knockoutZoneOutline( otherZone );
979  }
980  }
981 
982  for( FOOTPRINT* footprint : m_board->Footprints() )
983  {
984  for( ZONE* otherZone : footprint->Zones() )
985  {
986  if( otherZone->GetNetCode() == aZone->GetNetCode()
987  && otherZone->GetPriority() > aZone->GetPriority() )
988  {
989  knockoutZoneOutline( otherZone );
990  }
991  }
992  }
993 }
ZONES & Zones()
Definition: board.h:239
unsigned GetPriority() const
Definition: zone.h:122
BOARD * m_board
Definition: zone_filler.h:122
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 123 of file zone_filler.h.

Referenced by Fill(), and fillSingleZone().

◆ m_brdOutlinesValid

bool ZONE_FILLER::m_brdOutlinesValid
private

Definition at line 124 of file zone_filler.h.

Referenced by Fill(), and fillSingleZone().

◆ m_commit

COMMIT* ZONE_FILLER::m_commit
private

Definition at line 125 of file zone_filler.h.

Referenced by Fill(), and SetProgressReporter().

◆ m_debugZoneFiller

bool ZONE_FILLER::m_debugZoneFiller
private

Definition at line 133 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_uniqueReporter

std::unique_ptr<WX_PROGRESS_REPORTER> ZONE_FILLER::m_uniqueReporter
private

Definition at line 128 of file zone_filler.h.

Referenced by InstallNewProgressReporter().

◆ m_worstClearance

int ZONE_FILLER::m_worstClearance
private

Definition at line 131 of file zone_filler.h.

Referenced by buildCopperItemClearances(), and Fill().


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