70 RESULTS(
int aOutline1,
int aOutline2,
int aVertex1,
int aVertex2 ) :
117 SEG::ecoord min_dist = std::numeric_limits<SEG::ecoord>::max();
120 auto check_pt = [&](
VERTEX* p )
122 VECTOR2D diff( p->x - aPt->
x, p->y - aPt->
y );
125 if( dist2 > 0 && dist2 < limit2 && dist2 < min_dist && p->isEar(
true ) )
134 while( p && p->
z <= maxZ )
142 while( p && p->
z >= minZ )
157 std::set<VERTEX*> visited;
170 if( ( visited.empty() || !visited.contains( p ) ) && ( q =
getPoint( p ) ) )
174 if( !visited.contains( q ) &&
176 p->
i, q->
i ).second )
180 visited.insert( p->
prev );
182 visited.insert( p->
next );
185 visited.insert( q->
prev );
187 visited.insert( q->
next );
231 wxASSERT_MSG(
m_commit, wxT(
"ZONE_FILLER must have a valid commit to call SetProgressReporter" ) );
247 std::lock_guard<KISPINLOCK> lock(
m_board->GetConnectivity()->GetLock() );
249 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
250 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
HASH_128> oldFillHashes;
251 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> isolatedIslandsMap;
253 std::shared_ptr<CONNECTIVITY_DATA> connectivity =
m_board->GetConnectivity();
260 connectivity->ClearRatsnest();
268 :
_(
"Building zone fills..." ) );
281 zone->CacheBoundingBox();
285 for(
PAD*
pad : footprint->Pads() )
289 pad->BuildEffectiveShapes();
294 for(
ZONE* zone : footprint->Zones() )
295 zone->CacheBoundingBox();
298 footprint->BuildCourtyardCaches();
299 footprint->BuildNetTieCache();
304 auto findHighestPriorityZone =
306 const std::function<bool(
const ZONE* )>& testFn ) ->
ZONE*
308 unsigned highestPriority = 0;
309 ZONE* highestPriorityZone =
nullptr;
314 if( zone->GetIsRuleArea() )
317 if( zone->GetAssignedPriority() < highestPriority )
320 if( !zone->IsOnLayer( itemLayer ) )
324 if( zone->GetNumCorners() <= 2 )
327 if( !zone->GetBoundingBox().Intersects( bbox ) )
330 if( !testFn( zone ) )
334 if( zone->GetAssignedPriority() > highestPriority
335 || zone->GetNetCode() == netcode )
337 highestPriority = zone->GetAssignedPriority();
338 highestPriorityZone = zone;
342 return highestPriorityZone;
345 auto isInPourKeepoutArea =
350 if( !zone->GetIsRuleArea() )
353 if( !zone->HasKeepoutParametersSet() )
356 if( !zone->GetDoNotAllowZoneFills() )
359 if( !zone->IsOnLayer( itemLayer ) )
363 if( zone->GetNumCorners() <= 2 )
366 if( !zone->GetBoundingBox().Intersects( bbox ) )
369 if( zone->Outline()->Contains( testPoint ) )
386 via->ClearZoneLayerOverrides();
388 if( !
via->GetRemoveUnconnected() )
393 int holeRadius =
via->GetDrillValue() / 2 + 1;
394 int netcode =
via->GetNetCode();
395 LSET layers =
via->GetLayerSet() & boardCuMask;
399 [&](
const ZONE* aZone ) ->
bool
401 return aZone->Outline()->Contains(
center, -1, holeRadius );
406 if( !
via->ConditionallyFlashed( layer ) )
409 if( isInPourKeepoutArea( bbox, layer,
center ) )
415 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, viaTestFn );
420 || layer == padstack.
Drill().
end ) )
436 for(
PAD*
pad : footprint->Pads() )
438 pad->ClearZoneLayerOverrides();
440 if( !
pad->GetRemoveUnconnected() )
445 int netcode =
pad->GetNetCode();
446 LSET layers =
pad->GetLayerSet() & boardCuMask;
449 [&](
const ZONE* aZone ) ->
bool
451 return aZone->Outline()->Contains(
center );
456 if( !
pad->ConditionallyFlashed( layer ) )
459 if( isInPourKeepoutArea( bbox, layer,
center ) )
465 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, padTestFn );
476 for(
ZONE* zone : aZones )
479 if( zone->GetIsRuleArea() )
483 if( zone->GetNumCorners() <= 2 )
493 zone->BuildHashValue( layer );
494 oldFillHashes[ { zone, layer } ] = zone->GetHashValue( layer );
497 toFill.emplace_back( std::make_pair( zone, layer ) );
506 auto check_fill_dependency =
514 if( aOtherZone->GetFillFlag( aLayer ) )
519 if( aOtherZone->GetIsRuleArea() )
523 if( aOtherZone->GetNumCorners() <= 2 )
527 if( !aOtherZone->GetLayerSet().test( aLayer ) )
534 if( aOtherZone->SameNet( aZone ) )
542 if( !inflatedBBox.
Intersects( aOtherZone->GetBoundingBox() ) )
549 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
552 ZONE* zone = aFillItem.first;
557 for(
ZONE* otherZone : aZones )
559 if( otherZone == zone )
562 if( check_fill_dependency( zone, layer, otherZone ) )
577 std::unique_lock<std::mutex> zoneLock( zone->
GetLock(), std::try_to_lock );
579 if( !zoneLock.owns_lock() )
596 auto tesselate_lambda =
597 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
603 ZONE* zone = aFillItem.first;
606 std::unique_lock<std::mutex> zoneLock( zone->
GetLock(), std::try_to_lock );
608 if( !zoneLock.owns_lock() )
620 std::vector<std::pair<std::future<int>,
int>> returns;
621 returns.reserve( toFill.size() );
623 bool cancelled =
false;
627 for(
const std::pair<ZONE*, PCB_LAYER_ID>& fillItem : toFill )
629 returns.emplace_back( std::make_pair(
tp.submit_task(
632 return fill_lambda( fillItem );
636 while( !cancelled && finished != 2 * toFill.size() )
638 for(
size_t ii = 0; ii < returns.size(); ++ii )
640 auto& ret = returns[ii];
645 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
647 if( status == std::future_status::ready )
649 if( ret.first.get() )
658 if( ret.second == 0 )
660 returns[ii].first =
tp.submit_task(
663 return fill_lambda( toFill[idx] );
666 else if( ret.second == 1 )
668 returns[ii].first =
tp.submit_task(
671 return tesselate_lambda( toFill[idx] );
678 std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
692 for(
auto& ret : returns )
694 if( ret.first.valid() )
696 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
698 while( status != std::future_status::ready )
703 status = ret.first.wait_for( std::chrono::milliseconds( 100 ) );
722 connectivity->FillIsolatedIslandsMap( isolatedIslandsMap );
723 connectivity->SetProgressReporter(
nullptr );
728 for(
ZONE* zone : aZones )
731 if( zone->GetIsRuleArea() )
734 zone->SetIsFilled(
true );
741 std::set<ZONE*> zonesWithRemovedIslands;
743 for(
const auto& [ zone, zoneIslands ] : isolatedIslandsMap )
746 bool allIslands =
true;
748 for(
const auto& [ layer, layerIslands ] : zoneIslands )
750 if( layerIslands.m_IsolatedOutlines.size()
751 !=
static_cast<size_t>( zone->GetFilledPolysList( layer )->OutlineCount() ) )
761 for(
const auto& [ layer, layerIslands ] : zoneIslands )
766 if( layerIslands.m_IsolatedOutlines.empty() )
769 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
773 std::sort( islands.begin(), islands.end(), std::greater<int>() );
775 std::shared_ptr<SHAPE_POLY_SET> poly = zone->GetFilledPolysList( layer );
776 long long int minArea = zone->GetMinIslandArea();
779 wxLogTrace(
traceZoneFiller, wxT(
"Zone %s layer %d: %zu islands to process, mode=%d, poly has %d outlines, area %.0f" ),
780 zone->GetNetname(),
static_cast<int>( layer ), islands.size(),
781 static_cast<int>( mode ), poly->OutlineCount(), poly->Area() );
783 for(
int idx : islands )
789 wxLogTrace(
traceZoneFiller, wxT(
"Removing island %d from zone %s (ALWAYS mode)" ),
790 idx, zone->GetNetname() );
791 poly->DeletePolygonAndTriangulationData( idx,
false );
792 zonesWithRemovedIslands.insert( zone );
796 wxLogTrace(
traceZoneFiller, wxT(
"Removing island %d from zone %s (AREA mode, area=%.0f < min=%.0f)" ),
797 idx, zone->GetNetname(), outline.
Area(
true ),
798 static_cast<double>( minArea ) );
799 poly->DeletePolygonAndTriangulationData( idx,
false );
800 zonesWithRemovedIslands.insert( zone );
804 zone->SetIsIsland( layer, idx );
808 poly->UpdateTriangulationDataHash();
809 zone->CalculateFilledArea();
811 BOX2I bbox = poly->BBox();
812 wxLogTrace(
traceZoneFiller, wxT(
"After island removal, zone %s: %d outlines, area %.0f, bbox (%d,%d)-(%d,%d)" ),
813 zone->GetNetname(), poly->OutlineCount(), poly->Area(),
826 if( iterativeRefill && !zonesWithRemovedIslands.empty() )
830 wxLogTrace(
traceZoneFiller, wxT(
"Iterative refill: %zu zones had islands removed, cache size: %zu" ),
836 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zonesToRefill;
838 for(
ZONE* zoneWithIsland : zonesWithRemovedIslands )
840 BOX2I islandZoneBBox = zoneWithIsland->GetBoundingBox();
843 for(
ZONE* zone : aZones )
846 if( zone == zoneWithIsland )
850 if( zone->GetIsRuleArea() )
854 if( !zoneWithIsland->HigherPriority( zone ) )
858 LSET commonLayers = zone->GetLayerSet() & zoneWithIsland->GetLayerSet();
860 if( commonLayers.none() )
864 if( !zone->GetBoundingBox().Intersects( islandZoneBBox ) )
870 auto fillItem = std::make_pair( zone, layer );
872 if( std::find( zonesToRefill.begin(), zonesToRefill.end(), fillItem ) == zonesToRefill.end() )
874 zonesToRefill.push_back( fillItem );
880 if( !zonesToRefill.empty() )
882 wxLogTrace(
traceZoneFiller, wxT(
"Iterative refill: refilling %zu zone/layer pairs" ),
883 zonesToRefill.size() );
894 auto cached_refill_lambda =
895 [&](
const std::pair<ZONE*, PCB_LAYER_ID>& aFillItem ) ->
int
897 ZONE* zone = aFillItem.first;
905 wxT(
"Cached refill for zone %s: %d outlines, area %.0f" ),
913 std::vector<std::pair<std::future<int>,
int>> refillReturns;
914 refillReturns.reserve( zonesToRefill.size() );
915 size_t refillFinished = 0;
917 for(
const auto& fillItem : zonesToRefill )
919 refillReturns.emplace_back( std::make_pair(
tp.submit_task(
922 return cached_refill_lambda( fillItem );
926 while( !cancelled && refillFinished != 2 * zonesToRefill.size() )
928 for(
size_t ii = 0; ii < refillReturns.size(); ++ii )
930 auto& ret = refillReturns[ii];
935 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
937 if( status == std::future_status::ready )
939 if( ret.first.get() )
947 if( ret.second == 0 )
949 refillReturns[ii].first =
tp.submit_task(
952 return cached_refill_lambda( zonesToRefill[idx] );
955 else if( ret.second == 1 )
957 refillReturns[ii].first =
tp.submit_task(
960 return tesselate_lambda( zonesToRefill[idx] );
967 std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
979 for(
auto& ret : refillReturns )
981 if( ret.first.valid() )
983 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
985 while( status != std::future_status::ready )
990 status = ret.first.wait_for( std::chrono::milliseconds( 100 ) );
996 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> refillIslandsMap;
997 std::set<ZONE*> refillZones;
999 for(
const auto& [zone, layer] : zonesToRefill )
1000 refillZones.insert( zone );
1002 for(
ZONE* zone : refillZones )
1003 refillIslandsMap[zone] = std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>();
1005 connectivity->FillIsolatedIslandsMap( refillIslandsMap );
1008 for(
const auto& [ zone, zoneIslands ] : refillIslandsMap )
1010 bool allIslands =
true;
1012 for(
const auto& [ layer, layerIslands ] : zoneIslands )
1014 if( layerIslands.m_IsolatedOutlines.size()
1015 !=
static_cast<size_t>( zone->GetFilledPolysList( layer )->OutlineCount() ) )
1025 for(
const auto& [ layer, layerIslands ] : zoneIslands )
1030 if( layerIslands.m_IsolatedOutlines.empty() )
1033 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
1034 std::sort( islands.begin(), islands.end(), std::greater<int>() );
1036 std::shared_ptr<SHAPE_POLY_SET> poly = zone->GetFilledPolysList( layer );
1037 long long int minArea = zone->GetMinIslandArea();
1040 for(
int idx : islands )
1045 poly->DeletePolygonAndTriangulationData( idx,
false );
1047 poly->DeletePolygonAndTriangulationData( idx,
false );
1049 zone->SetIsIsland( layer, idx );
1052 poly->UpdateTriangulationDataHash();
1053 zone->CalculateFilledArea();
1057 wxLogTrace(
traceZoneFiller, wxT(
"Iterative refill completed in %0.3f ms" ),
1064 using island_check_return = std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
int>>;
1066 std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
double>> polys_to_check;
1069 polys_to_check.reserve(
m_board->GetCopperLayerCount() * aZones.size() );
1071 for(
ZONE* zone : aZones )
1081 double minArea = (double) zone->GetMinThickness() * zone->GetMinThickness() * 3;
1088 polys_to_check.emplace_back( zone->GetFilledPolysList( layer ), minArea );
1092 auto island_lambda =
1093 [&](
int aStart,
int aEnd ) -> island_check_return
1095 island_check_return retval;
1097 for(
int ii = aStart; ii < aEnd && !cancelled; ++ii )
1099 auto [poly, minArea] = polys_to_check[ii];
1101 for(
int jj = poly->OutlineCount() - 1; jj >= 0; jj-- )
1106 double island_area = test_poly.
Area();
1108 if( island_area < minArea )
1120 if( intersection.
Area() < island_area / 2.0 )
1121 retval.emplace_back( poly, jj );
1128 auto island_returns =
tp.submit_blocks( 0, polys_to_check.size(), island_lambda );
1132 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
1134 std::future<island_check_return>& ret = island_returns[ii];
1138 std::future_status status = ret.wait_for( std::chrono::seconds( 0 ) );
1140 while( status != std::future_status::ready )
1150 status = ret.wait_for( std::chrono::milliseconds( 100 ) );
1158 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
1160 std::future<island_check_return>& ret = island_returns[ii];
1164 for(
auto& action_item : ret.get() )
1165 action_item.first->DeletePolygonAndTriangulationData( action_item.second,
true );
1169 for(
ZONE* zone : aZones )
1170 zone->CalculateFilledArea();
1183 int holeRadius =
via->GetDrillValue() / 2;
1184 int netcode =
via->GetNetCode();
1185 LSET layers =
via->GetLayerSet() & boardCuMask;
1192 bool zoneReachesVia =
false;
1196 if( zone->GetIsRuleArea() )
1199 if( zone->GetNetCode() != netcode )
1202 if( !zone->IsOnLayer( layer ) )
1205 if( !zone->HasFilledPolysForLayer( layer ) )
1208 const std::shared_ptr<SHAPE_POLY_SET>& fill = zone->GetFilledPolysList( layer );
1210 if( fill->IsEmpty() )
1215 if( fill->Contains(
center, -1, holeRadius ) )
1217 zoneReachesVia =
true;
1222 if( !zoneReachesVia )
1230 for(
PAD*
pad : footprint->Pads() )
1233 int netcode =
pad->GetNetCode();
1234 LSET layers =
pad->GetLayerSet() & boardCuMask;
1241 bool zoneReachesPad =
false;
1245 if( zone->GetIsRuleArea() )
1248 if( zone->GetNetCode() != netcode )
1251 if( !zone->IsOnLayer( layer ) )
1254 if( !zone->HasFilledPolysForLayer( layer ) )
1257 const std::shared_ptr<SHAPE_POLY_SET>& fill = zone->GetFilledPolysList( layer );
1259 if( fill->IsEmpty() )
1262 if( fill->Contains(
center ) )
1264 zoneReachesPad =
true;
1269 if( !zoneReachesPad )
1277 bool outOfDate =
false;
1279 for(
ZONE* zone : aZones )
1282 if( zone->GetIsRuleArea() )
1287 zone->BuildHashValue( layer );
1289 if( oldFillHashes[ { zone, layer } ] != zone->GetHashValue( layer ) )
1295 &&
m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill ) )
1297 KIDIALOG dlg( aParent,
_(
"Prototype zone fill enabled. Disable setting and refill?" ),
_(
"Confirmation" ),
1298 wxOK | wxCANCEL | wxICON_WARNING );
1304 m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill =
false;
1306 else if( !outOfDate )
1314 KIDIALOG dlg( aParent,
_(
"Zone fills are out-of-date. Refill?" ),
_(
"Confirmation" ),
1315 wxOK | wxCANCEL | wxICON_WARNING );
1358 std::vector<VECTOR2I> convex_hull;
1363 for(
const VECTOR2I& pt : convex_hull )
1396 minorAxis = std::min( padSize.
x, padSize.
y );
1402 minorAxis =
via->GetWidth( aLayer );
1416 switch( aItem->
Type() )
1423 if(
text->IsVisible() )
1425 if(
text->IsKnockout() )
1481 std::vector<BOARD_ITEM*>& aThermalConnectionPads,
1482 std::vector<PAD*>& aNoConnectionPads )
1488 std::shared_ptr<SHAPE> padShape;
1494 for(
PAD*
pad : footprint->Pads() )
1496 if( !
pad->IsOnLayer( aLayer ) )
1499 BOX2I padBBox =
pad->GetBoundingBox();
1505 bool noConnection =
pad->GetNetCode() != aZone->
GetNetCode();
1512 noConnection =
true;
1517 if(
pad->IsBackdrilledOrPostMachined( aLayer ) )
1518 noConnection =
true;
1523 aNoConnectionPads.push_back(
pad );
1538 switch( connection )
1544 if( aFill.
Collide( padShape.get(), 0 ) )
1552 aThermalConnectionPads.push_back(
pad );
1561 aNoConnectionPads.push_back(
pad );
1586 switch( connection )
1591 if( aFill.
Collide( padShape.get(), 0 ) )
1596 aThermalConnectionPads.push_back(
pad );
1610 if(
pad->FlashLayer( aLayer ) )
1614 else if(
pad->GetDrillSize().x > 0 )
1621 holeClearance = padClearance;
1645 if( !
via->IsOnLayer( aLayer ) )
1648 BOX2I viaBBox =
via->GetBoundingBox();
1654 bool noConnection =
via->GetNetCode() != aZone->
GetNetCode()
1656 && aLayer !=
via->Padstack().Drill().start
1657 && aLayer !=
via->Padstack().Drill().end );
1660 if(
via->IsBackdrilledOrPostMachined( aLayer ) )
1662 noConnection =
true;
1674 pmSize = std::max( pmSize, frontPM.
size );
1680 pmSize = std::max( pmSize, backPM.
size );
1686 bdSize = secDrill.
size.
x;
1688 int knockoutSize = std::max( pmSize, bdSize );
1690 if( knockoutSize > 0 )
1706 aThermalConnectionPads.push_back(
via );
1721 const std::vector<PAD*>& aNoConnectionPads,
1723 bool aIncludeZoneClearances )
1728 auto checkForCancel =
1731 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
1744 auto evalRulesForItems =
1758 auto knockoutPadClearance =
1763 bool hasHole = aPad->GetDrillSize().x > 0;
1764 bool flashLayer = aPad->FlashLayer( aLayer );
1767 if( flashLayer || platedHole )
1772 if( flashLayer && gap >= 0 )
1773 addKnockout( aPad, aLayer, gap + extra_margin, aHoles );
1790 if( aPad->IsBackdrilledOrPostMachined( aLayer ) )
1801 pmSize = std::max( pmSize, frontPM.
size );
1807 pmSize = std::max( pmSize, backPM.
size );
1813 bdSize = secDrill.
size.
x;
1815 int knockoutSize = std::max( pmSize, bdSize );
1817 if( knockoutSize > 0 )
1819 int clearance = std::max( gap, 0 ) + extra_margin;
1827 for(
PAD*
pad : aNoConnectionPads )
1832 knockoutPadClearance(
pad );
1837 auto knockoutTrackClearance =
1840 if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
1842 bool sameNet = aTrack->GetNetCode() == aZone->
GetNetCode();
1864 if(
via->FlashLayer( aLayer ) && gap > 0 )
1866 via->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
m_maxError,
1885 if(
via->IsBackdrilledOrPostMachined( aLayer ) )
1896 pmSize = std::max( pmSize, frontPM.
size );
1902 pmSize = std::max( pmSize, backPM.
size );
1908 bdSize = secDrill.
size.
x;
1910 int knockoutSize = std::max( pmSize, bdSize );
1912 if( knockoutSize > 0 )
1914 int clearance = std::max( gap, 0 ) + extra_margin;
1925 aTrack->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
m_maxError,
1934 if( !track->IsOnLayer( aLayer ) )
1940 knockoutTrackClearance( track );
1945 auto knockoutGraphicClearance =
1951 shapeNet =
static_cast<PCB_SHAPE*
>( aItem )->GetNetCode();
1953 bool sameNet = shapeNet == aZone->
GetNetCode();
1959 if( aItem->IsOnLayer( aLayer )
1961 || aItem->IsOnLayer(
Margin ) )
1963 if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
1965 bool ignoreLineWidths =
false;
1968 if( aItem->IsOnLayer( aLayer ) && !sameNet )
1972 else if( aItem->IsOnLayer(
Edge_Cuts ) )
1975 ignoreLineWidths =
true;
1977 else if( aItem->IsOnLayer(
Margin ) )
1984 gap += extra_margin;
1985 addKnockout( aItem, aLayer, gap, ignoreLineWidths, aHoles );
1991 auto knockoutCourtyardClearance =
1994 if( aFootprint->GetBoundingBox().Intersects( zone_boundingbox ) )
2000 aHoles.
Append( aFootprint->GetCourtyard( aLayer ) );
2013 knockoutCourtyardClearance( footprint );
2014 knockoutGraphicClearance( &footprint->Reference() );
2015 knockoutGraphicClearance( &footprint->Value() );
2017 std::set<PAD*> allowedNetTiePads;
2021 if( footprint->IsNetTie() )
2023 for(
PAD*
pad : footprint->Pads() )
2032 if(
pad->IsOnLayer( aLayer ) )
2033 allowedNetTiePads.insert(
pad );
2035 for(
PAD* other : footprint->GetNetTiePads(
pad ) )
2037 if( other->IsOnLayer( aLayer ) )
2038 allowedNetTiePads.insert( other );
2044 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
2049 BOX2I itemBBox = item->GetBoundingBox();
2051 if( !zone_boundingbox.
Intersects( itemBBox ) )
2054 bool skipItem =
false;
2056 if( item->IsOnLayer( aLayer ) )
2058 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape();
2060 for(
PAD*
pad : allowedNetTiePads )
2062 if(
pad->GetBoundingBox().Intersects( itemBBox )
2063 &&
pad->GetEffectiveShape( aLayer )->Collide( itemShape.get() ) )
2072 knockoutGraphicClearance( item );
2081 knockoutGraphicClearance( item );
2086 auto knockoutZoneClearance =
2087 [&](
ZONE* aKnockout )
2090 if( !aKnockout->GetLayerSet().test( aLayer ) )
2093 if( aKnockout->GetBoundingBox().Intersects( zone_boundingbox ) )
2095 if( aKnockout->GetIsRuleArea() )
2108 aKnockout->TransformShapeToPolygon( poly, aLayer, gap + extra_margin,
m_maxError,
2115 if( aIncludeZoneClearances )
2123 if( !otherZone->GetBoundingBox().Intersects( zone_boundingbox ) )
2130 if( otherZone->GetIsRuleArea() )
2132 if( otherZone->GetDoNotAllowZoneFills() && !aZone->
IsTeardropArea() )
2133 knockoutZoneClearance( otherZone );
2135 else if( otherZone->HigherPriority( aZone ) )
2137 if( !otherZone->SameNet( aZone ) )
2138 knockoutZoneClearance( otherZone );
2144 for(
ZONE* otherZone : footprint->Zones() )
2150 if( !otherZone->GetBoundingBox().Intersects( zone_boundingbox ) )
2153 if( otherZone->GetIsRuleArea() )
2155 if( otherZone->GetDoNotAllowZoneFills() && !aZone->
IsTeardropArea() )
2156 knockoutZoneClearance( otherZone );
2158 else if( otherZone->HigherPriority( aZone ) )
2160 if( !otherZone->SameNet( aZone ) )
2161 knockoutZoneClearance( otherZone );
2184 auto evalRulesForItems =
2196 auto knockoutZoneClearance =
2197 [&](
ZONE* aKnockout )
2199 if( !aKnockout->GetLayerSet().test( aLayer ) )
2202 if( aKnockout->GetBoundingBox().Intersects( zone_boundingbox ) )
2204 if( aKnockout->GetIsRuleArea() )
2206 aKnockout->TransformSmoothedOutlineToPolygon( aHoles, 0,
m_maxError,
2212 aZone, aKnockout, aLayer ) );
2215 aKnockout, aLayer ) );
2218 aKnockout->TransformShapeToPolygon( poly, aLayer, gap + extra_margin,
2227 if( !otherZone->GetBoundingBox().Intersects( zone_boundingbox ) )
2234 if( !otherZone->GetIsRuleArea() && otherZone->HigherPriority( aZone ) )
2236 if( !otherZone->SameNet( aZone ) )
2237 knockoutZoneClearance( otherZone );
2243 for(
ZONE* otherZone : footprint->Zones() )
2245 if( !otherZone->GetBoundingBox().Intersects( zone_boundingbox ) )
2248 if( !otherZone->GetIsRuleArea() && otherZone->HigherPriority( aZone ) )
2250 if( !otherZone->SameNet( aZone ) )
2251 knockoutZoneClearance( otherZone );
2269 auto knockoutZoneOutline =
2270 [&](
ZONE* aKnockout )
2273 if( !aKnockout->GetLayerSet().test( aLayer ) )
2276 if( aKnockout->GetBoundingBox().Intersects( zoneBBox ) )
2292 if( otherZone->SameNet( aZone )
2296 if( !otherZone->IsTeardropArea() )
2297 knockoutZoneOutline( otherZone );
2303 for(
ZONE* otherZone : footprint->Zones() )
2305 if( otherZone->SameNet( aZone ) && otherZone->HigherPriority( aZone ) )
2308 if( !otherZone->IsTeardropArea() )
2309 knockoutZoneOutline( otherZone );
2327 std::map<int, std::vector<std::pair<int, VECTOR2I>>> insertion_points;
2339 insertion_points[
result.m_outline1].push_back( {
result.m_vertex1, pt1 } );
2340 insertion_points[
result.m_outline1].push_back( {
result.m_vertex1, pt2 } );
2343 for(
auto& [outline, vertices] : insertion_points )
2347 if( vertices.empty() )
2352 std::stable_sort( vertices.begin(), vertices.end(),
2353 [](
const std::pair<int, VECTOR2I>& a,
const std::pair<int, VECTOR2I>& b )
2355 return a.first < b.first;
2358 std::vector<VECTOR2I> new_points;
2359 new_points.reserve( line.
PointCount() + vertices.size() );
2361 size_t vertex_idx = 0;
2365 new_points.push_back( line.
CPoint( i ) );
2368 while( vertex_idx < vertices.size() && vertices[vertex_idx].first == i )
2370 new_points.push_back( vertices[vertex_idx].second );
2377 for(
const auto& pt : new_points )
2383#define DUMP_POLYS_TO_COPPER_LAYER( a, b, c ) \
2384 { if( m_debugZoneFiller && aDebugLayer == b ) \
2386 m_board->SetLayerName( b, c ); \
2387 SHAPE_POLY_SET d = a; \
2426 std::vector<BOARD_ITEM*> thermalConnectionPads;
2427 std::vector<PAD*> noConnectionPads;
2428 std::deque<SHAPE_LINE_CHAIN> thermalSpokes;
2431 aFillPolys = aSmoothedOutline;
2488 static const bool USE_BBOX_CACHES =
true;
2515 const VECTOR2I& testPt = spoke.CPoint( 3 );
2518 if( testAreas.
Contains( testPt, -1, 1, USE_BBOX_CACHES ) )
2527 if( interval++ > 400 )
2540 if( &other != &spoke
2541 && other.PointInside( testPt, 1, USE_BBOX_CACHES )
2542 && spoke.PointInside( other.CPoint( 3 ), 1, USE_BBOX_CACHES ) )
2572 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
2574 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
2575 BOX2I islandExtents;
2577 for(
const VECTOR2I& pt : island.front().CPoints() )
2579 islandExtents.
Merge( pt );
2600 || !
m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill ) )
2635 for(
BOARD_ITEM* item : thermalConnectionPads )
2652 if( iterativeRefill )
2662 wxT(
"Cached pre-knockout fill for zone %s layer %d: %d outlines, area %.0f, "
2663 "bbox (%d,%d)-(%d,%d)" ),
2664 aZone->
GetNetname(),
static_cast<int>( aLayer ),
2692 auto checkForCancel =
2695 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
2698 auto knockoutGraphicItem =
2701 if( aItem->IsKnockout() && aItem->IsOnLayer( aLayer )
2702 && aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
2704 addKnockout( aItem, aLayer, 0,
true, clearanceHoles );
2713 knockoutGraphicItem( &footprint->Reference() );
2714 knockoutGraphicItem( &footprint->Value() );
2716 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
2717 knockoutGraphicItem( item );
2725 knockoutGraphicItem( item );
2728 aFillPolys = aSmoothedOutline;
2731 auto subtractKeepout =
2732 [&](
ZONE* candidate )
2734 if( !candidate->GetIsRuleArea() )
2737 if( !candidate->HasKeepoutParametersSet() )
2740 if( candidate->GetDoNotAllowZoneFills() && candidate->IsOnLayer( aLayer ) )
2742 if( candidate->GetBoundingBox().Intersects( zone_boundingbox ) )
2744 if( candidate->Outline()->ArcCount() == 0 )
2763 subtractKeepout( keepout );
2771 for(
ZONE* keepout : footprint->Zones() )
2772 subtractKeepout( keepout );
2813 debugLayer = aLayer;
2817 if( !aZone->
BuildSmoothedPoly( maxExtents, aLayer, boardOutline, &smoothedPoly ) )
2825 if(
fillCopperZone( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aFillPolys ) )
2842 const std::vector<BOARD_ITEM*>& aSpokedPadsList,
2843 std::deque<SHAPE_LINE_CHAIN>& aSpokesList )
2862 if( !item->IsOnLayer( aLayer ) )
2865 int thermalReliefGap = 0;
2869 bool circular =
false;
2873 pad =
static_cast<PAD*
>( item );
2903 int spoke_max_allowed_w = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
2904 spoke_w = std::clamp( spoke_w, constraint.
Value().
Min(), constraint.
Value().
Max() );
2905 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
2907 if( spoke_w < aZone->GetMinThickness() )
2920 spoke_w = std::min( spoke_w,
via->GetWidth( aLayer ) );
2922 if( spoke_w < aZone->GetMinThickness() )
2941 int spoke_max_allowed_w = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
2943 spoke_w = std::clamp( spoke_w, constraint.
Value().
Min(), constraint.
Value().
Max() );
2946 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
2949 if( spoke_w < aZone->GetMinThickness() )
2958 int spoke_half_w = spoke_w / 2;
2961 BOX2I itemBB = item->GetBoundingBox();
2967 bool customSpokes =
false;
2971 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
2973 if( primitive->IsProxyItem() && primitive->GetShape() ==
SHAPE_T::SEGMENT )
2975 customSpokes =
true;
2986 auto buildSpokesFromOrigin =
2993 auto intersectBBox =
2996 double dx = spokeAngle.
Cos();
2997 double dy = spokeAngle.
Sin();
3003 *spoke_side =
VECTOR2I( spoke_half_w, 0 );
3004 return KiROUND( 0.0, dy * half_size.
y );
3008 *spoke_side =
VECTOR2I( 0, spoke_half_w );
3009 return KiROUND( dx * half_size.
x, 0.0 );
3014 double dist_x = half_size.
x /
std::abs( dx );
3015 double dist_y = half_size.
y /
std::abs( dy );
3017 if( dist_x < dist_y )
3019 *spoke_side =
KiROUND( 0.0, spoke_half_w / (
ANGLE_90 - spokeAngle ).Sin() );
3020 return KiROUND( dx * dist_x, dy * dist_x );
3024 *spoke_side =
KiROUND( spoke_half_w / spokeAngle.
Sin(), 0.0 );
3025 return KiROUND( dx * dist_y, dy * dist_y );
3038 for(
const EDA_ANGLE& spokeAngle : angles )
3041 VECTOR2I intersection = intersectBBox( spokeAngle, &spoke_side );
3050 aSpokesList.push_back( std::move( spoke ) );
3062 thermalOutline = thermalPoly.
Outline( 0 );
3066 auto trimToOutline = [&](
SEG& aSegment )
3070 if( padOutline.
Intersect( aSegment, intersections ) )
3072 intersections.clear();
3075 if( thermalOutline.
Intersect( aSegment, intersections ) )
3077 aSegment.B = intersections.front().p;
3084 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
3086 if( primitive->IsProxyItem() && primitive->GetShape() ==
SHAPE_T::SEGMENT )
3088 SEG seg( primitive->GetStart(), primitive->GetEnd() );
3093 seg.
A +=
pad->ShapePos( aLayer );
3094 seg.
B +=
pad->ShapePos( aLayer );
3108 if( trimToOutline( seg ) )
3110 VECTOR2I direction = ( seg.
B - seg.
A ).Resize( spoke_half_w );
3114 SEG segL( seg.
A - direction - offset, seg.
B + direction - offset );
3115 SEG segR( seg.
A - direction + offset, seg.
B + direction + offset );
3118 if( trimToOutline( segL ) && trimToOutline( segR ) )
3126 spoke.
Append( seg.
A + offset );
3127 spoke.
Append( seg.
A - offset );
3129 spoke.
Append( segL.
B + direction );
3130 spoke.
Append( seg.
B + direction );
3131 spoke.
Append( segR.
B + direction );
3134 aSpokesList.push_back( std::move( spoke ) );
3147 thermalSpokeAngle =
pad->GetThermalSpokeAngle();
3166 position =
pad->ShapePos( aLayer );
3167 orientation =
pad->GetOrientation();
3175 position =
via->GetPosition();
3180 spokesBox.
Inflate( thermalReliefGap +
epsilon + zone_half_width );
3187 buildSpokesFromOrigin( spokesBox,
ANGLE_0 );
3189 if( thermalSpokeAngle !=
ANGLE_0 )
3192 for(
auto it = aSpokesList.rbegin(); it != aSpokesList.rbegin() + 4; ++it )
3193 it->Rotate( thermalSpokeAngle );
3198 buildSpokesFromOrigin( spokesBox, thermalSpokeAngle );
3201 auto spokeIter = aSpokesList.rbegin();
3203 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
3205 spokeIter->Rotate( orientation );
3206 spokeIter->Move( position );
3211 for(
size_t ii = 0; ii < aSpokesList.size(); ++ii )
3212 aSpokesList[ii].GenerateBBoxCache();
3218 const std::vector<BOARD_ITEM*>& aThermalConnectionPads,
3224 for(
BOARD_ITEM* item : aThermalConnectionPads )
3226 if( !item->IsOnLayer( aLayer ) )
3231 bool isCircular =
false;
3239 pad =
static_cast<PAD*
>( item );
3241 position =
pad->ShapePos( aLayer );
3247 padRadius = std::max( padSize.
x, padSize.
y ) / 2;
3256 int spokeMaxWidth = std::min( padSize.
x, padSize.
y );
3257 spokeWidth = std::min( spokeWidth, spokeMaxWidth );
3262 position =
via->GetPosition();
3264 padRadius =
via->GetWidth( aLayer ) / 2;
3273 spokeWidth = std::min( spokeWidth, padRadius * 2 );
3281 if( spokeWidth < aZone->GetMinThickness() )
3291 int ringInnerRadius = padRadius + thermalGap;
3292 int ringWidth = spokeWidth;
3305 pad->TransformShapeToPolygon( outerShape, aLayer, thermalGap + spokeWidth,
3309 pad->TransformShapeToPolygon( innerShape, aLayer, thermalGap,
3312 thermalRing = outerShape;
3340 int maxError =
m_board->GetDesignSettings().m_MaxError;
3356 hole_base.
Append( corner );
3357 corner.
x += hole_size;
3358 hole_base.
Append( corner );
3359 corner.
y += hole_size;
3360 hole_base.
Append( corner );
3362 hole_base.
Append( corner );
3382 #define SMOOTH_MIN_VAL_MM 0.02
3383 #define SMOOTH_SMALL_VAL_MM 0.04
3399 smooth_value = std::min( smooth_value, aZone->
GetHatchGap() / 2 );
3402 maxError = std::max( maxError * 2, smooth_value / 20 );
3404 switch( smooth_level )
3416 hole_base = smooth_hole.
Fillet( smooth_value, maxError ).
Outline( 0 );
3428 auto& defaultOffsets =
m_board->GetDesignSettings().m_ZoneLayerProperties;
3431 VECTOR2I offset = defaultOffsets[aLayer].hatching_offset.value_or(
VECTOR2I() );
3433 if( localOffsets.contains( aLayer ) && localOffsets.at( aLayer ).hatching_offset.has_value() )
3434 offset = localOffsets.at( aLayer ).hatching_offset.value();
3436 int x_offset = bbox.
GetX() - ( bbox.
GetX() ) % gridsize - gridsize;
3437 int y_offset = bbox.
GetY() - ( bbox.
GetY() ) % gridsize - gridsize;
3440 for(
int xx = x_offset; xx <= bbox.
GetRight(); xx += gridsize )
3442 for(
int yy = y_offset; yy <= bbox.
GetBottom(); yy += gridsize )
3453 hole.
Move(
VECTOR2I( offset.
x % gridsize, offset.
y % gridsize ) );
3466 deflated_thickness = std::max( deflated_thickness, maxError * 2 );
3488 if( area < minimal_hole_area )
3505 auto cacheKey = std::make_pair(
static_cast<const ZONE*
>( aZone ), aLayer );
3513 wxLogTrace(
traceZoneFiller, wxT(
"Cache miss for zone %s layer %d (cache size: %zu)" ),
3518 wxLogTrace(
traceZoneFiller, wxT(
"Cache hit for zone %s layer %d: pre-knockout %d outlines" ),
3519 aZone->
GetNetname(),
static_cast<int>( aLayer ), it->second.OutlineCount() );
3522 aFillPolys = it->second;
3531 int board_clearance =
m_board->GetDesignSettings().m_MinClearance;
3535 if( otherZone == aZone )
3538 if( !otherZone->GetLayerSet().test( aLayer ) )
3541 if( otherZone->IsTeardropArea() )
3544 if( !otherZone->HigherPriority( aZone ) )
3547 if( !otherZone->GetBoundingBox().Intersects( zoneBBox ) )
3550 std::shared_ptr<SHAPE_POLY_SET> otherFill = otherZone->GetFilledPolysList( aLayer );
3552 if( !otherFill || otherFill->OutlineCount() == 0 )
3555 if( otherZone->SameNet( aZone ) )
3563 int clearance = std::max( zone_clearance, otherZone->GetLocalClearance().value() );
3574 for(
ZONE* otherZone : footprint->Zones() )
3576 if( !otherZone->GetLayerSet().test( aLayer ) )
3579 if( otherZone->IsTeardropArea() )
3582 if( !otherZone->HigherPriority( aZone ) )
3585 if( !otherZone->GetBoundingBox().Intersects( zoneBBox ) )
3588 std::shared_ptr<SHAPE_POLY_SET> otherFill = otherZone->GetFilledPolysList( aLayer );
3590 if( !otherFill || otherFill->OutlineCount() == 0 )
3593 if( otherZone->SameNet( aZone ) )
3599 int clearance = std::max( zone_clearance, otherZone->GetLocalClearance().value() );
constexpr EDA_IU_SCALE pcbIUScale
@ ZLO_FORCE_NO_ZONE_CONNECTION
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
wxString GetNetname() const
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.
virtual void SetIsKnockout(bool aKnockout)
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Information pertinent to a Pcbnew printed circuit board.
int GetCopperLayerCount() const
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
constexpr int GetSizeMax() const
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
constexpr coord_type GetY() const
constexpr size_type GetWidth() const
constexpr coord_type GetX() const
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
constexpr const Vec GetCenter() const
constexpr size_type GetHeight() const
constexpr coord_type GetRight() const
constexpr bool Intersects(const BOX2< Vec > &aRect) const
constexpr coord_type GetBottom() const
Represent a set of changes (additions, deletions or modifications) of a data model (e....
MINOPTMAX< int > & Value()
const MINOPTMAX< int > & GetValue() const
ZONE_CONNECTION m_ZoneConnection
DRC_CONSTRAINT EvalRules(DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
DRC_CONSTRAINT EvalZoneConnection(const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
KICAD_T Type() const
Returns the type of object.
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
bool SetOKCancelLabels(const ButtonLabel &ok, const ButtonLabel &cancel) override
LSET is a set of PCB_LAYER_IDs.
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
static const LSET & InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
UNCONNECTED_LAYER_MODE UnconnectedLayerMode() const
const BOX2I GetBoundingBox() const override
The bounding box is cached, so this will be efficient most of the time.
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
void SetOffset(PCB_LAYER_ID aLayer, const VECTOR2I &aOffset)
void SetPosition(const VECTOR2I &aPos) override
void SetOrientation(const EDA_ANGLE &aAngle)
Set the rotation angle of the pad.
bool TransformHoleToPolygon(SHAPE_POLY_SET &aBuffer, int aClearance, int aError, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Build the corner list of the polygonal drill shape in the board coordinate system.
void GetBoundingHull(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth=false) const override
Convert the item shape to a closed polygon.
void TransformTextToPolySet(SHAPE_POLY_SET &aBuffer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc) const
Function TransformTextToPolySet Convert the text to a polygonSet describing the actual character stro...
void SetPosition(const VECTOR2I &aPoint) override
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
A small class to help profiling.
double msecs(bool aSinceLast=false)
A progress reporter interface for use in multi-threaded environments.
RESULTS(int aOutline1, int aOutline2, int aVertex1, int aVertex2)
bool operator<(const RESULTS &aOther) const
VECTOR2I::extended_type ecoord
static SEG::ecoord Square(int a)
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.
int Intersect(const SEG &aSeg, INTERSECTIONS &aIp) const
Find all intersection points between our line chain and the segment aSeg.
int PointCount() const
Return the number of points (vertices) in this line chain.
void Clear()
Remove all points from the line chain.
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.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
std::vector< INTERSECTION > INTERSECTIONS
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 BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
void DeletePolygon(int aIdx)
Delete aIdx-th polygon from the set.
double Area()
Return the area of this poly set.
void Fracture()
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
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)
Return the aIndex-th subpolygon in the set.
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
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 Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
void Deflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError)
void BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
void BuildBBoxCaches() const
Construct BBoxCaches for Contains(), below.
int OutlineCount() const
Return the number of outlines in the set.
SHAPE_POLY_SET Fillet(int aRadius, int aErrorMax)
Return a filleted version of the polygon set.
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
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
const BOX2I BBoxFromCaches() const
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
constexpr extended_type SquaredEuclideanNorm() const
Compute the squared euclidean norm of the vector, which is defined as (x ** 2 + y ** 2).
constexpr VECTOR2< T > Perpendicular() const
Compute the perpendicular vector.
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
VERTEX * getPoint(VERTEX *aPt) const
std::set< RESULTS > GetResults() const
VERTEX_CONNECTOR(const BOX2I &aBBox, const SHAPE_POLY_SET &aPolys, int aDist)
std::set< RESULTS > m_results
std::deque< VERTEX > m_vertices
VERTEX * createList(const SHAPE_LINE_CHAIN &points, VERTEX *aTail=nullptr, void *aUserData=nullptr)
Create a list of vertices from a line chain.
void SetBoundingBox(const BOX2I &aBBox)
VERTEX_SET(int aSimplificationLevel)
uint32_t zOrder(const double aX, const double aY) const
Note that while the inputs are doubles, these are scaled by the size of the bounding box to fit into ...
void updateList()
After inserting or changing nodes, this function should be called to remove duplicate vertices and en...
void * GetUserData() const
bool isEar(bool aMatchUserData=false) const
Check whether the given vertex is in the middle of an ear.
bool refillZoneFromCache(ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aFillPolys)
Refill a zone from cached pre-knockout fill.
void buildCopperItemClearances(const ZONE *aZone, PCB_LAYER_ID aLayer, const std::vector< PAD * > &aNoConnectionPads, SHAPE_POLY_SET &aHoles, bool aIncludeZoneClearances=true)
Removes clearance from the shape for copper items which share the zone's layer but are not connected ...
void connect_nearby_polys(SHAPE_POLY_SET &aPolys, double aDistance)
Create strands of zero-width between elements of SHAPE_POLY_SET that are within aDistance of each oth...
void buildThermalSpokes(const ZONE *box, PCB_LAYER_ID aLayer, const std::vector< BOARD_ITEM * > &aSpokedPadsList, std::deque< SHAPE_LINE_CHAIN > &aSpokes)
Function buildThermalSpokes Constructs a list of all thermal spokes for the given zone.
void buildDifferentNetZoneClearances(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aHoles)
Build clearance knockout holes for higher-priority zones on different nets.
ZONE_FILLER(BOARD *aBoard, COMMIT *aCommit)
void subtractHigherPriorityZones(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aRawFill)
Removes the outlines of higher-proirity zones with the same net.
void knockoutThermalReliefs(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aFill, std::vector< BOARD_ITEM * > &aThermalConnectionPads, std::vector< PAD * > &aNoConnectionPads)
Removes thermal reliefs from the shape for any pads connected to the zone.
void addKnockout(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer, int aGap, SHAPE_POLY_SET &aHoles)
Add a knockout for a pad or via.
SHAPE_POLY_SET m_boardOutline
void buildHatchZoneThermalRings(const ZONE *aZone, PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aSmoothedOutline, const std::vector< BOARD_ITEM * > &aThermalConnectionPads, SHAPE_POLY_SET &aFillPolys)
Build thermal rings for pads in hatch zones.
std::map< std::pair< const ZONE *, PCB_LAYER_ID >, SHAPE_POLY_SET > m_preKnockoutFillCache
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)
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 *candidate, 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...
bool Fill(const std::vector< ZONE * > &aZones, bool aCheck=false, wxWindow *aParent=nullptr)
Fills the given list of zones.
Handle a list of polygons defining a copper zone.
void SetNeedRefill(bool aNeedRefill)
std::optional< int > GetLocalClearance() const override
ZONE_LAYER_PROPERTIES & LayerProperties(PCB_LAYER_ID aLayer)
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)
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
void TransformRingToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aCentre, int aRadius, int aWidth, int aError, ERROR_LOC aErrorLoc)
Convert arcs to multiple straight segments.
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.
CORNER_STRATEGY
define how inflate transform build inflated polygon
@ CHAMFER_ALL_CORNERS
All angles are chamfered.
@ ROUND_ALL_CORNERS
All angles are rounded.
@ 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 ANGLE_0
static constexpr EDA_ANGLE ANGLE_90
a few functions useful in geometry calculations.
bool m_ZoneFillIterativeRefill
Enable iterative zone filling to handle isolated islands in higher priority zones.
bool m_DebugZoneFiller
A mode that dumps the various stages of a F_Cu fill into In1_Cu through In9_Cu.
static const wxChar traceZoneFiller[]
Trace mask for zone filler timing information.
@ ALWAYS_FLASHED
Always flashed for connectivity.
PCB_LAYER_ID
A quick note on layer IDs:
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
@ PTH
Plated through hole pad.
BARCODE class definition.
A storage class for 128-bit hash value.
A struct recording the isolated and single-pad islands within a zone.
! The properties of a padstack drill. Drill position is always the pad position (origin).
VECTOR2I size
Drill diameter (x == y) or slot dimensions (x != y)
std::optional< PAD_DRILL_POST_MACHINING_MODE > mode
wxString result
Test unit parsing edge cases and error handling.
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::priority_thread_pool thread_pool
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
@ PCB_PAD_T
class PAD, a pad in a footprint
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D
#define SMOOTH_MIN_VAL_MM
int getHatchFillThermalClearance(const ZONE *aZone, BOARD_ITEM *aItem, PCB_LAYER_ID aLayer)
#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