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

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

68 {
69 }

Member Function Documentation

◆ addHatchFillTypeOnZone()

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

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

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

Definition at line 1358 of file zone_filler.cpp.

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

536 {
537  if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
538  {
539  SHAPE_POLY_SET poly;
540  aPad->TransformShapeWithClearanceToPolygon( poly, aLayer, aGap, m_maxError,
541  ERROR_OUTSIDE );
542 
543  // the pad shape in zone can be its convex hull or the shape itself
545  {
546  std::vector<wxPoint> convex_hull;
547  BuildConvexHull( convex_hull, poly );
548 
549  aHoles.NewOutline();
550 
551  for( const wxPoint& pt : convex_hull )
552  aHoles.Append( pt );
553  }
554  else
555  aHoles.Append( poly );
556  }
557  else
558  {
559  aPad->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_maxError,
560  ERROR_OUTSIDE );
561  }
562 }
PAD_SHAPE_T GetShape() const
Definition: pad.h:159
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:179
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:89

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

571 {
572  switch( aItem->Type() )
573  {
574  case PCB_SHAPE_T:
575  {
576  PCB_SHAPE* shape = (PCB_SHAPE*) aItem;
577  shape->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_maxError,
578  ERROR_OUTSIDE, aIgnoreLineWidth );
579  break;
580  }
581  case PCB_TEXT_T:
582  {
583  PCB_TEXT* text = (PCB_TEXT*) aItem;
584  text->TransformBoundingBoxWithClearanceToPolygon( &aHoles, aGap );
585  break;
586  }
587  case PCB_FP_SHAPE_T:
588  {
589  FP_SHAPE* shape = (FP_SHAPE*) aItem;
590  shape->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_maxError,
591  ERROR_OUTSIDE, aIgnoreLineWidth );
592  break;
593  }
594  case PCB_FP_TEXT_T:
595  {
596  FP_TEXT* text = (FP_TEXT*) aItem;
597 
598  if( text->IsVisible() )
599  text->TransformBoundingBoxWithClearanceToPolygon( &aHoles, aGap );
600 
601  break;
602  }
603  default:
604  break;
605  }
606 }
class FP_TEXT, text in a footprint
Definition: typeinfo.h:93
bool IsVisible() const
Definition: eda_text.h:192
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:94
void TransformBoundingBoxWithClearanceToPolygon(SHAPE_POLY_SET *aCornerBuffer, int aClearanceValue) const
Convert the text bounding box to a rectangular polygon depending on the text orientation,...
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 draw segment to a closed polygon Used in fi...
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:91
KICAD_T Type() const
Function Type()
Definition: eda_item.h:181

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

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

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

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

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

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

1172 {
1173  SHAPE_POLY_SET* boardOutline = m_brdOutlinesValid ? &m_boardOutline : nullptr;
1174  SHAPE_POLY_SET maxExtents;
1175  SHAPE_POLY_SET smoothedPoly;
1176  PCB_LAYER_ID debugLayer = UNDEFINED_LAYER;
1177 
1178  if( m_debugZoneFiller && LSET::InternalCuMask().Contains( aLayer ) )
1179  {
1180  debugLayer = aLayer;
1181  aLayer = F_Cu;
1182  }
1183 
1184  /*
1185  * convert outlines + holes to outlines without holes (adding extra segments if necessary)
1186  * m_Poly data is expected normalized, i.e. NormalizeAreaOutlines was used after building
1187  * this zone
1188  */
1189  if ( !aZone->BuildSmoothedPoly( maxExtents, aLayer, boardOutline, &smoothedPoly ) )
1190  return false;
1191 
1193  return false;
1194 
1195  if( aZone->IsOnCopperLayer() )
1196  {
1197  if( computeRawFilledArea( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aRawPolys ) )
1198  aZone->SetNeedRefill( false );
1199 
1200  aFinalPolys = aRawPolys;
1201  }
1202  else
1203  {
1204  // Features which are min_width should survive pruning; features that are *less* than
1205  // min_width should not. Therefore we subtract epsilon from the min_width when
1206  // deflating/inflating.
1207  int half_min_width = aZone->GetMinThickness() / 2;
1208  int epsilon = Millimeter2iu( 0.001 );
1209  int numSegs = GetArcToSegmentCount( half_min_width, m_maxError, 360.0 );
1210 
1211  smoothedPoly.Deflate( half_min_width - epsilon, numSegs );
1212 
1213  // Remove the non filled areas due to the hatch pattern
1214  if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
1215  addHatchFillTypeOnZone( aZone, aLayer, debugLayer, smoothedPoly );
1216 
1217  // Re-inflate after pruning of areas that don't meet minimum-width criteria
1218  if( aZone->GetFilledPolysUseThickness() )
1219  {
1220  // If we're stroking the zone with a min_width stroke then this will naturally
1221  // inflate the zone by half_min_width
1222  }
1223  else if( half_min_width - epsilon > epsilon )
1224  {
1225  smoothedPoly.Deflate( -( half_min_width - epsilon ), numSegs );
1226  }
1227 
1228  aRawPolys = smoothedPoly;
1229  aFinalPolys = smoothedPoly;
1230 
1232  aZone->SetNeedRefill( false );
1233  }
1234 
1235  return true;
1236 }
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:1168
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:242
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:236
static constexpr int Millimeter2iu(double mm)
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
bool GetFilledPolysUseThickness() const
Definition: zone.h:704

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

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

References m_uniqueReporter, and SetProgressReporter().

Referenced by ZONE_FILLER_TOOL::CheckAllZones(), PCB_EDIT_FRAME::Edit_Zone_Params(), ZONE_FILLER_TOOL::FillAllZones(), 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 613 of file zone_filler.cpp.

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

81 {
82  m_progressReporter = aReporter;
83  wxASSERT_MSG( m_commit, "ZONE_FILLER must have a valid commit to call SetProgressReporter" );
84 }
PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h: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 929 of file zone_filler.cpp.

931 {
932  auto knockoutZoneOutline =
933  [&]( ZONE* aKnockout )
934  {
935  // If the zones share no common layers
936  if( !aKnockout->GetLayerSet().test( aLayer ) )
937  return;
938 
939  if( aKnockout->GetCachedBoundingBox().Intersects( aZone->GetCachedBoundingBox() ) )
940  {
941  aRawFill.BooleanSubtract( *aKnockout->Outline(), SHAPE_POLY_SET::PM_FAST );
942  }
943  };
944 
945  for( ZONE* otherZone : m_board->Zones() )
946  {
947  if( otherZone->GetNetCode() == aZone->GetNetCode()
948  && otherZone->GetPriority() > aZone->GetPriority() )
949  {
950  knockoutZoneOutline( otherZone );
951  }
952  }
953 
954  for( FOOTPRINT* footprint : m_board->Footprints() )
955  {
956  for( ZONE* otherZone : footprint->Zones() )
957  {
958  if( otherZone->GetNetCode() == aZone->GetNetCode()
959  && otherZone->GetPriority() > aZone->GetPriority() )
960  {
961  knockoutZoneOutline( otherZone );
962  }
963  }
964  }
965 }
int GetNetCode() const
Function GetNetCode.
ZONES & Zones()
Definition: board.h:289
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:143
FOOTPRINTS & Footprints()
Definition: board.h:283
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: