KiCad PCB EDA Suite
ZONE_FILLER Class Reference

#include <zone_filler.h>

Public Member Functions

 ZONE_FILLER (BOARD *aBoard, COMMIT *aCommit=nullptr)
 
 ~ZONE_FILLER ()
 
void InstallNewProgressReporter (wxWindow *aParent, const wxString &aTitle, int aNumPhases)
 
bool Fill (const std::vector< ZONE_CONTAINER * > &aZones, bool aCheck=false)
 

Private Member Functions

void addKnockout (D_PAD *aPad, int aGap, SHAPE_POLY_SET &aHoles)
 Add a knockout for a pad. More...
 
void addKnockout (BOARD_ITEM *aItem, int aGap, bool aIgnoreLineWidth, SHAPE_POLY_SET &aHoles)
 Add a knockout for a graphic item. More...
 
void knockoutThermalReliefs (const ZONE_CONTAINER *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_CONTAINER *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 computeRawFilledArea (const ZONE_CONTAINER *aZone, PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aSmoothedOutline, std::set< VECTOR2I > *aPreserveCorners, SHAPE_POLY_SET &aRawPolys, SHAPE_POLY_SET &aFinalPolys)
 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_CONTAINER *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_CONTAINER *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...
 
void addHatchFillTypeOnZone (const ZONE_CONTAINER *aZone, PCB_LAYER_ID aLayer, 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
 
WX_PROGRESS_REPORTERm_progressReporter
 
std::unique_ptr< WX_PROGRESS_REPORTERm_uniqueReporter
 
int m_high_def
 
int m_low_def
 

Detailed Description

Definition at line 39 of file zone_filler.h.

Constructor & Destructor Documentation

◆ ZONE_FILLER()

ZONE_FILLER::ZONE_FILLER ( BOARD aBoard,
COMMIT aCommit = nullptr 
)

Definition at line 77 of file zone_filler.cpp.

77  :
78  m_board( aBoard ),
79  m_brdOutlinesValid( false ),
80  m_commit( aCommit ),
81  m_progressReporter( nullptr ),
82  m_high_def( 9 ),
83  m_low_def( 6 )
84 {
85 }
BOARD * m_board
Definition: zone_filler.h:110
WX_PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:115
COMMIT * m_commit
Definition: zone_filler.h:114
bool m_brdOutlinesValid
Definition: zone_filler.h:112

◆ ~ZONE_FILLER()

ZONE_FILLER::~ZONE_FILLER ( )

Definition at line 88 of file zone_filler.cpp.

89 {
90 }

Member Function Documentation

◆ addHatchFillTypeOnZone()

void ZONE_FILLER::addHatchFillTypeOnZone ( const ZONE_CONTAINER aZone,
PCB_LAYER_ID  aLayer,
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 1038 of file zone_filler.cpp.

1040 {
1041  // Build grid:
1042 
1043  // obviously line thickness must be > zone min thickness.
1044  // It can happens if a board file was edited by hand by a python script
1045  // Use 1 micron margin to be *sure* there is no issue in Gerber files
1046  // (Gbr file unit = 1 or 10 nm) due to some truncation in coordinates or calculations
1047  // This margin also avoid problems due to rounding coordinates in next calculations
1048  // that can create incorrect polygons
1049  int thickness = std::max( aZone->GetHatchFillTypeThickness(),
1050  aZone->GetMinThickness()+Millimeter2iu( 0.001 ) );
1051 
1052  int linethickness = thickness - aZone->GetMinThickness();
1053  int gridsize = thickness + aZone->GetHatchFillTypeGap();
1054  double orientation = aZone->GetHatchFillTypeOrientation();
1055 
1056  SHAPE_POLY_SET filledPolys = aRawPolys;
1057  // Use a area that contains the rotated bbox by orientation,
1058  // and after rotate the result by -orientation.
1059  if( orientation != 0.0 )
1060  {
1061  filledPolys.Rotate( M_PI/180.0 * orientation, VECTOR2I( 0,0 ) );
1062  }
1063 
1064  BOX2I bbox = filledPolys.BBox( 0 );
1065 
1066  // Build hole shape
1067  // the hole size is aZone->GetHatchFillTypeGap(), but because the outline thickness
1068  // is aZone->GetMinThickness(), the hole shape size must be larger
1069  SHAPE_LINE_CHAIN hole_base;
1070  int hole_size = aZone->GetHatchFillTypeGap() + aZone->GetMinThickness();
1071  VECTOR2I corner( 0, 0 );;
1072  hole_base.Append( corner );
1073  corner.x += hole_size;
1074  hole_base.Append( corner );
1075  corner.y += hole_size;
1076  hole_base.Append( corner );
1077  corner.x = 0;
1078  hole_base.Append( corner );
1079  hole_base.SetClosed( true );
1080 
1081  // Calculate minimal area of a grid hole.
1082  // All holes smaller than a threshold will be removed
1083  double minimal_hole_area = hole_base.Area() / 2;
1084 
1085  // Now convert this hole to a smoothed shape:
1086  if( aZone->GetHatchFillTypeSmoothingLevel() > 0 )
1087  {
1088  // the actual size of chamfer, or rounded corner radius is the half size
1089  // of the HatchFillTypeGap scaled by aZone->GetHatchFillTypeSmoothingValue()
1090  // aZone->GetHatchFillTypeSmoothingValue() = 1.0 is the max value for the chamfer or the
1091  // radius of corner (radius = half size of the hole)
1092  int smooth_value = KiROUND( aZone->GetHatchFillTypeGap()
1093  * aZone->GetHatchFillTypeSmoothingValue() / 2 );
1094 
1095  // Minimal optimization:
1096  // make smoothing only for reasonnable smooth values, to avoid a lot of useless segments
1097  // and if the smooth value is small, use chamfer even if fillet is requested
1098  #define SMOOTH_MIN_VAL_MM 0.02
1099  #define SMOOTH_SMALL_VAL_MM 0.04
1100  if( smooth_value > Millimeter2iu( SMOOTH_MIN_VAL_MM ) )
1101  {
1102  SHAPE_POLY_SET smooth_hole;
1103  smooth_hole.AddOutline( hole_base );
1104  int smooth_level = aZone->GetHatchFillTypeSmoothingLevel();
1105 
1106  if( smooth_value < Millimeter2iu( SMOOTH_SMALL_VAL_MM ) && smooth_level > 1 )
1107  smooth_level = 1;
1108  // Use a larger smooth_value to compensate the outline tickness
1109  // (chamfer is not visible is smooth value < outline thickess)
1110  smooth_value += aZone->GetMinThickness()/2;
1111 
1112  // smooth_value cannot be bigger than the half size oh the hole:
1113  smooth_value = std::min( smooth_value, aZone->GetHatchFillTypeGap()/2 );
1114  // the error to approximate a circle by segments when smoothing corners by a arc
1115  int error_max = std::max( Millimeter2iu( 0.01), smooth_value/20 );
1116 
1117  switch( smooth_level )
1118  {
1119  case 1:
1120  // Chamfer() uses the distance from a corner to create a end point
1121  // for the chamfer.
1122  hole_base = smooth_hole.Chamfer( smooth_value ).Outline( 0 );
1123  break;
1124 
1125  default:
1126  if( aZone->GetHatchFillTypeSmoothingLevel() > 2 )
1127  error_max /= 2; // Force better smoothing
1128  hole_base = smooth_hole.Fillet( smooth_value, error_max ).Outline( 0 );
1129  break;
1130 
1131  case 0:
1132  break;
1133  };
1134  }
1135  }
1136 
1137  // Build holes
1138  SHAPE_POLY_SET holes;
1139 
1140  for( int xx = 0; ; xx++ )
1141  {
1142  int xpos = xx * gridsize;
1143 
1144  if( xpos > bbox.GetWidth() )
1145  break;
1146 
1147  for( int yy = 0; ; yy++ )
1148  {
1149  int ypos = yy * gridsize;
1150 
1151  if( ypos > bbox.GetHeight() )
1152  break;
1153 
1154  // Generate hole
1155  SHAPE_LINE_CHAIN hole( hole_base );
1156  hole.Move( VECTOR2I( xpos, ypos ) );
1157  holes.AddOutline( hole );
1158  }
1159  }
1160 
1161  holes.Move( bbox.GetPosition() );
1162 
1163  // Clamp holes to the area of filled zones with a outline thickness
1164  // > aZone->GetMinThickness() to be sure the thermal pads can be built
1165  int outline_margin = std::max( (aZone->GetMinThickness()*10)/9, linethickness/2 );
1166  filledPolys.Deflate( outline_margin, 16 );
1167  holes.BooleanIntersection( filledPolys, SHAPE_POLY_SET::PM_FAST );
1168 
1169  if( orientation != 0.0 )
1170  holes.Rotate( -M_PI/180.0 * orientation, VECTOR2I( 0,0 ) );
1171 
1172  // Now filter truncated holes to avoid small holes in pattern
1173  // It happens for holes near the zone outline
1174  for( int ii = 0; ii < holes.OutlineCount(); )
1175  {
1176  double area = holes.Outline( ii ).Area();
1177 
1178  if( area < minimal_hole_area ) // The current hole is too small: remove it
1179  holes.DeletePolygon( ii );
1180  else
1181  ++ii;
1182  }
1183 
1184  // create grid. Use SHAPE_POLY_SET::PM_STRICTLY_SIMPLE to
1185  // generate strictly simple polygons needed by Gerber files and Fracture()
1186  aRawPolys.BooleanSubtract( aRawPolys, holes, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
1187 }
int OutlineCount() const
Returns the number of outlines in the set
int GetHatchFillTypeThickness() const
Definition: class_zone.h:210
#define SMOOTH_MIN_VAL_MM
double GetHatchFillTypeOrientation() const
Definition: class_zone.h:216
double GetHatchFillTypeSmoothingValue() const
Definition: class_zone.h:222
void Rotate(double aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Function Rotate rotates all vertices by a given angle.
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
void SetClosed(bool aClosed)
Function SetClosed()
void Move(const VECTOR2I &aVector) override
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:196
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:193
SHAPE_POLY_SET Fillet(int aRadius, int aErrorMax, std::set< VECTOR2I > *aPreserveCorners=nullptr)
Function Fillet returns a filleted version of the polygon set.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index
SHAPE_LINE_CHAIN.
SHAPE_POLY_SET Chamfer(int aDistance, std::set< VECTOR2I > *aPreserveCorners=nullptr)
Function Chamfer returns a chamfered version of the polygon set.
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:197
int GetMinThickness() const
Definition: class_zone.h:201
int GetHatchFillTypeSmoothingLevel() const
Definition: class_zone.h:219
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Performs boolean polyset difference For aFastMode meaning, see function booleanOp
const BOX2I BBox(int aClearance=0) const override
Function BBox()
int GetHatchFillTypeGap() const
Definition: class_zone.h:213

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(), SHAPE_POLY_SET::Fillet(), ZONE_CONTAINER::GetHatchFillTypeGap(), ZONE_CONTAINER::GetHatchFillTypeOrientation(), ZONE_CONTAINER::GetHatchFillTypeSmoothingLevel(), ZONE_CONTAINER::GetHatchFillTypeSmoothingValue(), ZONE_CONTAINER::GetHatchFillTypeThickness(), BOX2< Vec >::GetHeight(), ZONE_CONTAINER::GetMinThickness(), BOX2< Vec >::GetPosition(), BOX2< Vec >::GetWidth(), KiROUND(), SHAPE_LINE_CHAIN::Move(), SHAPE_POLY_SET::Move(), SHAPE_POLY_SET::Outline(), SHAPE_POLY_SET::OutlineCount(), 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, VECTOR2< T >::x, and VECTOR2< T >::y.

Referenced by computeRawFilledArea(), and fillSingleZone().

◆ addKnockout() [1/2]

void ZONE_FILLER::addKnockout ( D_PAD aPad,
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 429 of file zone_filler.cpp.

430 {
431  if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
432  {
433  SHAPE_POLY_SET poly;
435 
436  // the pad shape in zone can be its convex hull or the shape itself
438  {
439  std::vector<wxPoint> convex_hull;
440  BuildConvexHull( convex_hull, poly );
441 
442  aHoles.NewOutline();
443 
444  for( const wxPoint& pt : convex_hull )
445  aHoles.Append( pt );
446  }
447  else
448  aHoles.Append( poly );
449  }
450  else
451  {
452  // Optimizing polygon vertex count: the high definition is used for round
453  // and oval pads (pads with large arcs) but low def for other shapes (with
454  // small arcs)
455  if( aPad->GetShape() == PAD_SHAPE_CIRCLE || aPad->GetShape() == PAD_SHAPE_OVAL ||
456  ( aPad->GetShape() == PAD_SHAPE_ROUNDRECT && aPad->GetRoundRectRadiusRatio() > 0.4 ) )
457  aPad->TransformShapeWithClearanceToPolygon( aHoles, aGap, m_high_def );
458  else
459  aPad->TransformShapeWithClearanceToPolygon( aHoles, aGap, m_low_def );
460  }
461 }
SHAPE_POLY_SET.
int NewOutline()
Creates a new empty polygon in the set and returns its index
CUST_PAD_SHAPE_IN_ZONE GetCustomShapeInZoneOpt() const
Definition: class_pad.h:173
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, int aClearanceValue, int aMaxError=ARC_HIGH_DEF, bool ignoreLineWidth=false) const override
Function TransformShapeWithClearanceToPolygon Convert the pad shape to a closed polygon.
double GetRoundRectRadiusRatio() const
Definition: class_pad.h:470
PAD_SHAPE_T GetShape() const
Definition: class_pad.h:153
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, D_PAD::GetCustomShapeInZoneOpt(), D_PAD::GetRoundRectRadiusRatio(), D_PAD::GetShape(), m_high_def, m_low_def, SHAPE_POLY_SET::NewOutline(), PAD_SHAPE_CIRCLE, PAD_SHAPE_CUSTOM, PAD_SHAPE_OVAL, PAD_SHAPE_ROUNDRECT, and D_PAD::TransformShapeWithClearanceToPolygon().

Referenced by buildCopperItemClearances(), and knockoutThermalReliefs().

◆ addKnockout() [2/2]

void ZONE_FILLER::addKnockout ( BOARD_ITEM aItem,
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 468 of file zone_filler.cpp.

470 {
471  switch( aItem->Type() )
472  {
473  case PCB_LINE_T:
474  {
475  DRAWSEGMENT* seg = (DRAWSEGMENT*) aItem;
476  seg->TransformShapeWithClearanceToPolygon( aHoles, aGap, m_high_def, aIgnoreLineWidth );
477  break;
478  }
479  case PCB_TEXT_T:
480  {
481  TEXTE_PCB* text = (TEXTE_PCB*) aItem;
482  text->TransformBoundingBoxWithClearanceToPolygon( &aHoles, aGap );
483  break;
484  }
485  case PCB_MODULE_EDGE_T:
486  {
487  EDGE_MODULE* edge = (EDGE_MODULE*) aItem;
488  edge->TransformShapeWithClearanceToPolygon( aHoles, aGap, m_high_def, aIgnoreLineWidth );
489  break;
490  }
491  case PCB_MODULE_TEXT_T:
492  {
493  TEXTE_MODULE* text = (TEXTE_MODULE*) aItem;
494 
495  if( text->IsVisible() )
496  text->TransformBoundingBoxWithClearanceToPolygon( &aHoles, aGap );
497 
498  break;
499  }
500  default:
501  break;
502  }
503 }
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, int aClearanceValue, int aError=ARC_HIGH_DEF, bool ignoreLineWidth=false) const override
Function TransformShapeWithClearanceToPolygon Convert the draw segment to a closed polygon Used in fi...
bool IsVisible() const
Definition: eda_text.h:185
class TEXTE_PCB, text on a layer
Definition: typeinfo.h:92
void TransformBoundingBoxWithClearanceToPolygon(SHAPE_POLY_SET *aCornerBuffer, int aClearanceValue) const
Convert the text bounding box to a rectangular polygon depending on the text orientation,...
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:94
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:93
class DRAWSEGMENT, a segment not on copper layers
Definition: typeinfo.h:91
KICAD_T Type() const
Function Type()
Definition: base_struct.h:193

References EDA_TEXT::IsVisible(), m_high_def, PCB_LINE_T, PCB_MODULE_EDGE_T, PCB_MODULE_TEXT_T, PCB_TEXT_T, EDA_TEXT::TransformBoundingBoxWithClearanceToPolygon(), DRAWSEGMENT::TransformShapeWithClearanceToPolygon(), and EDA_ITEM::Type().

◆ buildCopperItemClearances()

void ZONE_FILLER::buildCopperItemClearances ( const ZONE_CONTAINER 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 553 of file zone_filler.cpp.

555 {
556  static DRAWSEGMENT dummyEdge;
557  dummyEdge.SetLayer( Edge_Cuts );
558 
559  // a small extra clearance to be sure actual track clearance is not smaller
560  // than requested clearance due to many approximations in calculations,
561  // like arc to segment approx, rounding issues...
562  // 2 microns are a good value
563  int extra_margin = Millimeter2iu( 0.002 );
564 
566  int zone_clearance = aZone->GetLocalClearance();
567  EDA_RECT zone_boundingbox = aZone->GetBoundingBox();
568 
569  // items outside the zone bounding box are skipped, so it needs to be inflated by
570  // the largest clearance value found in the netclasses and rules
571  int biggest_clearance = std::max( zone_clearance, bds.GetBiggestClearanceValue() );
572  zone_boundingbox.Inflate( biggest_clearance + extra_margin );
573 
574  // Use a dummy pad to calculate hole clearance when a pad has a hole but is not on the
575  // zone's copper layer. The dummy pad has the size and shape of the original pad's hole.
576  // We have to give it a parent because some functions expect a non-null parent to find
577  // clearance data, etc.
578  MODULE dummymodule( m_board );
579  D_PAD dummypad( &dummymodule );
580 
581  // Add non-connected pad clearances
582  //
583  for( auto module : m_board->Modules() )
584  {
585  for( auto pad : module->Pads() )
586  {
587  if( !pad->IsOnLayer( aLayer ) )
588  {
589  if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
590  continue;
591 
592  setupDummyPadForHole( pad, dummypad );
593  pad = &dummypad;
594  }
595 
596  if( pad->GetNetCode() != aZone->GetNetCode() || pad->GetNetCode() <= 0
597  || aZone->GetPadConnection( pad ) == ZONE_CONNECTION::NONE )
598  {
599  if( pad->GetBoundingBox().Intersects( zone_boundingbox ) )
600  {
601  int gap;
602 
603  // for pads having the same netcode as the zone, the net clearance has no
604  // meaning so use the greater of the zone clearance and the thermal relief
605  if( pad->GetNetCode() > 0 && pad->GetNetCode() == aZone->GetNetCode() )
606  gap = std::max( zone_clearance, aZone->GetThermalReliefGap( pad ) );
607  else
608  gap = aZone->GetClearance( pad );
609 
610  addKnockout( pad, gap, aHoles );
611  }
612  }
613  }
614  }
615 
616  // Add non-connected track clearances
617  //
618  for( auto track : m_board->Tracks() )
619  {
620  if( !track->IsOnLayer( aLayer ) )
621  continue;
622 
623  if( track->GetNetCode() == aZone->GetNetCode() && ( aZone->GetNetCode() != 0) )
624  continue;
625 
626  if( track->GetBoundingBox().Intersects( zone_boundingbox ) )
627  {
628  int gap = aZone->GetClearance( track ) + extra_margin;
629 
630  track->TransformShapeWithClearanceToPolygon( aHoles, gap, m_low_def );
631  }
632  }
633 
634  // Add graphic item clearances. They are by definition unconnected, and have no clearance
635  // definitions of their own.
636  //
637  auto doGraphicItem =
638  [&]( BOARD_ITEM* aItem )
639  {
640  // A item on the Edge_Cuts is always seen as on any layer:
641  if( !aItem->IsOnLayer( aLayer ) && !aItem->IsOnLayer( Edge_Cuts ) )
642  return;
643 
644  if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
645  {
646  bool ignoreLineWidth = aItem->IsOnLayer( Edge_Cuts );
647  int gap = aZone->GetClearance( aItem );
648 
649  addKnockout( aItem, gap, ignoreLineWidth, aHoles );
650  }
651  };
652 
653  for( auto module : m_board->Modules() )
654  {
655  doGraphicItem( &module->Reference() );
656  doGraphicItem( &module->Value() );
657 
658  for( auto item : module->GraphicalItems() )
659  doGraphicItem( item );
660  }
661 
662  for( auto item : m_board->Drawings() )
663  doGraphicItem( item );
664 
665  // Add zones outlines having an higher priority and keepout
666  //
667  for( ZONE_CONTAINER* zone : m_board->GetZoneList( true ) )
668  {
669 
670  // If the zones share no common layers
671  if( !zone->GetLayerSet().test( aLayer ) )
672  continue;
673 
674  if( !zone->GetIsKeepout() && zone->GetPriority() <= aZone->GetPriority() )
675  continue;
676 
677  if( zone->GetIsKeepout() && !zone->GetDoNotAllowCopperPour() )
678  continue;
679 
680  // A higher priority zone or keepout area is found: remove this area
681  EDA_RECT item_boundingbox = zone->GetBoundingBox();
682 
683  if( item_boundingbox.Intersects( zone_boundingbox ) )
684  {
685  // Add the zone outline area. Don't use any clearance for keepouts, or for zones
686  // with the same net (they will be connected but will honor their own clearance,
687  // thermal connections, etc.).
688  int gap = 0;
689 
690  if( !zone->GetIsKeepout() && aZone->GetNetCode() != zone->GetNetCode() )
691  gap = aZone->GetClearance( zone );
692 
693  zone->TransformOutlinesShapeWithClearanceToPolygon( aHoles, gap );
694  }
695  }
696 
698 }
ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:61
int GetNetCode() const
Function GetNetCode.
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
BOARD * m_board
Definition: zone_filler.h:110
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox (virtual)
Definition: class_zone.cpp:335
int GetBiggestClearanceValue()
Function GetBiggestClearanceValue.
void addKnockout(D_PAD *aPad, int aGap, SHAPE_POLY_SET &aHoles)
Add a knockout for a pad.
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:551
int GetThermalReliefGap(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:345
MODULES & Modules()
Definition: class_board.h:266
void Simplify(POLYGON_MODE aFastMode)
Simplifies the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFast...
int GetLocalClearance(wxString *aSource=nullptr) const override
Function GetLocalClearance returns any local clearances set in the "classic" (ie: pre-rule) system.
Definition: class_zone.cpp:547
ZONE_CONNECTION GetPadConnection(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:839
virtual int GetClearance(BOARD_ITEM *aItem=nullptr, wxString *aSource=nullptr) const
Function GetClearance returns the clearance in internal units.
unsigned GetPriority() const
Function GetPriority.
Definition: class_zone.h:101
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
Pads are not covered.
bool Intersects(const EDA_RECT &aRect) const
Function Intersects tests for a common area between rectangles.
static void setupDummyPadForHole(const D_PAD *aPad, D_PAD &aDummyPad)
Setup aDummyPad to have the same size and shape of aPad's hole.
DRAWINGS & Drawings()
Definition: class_board.h:275
TRACKS & Tracks()
Definition: class_board.h:257
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
std::list< ZONE_CONTAINER * > GetZoneList(bool aIncludeZonesInFootprints=false)
Function GetZoneList.
BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.

References addKnockout(), BOARD::Drawings(), Edge_Cuts, BOARD_DESIGN_SETTINGS::GetBiggestClearanceValue(), ZONE_CONTAINER::GetBoundingBox(), BOARD_CONNECTED_ITEM::GetClearance(), BOARD::GetDesignSettings(), ZONE_CONTAINER::GetLocalClearance(), BOARD_CONNECTED_ITEM::GetNetCode(), ZONE_CONTAINER::GetPadConnection(), ZONE_CONTAINER::GetPriority(), ZONE_CONTAINER::GetThermalReliefGap(), BOARD::GetZoneList(), EDA_RECT::Inflate(), EDA_RECT::Intersects(), m_board, m_low_def, BOARD::Modules(), NONE, SHAPE_POLY_SET::PM_FAST, BOARD_ITEM::SetLayer(), setupDummyPadForHole(), SHAPE_POLY_SET::Simplify(), and BOARD::Tracks().

Referenced by computeRawFilledArea().

◆ buildThermalSpokes()

void ZONE_FILLER::buildThermalSpokes ( const ZONE_CONTAINER 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 922 of file zone_filler.cpp.

924 {
925  auto zoneBB = aZone->GetBoundingBox();
926  int zone_clearance = aZone->GetZoneClearance();
927  int biggest_clearance = m_board->GetDesignSettings().GetBiggestClearanceValue();
928  biggest_clearance = std::max( biggest_clearance, zone_clearance );
929  zoneBB.Inflate( biggest_clearance );
930 
931  // Is a point on the boundary of the polygon inside or outside? This small epsilon lets
932  // us avoid the question.
933  int epsilon = KiROUND( IU_PER_MM * 0.04 ); // about 1.5 mil
934 
935  for( auto module : m_board->Modules() )
936  {
937  for( auto pad : module->Pads() )
938  {
939  if( !hasThermalConnection( pad, aZone ) )
940  continue;
941 
942  // We currently only connect to pads, not pad holes
943  if( !pad->IsOnLayer( aLayer ) )
944  continue;
945 
946  int thermalReliefGap = aZone->GetThermalReliefGap( pad );
947 
948  // Calculate thermal bridge half width
949  int spoke_w = aZone->GetThermalReliefCopperBridge( pad );
950  // Avoid spoke_w bigger than the smaller pad size, because
951  // it is not possible to create stubs bigger than the pad.
952  // Possible refinement: have a separate size for vertical and horizontal stubs
953  spoke_w = std::min( spoke_w, pad->GetSize().x );
954  spoke_w = std::min( spoke_w, pad->GetSize().y );
955 
956  // Cannot create stubs having a width < zone min thickness
957  if( spoke_w <= aZone->GetMinThickness() )
958  continue;
959 
960  int spoke_half_w = spoke_w / 2;
961 
962  // Quick test here to possibly save us some work
963  BOX2I itemBB = pad->GetBoundingBox();
964  itemBB.Inflate( thermalReliefGap + epsilon );
965 
966  if( !( itemBB.Intersects( zoneBB ) ) )
967  continue;
968 
969  // Thermal spokes consist of segments from the pad center to points just outside
970  // the thermal relief.
971  //
972  // We use the bounding-box to lay out the spokes, but for this to work the
973  // bounding box has to be built at the same rotation as the spokes.
974  // We have to use a dummy pad to avoid dirtying the cached shapes
975  wxPoint shapePos = pad->ShapePos();
976  double padAngle = pad->GetOrientation();
977  D_PAD dummy_pad( *pad );
978  dummy_pad.SetOrientation( 0.0 );
979  dummy_pad.SetPosition( { 0, 0 } );
980 
981  BOX2I reliefBB = dummy_pad.GetBoundingBox();
982  reliefBB.Inflate( thermalReliefGap + epsilon );
983 
984  // For circle pads, the thermal spoke orientation is 45 deg
985  if( pad->GetShape() == PAD_SHAPE_CIRCLE )
986  padAngle = s_RoundPadThermalSpokeAngle;
987 
988  for( int i = 0; i < 4; i++ )
989  {
990  SHAPE_LINE_CHAIN spoke;
991  switch( i )
992  {
993  case 0: // lower stub
994  spoke.Append( +spoke_half_w, -spoke_half_w );
995  spoke.Append( -spoke_half_w, -spoke_half_w );
996  spoke.Append( -spoke_half_w, reliefBB.GetBottom() );
997  spoke.Append( 0, reliefBB.GetBottom() ); // test pt
998  spoke.Append( +spoke_half_w, reliefBB.GetBottom() );
999  break;
1000 
1001  case 1: // upper stub
1002  spoke.Append( +spoke_half_w, spoke_half_w );
1003  spoke.Append( -spoke_half_w, spoke_half_w );
1004  spoke.Append( -spoke_half_w, reliefBB.GetTop() );
1005  spoke.Append( 0, reliefBB.GetTop() ); // test pt
1006  spoke.Append( +spoke_half_w, reliefBB.GetTop() );
1007  break;
1008 
1009  case 2: // right stub
1010  spoke.Append( -spoke_half_w, spoke_half_w );
1011  spoke.Append( -spoke_half_w, -spoke_half_w );
1012  spoke.Append( reliefBB.GetRight(), -spoke_half_w );
1013  spoke.Append( reliefBB.GetRight(), 0 ); // test pt
1014  spoke.Append( reliefBB.GetRight(), spoke_half_w );
1015  break;
1016 
1017  case 3: // left stub
1018  spoke.Append( spoke_half_w, spoke_half_w );
1019  spoke.Append( spoke_half_w, -spoke_half_w );
1020  spoke.Append( reliefBB.GetLeft(), -spoke_half_w );
1021  spoke.Append( reliefBB.GetLeft(), 0 ); // test pt
1022  spoke.Append( reliefBB.GetLeft(), spoke_half_w );
1023  break;
1024  }
1025 
1026  spoke.Rotate( -DECIDEG2RAD( padAngle ) );
1027  spoke.Move( shapePos );
1028 
1029  spoke.SetClosed( true );
1030  spoke.GenerateBBoxCache();
1031  aSpokesList.push_back( std::move( spoke ) );
1032  }
1033  }
1034  }
1035 }
int GetThermalReliefCopperBridge(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:354
BOARD * m_board
Definition: zone_filler.h:110
coord_type GetTop() const
Definition: box2.h:203
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox (virtual)
Definition: class_zone.cpp:335
int GetBiggestClearanceValue()
Function GetBiggestClearanceValue.
void Move(const VECTOR2I &aVector) override
static const double s_RoundPadThermalSpokeAngle
Definition: zone_filler.cpp:73
coord_type GetRight() const
Definition: box2.h:198
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:551
coord_type GetBottom() const
Definition: box2.h:199
int GetThermalReliefGap(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:345
void Append(int aX, int aY, bool aAllowDuplication=false)
Function Append()
bool Intersects(const BOX2< Vec > &aRect) const
Function Intersects.
Definition: box2.h:235
void SetClosed(bool aClosed)
Function SetClosed()
MODULES & Modules()
Definition: class_board.h:266
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:301
SHAPE_LINE_CHAIN.
double DECIDEG2RAD(double deg)
Definition: trigo.h:218
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 GetLeft() const
Definition: box2.h:202
int GetZoneClearance() const
Definition: class_zone.h:191
bool hasThermalConnection(D_PAD *pad, const ZONE_CONTAINER *aZone)
Return true if the given pad has a thermal connection with the given zone.

References SHAPE_LINE_CHAIN::Append(), DECIDEG2RAD(), SHAPE_LINE_CHAIN::GenerateBBoxCache(), BOARD_DESIGN_SETTINGS::GetBiggestClearanceValue(), BOX2< Vec >::GetBottom(), ZONE_CONTAINER::GetBoundingBox(), D_PAD::GetBoundingBox(), BOARD::GetDesignSettings(), BOX2< Vec >::GetLeft(), BOX2< Vec >::GetRight(), ZONE_CONTAINER::GetThermalReliefCopperBridge(), ZONE_CONTAINER::GetThermalReliefGap(), BOX2< Vec >::GetTop(), ZONE_CONTAINER::GetZoneClearance(), hasThermalConnection(), BOX2< Vec >::Inflate(), BOX2< Vec >::Intersects(), KiROUND(), m_board, BOARD::Modules(), SHAPE_LINE_CHAIN::Move(), PAD_SHAPE_CIRCLE, SHAPE_LINE_CHAIN::Rotate(), s_RoundPadThermalSpokeAngle, SHAPE_LINE_CHAIN::SetClosed(), D_PAD::SetOrientation(), and D_PAD::SetPosition().

Referenced by computeRawFilledArea().

◆ computeRawFilledArea()

void ZONE_FILLER::computeRawFilledArea ( const ZONE_CONTAINER aZone,
PCB_LAYER_ID  aLayer,
const SHAPE_POLY_SET aSmoothedOutline,
std::set< VECTOR2I > *  aPreserveCorners,
SHAPE_POLY_SET aRawPolys,
SHAPE_POLY_SET aFinalPolys 
)
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 712 of file zone_filler.cpp.

717 {
719  m_low_def = std::min( ARC_LOW_DEF, int( m_high_def*1.5 ) ); // Reasonable value
720 
721  // Features which are min_width should survive pruning; features that are *less* than
722  // min_width should not. Therefore we subtract epsilon from the min_width when
723  // deflating/inflating.
724  int half_min_width = aZone->GetMinThickness() / 2;
725  int epsilon = Millimeter2iu( 0.001 );
726  int numSegs = std::max( GetArcToSegmentCount( half_min_width, m_high_def, 360.0 ), 6 );
727 
728  // solid polygons are deflated and inflated during calculations.
729  // Polygons deflate usually do not create issues.
730  // Polygons inflate is a tricky transform, because it can create excessively long and narrow 'spikes'
731  // especially for acute angles.
732  // But in very case, the inflate transform caannot create bigger shapes than initial shapes.
733  // so the corner strategy is very important.
734  // The best is SHAPE_POLY_SET::ROUND_ALL_CORNERS.
735  // unfortunately, it creates a lot of small segments.
736  // SHAPE_POLY_SET::ALLOW_ACUTE_CORNERS is not acceptable
737  // So for intermediate transforms, we use CHAMFER_ALL_CORNERS.
738  // For final transform, we use ROUND_ALL_CORNERS
741 
742  std::deque<SHAPE_LINE_CHAIN> thermalSpokes;
743  SHAPE_POLY_SET clearanceHoles;
744 
745  std::unique_ptr<SHAPE_FILE_IO> dumper( new SHAPE_FILE_IO(
746  s_DumpZonesWhenFilling ? "zones_dump.txt" : "", SHAPE_FILE_IO::IOM_APPEND ) );
747 
748  aRawPolys = aSmoothedOutline;
749 
751  dumper->BeginGroup( "clipper-zone" );
752 
753  knockoutThermalReliefs( aZone, aLayer, aRawPolys );
754 
756  dumper->Write( &aRawPolys, "solid-areas-minus-thermal-reliefs" );
757 
758  buildCopperItemClearances( aZone, aLayer, clearanceHoles );
759 
761  dumper->Write( &aRawPolys, "clearance holes" );
762 
763  buildThermalSpokes( aZone, aLayer, thermalSpokes );
764 
765  // Create a temporary zone that we can hit-test spoke-ends against. It's only temporary
766  // because the "real" subtract-clearance-holes has to be done after the spokes are added.
767  static const bool USE_BBOX_CACHES = true;
768  SHAPE_POLY_SET testAreas = aRawPolys;
769  testAreas.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );
770 
771  // Prune features that don't meet minimum-width criteria
772  if( half_min_width - epsilon > epsilon )
773  {
774  testAreas.Deflate( half_min_width - epsilon, numSegs, intermediatecornerStrategy );
775  testAreas.Inflate( half_min_width - epsilon, numSegs, intermediatecornerStrategy );
776  }
777 
778  // Spoke-end-testing is hugely expensive so we generate cached bounding-boxes to speed
779  // things up a bit.
780  testAreas.BuildBBoxCaches();
781 
782  for( const SHAPE_LINE_CHAIN& spoke : thermalSpokes )
783  {
784  const VECTOR2I& testPt = spoke.CPoint( 3 );
785 
786  // Hit-test against zone body
787  if( testAreas.Contains( testPt, -1, 1, USE_BBOX_CACHES ) )
788  {
789  aRawPolys.AddOutline( spoke );
790  continue;
791  }
792 
793  // Hit-test against other spokes
794  for( const SHAPE_LINE_CHAIN& other : thermalSpokes )
795  {
796  if( &other != &spoke && other.PointInside( testPt, 1, USE_BBOX_CACHES ) )
797  {
798  aRawPolys.AddOutline( spoke );
799  break;
800  }
801  }
802  }
803 
804  // Ensure previous changes (adding thermal stubs) do not add
805  // filled areas outside the zone boundary
806  aRawPolys.BooleanIntersection( aSmoothedOutline, SHAPE_POLY_SET::PM_FAST );
807  aRawPolys.Simplify( SHAPE_POLY_SET::PM_FAST );
808 
810  dumper->Write( &aRawPolys, "solid-areas-with-thermal-spokes" );
811 
812  aRawPolys.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );
813  // Prune features that don't meet minimum-width criteria
814  if( half_min_width - epsilon > epsilon )
815  aRawPolys.Deflate( half_min_width - epsilon, numSegs, intermediatecornerStrategy );
816 
818  dumper->Write( &aRawPolys, "solid-areas-before-hatching" );
819 
820  // Now remove the non filled areas due to the hatch pattern
822  addHatchFillTypeOnZone( aZone, aLayer, aRawPolys );
823 
825  dumper->Write( &aRawPolys, "solid-areas-after-hatching" );
826 
827  // Re-inflate after pruning of areas that don't meet minimum-width criteria
828  if( aZone->GetFilledPolysUseThickness() )
829  {
830  // If we're stroking the zone with a min_width stroke then this will naturally
831  // inflate the zone by half_min_width
832  }
833  else if( half_min_width - epsilon > epsilon )
834  {
835  aRawPolys.Simplify( SHAPE_POLY_SET::PM_FAST );
836  aRawPolys.Inflate( half_min_width - epsilon, numSegs, finalcornerStrategy );
837 
838  // If we've deflated/inflated by something near our corner radius then we will have
839  // ended up with too-sharp corners. Apply outline smoothing again.
840  if( aZone->GetMinThickness() > (int)aZone->GetCornerRadius() )
841  aRawPolys.BooleanIntersection( aSmoothedOutline, SHAPE_POLY_SET::PM_FAST );
842  }
843 
844  aRawPolys.Fracture( SHAPE_POLY_SET::PM_FAST );
845 
847  dumper->Write( &aRawPolys, "areas_fractured" );
848 
849  aFinalPolys = aRawPolys;
850 
852  dumper->EndGroup();
853 }
SHAPE_FILE_IO.
Definition: shape_file_io.h:39
All angles are chamfered.
BOARD * m_board
Definition: zone_filler.h:110
CORNER_STRATEGY
< define how inflate transform build inflated polygon
bool GetFilledPolysUseThickness() const
Definition: class_zone.h:661
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:551
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.
void buildCopperItemClearances(const ZONE_CONTAINER *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 ...
static const bool s_DumpZonesWhenFilling
Definition: zone_filler.cpp:74
unsigned int GetCornerRadius() const
Definition: class_zone.h:659
SHAPE_POLY_SET.
ZONE_FILL_MODE GetFillMode() const
Definition: class_zone.h:148
void addHatchFillTypeOnZone(const ZONE_CONTAINER *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aRawPolys)
for zones having the ZONE_FILL_MODE::ZONE_FILL_MODE::HATCH_PATTERN, create a grid pattern in filled a...
void Deflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
void Simplify(POLYGON_MODE aFastMode)
Simplifies the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFast...
void buildThermalSpokes(const ZONE_CONTAINER *aZone, PCB_LAYER_ID aLayer, std::deque< SHAPE_LINE_CHAIN > &aSpokes)
Function buildThermalSpokes Constructs a list of all thermal spokes for the given zone.
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_CONTAINER *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.
int GetMinThickness() const
Definition: class_zone.h:201
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Performs boolean polyset difference For aFastMode meaning, see function booleanOp
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)

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(), SHAPE_POLY_SET::Fracture(), GetArcToSegmentCount(), ZONE_CONTAINER::GetCornerRadius(), BOARD::GetDesignSettings(), ZONE_CONTAINER::GetFilledPolysUseThickness(), ZONE_CONTAINER::GetFillMode(), ZONE_CONTAINER::GetMinThickness(), HATCH_PATTERN, SHAPE_POLY_SET::Inflate(), SHAPE_FILE_IO::IOM_APPEND, knockoutThermalReliefs(), m_board, m_high_def, m_low_def, BOARD_DESIGN_SETTINGS::m_MaxError, SHAPE_POLY_SET::PM_FAST, SHAPE_POLY_SET::ROUND_ALL_CORNERS, s_DumpZonesWhenFilling, and SHAPE_POLY_SET::Simplify().

Referenced by fillSingleZone().

◆ Fill()

bool ZONE_FILLER::Fill ( const std::vector< ZONE_CONTAINER * > &  aZones,
bool  aCheck = false 
)

Definition at line 101 of file zone_filler.cpp.

102 {
103  std::vector<std::pair<ZONE_CONTAINER*, PCB_LAYER_ID>> toFill;
104  std::vector<CN_ZONE_ISOLATED_ISLAND_LIST> islandsList;
105 
106  auto connectivity = m_board->GetConnectivity();
107  bool filledPolyWithOutline = not m_board->GetDesignSettings().m_ZoneUseNoOutlineInFill;
108 
109  std::unique_lock<std::mutex> lock( connectivity->GetLock(), std::try_to_lock );
110 
111  if( !lock )
112  return false;
113 
114  if( m_progressReporter )
115  {
116  m_progressReporter->Report( aCheck ? _( "Checking zone fills..." ) : _( "Building zone fills..." ) );
117  m_progressReporter->SetMaxProgress( aZones.size() );
118  }
119 
120  // The board outlines is used to clip solid areas inside the board (when outlines are valid)
123 
124  // Update the bounding box shape caches in the pads to prevent multi-threaded rebuilds
125  for( auto module : m_board->Modules() )
126  {
127  for( auto pad : module->Pads() )
128  {
129  if( pad->IsDirty() )
130  pad->BuildEffectiveShapes();
131  }
132  }
133 
134  for( auto zone : aZones )
135  {
136  // Keepout zones are not filled
137  if( zone->GetIsKeepout() )
138  continue;
139 
140  if( m_commit )
141  m_commit->Modify( zone );
142 
143  // calculate the hash value for filled areas. it will be used later
144  // to know if the current filled areas are up to date
145  for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
146  {
147  zone->BuildHashValue( layer );
148 
149  // Add the zone to the list of zones to test or refill
150  toFill.emplace_back( std::make_pair( zone, layer ) );
151  }
152 
153  islandsList.emplace_back( CN_ZONE_ISOLATED_ISLAND_LIST( zone ) );
154 
155  // Remove existing fill first to prevent drawing invalid polygons
156  // on some platforms
157  zone->UnFill();
158  }
159 
160  std::atomic<size_t> nextItem( 0 );
161  size_t parallelThreadCount =
162  std::min<size_t>( std::thread::hardware_concurrency(), aZones.size() );
163  std::vector<std::future<size_t>> returns( parallelThreadCount );
164 
165  auto fill_lambda = [&] ( PROGRESS_REPORTER* aReporter ) -> size_t
166  {
167  size_t num = 0;
168 
169  for( size_t i = nextItem++; i < toFill.size(); i = nextItem++ )
170  {
171  PCB_LAYER_ID layer = toFill[i].second;
172  ZONE_CONTAINER* zone = toFill[i].first;
173 
174  zone->SetFilledPolysUseThickness( filledPolyWithOutline );
175 
176  SHAPE_POLY_SET rawPolys, finalPolys;
177  fillSingleZone( zone, layer, rawPolys, finalPolys );
178 
179  std::unique_lock<std::mutex> zoneLock( zone->GetLock() );
180 
181  zone->SetRawPolysList( layer, rawPolys );
182  zone->SetFilledPolysList( layer, finalPolys );
183  zone->SetIsFilled( true );
184 
185  if( m_progressReporter )
187 
188  num++;
189  }
190 
191  return num;
192  };
193 
194  if( parallelThreadCount <= 1 )
195  fill_lambda( m_progressReporter );
196  else
197  {
198  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
199  returns[ii] = std::async( std::launch::async, fill_lambda, m_progressReporter );
200 
201  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
202  {
203  // Here we balance returns with a 100ms timeout to allow UI updating
204  std::future_status status;
205  do
206  {
207  if( m_progressReporter )
209 
210  status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) );
211  } while( status != std::future_status::ready );
212  }
213  }
214 
215  // Now update the connectivity to check for copper islands
216  if( m_progressReporter )
217  {
219  m_progressReporter->Report( _( "Removing insulated copper islands..." ) );
221  }
222 
223  connectivity->SetProgressReporter( m_progressReporter );
224  connectivity->FindIsolatedCopperIslands( islandsList );
225 
226  // Now remove insulated copper islands and islands outside the board edge
227  bool outOfDate = false;
228 
229  for( auto& zone : islandsList )
230  {
231  for( PCB_LAYER_ID layer : zone.m_zone->GetLayerSet().Seq() )
232  {
233  if( !zone.m_islands.count( layer ) )
234  continue;
235 
236  std::vector<int>& islands = zone.m_islands.at( layer );
237 
238  std::sort( islands.begin(), islands.end(), std::greater<int>() );
239  SHAPE_POLY_SET poly = zone.m_zone->GetFilledPolysList( layer );
240 
241  long long int minArea = zone.m_zone->GetMinIslandArea();
242  ISLAND_REMOVAL_MODE mode = zone.m_zone->GetIslandRemovalMode();
243 
244  // Remove solid areas outside the board cutouts and the insulated islands
245  // only zones with net code > 0 can have insulated islands by definition
246  if( zone.m_zone->GetNetCode() > 0 )
247  {
248  // solid areas outside the board cutouts are also removed, because they are usually
249  // insulated islands
250  for( auto idx : islands )
251  {
252  if( mode == ISLAND_REMOVAL_MODE::ALWAYS
253  || ( mode == ISLAND_REMOVAL_MODE::AREA
254  && poly.Outline( idx ).Area() < minArea )
255  || !m_boardOutline.Contains( poly.Polygon( idx ).front().CPoint( 0 ) ) )
256  poly.DeletePolygon( idx );
257  else
258  zone.m_zone->SetIsIsland( layer, idx );
259  }
260  }
261  // Zones with no net can have areas outside the board cutouts.
262  // By definition, Zones with no net have no isolated island
263  // (in fact all filled areas are isolated islands)
264  // but they can have some areas outside the board cutouts.
265  // A filled area outside the board cutouts has all points outside cutouts,
266  // so we only need to check one point for each filled polygon.
267  // Note also non copper zones are already clipped
268  else if( m_brdOutlinesValid && zone.m_zone->IsOnCopperLayer() )
269  {
270  for( int idx = 0; idx < poly.OutlineCount(); )
271  {
272  if( poly.Polygon( idx ).empty()
273  || !m_boardOutline.Contains( poly.Polygon( idx ).front().CPoint( 0 ) ) )
274  {
275  poly.DeletePolygon( idx );
276  }
277  else
278  idx++;
279  }
280  }
281 
282  zone.m_zone->SetFilledPolysList( layer, poly );
283  zone.m_zone->CalculateFilledArea();
284 
285  if( aCheck && zone.m_zone->GetHashValue( layer ) != poly.GetHash() )
286  outOfDate = true;
287  }
288  }
289 
290  if( aCheck && outOfDate )
291  {
293  KIDIALOG dlg( m_progressReporter->GetParent(),
294  _( "Zone fills are out-of-date. Refill?" ),
295  _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
296  dlg.SetOKCancelLabels( _( "Refill" ), _( "Continue without Refill" ) );
297  dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
298 
299  if( dlg.ShowModal() == wxID_CANCEL )
300  {
301  if( m_commit )
302  m_commit->Revert();
303 
304  connectivity->SetProgressReporter( nullptr );
305  return false;
306  }
307  }
308 
309  if( m_progressReporter )
310  {
312  m_progressReporter->Report( _( "Performing polygon fills..." ) );
313  m_progressReporter->SetMaxProgress( toFill.size() );
314  }
315 
316 
317  nextItem = 0;
318 
319  auto tri_lambda = [&] ( PROGRESS_REPORTER* aReporter ) -> size_t
320  {
321  size_t num = 0;
322 
323  for( size_t i = nextItem++; i < islandsList.size(); i = nextItem++ )
324  {
325  islandsList[i].m_zone->CacheTriangulation();
326  num++;
327 
328  if( m_progressReporter )
330  }
331 
332  return num;
333  };
334 
335  if( parallelThreadCount <= 1 )
336  tri_lambda( m_progressReporter );
337  else
338  {
339  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
340  returns[ii] = std::async( std::launch::async, tri_lambda, m_progressReporter );
341 
342  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
343  {
344  // Here we balance returns with a 100ms timeout to allow UI updating
345  std::future_status status;
346  do
347  {
348  if( m_progressReporter )
350 
351  status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) );
352  } while( status != std::future_status::ready );
353  }
354  }
355 
356  if( m_progressReporter )
357  {
359  m_progressReporter->Report( _( "Committing changes..." ) );
361  }
362 
363  connectivity->SetProgressReporter( nullptr );
364 
365  if( m_commit )
366  {
367  m_commit->Push( _( "Fill Zone(s)" ), false );
368  }
369  else
370  {
371  for( auto& i : toFill )
372  connectivity->Update( i.first );
373 
374  connectivity->RecalculateRatsnest();
375  }
376 
377  return true;
378 }
virtual void Revert()=0
Revertes the commit by restoring the modifed items state.
void AdvancePhase()
Uses the next vailable virtual zone of the dialog progress bar.
ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:61
COMMIT & Modify(EDA_ITEM *aItem)
Modifies a given item in the model.
Definition: commit.h:103
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox
Definition: confirm.cpp:53
int GetNetCode() const
Function GetNetCode.
void SetFilledPolysUseThickness(bool aOption)
Definition: class_zone.h:662
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: confirm.h:44
void SetRawPolysList(PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aPolysList)
Function SetFilledPolysList sets the list of filled polygons.
Definition: class_zone.h:626
BOARD * m_board
Definition: zone_filler.h:110
A progress reporter for use in multi-threaded environments.
void SetIsIsland(PCB_LAYER_ID aLayer, int aPolyIdx)
Definition: class_zone.h:639
WX_PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:115
void Report(const wxString &aMessage)
Display aMessage in the progress bar dialog.
const SHAPE_POLY_SET & GetFilledPolysList(PCB_LAYER_ID aLayer) const
Function GetFilledPolysList returns a reference to the list of filled polygons.
Definition: class_zone.h:602
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:551
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.
std::mutex & GetLock()
Definition: class_zone.h:180
void SetIsFilled(bool isFilled)
Definition: class_zone.h:186
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Function Seq returns an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:377
MD5_HASH GetHashValue(PCB_LAYER_ID aLayer)
Definition: class_zone.h:787
long long int GetMinIslandArea() const
Definition: class_zone.h:729
virtual LSET GetLayerSet() const override
Function GetLayerSet returns a "layer mask", which is a bitmap of all layers on which the TRACK segme...
Definition: class_zone.cpp:312
PCB_LAYER_ID
A quick note on layer IDs:
COMMIT * m_commit
Definition: zone_filler.h:114
MODULES & Modules()
Definition: class_board.h:266
SHAPE_POLY_SET.
bool fillSingleZone(ZONE_CONTAINER *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...
const ISLAND_REMOVAL_MODE GetIslandRemovalMode() const
Definition: class_zone.h:725
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Function GetConnectivity() returns list of missing connections between components/tracks.
Definition: class_board.h:355
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, wxString *aErrorText=nullptr, wxPoint *aErrorLocation=nullptr)
Function GetBoardPolygonOutlines Extracts the board outlines and build a closed polygon from lines,...
void SetFilledPolysList(PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aPolysList)
Function SetFilledPolysList sets the list of filled polygons.
Definition: class_zone.h:617
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true)=0
Executes the changes.
double CalculateFilledArea()
Compute the area currently occupied by the zone fill.
#define _(s)
Definition: 3d_actions.cpp:33
bool m_ZoneUseNoOutlineInFill
Option to handle filled polygons in zones: the "legacy" option is using thick outlines around filled ...
ISLAND_REMOVAL_MODE
Whether or not to remove isolated islands from a zone.
Definition: zone_settings.h:54
void RemoveAllContours()
Removes all outlines & holes (clears) the polygon set.
bool KeepRefreshing(bool aWait=false)
Update the UI dialog.
SHAPE_POLY_SET m_boardOutline
Definition: zone_filler.h:111
bool m_brdOutlinesValid
Definition: zone_filler.h:112
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)
bool IsOnCopperLayer() const override
Function IsOnCopperLayer.
Definition: class_zone.cpp:242
A structure used for calculating isolated islands on a given zone across all its layers.

References _, PROGRESS_REPORTER::AdvancePhase(), PROGRESS_REPORTER::AdvanceProgress(), ALWAYS, AREA, SHAPE_POLY_SET::Contains(), SHAPE_POLY_SET::DeletePolygon(), KIDIALOG::DoNotShowCheckbox(), fillSingleZone(), BOARD::GetBoardPolygonOutlines(), BOARD::GetConnectivity(), BOARD::GetDesignSettings(), ZONE_CONTAINER::GetLock(), PROGRESS_REPORTER::KeepRefreshing(), m_board, m_boardOutline, m_brdOutlinesValid, m_commit, m_progressReporter, BOARD_DESIGN_SETTINGS::m_ZoneUseNoOutlineInFill, COMMIT::Modify(), BOARD::Modules(), COMMIT::Push(), SHAPE_POLY_SET::RemoveAllContours(), PROGRESS_REPORTER::Report(), COMMIT::Revert(), ZONE_CONTAINER::SetFilledPolysList(), ZONE_CONTAINER::SetFilledPolysUseThickness(), ZONE_CONTAINER::SetIsFilled(), PROGRESS_REPORTER::SetMaxProgress(), and ZONE_CONTAINER::SetRawPolysList().

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(), EDIT_TOOL::Remove(), and ZONE_FILLER_TOOL::ZoneFill().

◆ fillSingleZone()

bool ZONE_FILLER::fillSingleZone ( ZONE_CONTAINER 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 861 of file zone_filler.cpp.

863 {
864  SHAPE_POLY_SET smoothedPoly;
865  std::set<VECTOR2I> colinearCorners;
866  aZone->GetColinearCorners( m_board, colinearCorners );
867 
868  /*
869  * convert outlines + holes to outlines without holes (adding extra segments if necessary)
870  * m_Poly data is expected normalized, i.e. NormalizeAreaOutlines was used after building
871  * this zone
872  */
873  if ( !aZone->BuildSmoothedPoly( smoothedPoly, &colinearCorners ) )
874  return false;
875 
876  if( aZone->IsOnCopperLayer() )
877  {
879  aZone, aLayer, smoothedPoly, &colinearCorners, aRawPolys, aFinalPolys );
880  }
881  else
882  {
883  // Features which are min_width should survive pruning; features that are *less* than
884  // min_width should not. Therefore we subtract epsilon from the min_width when
885  // deflating/inflating.
886  int half_min_width = aZone->GetMinThickness() / 2;
887  int epsilon = Millimeter2iu( 0.001 );
888  int numSegs = std::max( GetArcToSegmentCount( half_min_width, m_high_def, 360.0 ), 6 );
889 
890  if( m_brdOutlinesValid )
892 
893  smoothedPoly.Deflate( half_min_width/* - epsilon*/, numSegs );
894 
895  // Remove the non filled areas due to the hatch pattern
897  addHatchFillTypeOnZone( aZone, aLayer, smoothedPoly );
898 
899  // Re-inflate after pruning of areas that don't meet minimum-width criteria
900  if( aZone->GetFilledPolysUseThickness() )
901  {
902  // If we're stroking the zone with a min_width stroke then this will naturally
903  // inflate the zone by half_min_width
904  }
905  else if( half_min_width - epsilon > epsilon )
906  smoothedPoly.Deflate( -( half_min_width - epsilon ), numSegs );
907 
908  aRawPolys = smoothedPoly;
909  aFinalPolys = smoothedPoly;
910 
912  }
913 
914  aZone->SetNeedRefill( false );
915  return true;
916 }
BOARD * m_board
Definition: zone_filler.h:110
void computeRawFilledArea(const ZONE_CONTAINER *aZone, PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aSmoothedOutline, std::set< VECTOR2I > *aPreserveCorners, SHAPE_POLY_SET &aRawPolys, SHAPE_POLY_SET &aFinalPolys)
Function computeRawFilledArea Add non copper areas polygons (pads and tracks with clearance) to a fil...
bool GetFilledPolysUseThickness() const
Definition: class_zone.h:661
void GetColinearCorners(BOARD *aBoard, std::set< VECTOR2I > &colinearCorners)
Some intersecting zones, despite being on the same layer with the same net, cannot be merged due to o...
SHAPE_POLY_SET.
bool BuildSmoothedPoly(SHAPE_POLY_SET &aSmoothedPoly, std::set< VECTOR2I > *aPreserveCorners) const
Function GetSmoothedPoly returns a pointer to the corner-smoothed version of m_Poly.
ZONE_FILL_MODE GetFillMode() const
Definition: class_zone.h:148
void addHatchFillTypeOnZone(const ZONE_CONTAINER *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aRawPolys)
for zones having the ZONE_FILL_MODE::ZONE_FILL_MODE::HATCH_PATTERN, create a grid pattern in filled a...
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
void Fracture(POLYGON_MODE aFastMode)
Converts a set of polygons with holes to a singe outline with "slits"/"fractures" connecting the oute...
int GetMinThickness() const
Definition: class_zone.h:201
SHAPE_POLY_SET m_boardOutline
Definition: zone_filler.h:111
bool m_brdOutlinesValid
Definition: zone_filler.h:112
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
bool IsOnCopperLayer() const override
Function IsOnCopperLayer.
Definition: class_zone.cpp:242
void SetNeedRefill(bool aNeedRefill)
Definition: class_zone.h:189

References addHatchFillTypeOnZone(), SHAPE_POLY_SET::BooleanIntersection(), ZONE_CONTAINER::BuildSmoothedPoly(), computeRawFilledArea(), SHAPE_POLY_SET::Deflate(), SHAPE_POLY_SET::Fracture(), GetArcToSegmentCount(), ZONE_CONTAINER::GetColinearCorners(), ZONE_CONTAINER::GetFilledPolysUseThickness(), ZONE_CONTAINER::GetFillMode(), ZONE_CONTAINER::GetMinThickness(), HATCH_PATTERN, ZONE_CONTAINER::IsOnCopperLayer(), m_board, m_boardOutline, m_brdOutlinesValid, m_high_def, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE, and ZONE_CONTAINER::SetNeedRefill().

Referenced by Fill().

◆ InstallNewProgressReporter()

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

Definition at line 93 of file zone_filler.cpp.

95 {
96  m_uniqueReporter = std::make_unique<WX_PROGRESS_REPORTER>( aParent, aTitle, aNumPhases );
98 }
WX_PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:115
std::unique_ptr< WX_PROGRESS_REPORTER > m_uniqueReporter
Definition: zone_filler.h:116

References m_progressReporter, and m_uniqueReporter.

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

◆ knockoutThermalReliefs()

void ZONE_FILLER::knockoutThermalReliefs ( const ZONE_CONTAINER 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 510 of file zone_filler.cpp.

512 {
513  SHAPE_POLY_SET holes;
514 
515  // Use a dummy pad to calculate relief when a pad has a hole but is not on the zone's
516  // copper layer. The dummy pad has the size and shape of the original pad's hole. We have
517  // to give it a parent because some functions expect a non-null parent to find clearance
518  // data, etc.
519  MODULE dummymodule( m_board );
520  D_PAD dummypad( &dummymodule );
521 
522  for( auto module : m_board->Modules() )
523  {
524  for( auto pad : module->Pads() )
525  {
526  if( !hasThermalConnection( pad, aZone ) )
527  continue;
528 
529  // If the pad isn't on the current layer but has a hole, knock out a thermal relief
530  // for the hole.
531  if( !pad->IsOnLayer( aLayer ) )
532  {
533  if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
534  continue;
535 
536  setupDummyPadForHole( pad, dummypad );
537  pad = &dummypad;
538  }
539 
540  addKnockout( pad, aZone->GetThermalReliefGap( pad ), holes );
541  }
542  }
543 
546 }
BOARD * m_board
Definition: zone_filler.h:110
void addKnockout(D_PAD *aPad, int aGap, SHAPE_POLY_SET &aHoles)
Add a knockout for a pad.
int GetThermalReliefGap(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:345
MODULES & Modules()
Definition: class_board.h:266
SHAPE_POLY_SET.
void Simplify(POLYGON_MODE aFastMode)
Simplifies the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFast...
static void setupDummyPadForHole(const D_PAD *aPad, D_PAD &aDummyPad)
Setup aDummyPad to have the same size and shape of aPad's hole.
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Performs boolean polyset difference For aFastMode meaning, see function booleanOp
bool hasThermalConnection(D_PAD *pad, const ZONE_CONTAINER *aZone)
Return true if the given pad has a thermal connection with the given zone.

References addKnockout(), SHAPE_POLY_SET::BooleanSubtract(), ZONE_CONTAINER::GetThermalReliefGap(), hasThermalConnection(), m_board, BOARD::Modules(), SHAPE_POLY_SET::PM_FAST, setupDummyPadForHole(), and SHAPE_POLY_SET::Simplify().

Referenced by computeRawFilledArea().

Member Data Documentation

◆ m_board

BOARD* ZONE_FILLER::m_board
private

◆ m_boardOutline

SHAPE_POLY_SET ZONE_FILLER::m_boardOutline
private

Definition at line 111 of file zone_filler.h.

Referenced by Fill(), and fillSingleZone().

◆ m_brdOutlinesValid

bool ZONE_FILLER::m_brdOutlinesValid
private

Definition at line 112 of file zone_filler.h.

Referenced by Fill(), and fillSingleZone().

◆ m_commit

COMMIT* ZONE_FILLER::m_commit
private

Definition at line 114 of file zone_filler.h.

Referenced by Fill().

◆ m_high_def

int ZONE_FILLER::m_high_def
private

Definition at line 119 of file zone_filler.h.

Referenced by addKnockout(), computeRawFilledArea(), and fillSingleZone().

◆ m_low_def

int ZONE_FILLER::m_low_def
private

Definition at line 125 of file zone_filler.h.

Referenced by addKnockout(), buildCopperItemClearances(), and computeRawFilledArea().

◆ m_progressReporter

WX_PROGRESS_REPORTER* ZONE_FILLER::m_progressReporter
private

Definition at line 115 of file zone_filler.h.

Referenced by Fill(), and InstallNewProgressReporter().

◆ m_uniqueReporter

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

Definition at line 116 of file zone_filler.h.

Referenced by InstallNewProgressReporter().


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