55 m_brdOutlinesValid( false ),
57 m_progressReporter( nullptr ),
74 wxASSERT_MSG(
m_commit, wxT(
"ZONE_FILLER must have a valid commit to call "
75 "SetProgressReporter" ) );
93 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
94 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
MD5_HASH> oldFillHashes;
95 std::vector<CN_ZONE_ISOLATED_ISLAND_LIST> islandsList;
100 connectivity->ClearRatsnest();
110 :
_(
"Building zone fills..." ) );
124 zone->CacheBoundingBox();
130 for(
PAD*
pad : footprint->Pads() )
135 pad->BuildEffectivePolygon();
141 for(
ZONE* zone : footprint->Zones() )
143 zone->CacheBoundingBox();
148 footprint->BuildCourtyardCaches();
153 auto findHighestPriorityZone = [&](
const BOX2I& aBBox,
const PCB_LAYER_ID aItemLayer,
155 const std::function<bool(
const ZONE* )> aTestFn ) ->
ZONE*
157 unsigned highestPriority = 0;
158 ZONE* highestPriorityZone =
nullptr;
163 if( zone->GetIsRuleArea() )
166 if( zone->GetAssignedPriority() < highestPriority )
169 if( !zone->IsOnLayer( aItemLayer ) )
173 if( zone->GetNumCorners() <= 2 )
176 if( !zone->GetBoundingBox().Intersects( aBBox ) )
179 if( !aTestFn( zone ) )
183 if( zone->GetAssignedPriority() > highestPriority || zone->GetNetCode() == aNetcode )
186 highestPriorityZone = zone;
190 return highestPriorityZone;
193 auto isInPourKeepoutArea = [&](
const BOX2I& aBBox,
const PCB_LAYER_ID aItemLayer,
198 if( !zone->GetIsRuleArea() )
201 if( !zone->GetDoNotAllowCopperPour() )
204 if( !zone->IsOnLayer( aItemLayer ) )
208 if( zone->GetNumCorners() <= 2 )
211 if( !zone->GetBoundingBox().Intersects( aBBox ) )
214 if( zone->Outline()->Contains( aTestPoint ) )
228 via->ClearZoneLayerOverrides();
230 if( !
via->GetRemoveUnconnected() )
235 int testRadius =
via->GetDrillValue() / 2 + 1;
236 unsigned netcode =
via->GetNetCode();
237 LSET layers =
via->GetLayerSet() & boardCuMask;
240 auto viaTestFn = [&](
const ZONE* aZone ) ->
bool
242 return aZone->Outline()->
Contains( center, -1, testRadius );
247 if( !
via->ConditionallyFlashed( layer ) )
250 if( isInPourKeepoutArea( bbox, layer, center ) )
256 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, viaTestFn );
270 for(
PAD*
pad : footprint->Pads() )
272 pad->ClearZoneLayerOverrides();
274 if( !
pad->GetRemoveUnconnected() )
279 unsigned netcode =
pad->GetNetCode();
280 LSET layers =
pad->GetLayerSet() & boardCuMask;
282 auto padTestFn = [&](
const ZONE* aZone ) ->
bool
284 return aZone->Outline()->
Contains( center );
289 if( !
pad->ConditionallyFlashed( layer ) )
292 if( isInPourKeepoutArea( bbox, layer, center ) )
298 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, padTestFn );
309 for(
ZONE* zone : aZones )
312 if( zone->GetIsRuleArea() )
316 if( zone->GetNumCorners() <= 2 )
326 zone->BuildHashValue( layer );
327 oldFillHashes[ { zone, layer } ] = zone->GetHashValue( layer );
330 toFill.emplace_back( std::make_pair( zone, layer ) );
339 auto check_fill_dependency =
347 if( aOtherZone->GetFillFlag( aLayer ) )
352 if( aOtherZone->GetIsRuleArea() )
356 if( aOtherZone->GetNumCorners() <= 2 )
360 if( !aOtherZone->GetLayerSet().test( aLayer ) )
367 if( aOtherZone->SameNet( aZone ) )
375 if( !inflatedBBox.
Intersects( aOtherZone->GetBoundingBox() ) )
382 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
385 ZONE* zone = aFillItem.first;
390 for(
ZONE* otherZone : aZones )
392 if( otherZone == zone )
395 if( check_fill_dependency( zone, layer, otherZone ) )
410 std::unique_lock<std::mutex> zoneLock( zone->
GetLock(), std::try_to_lock );
412 if( !zoneLock.owns_lock() )
429 auto tesselate_lambda =
430 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
436 ZONE* zone = aFillItem.first;
439 std::unique_lock<std::mutex> zoneLock( zone->
GetLock(), std::try_to_lock );
441 if( !zoneLock.owns_lock() )
453 std::vector<std::pair<std::future<int>,
int>> returns;
454 returns.reserve( toFill.size() );
456 bool cancelled =
false;
460 for(
const std::pair<ZONE*, PCB_LAYER_ID>& fillItem : toFill )
461 returns.emplace_back( std::make_pair(
tp.submit( fill_lambda, fillItem ), 0 ) );
463 while( !cancelled && finished != 2 * toFill.size() )
465 for(
size_t ii = 0; ii < returns.size(); ++ii )
467 auto& ret = returns[ii];
472 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
474 if( status == std::future_status::ready )
476 if( ret.first.get() )
485 if( ret.second == 0 )
486 returns[ii].first =
tp.submit( fill_lambda, toFill[ii] );
487 else if( ret.second == 1 )
488 returns[ii].first =
tp.submit( tesselate_lambda, toFill[ii] );
493 std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
507 for(
auto& ret : returns )
509 if( ret.first.valid() )
511 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
513 while( status != std::future_status::ready )
518 status = ret.first.wait_for( std::chrono::milliseconds( 100 ) );
537 connectivity->FindIsolatedCopperIslands( islandsList );
538 connectivity->SetProgressReporter(
nullptr );
543 for(
ZONE* zone : aZones )
546 if( zone->GetIsRuleArea() )
549 zone->SetIsFilled(
true );
558 bool allIslands =
true;
560 for(
PCB_LAYER_ID layer : zone.m_zone->GetLayerSet().Seq() )
562 std::shared_ptr<SHAPE_POLY_SET> poly = zone.m_zone->GetFilledPolysList( layer );
564 if( !zone.m_islands.count( layer ) )
566 if( poly->OutlineCount() > 0 )
572 std::vector<int>& islands = zone.m_islands.at( layer );
574 if( islands.size() !=
static_cast<size_t>( poly->OutlineCount() ) )
584 for(
PCB_LAYER_ID layer : zone.m_zone->GetLayerSet().Seq() )
589 if( !zone.m_islands.count( layer ) )
592 std::vector<int>& islands = zone.m_islands.at( layer );
596 std::sort( islands.begin(), islands.end(), std::greater<int>() );
598 std::shared_ptr<SHAPE_POLY_SET> poly = zone.m_zone->GetFilledPolysList( layer );
599 long long int minArea = zone.m_zone->GetMinIslandArea();
602 for(
int idx : islands )
607 poly->DeletePolygonAndTriangulationData( idx,
false );
609 poly->DeletePolygonAndTriangulationData( idx,
false );
611 zone.m_zone->SetIsIsland( layer, idx );
614 poly->UpdateTriangulationDataHash();
615 zone.m_zone->CalculateFilledArea();
624 using island_check_return = std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
int>>;
626 std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
double>> polys_to_check;
631 for(
ZONE* zone : aZones )
638 double minArea = (double) zone->GetMinThickness() * zone->GetMinThickness() * 2;
645 polys_to_check.emplace_back( zone->GetFilledPolysList( layer ), minArea );
649 auto island_lambda = [&](
int aStart,
int aEnd ) -> island_check_return
651 island_check_return retval;
653 for(
int ii = aStart; ii < aEnd && !cancelled; ++ii )
655 auto [poly, minArea] = polys_to_check[ii];
657 for(
int jj = poly->OutlineCount() - 1; jj >= 0; jj-- )
662 double island_area = test_poly.
Area();
664 if( island_area < minArea )
675 if( intersection.
Area() < island_area / 2.0 )
676 retval.emplace_back( poly, jj );
683 auto island_returns =
tp.parallelize_loop( 0, polys_to_check.size(), island_lambda );
687 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
689 std::future<island_check_return>& ret = island_returns[ii];
693 std::future_status status = ret.wait_for( std::chrono::seconds( 0 ) );
695 while( status != std::future_status::ready )
705 status = ret.wait_for( std::chrono::milliseconds( 100 ) );
713 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
715 std::future<island_check_return>& ret = island_returns[ii];
719 for(
auto& action_item : ret.get() )
720 action_item.first->DeletePolygonAndTriangulationData( action_item.second,
true );
724 for(
ZONE* zone : aZones )
725 zone->CalculateFilledArea();
730 bool outOfDate =
false;
732 for(
ZONE* zone : aZones )
735 if( zone->GetIsRuleArea() )
740 zone->BuildHashValue( layer );
742 if( oldFillHashes[ { zone, layer } ] != zone->GetHashValue( layer ) )
749 KIDIALOG dlg( aParent,
_(
"Zone fills are out-of-date. Refill?" ),
750 _(
"Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
792 std::vector<VECTOR2I> convex_hull;
797 for(
const VECTOR2I& pt : convex_hull )
828 switch( aItem->
Type() )
840 switch( aItem->
Type() )
853 if(
text->IsVisible() )
873 std::vector<PAD*>& aThermalConnectionPads,
874 std::vector<PAD*>& aNoConnectionPads )
885 for(
PAD*
pad : footprint->Pads() )
887 BOX2I padBBox =
pad->GetBoundingBox();
894 ||
pad->GetNetCode() <= 0
898 aNoConnectionPads.push_back(
pad );
908 constraint = bds.
m_DRCEngine->EvalZoneConnection(
pad, aZone, aLayer );
919 if(
pad->CanFlashLayer( aLayer ) )
921 aThermalConnectionPads.push_back(
pad );
924 else if(
pad->GetDrillSize().x > 0 )
940 if(
pad->FlashLayer( aLayer ) )
944 else if(
pad->GetDrillSize().x > 0 )
947 pad, aZone, aLayer );
952 holeClearance = padClearance;
975 const std::vector<PAD*> aNoConnectionPads,
981 auto checkForCancel =
984 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
997 auto evalRulesForItems =
1007 auto knockoutPadClearance =
1011 bool hasHole = aPad->GetDrillSize().x > 0;
1012 bool flashLayer = aPad->FlashLayer( aLayer );
1015 if( flashLayer || platedHole )
1018 aZone, aPad, aLayer ) );
1021 if( flashLayer && gap > 0 )
1022 addKnockout( aPad, aLayer, gap + extra_margin, aHoles );
1027 aZone, aPad, aLayer ) );
1030 aZone, aPad, aLayer ) );
1037 for(
PAD*
pad : aNoConnectionPads )
1042 knockoutPadClearance(
pad );
1047 auto knockoutTrackClearance =
1050 if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
1052 bool sameNet = aTrack->GetNetCode() == aZone->
GetNetCode()
1056 aZone, aTrack, aLayer );
1069 aZone, aTrack, aLayer ) );
1076 if(
via->FlashLayer( aLayer ) && gap > 0 )
1078 via->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
1083 aZone,
via, aLayer ) );
1088 aZone,
via, aLayer ) );
1093 int radius =
via->GetDrillValue() / 2;
1096 radius + gap + extra_margin,
1104 aTrack->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
1113 if( !track->IsOnLayer( aLayer ) )
1119 knockoutTrackClearance( track );
1125 auto knockoutGraphicClearance =
1129 if( aItem->IsOnLayer( aLayer )
1131 || aItem->IsOnLayer(
Margin ) )
1133 if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
1135 bool ignoreLineWidths =
false;
1137 aZone, aItem, aLayer );
1139 if( aItem->IsOnLayer( aLayer ) )
1142 aZone, aItem, aLayer ) );
1144 else if( aItem->IsOnLayer(
Edge_Cuts ) )
1148 ignoreLineWidths =
true;
1150 else if( aItem->IsOnLayer(
Margin ) )
1153 aZone, aItem,
Margin ) );
1156 addKnockout( aItem, aLayer, gap + extra_margin, ignoreLineWidths, aHoles );
1163 knockoutGraphicClearance( &footprint->Reference() );
1164 knockoutGraphicClearance( &footprint->Value() );
1166 std::set<PAD*> allowedNetTiePads;
1170 if( footprint->IsNetTie() )
1172 for(
PAD*
pad : footprint->Pads() )
1176 if(
pad->IsOnLayer( aLayer ) )
1177 allowedNetTiePads.insert(
pad );
1179 for(
PAD* other : footprint->GetNetTiePads(
pad ) )
1181 if( other->IsOnLayer( aLayer ) )
1182 allowedNetTiePads.insert( other );
1188 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
1193 BOX2I itemBBox = item->GetBoundingBox();
1195 if( !zone_boundingbox.
Intersects( itemBBox ) )
1198 bool skipItem =
false;
1200 if( item->IsOnLayer( aLayer ) )
1202 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape();
1204 for(
PAD*
pad : allowedNetTiePads )
1206 if(
pad->GetBoundingBox().Intersects( itemBBox )
1207 &&
pad->GetEffectiveShape()->Collide( itemShape.get() ) )
1216 knockoutGraphicClearance( item );
1225 knockoutGraphicClearance( item );
1230 auto knockoutZoneClearance =
1231 [&](
ZONE* aKnockout )
1234 if( !aKnockout->GetLayerSet().test( aLayer ) )
1237 if( aKnockout->GetBoundingBox().Intersects( zone_boundingbox ) )
1239 if( aKnockout->GetIsRuleArea() )
1242 aKnockout->TransformSmoothedOutlineToPolygon( aHoles, 0,
m_maxError,
1248 aKnockout, aLayer );
1251 aKnockout, aLayer ) );
1254 aKnockout->TransformShapeToPolygon( poly, aLayer, gap + extra_margin,
1270 if( otherZone->GetIsRuleArea() )
1272 if( otherZone->GetDoNotAllowCopperPour() && !aZone->
IsTeardropArea() )
1273 knockoutZoneClearance( otherZone );
1275 else if( otherZone->HigherPriority( aZone ) )
1277 if( !otherZone->SameNet( aZone ) )
1278 knockoutZoneClearance( otherZone );
1284 for(
ZONE* otherZone : footprint->Zones() )
1289 if( otherZone->GetIsRuleArea() )
1291 if( otherZone->GetDoNotAllowCopperPour() && !aZone->
IsTeardropArea() )
1292 knockoutZoneClearance( otherZone );
1294 else if( otherZone->HigherPriority( aZone ) )
1296 if( !otherZone->SameNet( aZone ) )
1297 knockoutZoneClearance( otherZone );
1315 auto knockoutZoneOutline =
1316 [&](
ZONE* aKnockout )
1319 if( !aKnockout->GetLayerSet().test( aLayer ) )
1322 if( aKnockout->GetBoundingBox().Intersects( zoneBBox ) )
1338 if( otherZone->SameNet( aZone )
1342 if( !otherZone->IsTeardropArea() )
1343 knockoutZoneOutline( otherZone );
1349 for(
ZONE* otherZone : footprint->Zones() )
1351 if( otherZone->SameNet( aZone ) && otherZone->HigherPriority( aZone ) )
1354 if( !otherZone->IsTeardropArea() )
1355 knockoutZoneOutline( otherZone );
1362#define DUMP_POLYS_TO_COPPER_LAYER( a, b, c ) \
1363 { if( m_debugZoneFiller && aDebugLayer == b ) \
1365 m_board->SetLayerName( b, c ); \
1366 SHAPE_POLY_SET d = a; \
1367 d.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE ); \
1411 std::vector<PAD*> thermalConnectionPads;
1412 std::vector<PAD*> noConnectionPads;
1413 std::deque<SHAPE_LINE_CHAIN> thermalSpokes;
1416 aFillPolys = aSmoothedOutline;
1453 static const bool USE_BBOX_CACHES =
true;
1459 if( half_min_width - epsilon > epsilon )
1461 testAreas.
Deflate( half_min_width - epsilon, numSegs, fastCornerStrategy );
1464 testAreas.
Inflate( half_min_width - epsilon, numSegs, fastCornerStrategy );
1480 const VECTOR2I& testPt = spoke.CPoint( 3 );
1483 if( testAreas.
Contains( testPt, -1, 1, USE_BBOX_CACHES ) )
1492 if( interval++ > 400 )
1505 if( &other != &spoke
1506 && other.PointInside( testPt, 1, USE_BBOX_CACHES )
1507 && spoke.PointInside( other.CPoint( 3 ), 1, USE_BBOX_CACHES ) )
1530 if( half_min_width - epsilon > epsilon )
1531 aFillPolys.
Deflate( half_min_width - epsilon, numSegs, fastCornerStrategy );
1536 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
1538 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
1539 BOX2I islandExtents = island.front().BBox();
1541 if( islandExtents.
GetSizeMax() < half_min_width )
1567 if( half_min_width - epsilon > epsilon )
1568 aFillPolys.
Inflate( half_min_width - epsilon, numSegs, cornerStrategy );
1603 auto checkForCancel =
1606 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
1609 auto knockoutGraphicClearance =
1612 if( aItem->IsKnockout() && aItem->IsOnLayer( aLayer )
1613 && aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
1616 aZone, aItem, aLayer );
1627 knockoutGraphicClearance( &footprint->Reference() );
1628 knockoutGraphicClearance( &footprint->Value() );
1630 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
1631 knockoutGraphicClearance( item );
1639 knockoutGraphicClearance( item );
1642 aFillPolys = aSmoothedOutline;
1652 aFillPolys.
Deflate( half_min_width - epsilon, numSegs );
1662 if( half_min_width - epsilon > epsilon )
1663 aFillPolys.
Inflate( half_min_width - epsilon, numSegs );
1684 debugLayer = aLayer;
1688 if( !aZone->
BuildSmoothedPoly( maxExtents, aLayer, boardOutline, &smoothedPoly ) )
1696 if(
fillCopperZone( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aFillPolys ) )
1713 const std::vector<PAD*>& aSpokedPadsList,
1714 std::deque<SHAPE_LINE_CHAIN>& aSpokesList )
1726 for(
PAD*
pad : aSpokedPadsList )
1729 if( !
pad->IsOnLayer( aLayer ) )
1733 int thermalReliefGap = constraint.
GetValue().
Min();
1741 int spoke_max_allowed_w = std::min(
pad->GetSize().x,
pad->GetSize().y );
1743 spoke_w = std::max( spoke_w, constraint.
Value().
Min() );
1744 spoke_w = std::min( spoke_w, constraint.
Value().
Max() );
1747 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
1750 if( spoke_w < aZone->GetMinThickness() )
1753 int spoke_half_w = spoke_w / 2;
1756 BOX2I itemBB =
pad->GetBoundingBox();
1757 itemBB.
Inflate( thermalReliefGap + epsilon );
1767 auto buildSpokesFromOrigin =
1768 [&](
const BOX2I& box )
1770 for(
int i = 0; i < 4; i++ )
1777 spoke.
Append( +spoke_half_w, -spoke_half_w );
1778 spoke.
Append( -spoke_half_w, -spoke_half_w );
1779 spoke.
Append( -spoke_half_w, box.GetBottom() );
1780 spoke.
Append( 0, box.GetBottom() );
1781 spoke.
Append( +spoke_half_w, box.GetBottom() );
1785 spoke.
Append( +spoke_half_w, +spoke_half_w );
1786 spoke.
Append( -spoke_half_w, +spoke_half_w );
1787 spoke.
Append( -spoke_half_w, box.GetTop() );
1788 spoke.
Append( 0, box.GetTop() );
1789 spoke.
Append( +spoke_half_w, box.GetTop() );
1793 spoke.
Append( -spoke_half_w, +spoke_half_w );
1794 spoke.
Append( -spoke_half_w, -spoke_half_w );
1795 spoke.
Append( box.GetRight(), -spoke_half_w );
1796 spoke.
Append( box.GetRight(), 0 );
1797 spoke.
Append( box.GetRight(), +spoke_half_w );
1801 spoke.
Append( +spoke_half_w, +spoke_half_w );
1802 spoke.
Append( +spoke_half_w, -spoke_half_w );
1803 spoke.
Append( box.GetLeft(), -spoke_half_w );
1804 spoke.
Append( box.GetLeft(), 0 );
1805 spoke.
Append( box.GetLeft(), +spoke_half_w );
1810 aSpokesList.push_back( std::move( spoke ) );
1816 if( (
pad->GetOrientation() +
pad->GetThermalSpokeAngle() ).IsCardinal() )
1818 BOX2I spokesBox =
pad->GetBoundingBox();
1819 spokesBox.
Inflate( thermalReliefGap + epsilon );
1824 buildSpokesFromOrigin( spokesBox );
1826 auto spokeIter = aSpokesList.rbegin();
1828 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
1829 spokeIter->Move(
pad->ShapePos() );
1846 spokesBox.
Inflate( thermalReliefGap + epsilon );
1848 buildSpokesFromOrigin( spokesBox );
1850 auto spokeIter = aSpokesList.rbegin();
1852 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
1854 spokeIter->Rotate(
pad->GetOrientation() +
pad->GetThermalSpokeAngle() );
1855 spokeIter->Move(
pad->ShapePos() );
1877 buildSpokesFromOrigin( spokesBox );
1879 BOX2I realBBox =
pad->GetBoundingBox();
1880 realBBox.
Inflate( thermalReliefGap + epsilon );
1882 auto spokeIter = aSpokesList.rbegin();
1884 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
1886 spokeIter->Rotate(
pad->GetOrientation() +
pad->GetThermalSpokeAngle() );
1887 spokeIter->
Move(
pad->ShapePos() );
1889 VECTOR2I origin_p = spokeIter->GetPoint( 0 );
1890 VECTOR2I origin_m = spokeIter->GetPoint( 1 );
1891 VECTOR2I origin = ( origin_p + origin_m ) / 2;
1892 VECTOR2I end_m = spokeIter->GetPoint( 2 );
1893 VECTOR2I end = spokeIter->GetPoint( 3 );
1894 VECTOR2I end_p = spokeIter->GetPoint( 4 );
1896 ClipLine( &realBBox, origin_p.
x, origin_p.
y, end_p.
x, end_p.
y );
1897 ClipLine( &realBBox, origin_m.
x, origin_m.
y, end_m.
x, end_m.
y );
1898 ClipLine( &realBBox, origin.
x, origin.
y, end.
x, end.
y );
1900 spokeIter->SetPoint( 2, end_m );
1901 spokeIter->SetPoint( 3, end );
1902 spokeIter->SetPoint( 4, end_p );
1907 for(
size_t ii = 0; ii < aSpokesList.size(); ++ii )
1908 aSpokesList[ii].GenerateBBoxCache();
1943 hole_base.
Append( corner );
1944 corner.
x += hole_size;
1945 hole_base.
Append( corner );
1946 corner.
y += hole_size;
1947 hole_base.
Append( corner );
1949 hole_base.
Append( corner );
1969 #define SMOOTH_MIN_VAL_MM 0.02
1970 #define SMOOTH_SMALL_VAL_MM 0.04
1986 smooth_value = std::min( smooth_value, aZone->
GetHatchGap() / 2 );
1991 switch( smooth_level )
2003 hole_base = smooth_hole.
Fillet( smooth_value, error_max ).
Outline( 0 );
2015 for(
int xx = 0; ; xx++ )
2017 int xpos = xx * gridsize;
2022 for(
int yy = 0; ; yy++ )
2024 int ypos = yy * gridsize;
2057 deflatedOutline.
Deflate( outline_margin, 16 );
2069 int min_apron_radius = ( aZone->
GetHatchGap() * 10 ) / 19;
2078 &&
via->IsOnLayer( aLayer )
2079 &&
via->GetBoundingBox().Intersects( zone_boundingbox ) )
2081 int r = std::max( min_apron_radius,
2082 via->GetDrillValue() / 2 + outline_margin );
2092 for(
PAD*
pad : footprint->Pads() )
2095 &&
pad->IsOnLayer( aLayer )
2096 &&
pad->GetBoundingBox().Intersects( zone_boundingbox ) )
2103 int pad_width = std::min(
pad->GetSize().x,
pad->GetSize().y );
2104 int slot_width = std::min(
pad->GetDrillSize().x,
pad->GetDrillSize().y );
2105 int min_annular_ring_width = ( pad_width - slot_width ) / 2;
2106 int clearance = std::max( min_apron_radius - pad_width / 2,
2107 outline_margin - min_annular_ring_width );
2109 clearance = std::max( 0, clearance - linethickness / 2 );
2110 pad->TransformShapeToPolygon( aprons, aLayer, clearance,
ARC_HIGH_DEF,
2126 if( area < minimal_hole_area )
constexpr int ARC_HIGH_DEF
constexpr EDA_IU_SCALE pcbIUScale
@ ZLO_FORCE_NO_ZONE_CONNECTION
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
Container for design settings for a BOARD object.
std::shared_ptr< DRC_ENGINE > m_DRCEngine
int GetBiggestClearanceValue() const
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const
Convert the item shape to a closed polygon.
Information pertinent to a Pcbnew printed circuit board.
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
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...
FOOTPRINTS & Footprints()
int GetCopperLayerCount() const
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
const Vec & GetPosition() const
void Offset(coord_type dx, coord_type dy)
bool Intersects(const BOX2< Vec > &aRect) const
coord_type GetHeight() const
coord_type GetWidth() const
void Move(const Vec &aMoveVector)
Move the rectangle by the aMoveVector.
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Represent a set of changes (additions, deletions or modifications) of a data model (e....
COMMIT & Modify(EDA_ITEM *aItem)
Create an undo entry for an item that has been already modified.
MINOPTMAX< int > & Value()
const MINOPTMAX< int > & GetValue() const
ZONE_CONNECTION m_ZoneConnection
KICAD_T Type() const
Returns the type of object.
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
void DoNotShowCheckbox(wxString file, int line)
Checks the 'do not show again' setting for the dialog.
bool SetOKCancelLabels(const ButtonLabel &ok, const ButtonLabel &cancel) override
Shows the 'do not show again' checkbox.
LSET is a set of PCB_LAYER_IDs.
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
bool Contains(PCB_LAYER_ID aLayer)
See if the layer set contains a PCB layer.
static LSET InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
const BOX2I GetBoundingBox() const override
The bounding box is cached, so this will be efficient most of the time.
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
bool TransformHoleToPolygon(SHAPE_POLY_SET &aBuffer, int aClearance, int aError, ERROR_LOC aErrorLoc) const
Build the corner list of the polygonal drill shape in the board coordinate system.
void SetOffset(const VECTOR2I &aOffset)
CUST_PAD_SHAPE_IN_ZONE GetCustomShapeInZoneOpt() const
void SetPosition(const VECTOR2I &aPos) override
PAD_SHAPE GetShape() const
void SetOrientation(const EDA_ANGLE &aAngle)
Set the rotation angle of the pad.
A progress reporter interface for use in multi-threaded environments.
virtual bool IsCancelled() const =0
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void Report(const wxString &aMessage)=0
Display aMessage in the progress bar dialog.
virtual void AdvancePhase()=0
Use the next available virtual zone of the dialog progress bar.
virtual void AdvanceProgress()=0
Increment the progress bar length (inside the current virtual zone).
virtual void SetMaxProgress(int aMaxProgress)=0
Fix the value that gives the 100 percent progress bar length (inside the current virtual zone).
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void Move(const VECTOR2I &aVector) override
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
double Area(bool aAbsolute=true) const
Return the area of this chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
Represent a set of closed polygons.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
SHAPE_POLY_SET Chamfer(int aDistance)
Return a chamfered version of the polygon set.
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
void Fracture(POLYGON_MODE aFastMode)
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
void ClearArcs()
Appends a vertex at the end of the given outline/hole (default: the last outline)
CORNER_STRATEGY
< define how inflate transform build inflated polygon
@ CHAMFER_ALL_CORNERS
All angles are chamfered.
@ ROUND_ALL_CORNERS
All angles are rounded.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new hole to the given outline (default: last) and returns its index.
void DeletePolygon(int aIdx)
Delete aIdx-th polygon and its triangulation data from the set.
double Area()
Count the number of arc shapes present.
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
POLYGON & Polygon(int aIndex)
void Deflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=CHAMFER_ALL_CORNERS)
void Inflate(int aAmount, int aCircleSegCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
Perform outline inflation/deflation.
void BooleanIntersection(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset union between a and b, store the result in it self For aFastMode meaning,...
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...
void Simplify(POLYGON_MODE aFastMode)
SHAPE_LINE_CHAIN & Outline(int aIndex)
int NewOutline()
Creates a new hole in a given outline.
void BuildBBoxCaches() const
Construct BBoxCaches for Contains(), below.
int OutlineCount() const
Return the number of vertices in a given outline/hole.
SHAPE_POLY_SET Fillet(int aRadius, int aErrorMax)
Return a filleted version of the polygon set.
void Move(const VECTOR2I &aVector) override
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
SHAPE_POLY_SET CloneDropTriangulation() const
Creates a new empty polygon in the set and returns its index.
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
void addKnockout(PAD *aPad, PCB_LAYER_ID aLayer, int aGap, SHAPE_POLY_SET &aHoles)
Add a knockout for a pad.
void buildCopperItemClearances(const ZONE *aZone, PCB_LAYER_ID aLayer, const std::vector< PAD * > aNoConnectionPads, SHAPE_POLY_SET &aHoles)
Removes clearance from the shape for copper items which share the zone's layer but are not connected ...
ZONE_FILLER(BOARD *aBoard, COMMIT *aCommit)
void buildThermalSpokes(const ZONE *box, PCB_LAYER_ID aLayer, const std::vector< PAD * > &aSpokedPadsList, std::deque< SHAPE_LINE_CHAIN > &aSpokes)
Function buildThermalSpokes Constructs a list of all thermal spokes for the given zone.
void subtractHigherPriorityZones(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aRawFill)
Removes the outlines of higher-proirity zones with the same net.
SHAPE_POLY_SET m_boardOutline
bool addHatchFillTypeOnZone(const ZONE *aZone, PCB_LAYER_ID aLayer, PCB_LAYER_ID aDebugLayer, SHAPE_POLY_SET &aFillPolys)
for zones having the ZONE_FILL_MODE::ZONE_FILL_MODE::HATCH_PATTERN, create a grid pattern in filled a...
void SetProgressReporter(PROGRESS_REPORTER *aReporter)
bool Fill(std::vector< ZONE * > &aZones, bool aCheck=false, wxWindow *aParent=nullptr)
Fills the given list of zones.
void knockoutThermalReliefs(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aFill, std::vector< PAD * > &aThermalConnectionPads, std::vector< PAD * > &aNoConnectionPads)
Removes thermal reliefs from the shape for any pads connected to the zone.
PROGRESS_REPORTER * m_progressReporter
bool fillCopperZone(const ZONE *aZone, PCB_LAYER_ID aLayer, PCB_LAYER_ID aDebugLayer, const SHAPE_POLY_SET &aSmoothedOutline, const SHAPE_POLY_SET &aMaxExtents, SHAPE_POLY_SET &aFillPolys)
Function fillCopperZone Add non copper areas polygons (pads and tracks with clearance) to a filled co...
void addHoleKnockout(PAD *aPad, int aGap, SHAPE_POLY_SET &aHoles)
Add a knockout for a pad's hole.
bool fillNonCopperZone(const ZONE *aZone, PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aSmoothedOutline, SHAPE_POLY_SET &aFillPolys)
bool fillSingleZone(ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aFillPolys)
Build the filled solid areas polygons from zone outlines (stored in m_Poly) The solid areas can be mo...
Handle a list of polygons defining a copper zone.
void SetNeedRefill(bool aNeedRefill)
int GetHatchBorderAlgorithm() const
void CacheTriangulation(PCB_LAYER_ID aLayer=UNDEFINED_LAYER)
Create a list of triangles that "fill" the solid areas used for instance to draw these solid areas on...
const BOX2I GetBoundingBox() const override
SHAPE_POLY_SET * Outline()
void SetFillFlag(PCB_LAYER_ID aLayer, bool aFlag)
int GetLocalClearance(wxString *aSource) const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
void SetFilledPolysList(PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPolysList)
Set the list of filled polygons.
int GetMinThickness() const
bool HigherPriority(const ZONE *aOther) const
int GetHatchThickness() const
double GetHatchHoleMinArea() const
bool IsTeardropArea() const
EDA_ANGLE GetHatchOrientation() const
bool BuildSmoothedPoly(SHAPE_POLY_SET &aSmoothedPoly, PCB_LAYER_ID aLayer, SHAPE_POLY_SET *aBoardOutline, SHAPE_POLY_SET *aSmoothedPolyWithApron=nullptr) const
ZONE_FILL_MODE GetFillMode() const
double GetHatchSmoothingValue() const
int GetHatchSmoothingLevel() const
bool IsOnCopperLayer() const override
unsigned GetAssignedPriority() const
This file is part of the common library.
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void BuildConvexHull(std::vector< VECTOR2I > &aResult, const std::vector< VECTOR2I > &aPoly)
Calculate the convex hull of a list of points in counter-clockwise order.
@ EDGE_CLEARANCE_CONSTRAINT
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
@ THERMAL_SPOKE_WIDTH_CONSTRAINT
@ THERMAL_RELIEF_GAP_CONSTRAINT
@ HOLE_CLEARANCE_CONSTRAINT
@ PHYSICAL_CLEARANCE_CONSTRAINT
static constexpr EDA_ANGLE & FULL_CIRCLE
a few functions useful in geometry calculations.
bool ClipLine(const BOX2I *aClipBox, int &x1, int &y1, int &x2, int &y2)
Test if any part of a line falls within the bounds of a rectangle.
int GetArcToSegmentCount(int aRadius, int aErrorMax, const EDA_ANGLE &aArcAngle)
int GetKnockoutTextMargin(const VECTOR2I &aSize, int aThickness)
Returns the margin for knocking out text.
double m_ExtraClearance
Extra fill clearance for zone fills.
bool m_DebugZoneFiller
A mode that dumps the various stages of a F_Cu fill into In1_Cu through In9_Cu.
PCB_LAYER_ID
A quick note on layer IDs:
@ CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL
@ PTH
Plated through hole pad.
A structure used for calculating isolated islands on a given zone across all its layers.
constexpr int mmToIU(double mm) const
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::thread_pool thread_pool
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_FP_SHAPE_T
class FP_SHAPE, a footprint edge
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_FP_TEXTBOX_T
class FP_TEXTBOX, wrapped text in a footprint
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
@ PCB_FP_TEXT_T
class FP_TEXT, text in a footprint
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
#define SMOOTH_MIN_VAL_MM
#define DUMP_POLYS_TO_COPPER_LAYER(a, b, c)
#define SMOOTH_SMALL_VAL_MM
ISLAND_REMOVAL_MODE
Whether or not to remove isolated islands from a zone.
ZONE_CONNECTION
How pads are covered by copper in zone.
@ THERMAL
Use thermal relief for pads.
@ NONE
Pads are not covered.
@ FULL
pads are covered by copper