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

52  :
53  m_board( aBoard ),
54  m_brdOutlinesValid( false ),
55  m_commit( aCommit ),
56  m_progressReporter( nullptr ),
57  m_maxError( ARC_HIGH_DEF ),
58  m_worstClearance( 0 )
59 {
60  // To enable add "DebugZoneFiller=1" to kicad_advanced settings file.
62 }
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 65 of file zone_filler.cpp.

66 {
67 }

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

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

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

538 {
539  if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
540  {
541  SHAPE_POLY_SET poly;
542  aPad->TransformShapeWithClearanceToPolygon( poly, aLayer, aGap, m_maxError,
543  ERROR_OUTSIDE );
544 
545  // the pad shape in zone can be its convex hull or the shape itself
547  {
548  std::vector<wxPoint> convex_hull;
549  BuildConvexHull( convex_hull, poly );
550 
551  aHoles.NewOutline();
552 
553  for( const wxPoint& pt : convex_hull )
554  aHoles.Append( pt );
555  }
556  else
557  aHoles.Append( poly );
558  }
559  else
560  {
561  aPad->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_maxError,
562  ERROR_OUTSIDE );
563  }
564 }
PAD_SHAPE_T GetShape() const
Definition: pad.h:169
Represent a set of closed polygons.
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:187
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, ERROR_OUTSIDE, PAD::GetCustomShapeInZoneOpt(), PAD::GetShape(), m_maxError, SHAPE_POLY_SET::NewOutline(), PAD_SHAPE_CUSTOM, 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 571 of file zone_filler.cpp.

573 {
574  switch( aItem->Type() )
575  {
576  case PCB_SHAPE_T:
577  case PCB_TEXT_T:
578  case PCB_FP_SHAPE_T:
579  aItem->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_maxError,
580  ERROR_OUTSIDE, aIgnoreLineWidth );
581  break;
582 
583  case PCB_FP_TEXT_T:
584  {
585  FP_TEXT* text = static_cast<FP_TEXT*>( aItem );
586 
587  if( text->IsVisible() )
588  {
589  text->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_maxError,
590  ERROR_OUTSIDE, aIgnoreLineWidth );
591  }
592  }
593  break;
594 
595  default:
596  break;
597  }
598 }
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:129
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:163

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

652 {
653  long ticker = 0;
654 
655  auto checkForCancel =
656  [&ticker]( PROGRESS_REPORTER* aReporter ) -> bool
657  {
658  return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
659  };
660 
661  // A small extra clearance to be sure actual track clearances are not smaller than
662  // requested clearance due to many approximations in calculations, like arc to segment
663  // approx, rounding issues, etc.
664  int extra_margin = Millimeter2iu( ADVANCED_CFG::GetCfg().m_ExtraClearance );
665 
667  int zone_clearance = aZone->GetLocalClearance();
668  EDA_RECT zone_boundingbox = aZone->GetCachedBoundingBox();
669 
670  // Items outside the zone bounding box are skipped, so it needs to be inflated by the
671  // largest clearance value found in the netclasses and rules
672  zone_boundingbox.Inflate( m_worstClearance + extra_margin );
673 
674  auto evalRulesForItems =
675  [&bds]( DRC_CONSTRAINT_T aConstraint, const BOARD_ITEM* a, const BOARD_ITEM* b,
676  PCB_LAYER_ID aEvalLayer ) -> int
677  {
678  auto c = bds.m_DRCEngine->EvalRules( aConstraint, a, b, aEvalLayer );
679  return c.Value().Min();
680  };
681 
682  // Add non-connected pad clearances
683  //
684  auto knockoutPadClearance =
685  [&]( PAD* aPad )
686  {
687  if( aPad->GetBoundingBox().Intersects( zone_boundingbox ) )
688  {
689  int gap;
690 
691  // For pads having the same netcode as the zone, the net clearance has no
692  // meaning so use the greater of the zone clearance and the thermal relief.
693  if( aPad->GetNetCode() > 0 && aPad->GetNetCode() == aZone->GetNetCode() )
694  gap = std::max( zone_clearance, aZone->GetThermalReliefGap( aPad ) );
695  else
696  gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aPad, aLayer );
697 
698  gap += extra_margin;
699 
700  // If the pad isn't on the current layer but has a hole, knock out the hole.
701  if( !aPad->FlashLayer( aLayer ) )
702  {
703  if( aPad->GetDrillSize().x == 0 && aPad->GetDrillSize().y == 0 )
704  return;
705 
706  // Note: drill size represents finish size, which means the actual hole
707  // size is the plating thickness larger.
708  if( aPad->GetAttribute() == PAD_ATTRIB_PTH )
709  gap += aPad->GetBoard()->GetDesignSettings().GetHolePlatingThickness();
710 
711  aPad->TransformHoleWithClearanceToPolygon( aHoles, gap, m_maxError,
712  ERROR_OUTSIDE );
713  }
714  else
715  {
716  addKnockout( aPad, aLayer, gap, aHoles );
717  }
718  }
719  };
720 
721  for( FOOTPRINT* footprint : m_board->Footprints() )
722  {
723  for( PAD* pad : footprint->Pads() )
724  {
725  if( checkForCancel( m_progressReporter ) )
726  return;
727 
728  if( pad->GetNetCode() != aZone->GetNetCode()
729  || pad->GetNetCode() <= 0
730  || aZone->GetPadConnection( pad ) == ZONE_CONNECTION::NONE )
731  {
732  knockoutPadClearance( pad );
733  }
734  }
735  }
736 
737  // Add non-connected track clearances
738  //
739  auto knockoutTrackClearance =
740  [&]( TRACK* aTrack )
741  {
742  if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
743  {
744  int gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aTrack, aLayer );
745 
746  gap += extra_margin;
747 
748  if( aTrack->Type() == PCB_VIA_T )
749  {
750  VIA* via = static_cast<VIA*>( aTrack );
751 
752  if( !via->FlashLayer( aLayer ) && via->GetNetCode() != aZone->GetNetCode() )
753  {
754  int radius = via->GetDrillValue() / 2 + bds.GetHolePlatingThickness();
755  TransformCircleToPolygon( aHoles, via->GetPosition(), radius + gap,
757  }
758  else
759  {
760  via->TransformShapeWithClearanceToPolygon( aHoles, aLayer, gap,
762  }
763  }
764  else
765  {
766  aTrack->TransformShapeWithClearanceToPolygon( aHoles, aLayer, gap,
768  }
769  }
770  };
771 
772  for( TRACK* track : m_board->Tracks() )
773  {
774  if( !track->IsOnLayer( aLayer ) )
775  continue;
776 
777  if( track->GetNetCode() == aZone->GetNetCode() && ( aZone->GetNetCode() != 0) )
778  continue;
779 
780  if( checkForCancel( m_progressReporter ) )
781  return;
782 
783  knockoutTrackClearance( track );
784  }
785 
786  // Add graphic item clearances. They are by definition unconnected, and have no clearance
787  // definitions of their own.
788  //
789  auto knockoutGraphicClearance =
790  [&]( BOARD_ITEM* aItem )
791  {
792  // A item on the Edge_Cuts or Margin is always seen as on any layer:
793  if( aItem->IsOnLayer( aLayer )
794  || aItem->IsOnLayer( Edge_Cuts )
795  || aItem->IsOnLayer( Margin ) )
796  {
797  if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
798  {
799  int gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aItem, aLayer );
800 
801  if( aItem->IsOnLayer( Edge_Cuts ) )
802  {
803  gap = std::max( gap, evalRulesForItems( EDGE_CLEARANCE_CONSTRAINT,
804  aZone, aItem, Edge_Cuts ) );
805  }
806 
807  if( aItem->IsOnLayer( Margin ) )
808  {
809  gap = std::max( gap, evalRulesForItems( EDGE_CLEARANCE_CONSTRAINT,
810  aZone, aItem, Margin ) );
811  }
812 
813  addKnockout( aItem, aLayer, gap, aItem->IsOnLayer( Edge_Cuts ), aHoles );
814  }
815  }
816  };
817 
818  for( FOOTPRINT* footprint : m_board->Footprints() )
819  {
820  bool skipFootprint = false;
821 
822  knockoutGraphicClearance( &footprint->Reference() );
823  knockoutGraphicClearance( &footprint->Value() );
824 
825  // Don't knock out holes in zones that share a net
826  // with a nettie footprint
827  if( footprint->IsNetTie() )
828  {
829  for( PAD* pad : footprint->Pads() )
830  {
831  if( aZone->GetNetCode() == pad->GetNetCode() )
832  {
833  skipFootprint = true;
834  break;
835  }
836  }
837  }
838 
839  if( skipFootprint )
840  continue;
841 
842  for( BOARD_ITEM* item : footprint->GraphicalItems() )
843  {
844  if( checkForCancel( m_progressReporter ) )
845  return;
846 
847  knockoutGraphicClearance( item );
848  }
849  }
850 
851  for( BOARD_ITEM* item : m_board->Drawings() )
852  {
853  if( checkForCancel( m_progressReporter ) )
854  return;
855 
856  knockoutGraphicClearance( item );
857  }
858 
859  // Add non-connected zone clearances
860  //
861  auto knockoutZoneClearance =
862  [&]( ZONE* aKnockout )
863  {
864  // If the zones share no common layers
865  if( !aKnockout->GetLayerSet().test( aLayer ) )
866  return;
867 
868  if( aKnockout->GetCachedBoundingBox().Intersects( zone_boundingbox ) )
869  {
870  if( aKnockout->GetIsRuleArea() )
871  {
872  // Keepouts use outline with no clearance
873  aKnockout->TransformSmoothedOutlineToPolygon( aHoles, 0, nullptr );
874  }
875  else if( bds.m_ZoneFillVersion == 5 )
876  {
877  // 5.x used outline with clearance
878  int gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aKnockout,
879  aLayer );
880 
881  aKnockout->TransformSmoothedOutlineToPolygon( aHoles, gap, nullptr );
882  }
883  else
884  {
885  // 6.0 uses filled areas with clearance
886  int gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aKnockout,
887  aLayer );
888 
889  SHAPE_POLY_SET poly;
890  aKnockout->TransformShapeWithClearanceToPolygon( poly, aLayer, gap,
891  m_maxError,
892  ERROR_OUTSIDE );
893  aHoles.Append( poly );
894  }
895  }
896  };
897 
898  for( ZONE* otherZone : m_board->Zones() )
899  {
900  if( checkForCancel( m_progressReporter ) )
901  return;
902 
903  if( otherZone->GetNetCode() != aZone->GetNetCode()
904  && otherZone->GetPriority() > aZone->GetPriority() )
905  {
906  knockoutZoneClearance( otherZone );
907  }
908  else if( otherZone->GetIsRuleArea() && otherZone->GetDoNotAllowCopperPour() )
909  {
910  knockoutZoneClearance( otherZone );
911  }
912  }
913 
914  for( FOOTPRINT* footprint : m_board->Footprints() )
915  {
916  for( ZONE* otherZone : footprint->Zones() )
917  {
918  if( checkForCancel( m_progressReporter ) )
919  return;
920 
921  if( otherZone->GetNetCode() != aZone->GetNetCode()
922  && otherZone->GetPriority() > aZone->GetPriority() )
923  {
924  knockoutZoneClearance( otherZone );
925  }
926  else if( otherZone->GetIsRuleArea() && otherZone->GetDoNotAllowCopperPour() )
927  {
928  knockoutZoneClearance( otherZone );
929  }
930  }
931  }
932 
934 }
int m_ZoneFillVersion
Option to select different fill algorithms.
Definition: track.h:343
PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:126
ZONES & Zones()
Definition: board.h:311
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:82
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.
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.h:593
int GetThermalReliefGap() const
Definition: zone.h:190
DRC_CONSTRAINT_T
Definition: drc_rule.h:41
PCB_LAYER_ID
A quick note on layer IDs:
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:492
FOOTPRINTS & Footprints()
Definition: board.h:305
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:57
Plated through hole pad.
Definition: pad_shapes.h:80
Handle the component boundary box.
Definition: eda_rect.h:42
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aCornerBuffer, wxPoint aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc)
Function TransformCircleToPolygon convert a circle to a polygon, using multiple straight lines.
Pads are not covered.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
class 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:771
Definition: pad.h:60
static constexpr int Millimeter2iu(double mm)
DRAWINGS & Drawings()
Definition: board.h:308
TRACKS & Tracks()
Definition: board.h:302
std::shared_ptr< DRC_ENGINE > m_DRCEngine
Definition: track.h:83
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:363
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, 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, PAD_ATTRIB_PTH, 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 1249 of file zone_filler.cpp.

1251 {
1252  auto zoneBB = aZone->GetCachedBoundingBox();
1253  int zone_clearance = aZone->GetLocalClearance();
1254  int biggest_clearance = m_board->GetDesignSettings().GetBiggestClearanceValue();
1255  biggest_clearance = std::max( biggest_clearance, zone_clearance );
1256  zoneBB.Inflate( biggest_clearance );
1257 
1258  // Is a point on the boundary of the polygon inside or outside? This small epsilon lets
1259  // us avoid the question.
1260  int epsilon = KiROUND( IU_PER_MM * 0.04 ); // about 1.5 mil
1261 
1262  for( FOOTPRINT* footprint : m_board->Footprints() )
1263  {
1264  for( PAD* pad : footprint->Pads() )
1265  {
1266  if( !hasThermalConnection( pad, aZone ) )
1267  continue;
1268 
1269  // We currently only connect to pads, not pad holes
1270  if( !pad->IsOnLayer( aLayer ) )
1271  continue;
1272 
1273  int thermalReliefGap = aZone->GetThermalReliefGap( pad );
1274 
1275  // Calculate thermal bridge half width
1276  int spoke_w = aZone->GetThermalReliefSpokeWidth( pad );
1277  // Avoid spoke_w bigger than the smaller pad size, because
1278  // it is not possible to create stubs bigger than the pad.
1279  // Possible refinement: have a separate size for vertical and horizontal stubs
1280  spoke_w = std::min( spoke_w, pad->GetSize().x );
1281  spoke_w = std::min( spoke_w, pad->GetSize().y );
1282 
1283  // Cannot create stubs having a width < zone min thickness
1284  if( spoke_w < aZone->GetMinThickness() )
1285  continue;
1286 
1287  int spoke_half_w = spoke_w / 2;
1288 
1289  // Quick test here to possibly save us some work
1290  BOX2I itemBB = pad->GetBoundingBox();
1291  itemBB.Inflate( thermalReliefGap + epsilon );
1292 
1293  if( !( itemBB.Intersects( zoneBB ) ) )
1294  continue;
1295 
1296  // Thermal spokes consist of segments from the pad center to points just outside
1297  // the thermal relief.
1298  //
1299  // We use the bounding-box to lay out the spokes, but for this to work the
1300  // bounding box has to be built at the same rotation as the spokes.
1301  // We have to use a dummy pad to avoid dirtying the cached shapes
1302  wxPoint shapePos = pad->ShapePos();
1303  double padAngle = pad->GetOrientation();
1304  PAD dummy_pad( *pad );
1305  dummy_pad.SetOrientation( 0.0 );
1306 
1307  // Spokes are from center of pad, not from hole
1308  dummy_pad.SetPosition( -pad->GetOffset() );
1309 
1310  BOX2I reliefBB = dummy_pad.GetBoundingBox();
1311  reliefBB.Inflate( thermalReliefGap + epsilon );
1312 
1313  // For circle pads, the thermal spoke orientation is 45 deg
1314  if( pad->GetShape() == PAD_SHAPE_CIRCLE )
1315  padAngle = s_RoundPadThermalSpokeAngle;
1316 
1317  for( int i = 0; i < 4; i++ )
1318  {
1319  SHAPE_LINE_CHAIN spoke;
1320  switch( i )
1321  {
1322  case 0: // lower stub
1323  spoke.Append( +spoke_half_w, -spoke_half_w );
1324  spoke.Append( -spoke_half_w, -spoke_half_w );
1325  spoke.Append( -spoke_half_w, reliefBB.GetBottom() );
1326  spoke.Append( 0, reliefBB.GetBottom() ); // test pt
1327  spoke.Append( +spoke_half_w, reliefBB.GetBottom() );
1328  break;
1329 
1330  case 1: // upper stub
1331  spoke.Append( +spoke_half_w, spoke_half_w );
1332  spoke.Append( -spoke_half_w, spoke_half_w );
1333  spoke.Append( -spoke_half_w, reliefBB.GetTop() );
1334  spoke.Append( 0, reliefBB.GetTop() ); // test pt
1335  spoke.Append( +spoke_half_w, reliefBB.GetTop() );
1336  break;
1337 
1338  case 2: // right stub
1339  spoke.Append( -spoke_half_w, spoke_half_w );
1340  spoke.Append( -spoke_half_w, -spoke_half_w );
1341  spoke.Append( reliefBB.GetRight(), -spoke_half_w );
1342  spoke.Append( reliefBB.GetRight(), 0 ); // test pt
1343  spoke.Append( reliefBB.GetRight(), spoke_half_w );
1344  break;
1345 
1346  case 3: // left stub
1347  spoke.Append( spoke_half_w, spoke_half_w );
1348  spoke.Append( spoke_half_w, -spoke_half_w );
1349  spoke.Append( reliefBB.GetLeft(), -spoke_half_w );
1350  spoke.Append( reliefBB.GetLeft(), 0 ); // test pt
1351  spoke.Append( reliefBB.GetLeft(), spoke_half_w );
1352  break;
1353  }
1354 
1355  spoke.Rotate( -DECIDEG2RAD( padAngle ) );
1356  spoke.Move( shapePos );
1357 
1358  spoke.SetClosed( true );
1359  spoke.GenerateBBoxCache();
1360  aSpokesList.push_back( std::move( spoke ) );
1361  }
1362  }
1363  }
1364 }
BOARD * m_board
Definition: zone_filler.h:122
coord_type GetTop() const
Definition: box2.h:204
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:49
coord_type GetRight() const
Definition: box2.h:199
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.h:593
coord_type GetBottom() const
Definition: box2.h:200
void Append(int aX, int aY, bool aAllowDuplication=false)
Function Append()
int GetThermalReliefGap() const
Definition: zone.h:190
bool Intersects(const BOX2< Vec > &aRect) const
Function Intersects.
Definition: box2.h:236
void SetClosed(bool aClosed)
Function SetClosed()
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:492
FOOTPRINTS & Footprints()
Definition: board.h:305
void Rotate(double aAngle, const VECTOR2I &aCenter=VECTOR2I(0, 0)) override
Function Rotate rotates all vertices by a given angle.
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:302
SHAPE_LINE_CHAIN.
double DECIDEG2RAD(double deg)
Definition: trigo.h:235
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:68
void GenerateBBoxCache() const
int GetThermalReliefSpokeWidth() const
Definition: zone.h:200
coord_type GetLeft() const
Definition: box2.h:203
Definition: pad.h:60
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(), 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, PAD_SHAPE_CIRCLE, 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 1004 of file zone_filler.cpp.

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

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

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

1184 {
1185  SHAPE_POLY_SET* boardOutline = m_brdOutlinesValid ? &m_boardOutline : nullptr;
1186  SHAPE_POLY_SET maxExtents;
1187  SHAPE_POLY_SET smoothedPoly;
1188  PCB_LAYER_ID debugLayer = UNDEFINED_LAYER;
1189 
1190  if( m_debugZoneFiller && LSET::InternalCuMask().Contains( aLayer ) )
1191  {
1192  debugLayer = aLayer;
1193  aLayer = F_Cu;
1194  }
1195 
1196  if ( !aZone->BuildSmoothedPoly( maxExtents, aLayer, boardOutline, &smoothedPoly ) )
1197  return false;
1198 
1200  return false;
1201 
1202  if( aZone->IsOnCopperLayer() )
1203  {
1204  if( computeRawFilledArea( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aRawPolys ) )
1205  aZone->SetNeedRefill( false );
1206 
1207  aFinalPolys = aRawPolys;
1208  }
1209  else
1210  {
1211  // Features which are min_width should survive pruning; features that are *less* than
1212  // min_width should not. Therefore we subtract epsilon from the min_width when
1213  // deflating/inflating.
1214  int half_min_width = aZone->GetMinThickness() / 2;
1215  int epsilon = Millimeter2iu( 0.001 );
1216  int numSegs = GetArcToSegmentCount( half_min_width, m_maxError, 360.0 );
1217 
1218  smoothedPoly.Deflate( half_min_width - epsilon, numSegs );
1219 
1220  // Remove the non filled areas due to the hatch pattern
1221  if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
1222  addHatchFillTypeOnZone( aZone, aLayer, debugLayer, smoothedPoly );
1223 
1224  // Re-inflate after pruning of areas that don't meet minimum-width criteria
1225  if( aZone->GetFilledPolysUseThickness() )
1226  {
1227  // If we're stroking the zone with a min_width stroke then this will naturally
1228  // inflate the zone by half_min_width
1229  }
1230  else if( half_min_width - epsilon > epsilon )
1231  {
1232  smoothedPoly.Inflate( half_min_width - epsilon, numSegs );
1233  }
1234 
1235  aRawPolys = smoothedPoly;
1236  aFinalPolys = smoothedPoly;
1237 
1239  aZone->SetNeedRefill( false );
1240  }
1241 
1242  return true;
1243 }
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:1164
void Inflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
Perform outline inflation/deflation.
ZONE_FILL_MODE GetFillMode() const
Definition: zone.h:181
PCB_LAYER_ID
A quick note on layer IDs:
bool IsCancelled() const
int GetMinThickness() const
Definition: zone.h:241
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.
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...
bool m_debugZoneFiller
Definition: zone_filler.h:133
bool IsOnCopperLayer() const override
Definition: zone.cpp:222
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:235
static constexpr int Millimeter2iu(double mm)
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
bool GetFilledPolysUseThickness() const
Definition: zone.h:686

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

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

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

607 {
608  SHAPE_POLY_SET holes;
609 
610  for( FOOTPRINT* footprint : m_board->Footprints() )
611  {
612  for( PAD* pad : footprint->Pads() )
613  {
614  if( !hasThermalConnection( pad, aZone ) )
615  continue;
616 
617  int gap = aZone->GetThermalReliefGap( pad );
618 
619  // If the pad is flashed to the current layer, or is on the same layer and shares a netcode, then
620  // we need to knock out the thermal relief.
621  if( pad->FlashLayer( aLayer ) || ( pad->IsOnLayer( aLayer ) && pad->GetNetCode() == aZone->GetNetCode() ) )
622  {
623  addKnockout( pad, aLayer, gap, holes );
624  }
625  else
626  {
627  // If the pad isn't on the current layer but has a hole, knock out a thermal relief
628  // for the hole.
629  if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
630  continue;
631 
632  // Note: drill size represents finish size, which means the actual holes size is
633  // the plating thickness larger.
634  if( pad->GetAttribute() == PAD_ATTRIB_PTH )
635  gap += pad->GetBoard()->GetDesignSettings().GetHolePlatingThickness();
636 
637  pad->TransformHoleWithClearanceToPolygon( holes, gap, m_maxError, ERROR_OUTSIDE );
638  }
639  }
640  }
641 
643 }
BOARD * m_board
Definition: zone_filler.h:122
int GetThermalReliefGap() const
Definition: zone.h:190
Represent a set of closed polygons.
FOOTPRINTS & Footprints()
Definition: board.h:305
void addKnockout(PAD *aPad, PCB_LAYER_ID aLayer, int aGap, SHAPE_POLY_SET &aHoles)
Add a knockout for a pad.
Plated through hole pad.
Definition: pad_shapes.h:80
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
Definition: pad.h:60
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, PAD_ATTRIB_PTH, and SHAPE_POLY_SET::PM_FAST.

Referenced by computeRawFilledArea().

◆ SetProgressReporter()

void ZONE_FILLER::SetProgressReporter ( PROGRESS_REPORTER aReporter)

Definition at line 78 of file zone_filler.cpp.

79 {
80  m_progressReporter = aReporter;
81  wxASSERT_MSG( m_commit, "ZONE_FILLER must have a valid commit to call SetProgressReporter" );
82 }
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 941 of file zone_filler.cpp.

943 {
944  auto knockoutZoneOutline =
945  [&]( ZONE* aKnockout )
946  {
947  // If the zones share no common layers
948  if( !aKnockout->GetLayerSet().test( aLayer ) )
949  return;
950 
951  if( aKnockout->GetCachedBoundingBox().Intersects( aZone->GetCachedBoundingBox() ) )
952  {
953  aRawFill.BooleanSubtract( *aKnockout->Outline(), SHAPE_POLY_SET::PM_FAST );
954  }
955  };
956 
957  for( ZONE* otherZone : m_board->Zones() )
958  {
959  if( otherZone->GetNetCode() == aZone->GetNetCode()
960  && otherZone->GetPriority() > aZone->GetPriority() )
961  {
962  knockoutZoneOutline( otherZone );
963  }
964  }
965 
966  for( FOOTPRINT* footprint : m_board->Footprints() )
967  {
968  for( ZONE* otherZone : footprint->Zones() )
969  {
970  if( otherZone->GetNetCode() == aZone->GetNetCode()
971  && otherZone->GetPriority() > aZone->GetPriority() )
972  {
973  knockoutZoneOutline( otherZone );
974  }
975  }
976  }
977 }
ZONES & Zones()
Definition: board.h:311
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:305
Handle a list of polygons defining a copper zone.
Definition: zone.h:57
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: