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)
 
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:119
BOARD * m_board
Definition: zone_filler.h:115
COMMIT * m_commit
Definition: zone_filler.h:118
bool m_debugZoneFiller
Definition: zone_filler.h:126
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
bool m_brdOutlinesValid
Definition: zone_filler.h:117
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:124

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

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

542 {
543  if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
544  {
545  SHAPE_POLY_SET poly;
546  aPad->TransformShapeWithClearanceToPolygon( poly, aLayer, aGap, m_maxError,
547  ERROR_OUTSIDE );
548 
549  // the pad shape in zone can be its convex hull or the shape itself
551  {
552  std::vector<wxPoint> convex_hull;
553  BuildConvexHull( convex_hull, poly );
554 
555  aHoles.NewOutline();
556 
557  for( const wxPoint& pt : convex_hull )
558  aHoles.Append( pt );
559  }
560  else
561  aHoles.Append( poly );
562  }
563  else
564  {
565  aPad->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_maxError,
566  ERROR_OUTSIDE );
567  }
568 }
PAD_SHAPE_T GetShape() const
Definition: pad.h:162
SHAPE_POLY_SET.
int NewOutline()
Creates a new empty polygon in the set and returns its index
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, PCB_LAYER_ID aLayer, int aClearanceValue, int aMaxError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Function TransformShapeWithClearanceToPolygon Convert the pad shape to a closed polygon.
CUST_PAD_SHAPE_IN_ZONE GetCustomShapeInZoneOpt() const
Definition: pad.h:182
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
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 575 of file zone_filler.cpp.

577 {
578  switch( aItem->Type() )
579  {
580  case PCB_SHAPE_T:
581  case PCB_TEXT_T:
582  case PCB_FP_SHAPE_T:
583  aItem->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_maxError,
584  ERROR_OUTSIDE, aIgnoreLineWidth );
585  break;
586 
587  case PCB_FP_TEXT_T:
588  {
589  FP_TEXT* text = static_cast<FP_TEXT*>( aItem );
590 
591  if( text->IsVisible() )
592  {
593  text->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_maxError,
594  ERROR_OUTSIDE, aIgnoreLineWidth );
595  }
596  }
597  break;
598 
599  default:
600  break;
601  }
602 }
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
bool IsVisible() const
Definition: eda_text.h:193
class PCB_TEXT, text on a layer
Definition: typeinfo.h:91
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:93
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth) const override
Convert the item shape to a closed polygon.
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:161

References ERROR_OUTSIDE, EDA_TEXT::IsVisible(), m_maxError, PCB_FP_SHAPE_T, PCB_FP_TEXT_T, PCB_SHAPE_T, PCB_TEXT_T, FP_TEXT::TransformShapeWithClearanceToPolygon(), 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 652 of file zone_filler.cpp.

654 {
655  long ticker = 0;
656 
657  auto checkForCancel =
658  [&ticker]( PROGRESS_REPORTER* aReporter ) -> bool
659  {
660  return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
661  };
662 
663  // A small extra clearance to be sure actual track clearances are not smaller than
664  // requested clearance due to many approximations in calculations, like arc to segment
665  // approx, rounding issues, etc.
666  int extra_margin = Millimeter2iu( ADVANCED_CFG::GetCfg().m_ExtraClearance );
667 
669  int zone_clearance = aZone->GetLocalClearance();
670  EDA_RECT zone_boundingbox = aZone->GetCachedBoundingBox();
671 
672  // Items outside the zone bounding box are skipped, so it needs to be inflated by the
673  // largest clearance value found in the netclasses and rules
674  zone_boundingbox.Inflate( m_worstClearance + extra_margin );
675 
676  auto evalRulesForItems =
677  [&bds]( DRC_CONSTRAINT_T aConstraint, const BOARD_ITEM* a, const BOARD_ITEM* b,
678  PCB_LAYER_ID aEvalLayer ) -> int
679  {
680  auto c = bds.m_DRCEngine->EvalRulesForItems( aConstraint, a, b, aEvalLayer );
681  return c.Value().Min();
682  };
683 
684  // Add non-connected pad clearances
685  //
686  auto knockoutPadClearance =
687  [&]( PAD* aPad )
688  {
689  if( aPad->GetBoundingBox().Intersects( zone_boundingbox ) )
690  {
691  int gap;
692 
693  // For pads having the same netcode as the zone, the net clearance has no
694  // meaning so use the greater of the zone clearance and the thermal relief.
695  if( aPad->GetNetCode() > 0 && aPad->GetNetCode() == aZone->GetNetCode() )
696  gap = std::max( zone_clearance, aZone->GetThermalReliefGap( aPad ) );
697  else
698  gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aPad, aLayer );
699 
700  gap += extra_margin;
701 
702  // If the pad isn't on the current layer but has a hole, knock out the
703  // hole.
704  if( !aPad->FlashLayer( aLayer ) )
705  {
706  if( aPad->GetDrillSize().x == 0 && aPad->GetDrillSize().y == 0 )
707  return;
708 
709  // Note: drill size represents finish size, which means the actual hole
710  // size is the plating thickness larger.
711  if( aPad->GetAttribute() == PAD_ATTRIB_PTH )
712  gap += aPad->GetBoard()->GetDesignSettings().GetHolePlatingThickness();
713 
714  aPad->TransformHoleWithClearanceToPolygon( aHoles, gap, m_maxError,
715  ERROR_OUTSIDE );
716  }
717  else
718  {
719  addKnockout( aPad, aLayer, gap, aHoles );
720  }
721  }
722  };
723 
724  for( FOOTPRINT* footprint : m_board->Footprints() )
725  {
726  for( PAD* pad : footprint->Pads() )
727  {
728  if( checkForCancel( m_progressReporter ) )
729  return;
730 
731  if( pad->GetNetCode() != aZone->GetNetCode()
732  || pad->GetNetCode() <= 0
733  || aZone->GetPadConnection( pad ) == ZONE_CONNECTION::NONE )
734  {
735  knockoutPadClearance( pad );
736  }
737  }
738  }
739 
740  // Add non-connected track clearances
741  //
742  auto knockoutTrackClearance =
743  [&]( TRACK* aTrack )
744  {
745  if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
746  {
747  int gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aTrack, aLayer );
748 
749  gap += extra_margin;
750 
751  if( aTrack->Type() == PCB_VIA_T )
752  {
753  VIA* via = static_cast<VIA*>( aTrack );
754 
755  if( !via->FlashLayer( aLayer ) )
756  {
757  int radius = via->GetDrillValue() / 2 + bds.GetHolePlatingThickness();
758  TransformCircleToPolygon( aHoles, via->GetPosition(), radius + gap,
760  }
761  else
762  {
763  via->TransformShapeWithClearanceToPolygon( aHoles, aLayer, gap,
765  }
766  }
767  else
768  {
769  aTrack->TransformShapeWithClearanceToPolygon( aHoles, aLayer, gap,
771  }
772  }
773  };
774 
775  for( TRACK* track : m_board->Tracks() )
776  {
777  if( !track->IsOnLayer( aLayer ) )
778  continue;
779 
780  if( track->GetNetCode() == aZone->GetNetCode() && ( aZone->GetNetCode() != 0) )
781  continue;
782 
783  if( checkForCancel( m_progressReporter ) )
784  return;
785 
786  knockoutTrackClearance( track );
787  }
788 
789  // Add graphic item clearances. They are by definition unconnected, and have no clearance
790  // definitions of their own.
791  //
792  auto knockoutGraphicClearance =
793  [&]( BOARD_ITEM* aItem )
794  {
795  // A item on the Edge_Cuts or Margin is always seen as on any layer:
796  if( aItem->IsOnLayer( aLayer )
797  || aItem->IsOnLayer( Edge_Cuts )
798  || aItem->IsOnLayer( Margin ) )
799  {
800  if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
801  {
802  int gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aItem, aLayer );
803 
804  if( aItem->IsOnLayer( Edge_Cuts ) )
805  {
806  gap = std::max( gap, evalRulesForItems( EDGE_CLEARANCE_CONSTRAINT,
807  aZone, aItem, Edge_Cuts ) );
808  }
809 
810  if( aItem->IsOnLayer( Margin ) )
811  {
812  gap = std::max( gap, evalRulesForItems( EDGE_CLEARANCE_CONSTRAINT,
813  aZone, aItem, Margin ) );
814  }
815 
816  addKnockout( aItem, aLayer, gap, aItem->IsOnLayer( Edge_Cuts ), aHoles );
817  }
818  }
819  };
820 
821  for( FOOTPRINT* footprint : m_board->Footprints() )
822  {
823  knockoutGraphicClearance( &footprint->Reference() );
824  knockoutGraphicClearance( &footprint->Value() );
825 
826  for( BOARD_ITEM* item : footprint->GraphicalItems() )
827  {
828  if( checkForCancel( m_progressReporter ) )
829  return;
830 
831  knockoutGraphicClearance( item );
832  }
833  }
834 
835  for( BOARD_ITEM* item : m_board->Drawings() )
836  {
837  if( checkForCancel( m_progressReporter ) )
838  return;
839 
840  knockoutGraphicClearance( item );
841  }
842 
843  // Add non-connected zone clearances
844  //
845  auto knockoutZoneClearance =
846  [&]( ZONE* aKnockout )
847  {
848  // If the zones share no common layers
849  if( !aKnockout->GetLayerSet().test( aLayer ) )
850  return;
851 
852  if( aKnockout->GetCachedBoundingBox().Intersects( zone_boundingbox ) )
853  {
854  if( aKnockout->GetIsRuleArea() )
855  {
856  // Keepouts use outline with no clearance
857  aKnockout->TransformSmoothedOutlineToPolygon( aHoles, 0, nullptr );
858  }
859  else if( bds.m_ZoneFillVersion == 5 )
860  {
861  // 5.x used outline with clearance
862  int gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aKnockout,
863  aLayer );
864 
865  aKnockout->TransformSmoothedOutlineToPolygon( aHoles, gap, nullptr );
866  }
867  else
868  {
869  // 6.0 uses filled areas with clearance
870  int gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aKnockout,
871  aLayer );
872 
873  SHAPE_POLY_SET poly;
874  aKnockout->TransformShapeWithClearanceToPolygon( poly, aLayer, gap,
875  m_maxError,
876  ERROR_OUTSIDE );
877  aHoles.Append( poly );
878  }
879  }
880  };
881 
882  for( ZONE* otherZone : m_board->Zones() )
883  {
884  if( checkForCancel( m_progressReporter ) )
885  return;
886 
887  if( otherZone->GetNetCode() != aZone->GetNetCode()
888  && otherZone->GetPriority() > aZone->GetPriority() )
889  {
890  knockoutZoneClearance( otherZone );
891  }
892  else if( otherZone->GetIsRuleArea() && otherZone->GetDoNotAllowCopperPour() )
893  {
894  knockoutZoneClearance( otherZone );
895  }
896  }
897 
898  for( FOOTPRINT* footprint : m_board->Footprints() )
899  {
900  for( ZONE* otherZone : footprint->Zones() )
901  {
902  if( checkForCancel( m_progressReporter ) )
903  return;
904 
905  if( otherZone->GetNetCode() != aZone->GetNetCode()
906  && otherZone->GetPriority() > aZone->GetPriority() )
907  {
908  knockoutZoneClearance( otherZone );
909  }
910  else if( otherZone->GetIsRuleArea() && otherZone->GetDoNotAllowCopperPour() )
911  {
912  knockoutZoneClearance( otherZone );
913  }
914  }
915  }
916 
918 }
int m_ZoneFillVersion
Option to select different fill algorithms.
Definition: track.h:344
int GetNetCode() const
Function GetNetCode.
PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:119
ZONES & Zones()
Definition: board.h:292
unsigned GetPriority() const
Function GetPriority.
Definition: zone.h:124
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:115
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:574
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, PCB_LAYER_ID aLayer, int aClearanceValue, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Function TransformShapeWithClearanceToPolygon Convert the track shape to a closed polygon Used in fil...
int GetThermalReliefGap() const
Definition: zone.h:195
DRC_CONSTRAINT_T
Definition: drc_rule.h:41
bool FlashLayer(int aLayer, bool aIncludeZones=false) const
Checks to see whether the via should have a pad on the specific layer.
Definition: track.cpp:482
PCB_LAYER_ID
A quick note on layer IDs:
int GetDrillValue() const
Function GetDrillValue "calculates" the drill value for vias (m-Drill if > 0, or default drill value ...
Definition: track.cpp:171
const EDA_RECT GetCachedBoundingBox() const
ONLY TO BE USED BY CLIENTS WHICH SET UP THE CACHE!
Definition: zone.h:148
SHAPE_POLY_SET.
int GetLocalClearance(wxString *aSource) const override
Function GetLocalClearance returns any local clearances set in the "classic" (ie: pre-rule) system.
Definition: zone.cpp:491
FOOTPRINTS & Footprints()
Definition: board.h:286
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)
Simplifies the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFast...
ZONE handles 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:770
Definition: pad.h:60
wxPoint GetPosition() const override
Definition: track.h:412
static constexpr int Millimeter2iu(double mm)
DRAWINGS & Drawings()
Definition: board.h:289
TRACKS & Tracks()
Definition: board.h:283
std::shared_ptr< DRC_ENGINE > m_DRCEngine
Definition: track.h:83
int m_worstClearance
Definition: zone_filler.h:124
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)
Appends a vertex at the end of the given outline/hole (default: the last outline)

References addKnockout(), SHAPE_POLY_SET::Append(), CLEARANCE_CONSTRAINT, BOARD::Drawings(), EDGE_CLEARANCE_CONSTRAINT, Edge_Cuts, ERROR_OUTSIDE, VIA::FlashLayer(), BOARD::Footprints(), ZONE::GetCachedBoundingBox(), ADVANCED_CFG::GetCfg(), BOARD::GetDesignSettings(), VIA::GetDrillValue(), BOARD_DESIGN_SETTINGS::GetHolePlatingThickness(), ZONE::GetLocalClearance(), BOARD_CONNECTED_ITEM::GetNetCode(), ZONE::GetPadConnection(), VIA::GetPosition(), 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_ATTRIB_PTH, PCB_VIA_T, SHAPE_POLY_SET::PM_FAST, SHAPE_POLY_SET::Simplify(), BOARD::Tracks(), TransformCircleToPolygon(), TRACK::TransformShapeWithClearanceToPolygon(), 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 1238 of file zone_filler.cpp.

1240 {
1241  auto zoneBB = aZone->GetCachedBoundingBox();
1242  int zone_clearance = aZone->GetLocalClearance();
1243  int biggest_clearance = m_board->GetDesignSettings().GetBiggestClearanceValue();
1244  biggest_clearance = std::max( biggest_clearance, zone_clearance );
1245  zoneBB.Inflate( biggest_clearance );
1246 
1247  // Is a point on the boundary of the polygon inside or outside? This small epsilon lets
1248  // us avoid the question.
1249  int epsilon = KiROUND( IU_PER_MM * 0.04 ); // about 1.5 mil
1250 
1251  for( FOOTPRINT* footprint : m_board->Footprints() )
1252  {
1253  for( PAD* pad : footprint->Pads() )
1254  {
1255  if( !hasThermalConnection( pad, aZone ) )
1256  continue;
1257 
1258  // We currently only connect to pads, not pad holes
1259  if( !pad->IsOnLayer( aLayer ) )
1260  continue;
1261 
1262  int thermalReliefGap = aZone->GetThermalReliefGap( pad );
1263 
1264  // Calculate thermal bridge half width
1265  int spoke_w = aZone->GetThermalReliefSpokeWidth( pad );
1266  // Avoid spoke_w bigger than the smaller pad size, because
1267  // it is not possible to create stubs bigger than the pad.
1268  // Possible refinement: have a separate size for vertical and horizontal stubs
1269  spoke_w = std::min( spoke_w, pad->GetSize().x );
1270  spoke_w = std::min( spoke_w, pad->GetSize().y );
1271 
1272  // Cannot create stubs having a width < zone min thickness
1273  if( spoke_w < aZone->GetMinThickness() )
1274  continue;
1275 
1276  int spoke_half_w = spoke_w / 2;
1277 
1278  // Quick test here to possibly save us some work
1279  BOX2I itemBB = pad->GetBoundingBox();
1280  itemBB.Inflate( thermalReliefGap + epsilon );
1281 
1282  if( !( itemBB.Intersects( zoneBB ) ) )
1283  continue;
1284 
1285  // Thermal spokes consist of segments from the pad center to points just outside
1286  // the thermal relief.
1287  //
1288  // We use the bounding-box to lay out the spokes, but for this to work the
1289  // bounding box has to be built at the same rotation as the spokes.
1290  // We have to use a dummy pad to avoid dirtying the cached shapes
1291  wxPoint shapePos = pad->ShapePos();
1292  double padAngle = pad->GetOrientation();
1293  PAD dummy_pad( *pad );
1294  dummy_pad.SetOrientation( 0.0 );
1295  dummy_pad.SetPosition( { 0, 0 } );
1296 
1297  BOX2I reliefBB = dummy_pad.GetBoundingBox();
1298  reliefBB.Inflate( thermalReliefGap + epsilon );
1299 
1300  // For circle pads, the thermal spoke orientation is 45 deg
1301  if( pad->GetShape() == PAD_SHAPE_CIRCLE )
1302  padAngle = s_RoundPadThermalSpokeAngle;
1303 
1304  for( int i = 0; i < 4; i++ )
1305  {
1306  SHAPE_LINE_CHAIN spoke;
1307  switch( i )
1308  {
1309  case 0: // lower stub
1310  spoke.Append( +spoke_half_w, -spoke_half_w );
1311  spoke.Append( -spoke_half_w, -spoke_half_w );
1312  spoke.Append( -spoke_half_w, reliefBB.GetBottom() );
1313  spoke.Append( 0, reliefBB.GetBottom() ); // test pt
1314  spoke.Append( +spoke_half_w, reliefBB.GetBottom() );
1315  break;
1316 
1317  case 1: // upper stub
1318  spoke.Append( +spoke_half_w, spoke_half_w );
1319  spoke.Append( -spoke_half_w, spoke_half_w );
1320  spoke.Append( -spoke_half_w, reliefBB.GetTop() );
1321  spoke.Append( 0, reliefBB.GetTop() ); // test pt
1322  spoke.Append( +spoke_half_w, reliefBB.GetTop() );
1323  break;
1324 
1325  case 2: // right stub
1326  spoke.Append( -spoke_half_w, spoke_half_w );
1327  spoke.Append( -spoke_half_w, -spoke_half_w );
1328  spoke.Append( reliefBB.GetRight(), -spoke_half_w );
1329  spoke.Append( reliefBB.GetRight(), 0 ); // test pt
1330  spoke.Append( reliefBB.GetRight(), spoke_half_w );
1331  break;
1332 
1333  case 3: // left stub
1334  spoke.Append( spoke_half_w, spoke_half_w );
1335  spoke.Append( spoke_half_w, -spoke_half_w );
1336  spoke.Append( reliefBB.GetLeft(), -spoke_half_w );
1337  spoke.Append( reliefBB.GetLeft(), 0 ); // test pt
1338  spoke.Append( reliefBB.GetLeft(), spoke_half_w );
1339  break;
1340  }
1341 
1342  spoke.Rotate( -DECIDEG2RAD( padAngle ) );
1343  spoke.Move( shapePos );
1344 
1345  spoke.SetClosed( true );
1346  spoke.GenerateBBoxCache();
1347  aSpokesList.push_back( std::move( spoke ) );
1348  }
1349  }
1350  }
1351 }
BOARD * m_board
Definition: zone_filler.h:115
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:574
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:195
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:148
int GetLocalClearance(wxString *aSource) const override
Function GetLocalClearance returns any local clearances set in the "classic" (ie: pre-rule) system.
Definition: zone.cpp:491
FOOTPRINTS & Footprints()
Definition: board.h:286
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:221
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
int GetThermalReliefSpokeWidth() const
Definition: zone.h:205
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_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 988 of file zone_filler.cpp.

993 {
995 
996  // Features which are min_width should survive pruning; features that are *less* than
997  // min_width should not. Therefore we subtract epsilon from the min_width when
998  // deflating/inflating.
999  int half_min_width = aZone->GetMinThickness() / 2;
1000  int epsilon = Millimeter2iu( 0.001 );
1001  int numSegs = GetArcToSegmentCount( half_min_width, m_maxError, 360.0 );
1002 
1003  // Solid polygons are deflated and inflated during calculations. Deflating doesn't cause
1004  // issues, but inflate is tricky as it can create excessively long and narrow spikes for
1005  // acute angles.
1006  // ALLOW_ACUTE_CORNERS cannot be used due to the spike problem.
1007  // CHAMFER_ACUTE_CORNERS is tempting, but can still produce spikes in some unusual
1008  // circumstances (https://gitlab.com/kicad/code/kicad/-/issues/5581).
1009  // It's unclear if ROUND_ACUTE_CORNERS would have the same issues, but is currently avoided
1010  // as a "less-safe" option.
1011  // ROUND_ALL_CORNERS produces the uniformly nicest shapes, but also a lot of segments.
1012  // CHAMFER_ALL_CORNERS improves the segement count.
1015 
1016  std::deque<SHAPE_LINE_CHAIN> thermalSpokes;
1017  SHAPE_POLY_SET clearanceHoles;
1018 
1019  aRawPolys = aSmoothedOutline;
1020  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In1_Cu, "smoothed-outline" );
1021 
1023  return false;
1024 
1025  knockoutThermalReliefs( aZone, aLayer, aRawPolys );
1026  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In2_Cu, "minus-thermal-reliefs" );
1027 
1029  return false;
1030 
1031  buildCopperItemClearances( aZone, aLayer, clearanceHoles );
1032  DUMP_POLYS_TO_COPPER_LAYER( clearanceHoles, In3_Cu, "clearance-holes" );
1033 
1035  return false;
1036 
1037  buildThermalSpokes( aZone, aLayer, thermalSpokes );
1038 
1040  return false;
1041 
1042  // Create a temporary zone that we can hit-test spoke-ends against. It's only temporary
1043  // because the "real" subtract-clearance-holes has to be done after the spokes are added.
1044  static const bool USE_BBOX_CACHES = true;
1045  SHAPE_POLY_SET testAreas = aRawPolys;
1046  testAreas.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );
1047  DUMP_POLYS_TO_COPPER_LAYER( testAreas, In4_Cu, "minus-clearance-holes" );
1048 
1049  // Prune features that don't meet minimum-width criteria
1050  if( half_min_width - epsilon > epsilon )
1051  {
1052  testAreas.Deflate( half_min_width - epsilon, numSegs, fastCornerStrategy );
1053  DUMP_POLYS_TO_COPPER_LAYER( testAreas, In5_Cu, "spoke-test-deflated" );
1054 
1055  testAreas.Inflate( half_min_width - epsilon, numSegs, fastCornerStrategy );
1056  DUMP_POLYS_TO_COPPER_LAYER( testAreas, In6_Cu, "spoke-test-reinflated" );
1057  }
1058 
1060  return false;
1061 
1062  // Spoke-end-testing is hugely expensive so we generate cached bounding-boxes to speed
1063  // things up a bit.
1064  testAreas.BuildBBoxCaches();
1065  int interval = 0;
1066 
1067  SHAPE_POLY_SET debugSpokes;
1068 
1069  for( const SHAPE_LINE_CHAIN& spoke : thermalSpokes )
1070  {
1071  const VECTOR2I& testPt = spoke.CPoint( 3 );
1072 
1073  // Hit-test against zone body
1074  if( testAreas.Contains( testPt, -1, 1, USE_BBOX_CACHES ) )
1075  {
1076  if( m_debugZoneFiller )
1077  debugSpokes.AddOutline( spoke );
1078 
1079  aRawPolys.AddOutline( spoke );
1080  continue;
1081  }
1082 
1083  if( interval++ > 400 )
1084  {
1086  return false;
1087 
1088  interval = 0;
1089  }
1090 
1091  // Hit-test against other spokes
1092  for( const SHAPE_LINE_CHAIN& other : thermalSpokes )
1093  {
1094  if( &other != &spoke && other.PointInside( testPt, 1, USE_BBOX_CACHES ) )
1095  {
1096  if( m_debugZoneFiller )
1097  debugSpokes.AddOutline( spoke );
1098 
1099  aRawPolys.AddOutline( spoke );
1100  break;
1101  }
1102  }
1103  }
1104 
1105  DUMP_POLYS_TO_COPPER_LAYER( debugSpokes, In7_Cu, "spokes" );
1106 
1108  return false;
1109 
1110  aRawPolys.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );
1111  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In8_Cu, "after-spoke-trimming" );
1112 
1113  // Prune features that don't meet minimum-width criteria
1114  if( half_min_width - epsilon > epsilon )
1115  aRawPolys.Deflate( half_min_width - epsilon, numSegs, cornerStrategy );
1116 
1117  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In9_Cu, "deflated" );
1118 
1120  return false;
1121 
1122  // Now remove the non filled areas due to the hatch pattern
1123  if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
1124  {
1125  if( !addHatchFillTypeOnZone( aZone, aLayer, aDebugLayer, aRawPolys ) )
1126  return false;
1127  }
1128 
1130  return false;
1131 
1132  // Re-inflate after pruning of areas that don't meet minimum-width criteria
1133  if( aZone->GetFilledPolysUseThickness() )
1134  {
1135  // If we're stroking the zone with a min_width stroke then this will naturally inflate
1136  // the zone by half_min_width
1137  }
1138  else if( half_min_width - epsilon > epsilon )
1139  {
1140  aRawPolys.Inflate( half_min_width - epsilon, numSegs, cornerStrategy );
1141  }
1142 
1143  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In15_Cu, "after-reinflating" );
1144 
1145  // Ensure additive changes (thermal stubs and particularly inflating acute corners) do not
1146  // add copper outside the zone boundary or inside the clearance holes
1147  aRawPolys.BooleanIntersection( aMaxExtents, SHAPE_POLY_SET::PM_FAST );
1148  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In16_Cu, "after-trim-to-outline" );
1149  aRawPolys.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );
1150  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In17_Cu, "after-trim-to-clearance-holes" );
1151 
1152  // Lastly give any same-net but higher-priority zones control over their own area.
1153  subtractHigherPriorityZones( aZone, aLayer, aRawPolys );
1154  DUMP_POLYS_TO_COPPER_LAYER( aRawPolys, In18_Cu, "minus-higher-priority-zones" );
1155 
1156  aRawPolys.Fracture( SHAPE_POLY_SET::PM_FAST );
1157  return true;
1158 }
#define DUMP_POLYS_TO_COPPER_LAYER(a, b, c)
All angles are chamfered.
PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:119
BOARD * m_board
Definition: zone_filler.h:115
CORNER_STRATEGY
< define how inflate transform build inflated polygon
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.h:574
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Returns true if a given subpolygon contains the point aP.
void Inflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
Performs outline inflation/deflation.
ZONE_FILL_MODE GetFillMode() const
Definition: zone.h:186
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:247
SHAPE_POLY_SET.
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)
Performs boolean polyset intersection For aFastMode meaning, see function booleanOp
void Fracture(POLYGON_MODE aFastMode)
Converts a set of polygons with holes to a singe outline with "slits"/"fractures" connecting the oute...
void BuildBBoxCaches()
Constructs BBoxCaches for Contains(), below.
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 outline to the set and returns its index
SHAPE_LINE_CHAIN.
bool m_debugZoneFiller
Definition: zone_filler.h:126
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)
Performs boolean polyset difference 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:712

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 
)

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

1168 {
1169  SHAPE_POLY_SET* boardOutline = m_brdOutlinesValid ? &m_boardOutline : nullptr;
1170  SHAPE_POLY_SET maxExtents;
1171  SHAPE_POLY_SET smoothedPoly;
1172  PCB_LAYER_ID debugLayer = UNDEFINED_LAYER;
1173 
1174  if( m_debugZoneFiller && LSET::InternalCuMask().Contains( aLayer ) )
1175  {
1176  debugLayer = aLayer;
1177  aLayer = F_Cu;
1178  }
1179 
1180  /*
1181  * convert outlines + holes to outlines without holes (adding extra segments if necessary)
1182  * m_Poly data is expected normalized, i.e. NormalizeAreaOutlines was used after building
1183  * this zone
1184  */
1185  if ( !aZone->BuildSmoothedPoly( maxExtents, aLayer, boardOutline, &smoothedPoly ) )
1186  return false;
1187 
1189  return false;
1190 
1191  if( aZone->IsOnCopperLayer() )
1192  {
1193  if( computeRawFilledArea( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aRawPolys ) )
1194  aZone->SetNeedRefill( false );
1195 
1196  aFinalPolys = aRawPolys;
1197  }
1198  else
1199  {
1200  // Features which are min_width should survive pruning; features that are *less* than
1201  // min_width should not. Therefore we subtract epsilon from the min_width when
1202  // deflating/inflating.
1203  int half_min_width = aZone->GetMinThickness() / 2;
1204  int epsilon = Millimeter2iu( 0.001 );
1205  int numSegs = GetArcToSegmentCount( half_min_width, m_maxError, 360.0 );
1206 
1207  smoothedPoly.Deflate( half_min_width - epsilon, numSegs );
1208 
1209  // Remove the non filled areas due to the hatch pattern
1210  if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
1211  addHatchFillTypeOnZone( aZone, aLayer, debugLayer, smoothedPoly );
1212 
1213  // Re-inflate after pruning of areas that don't meet minimum-width criteria
1214  if( aZone->GetFilledPolysUseThickness() )
1215  {
1216  // If we're stroking the zone with a min_width stroke then this will naturally
1217  // inflate the zone by half_min_width
1218  }
1219  else if( half_min_width - epsilon > epsilon )
1220  {
1221  smoothedPoly.Deflate( -( half_min_width - epsilon ), numSegs );
1222  }
1223 
1224  aRawPolys = smoothedPoly;
1225  aFinalPolys = smoothedPoly;
1226 
1228  aZone->SetNeedRefill( false );
1229  }
1230 
1231  return true;
1232 }
PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:119
bool BuildSmoothedPoly(SHAPE_POLY_SET &aSmoothedPoly, PCB_LAYER_ID aLayer, SHAPE_POLY_SET *aBoardOutline, SHAPE_POLY_SET *aSmoothedPolyWithApron=nullptr) const
Function GetSmoothedPoly.
Definition: zone.cpp:1167
ZONE_FILL_MODE GetFillMode() const
Definition: zone.h:186
PCB_LAYER_ID
A quick note on layer IDs:
bool IsCancelled() const
int GetMinThickness() const
Definition: zone.h:247
SHAPE_POLY_SET.
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)
Converts a set of polygons with holes to a singe outline with "slits"/"fractures" connecting the oute...
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:126
bool IsOnCopperLayer() const override
Function IsOnCopperLayer.
Definition: zone.cpp:221
SHAPE_POLY_SET m_boardOutline
Definition: zone_filler.h:116
bool m_brdOutlinesValid
Definition: zone_filler.h:117
void SetNeedRefill(bool aNeedRefill)
Definition: zone.h:241
static constexpr int Millimeter2iu(double mm)
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
bool GetFilledPolysUseThickness() const
Definition: zone.h:712

References addHatchFillTypeOnZone(), ZONE::BuildSmoothedPoly(), computeRawFilledArea(), SHAPE_POLY_SET::Deflate(), F_Cu, SHAPE_POLY_SET::Fracture(), GetArcToSegmentCount(), ZONE::GetFilledPolysUseThickness(), ZONE::GetFillMode(), ZONE::GetMinThickness(), HATCH_PATTERN, 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:121
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(), EDIT_TOOL::Remove(), and ZONE_FILLER_TOOL::ZoneFill().

◆ IsDebug()

bool ZONE_FILLER::IsDebug ( ) const
inline

Definition at line 49 of file zone_filler.h.

49 { return m_debugZoneFiller; }
bool m_debugZoneFiller
Definition: zone_filler.h:126

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

611 {
612  SHAPE_POLY_SET holes;
613 
614  for( FOOTPRINT* footprint : m_board->Footprints() )
615  {
616  for( PAD* pad : footprint->Pads() )
617  {
618  if( !hasThermalConnection( pad, aZone ) )
619  continue;
620 
621  int gap = aZone->GetThermalReliefGap( pad );
622 
623  // If the pad isn't on the current layer but has a hole, knock out a thermal relief
624  // for the hole.
625  if( !pad->FlashLayer( aLayer ) )
626  {
627  if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
628  continue;
629 
630  // Note: drill size represents finish size, which means the actual holes size is
631  // the plating thickness larger.
632  if( pad->GetAttribute() == PAD_ATTRIB_PTH )
633  gap += pad->GetBoard()->GetDesignSettings().GetHolePlatingThickness();
634 
635  pad->TransformHoleWithClearanceToPolygon( holes, gap, m_maxError, ERROR_OUTSIDE );
636  }
637  else
638  {
639  addKnockout( pad, aLayer, gap, holes );
640  }
641  }
642  }
643 
645 }
BOARD * m_board
Definition: zone_filler.h:115
int GetThermalReliefGap() const
Definition: zone.h:195
SHAPE_POLY_SET.
FOOTPRINTS & Footprints()
Definition: board.h:286
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)
Performs boolean polyset difference 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(), ZONE::GetThermalReliefGap(), hasThermalConnection(), m_board, m_maxError, 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:119
COMMIT * m_commit
Definition: zone_filler.h:118

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

927 {
928  auto knockoutZoneOutline =
929  [&]( ZONE* aKnockout )
930  {
931  // If the zones share no common layers
932  if( !aKnockout->GetLayerSet().test( aLayer ) )
933  return;
934 
935  if( aKnockout->GetCachedBoundingBox().Intersects( aZone->GetCachedBoundingBox() ) )
936  {
937  aRawFill.BooleanSubtract( *aKnockout->Outline(), SHAPE_POLY_SET::PM_FAST );
938  }
939  };
940 
941  for( ZONE* otherZone : m_board->Zones() )
942  {
943  if( otherZone->GetNetCode() == aZone->GetNetCode()
944  && otherZone->GetPriority() > aZone->GetPriority() )
945  {
946  knockoutZoneOutline( otherZone );
947  }
948  }
949 
950  for( FOOTPRINT* footprint : m_board->Footprints() )
951  {
952  for( ZONE* otherZone : footprint->Zones() )
953  {
954  if( otherZone->GetNetCode() == aZone->GetNetCode()
955  && otherZone->GetPriority() > aZone->GetPriority() )
956  {
957  knockoutZoneOutline( otherZone );
958  }
959  }
960  }
961 }
int GetNetCode() const
Function GetNetCode.
ZONES & Zones()
Definition: board.h:292
unsigned GetPriority() const
Function GetPriority.
Definition: zone.h:124
BOARD * m_board
Definition: zone_filler.h:115
const EDA_RECT GetCachedBoundingBox() const
ONLY TO BE USED BY CLIENTS WHICH SET UP THE CACHE!
Definition: zone.h:148
FOOTPRINTS & Footprints()
Definition: board.h:286
ZONE handles a list of polygons defining a copper zone.
Definition: zone.h:57
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Performs boolean polyset difference 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 116 of file zone_filler.h.

Referenced by Fill(), and fillSingleZone().

◆ m_brdOutlinesValid

bool ZONE_FILLER::m_brdOutlinesValid
private

Definition at line 117 of file zone_filler.h.

Referenced by Fill(), and fillSingleZone().

◆ m_commit

COMMIT* ZONE_FILLER::m_commit
private

Definition at line 118 of file zone_filler.h.

Referenced by Fill(), and SetProgressReporter().

◆ m_debugZoneFiller

bool ZONE_FILLER::m_debugZoneFiller
private

Definition at line 126 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 121 of file zone_filler.h.

Referenced by InstallNewProgressReporter().

◆ m_worstClearance

int ZONE_FILLER::m_worstClearance
private

Definition at line 124 of file zone_filler.h.

Referenced by buildCopperItemClearances(), and Fill().


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