30#include <unordered_set>
74 RESULTS(
int aOutline1,
int aOutline2,
int aVertex1,
int aVertex2 ) :
121 SEG::ecoord min_dist = std::numeric_limits<SEG::ecoord>::max();
124 auto check_pt = [&](
VERTEX* p )
126 VECTOR2D diff( p->x - aPt->
x, p->y - aPt->
y );
129 if( dist2 > 0 && dist2 < limit2 && dist2 < min_dist && p->isEar(
true ) )
138 while( p && p->
z <= maxZ )
146 while( p && p->
z >= minZ )
161 std::set<VERTEX*> visited;
174 if( ( visited.empty() || !visited.contains( p ) ) && ( q =
getPoint( p ) ) )
178 if( !visited.contains( q ) &&
180 p->
i, q->
i ).second )
184 visited.insert( p->
prev );
186 visited.insert( p->
next );
189 visited.insert( q->
prev );
191 visited.insert( q->
next );
224struct PAD_KNOCKOUT_KEY
231 bool operator==(
const PAD_KNOCKOUT_KEY& other )
const
233 return position == other.position && effectiveSize == other.effectiveSize
234 && shape == other.shape && orientation == other.orientation;
238struct PAD_KNOCKOUT_KEY_HASH
240 size_t operator()(
const PAD_KNOCKOUT_KEY& key )
const
242 return hash_val( key.position.
x, key.position.
y, key.effectiveSize.
x, key.effectiveSize.
y,
243 key.shape, key.orientation.
AsDegrees() );
248struct VIA_KNOCKOUT_KEY
253 bool operator==(
const VIA_KNOCKOUT_KEY& other )
const
255 return position == other.position && effectiveSize == other.effectiveSize;
259struct VIA_KNOCKOUT_KEY_HASH
261 size_t operator()(
const VIA_KNOCKOUT_KEY& key )
const
263 return hash_val( key.position.
x, key.position.
y, key.effectiveSize );
269struct TRACK_KNOCKOUT_KEY
275 TRACK_KNOCKOUT_KEY(
const VECTOR2I& aStart,
const VECTOR2I& aEnd,
int aWidth ) :
279 if( aStart.
x < aEnd.
x || ( aStart.
x == aEnd.
x && aStart.
y <= aEnd.
y ) )
291 bool operator==(
const TRACK_KNOCKOUT_KEY& other )
const
293 return start == other.start && end == other.end && width == other.width;
297struct TRACK_KNOCKOUT_KEY_HASH
299 size_t operator()(
const TRACK_KNOCKOUT_KEY& key )
const
301 return hash_val( key.start.
x, key.start.
y, key.end.
x, key.end.
y, key.width );
345 std::lock_guard<KISPINLOCK> lock(
m_board->GetConnectivity()->GetLock() );
347 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
348 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
HASH_128> oldFillHashes;
349 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> isolatedIslandsMap;
351 std::shared_ptr<CONNECTIVITY_DATA> connectivity =
m_board->GetConnectivity();
358 connectivity->ClearRatsnest();
366 :
_(
"Building zone fills..." ) );
379 zone->CacheBoundingBox();
383 for(
PAD*
pad : footprint->Pads() )
387 pad->BuildEffectiveShapes();
392 for(
ZONE* zone : footprint->Zones() )
393 zone->CacheBoundingBox();
396 footprint->BuildCourtyardCaches();
397 footprint->BuildNetTieCache();
402 auto findHighestPriorityZone =
404 const std::function<bool(
const ZONE* )>& testFn ) ->
ZONE*
406 unsigned highestPriority = 0;
407 ZONE* highestPriorityZone =
nullptr;
412 if( zone->GetIsRuleArea() )
415 if( zone->GetAssignedPriority() < highestPriority )
418 if( !zone->IsOnLayer( itemLayer ) )
422 if( zone->GetNumCorners() <= 2 )
425 if( !zone->GetBoundingBox().Intersects( bbox ) )
428 if( !testFn( zone ) )
432 if( zone->GetAssignedPriority() > highestPriority
433 || zone->GetNetCode() == netcode )
435 highestPriority = zone->GetAssignedPriority();
436 highestPriorityZone = zone;
440 return highestPriorityZone;
443 auto isInPourKeepoutArea =
448 if( !zone->GetIsRuleArea() )
451 if( !zone->HasKeepoutParametersSet() )
454 if( !zone->GetDoNotAllowZoneFills() )
457 if( !zone->IsOnLayer( itemLayer ) )
461 if( zone->GetNumCorners() <= 2 )
464 if( !zone->GetBoundingBox().Intersects( bbox ) )
467 if( zone->Outline()->Contains( testPoint ) )
484 via->ClearZoneLayerOverrides();
486 if( !
via->GetRemoveUnconnected() )
491 int holeRadius =
via->GetDrillValue() / 2 + 1;
492 int netcode =
via->GetNetCode();
493 LSET layers =
via->GetLayerSet() & boardCuMask;
497 [&](
const ZONE* aZone ) ->
bool
499 return aZone->Outline()->Contains(
center, -1, holeRadius );
504 if( !
via->ConditionallyFlashed( layer ) )
507 if( isInPourKeepoutArea( bbox, layer,
center ) )
513 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, viaTestFn );
518 || layer == padstack.
Drill().
end ) )
534 for(
PAD*
pad : footprint->Pads() )
536 pad->ClearZoneLayerOverrides();
538 if( !
pad->GetRemoveUnconnected() )
543 int netcode =
pad->GetNetCode();
544 LSET layers =
pad->GetLayerSet() & boardCuMask;
547 [&](
const ZONE* aZone ) ->
bool
549 return aZone->Outline()->Contains(
center );
554 if( !
pad->ConditionallyFlashed( layer ) )
557 if( isInPourKeepoutArea( bbox, layer,
center ) )
563 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, padTestFn );
574 for(
ZONE* zone : aZones )
577 if( zone->GetIsRuleArea() )
581 if( zone->GetNumCorners() <= 2 )
591 zone->BuildHashValue( layer );
592 oldFillHashes[ { zone, layer } ] = zone->GetHashValue( layer );
595 toFill.emplace_back( std::make_pair( zone, layer ) );
604 auto check_fill_dependency =
612 if( aOtherZone->GetFillFlag( aLayer ) )
617 if( aOtherZone->GetIsRuleArea() )
621 if( aOtherZone->GetNumCorners() <= 2 )
625 if( !aOtherZone->GetLayerSet().test( aLayer ) )
632 if( aOtherZone->SameNet( aZone ) )
640 if( !inflatedBBox.
Intersects( aOtherZone->GetBoundingBox() ) )
647 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
650 ZONE* zone = aFillItem.first;
655 for(
ZONE* otherZone : aZones )
657 if( otherZone == zone )
660 if( check_fill_dependency( zone, layer, otherZone ) )
675 std::unique_lock<std::mutex> zoneLock( zone->
GetLock(), std::try_to_lock );
677 if( !zoneLock.owns_lock() )
694 auto tesselate_lambda =
695 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
701 ZONE* zone = aFillItem.first;
704 std::unique_lock<std::mutex> zoneLock( zone->
GetLock(), std::try_to_lock );
706 if( !zoneLock.owns_lock() )
718 std::vector<std::pair<std::future<int>,
int>> returns;
719 returns.reserve( toFill.size() );
721 std::atomic<bool> cancelled(
false );
725 for(
const std::pair<ZONE*, PCB_LAYER_ID>& fillItem : toFill )
727 returns.emplace_back( std::make_pair(
tp.submit_task(
730 return fill_lambda( fillItem );
734 while( !cancelled && finished != 2 * toFill.size() )
736 for(
size_t ii = 0; ii < returns.size(); ++ii )
738 auto& ret = returns[ii];
743 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
745 if( status == std::future_status::ready )
747 if( ret.first.get() )
756 if( ret.second == 0 )
758 returns[ii].first =
tp.submit_task(
761 return fill_lambda( toFill[idx] );
764 else if( ret.second == 1 )
766 returns[ii].first =
tp.submit_task(
769 return tesselate_lambda( toFill[idx] );
776 std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
790 for(
auto& ret : returns )
792 if( ret.first.valid() )
794 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
796 while( status != std::future_status::ready )
801 status = ret.first.wait_for( std::chrono::milliseconds( 100 ) );
820 connectivity->FillIsolatedIslandsMap( isolatedIslandsMap );
821 connectivity->SetProgressReporter(
nullptr );
826 for(
ZONE* zone : aZones )
829 if( zone->GetIsRuleArea() )
832 zone->SetIsFilled(
true );
839 std::set<ZONE*> zonesWithRemovedIslands;
841 for(
const auto& [ zone, zoneIslands ] : isolatedIslandsMap )
844 bool allIslands =
true;
846 for(
const auto& [ layer, layerIslands ] : zoneIslands )
848 if( layerIslands.m_IsolatedOutlines.size()
849 !=
static_cast<size_t>( zone->GetFilledPolysList( layer )->OutlineCount() ) )
859 for(
const auto& [ layer, layerIslands ] : zoneIslands )
864 if( layerIslands.m_IsolatedOutlines.empty() )
867 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
871 std::sort( islands.begin(), islands.end(), std::greater<int>() );
873 std::shared_ptr<SHAPE_POLY_SET> poly = zone->GetFilledPolysList( layer );
874 long long int minArea = zone->GetMinIslandArea();
877 wxLogTrace(
traceZoneFiller, wxT(
"Zone %s layer %d: %zu islands to process, mode=%d, poly has %d outlines, area %.0f" ),
878 zone->GetNetname(),
static_cast<int>( layer ), islands.size(),
879 static_cast<int>( mode ), poly->OutlineCount(), poly->Area() );
881 for(
int idx : islands )
887 wxLogTrace(
traceZoneFiller, wxT(
"Removing island %d from zone %s (ALWAYS mode)" ),
888 idx, zone->GetNetname() );
889 poly->DeletePolygonAndTriangulationData( idx,
false );
890 zonesWithRemovedIslands.insert( zone );
894 wxLogTrace(
traceZoneFiller, wxT(
"Removing island %d from zone %s (AREA mode, area=%.0f < min=%.0f)" ),
895 idx, zone->GetNetname(), outline.
Area(
true ),
896 static_cast<double>( minArea ) );
897 poly->DeletePolygonAndTriangulationData( idx,
false );
898 zonesWithRemovedIslands.insert( zone );
902 zone->SetIsIsland( layer, idx );
906 poly->UpdateTriangulationDataHash();
907 zone->CalculateFilledArea();
909 BOX2I bbox = poly->BBox();
910 wxLogTrace(
traceZoneFiller, wxT(
"After island removal, zone %s: %d outlines, area %.0f, bbox (%d,%d)-(%d,%d)" ),
911 zone->GetNetname(), poly->OutlineCount(), poly->Area(),
924 if( iterativeRefill && !zonesWithRemovedIslands.empty() )
928 wxLogTrace(
traceZoneFiller, wxT(
"Iterative refill: %zu zones had islands removed, cache size: %zu" ),
934 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zonesToRefill;
936 for(
ZONE* zoneWithIsland : zonesWithRemovedIslands )
938 BOX2I islandZoneBBox = zoneWithIsland->GetBoundingBox();
941 for(
ZONE* zone : aZones )
944 if( zone == zoneWithIsland )
948 if( zone->GetIsRuleArea() )
952 if( !zoneWithIsland->HigherPriority( zone ) )
956 LSET commonLayers = zone->GetLayerSet() & zoneWithIsland->GetLayerSet();
958 if( commonLayers.none() )
962 if( !zone->GetBoundingBox().Intersects( islandZoneBBox ) )
968 auto fillItem = std::make_pair( zone, layer );
970 if( std::find( zonesToRefill.begin(), zonesToRefill.end(), fillItem ) == zonesToRefill.end() )
972 zonesToRefill.push_back( fillItem );
978 if( !zonesToRefill.empty() )
980 wxLogTrace(
traceZoneFiller, wxT(
"Iterative refill: refilling %zu zone/layer pairs" ),
981 zonesToRefill.size() );
992 auto cached_refill_lambda =
993 [&](
const std::pair<ZONE*, PCB_LAYER_ID>& aFillItem ) ->
int
995 ZONE* zone = aFillItem.first;
1002 wxLogTrace(
traceZoneFiller, wxT(
"Cached refill for zone %s: %d outlines, area %.0f" ),
1010 std::vector<std::pair<std::future<int>,
int>> refillReturns;
1011 refillReturns.reserve( zonesToRefill.size() );
1012 size_t refillFinished = 0;
1014 for(
const auto& fillItem : zonesToRefill )
1016 refillReturns.emplace_back( std::make_pair(
tp.submit_task(
1019 return cached_refill_lambda( fillItem );
1023 while( !cancelled && refillFinished != 2 * zonesToRefill.size() )
1025 for(
size_t ii = 0; ii < refillReturns.size(); ++ii )
1027 auto& ret = refillReturns[ii];
1029 if( ret.second > 1 )
1032 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
1034 if( status == std::future_status::ready )
1036 if( ret.first.get() )
1041 else if( ret.second == 0 )
1045 refillFinished += 2;
1052 if( ret.second == 1 )
1054 refillReturns[ii].first =
tp.submit_task(
1057 return tesselate_lambda( zonesToRefill[idx] );
1064 std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
1076 for(
auto& ret : refillReturns )
1078 if( ret.first.valid() )
1080 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
1082 while( status != std::future_status::ready )
1087 status = ret.first.wait_for( std::chrono::milliseconds( 100 ) );
1093 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> refillIslandsMap;
1094 std::set<ZONE*> refillZones;
1096 for(
const auto& [zone, layer] : zonesToRefill )
1097 refillZones.insert( zone );
1099 for(
ZONE* zone : refillZones )
1101 refillIslandsMap[zone] = std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>();
1107 connectivity->FillIsolatedIslandsMap( refillIslandsMap );
1110 for(
const auto& [ zone, zoneIslands ] : refillIslandsMap )
1112 bool allIslands =
true;
1114 for(
const auto& [ layer, layerIslands ] : zoneIslands )
1116 if( layerIslands.m_IsolatedOutlines.size()
1117 !=
static_cast<size_t>( zone->GetFilledPolysList( layer )->OutlineCount() ) )
1127 for(
const auto& [ layer, layerIslands ] : zoneIslands )
1132 if( layerIslands.m_IsolatedOutlines.empty() )
1135 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
1136 std::sort( islands.begin(), islands.end(), std::greater<int>() );
1138 std::shared_ptr<SHAPE_POLY_SET> poly = zone->GetFilledPolysList( layer );
1139 long long int minArea = zone->GetMinIslandArea();
1142 for(
int idx : islands )
1147 poly->DeletePolygonAndTriangulationData( idx,
false );
1149 poly->DeletePolygonAndTriangulationData( idx,
false );
1151 zone->SetIsIsland( layer, idx );
1154 poly->UpdateTriangulationDataHash();
1155 zone->CalculateFilledArea();
1165 using island_check_return = std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
int>>;
1167 std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
double>> polys_to_check;
1170 polys_to_check.reserve(
m_board->GetCopperLayerCount() * aZones.size() );
1172 for(
ZONE* zone : aZones )
1182 double minArea = (double) zone->GetMinThickness() * zone->GetMinThickness() * 3;
1189 polys_to_check.emplace_back( zone->GetFilledPolysList( layer ), minArea );
1193 auto island_lambda =
1194 [&](
int aStart,
int aEnd ) -> island_check_return
1196 island_check_return retval;
1198 for(
int ii = aStart; ii < aEnd && !cancelled; ++ii )
1200 auto [poly, minArea] = polys_to_check[ii];
1202 for(
int jj = poly->OutlineCount() - 1; jj >= 0; jj-- )
1207 double island_area = test_poly.
Area();
1209 if( island_area < minArea )
1221 if( intersection.
Area() < island_area / 2.0 )
1222 retval.emplace_back( poly, jj );
1229 auto island_returns =
tp.submit_blocks( 0, polys_to_check.size(), island_lambda );
1233 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
1235 std::future<island_check_return>& ret = island_returns[ii];
1239 std::future_status status = ret.wait_for( std::chrono::seconds( 0 ) );
1241 while( status != std::future_status::ready )
1251 status = ret.wait_for( std::chrono::milliseconds( 100 ) );
1259 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
1261 std::future<island_check_return>& ret = island_returns[ii];
1265 for(
auto& action_item : ret.get() )
1266 action_item.first->DeletePolygonAndTriangulationData( action_item.second,
true );
1270 for(
ZONE* zone : aZones )
1271 zone->CalculateFilledArea();
1284 int holeRadius =
via->GetDrillValue() / 2;
1285 int netcode =
via->GetNetCode();
1286 LSET layers =
via->GetLayerSet() & boardCuMask;
1293 bool zoneReachesVia =
false;
1297 if( zone->GetIsRuleArea() )
1300 if( zone->GetNetCode() != netcode )
1303 if( !zone->IsOnLayer( layer ) )
1306 if( !zone->HasFilledPolysForLayer( layer ) )
1309 const std::shared_ptr<SHAPE_POLY_SET>& fill = zone->GetFilledPolysList( layer );
1311 if( fill->IsEmpty() )
1316 if( fill->Contains(
center, -1, holeRadius ) )
1318 zoneReachesVia =
true;
1323 if( !zoneReachesVia )
1331 for(
PAD*
pad : footprint->Pads() )
1334 int netcode =
pad->GetNetCode();
1335 LSET layers =
pad->GetLayerSet() & boardCuMask;
1341 if(
pad->HasHole() )
1342 holeRadius = std::min(
pad->GetDrillSizeX(),
pad->GetDrillSizeY() ) / 2;
1349 bool zoneReachesPad =
false;
1353 if( zone->GetIsRuleArea() )
1356 if( zone->GetNetCode() != netcode )
1359 if( !zone->IsOnLayer( layer ) )
1362 if( !zone->HasFilledPolysForLayer( layer ) )
1365 const std::shared_ptr<SHAPE_POLY_SET>& fill = zone->GetFilledPolysList( layer );
1367 if( fill->IsEmpty() )
1370 if( fill->Contains(
center, -1, holeRadius ) )
1372 zoneReachesPad =
true;
1377 if( !zoneReachesPad )
1385 bool outOfDate =
false;
1387 for(
ZONE* zone : aZones )
1390 if( zone->GetIsRuleArea() )
1395 zone->BuildHashValue( layer );
1397 if( oldFillHashes[ { zone, layer } ] != zone->GetHashValue( layer ) )
1403 &&
m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill ) )
1405 KIDIALOG dlg( aParent,
_(
"Prototype zone fill enabled. Disable setting and refill?" ),
_(
"Confirmation" ),
1406 wxOK | wxCANCEL | wxICON_WARNING );
1412 m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill =
false;
1414 else if( !outOfDate )
1422 KIDIALOG dlg( aParent,
_(
"Zone fills are out-of-date. Refill?" ),
_(
"Confirmation" ),
1423 wxOK | wxCANCEL | wxICON_WARNING );
1466 std::vector<VECTOR2I> convex_hull;
1471 for(
const VECTOR2I& pt : convex_hull )
1504 minorAxis = std::min( padSize.
x, padSize.
y );
1510 minorAxis =
via->GetWidth( aLayer );
1524 switch( aItem->
Type() )
1531 if(
text->IsVisible() )
1533 if(
text->IsKnockout() )
1589 std::vector<BOARD_ITEM*>& aThermalConnectionPads,
1590 std::vector<PAD*>& aNoConnectionPads )
1596 std::shared_ptr<SHAPE> padShape;
1601 std::unordered_set<PAD_KNOCKOUT_KEY, PAD_KNOCKOUT_KEY_HASH> processedPads;
1602 std::unordered_set<VIA_KNOCKOUT_KEY, VIA_KNOCKOUT_KEY_HASH> processedVias;
1606 for(
PAD*
pad : footprint->Pads() )
1608 if( !
pad->IsOnLayer( aLayer ) )
1611 BOX2I padBBox =
pad->GetBoundingBox();
1628 int drill = std::max(
pad->GetDrillSize().x,
pad->GetDrillSize().y );
1629 int maxDim = std::max( { padSize.
x, padSize.
y, drill } );
1630 effectiveSize =
VECTOR2I( maxDim, maxDim );
1634 effectiveSize = padSize;
1637 PAD_KNOCKOUT_KEY padKey{
pad->GetPosition(), effectiveSize,
1638 static_cast<int>( padShapeType ),
pad->GetOrientation() };
1640 if( !processedPads.insert( padKey ).second )
1644 bool noConnection =
pad->GetNetCode() != aZone->
GetNetCode();
1651 noConnection =
true;
1656 if(
pad->IsBackdrilledOrPostMachined( aLayer ) )
1657 noConnection =
true;
1662 aNoConnectionPads.push_back(
pad );
1677 switch( connection )
1683 if( aFill.
Collide( padShape.get(), 0 ) )
1691 aThermalConnectionPads.push_back(
pad );
1700 aNoConnectionPads.push_back(
pad );
1725 switch( connection )
1730 if( aFill.
Collide( padShape.get(), 0 ) )
1735 aThermalConnectionPads.push_back(
pad );
1749 if(
pad->FlashLayer( aLayer ) )
1753 else if(
pad->GetDrillSize().x > 0 )
1760 holeClearance = padClearance;
1784 if( !
via->IsOnLayer( aLayer ) )
1787 BOX2I viaBBox =
via->GetBoundingBox();
1794 int viaEffectiveSize = std::max(
via->GetDrillValue(),
via->GetWidth( aLayer ) );
1795 VIA_KNOCKOUT_KEY viaKey{
via->GetPosition(), viaEffectiveSize };
1797 if( !processedVias.insert( viaKey ).second )
1800 bool noConnection =
via->GetNetCode() != aZone->
GetNetCode()
1802 && aLayer !=
via->Padstack().Drill().start
1803 && aLayer !=
via->Padstack().Drill().end );
1806 if(
via->IsBackdrilledOrPostMachined( aLayer ) )
1808 noConnection =
true;
1820 pmSize = std::max( pmSize, frontPM.
size );
1826 pmSize = std::max( pmSize, backPM.
size );
1832 bdSize = secDrill.
size.
x;
1834 int knockoutSize = std::max( pmSize, bdSize );
1836 if( knockoutSize > 0 )
1852 aThermalConnectionPads.push_back(
via );
1867 const std::vector<PAD*>& aNoConnectionPads,
1869 bool aIncludeZoneClearances )
1875 std::unordered_set<PAD_KNOCKOUT_KEY, PAD_KNOCKOUT_KEY_HASH> processedPads;
1876 std::unordered_set<VIA_KNOCKOUT_KEY, VIA_KNOCKOUT_KEY_HASH> processedVias;
1877 std::unordered_set<TRACK_KNOCKOUT_KEY, TRACK_KNOCKOUT_KEY_HASH> processedTracks;
1879 auto checkForCancel =
1882 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
1895 auto evalRulesForItems =
1909 auto knockoutPadClearance =
1914 bool hasHole = aPad->GetDrillSize().x > 0;
1915 bool flashLayer = aPad->FlashLayer( aLayer );
1918 if( flashLayer || platedHole )
1923 if( flashLayer && gap >= 0 )
1924 addKnockout( aPad, aLayer, gap + extra_margin, aHoles );
1941 if( aPad->IsBackdrilledOrPostMachined( aLayer ) )
1952 pmSize = std::max( pmSize, frontPM.
size );
1958 pmSize = std::max( pmSize, backPM.
size );
1964 bdSize = secDrill.
size.
x;
1966 int knockoutSize = std::max( pmSize, bdSize );
1968 if( knockoutSize > 0 )
1970 int clearance = std::max( gap, 0 ) + extra_margin;
1978 for(
PAD*
pad : aNoConnectionPads )
1994 int drill = std::max(
pad->GetDrillSize().x,
pad->GetDrillSize().y );
1995 int maxDim = std::max( { padSize.
x, padSize.
y, drill } );
1996 effectiveSize =
VECTOR2I( maxDim, maxDim );
2000 effectiveSize = padSize;
2003 PAD_KNOCKOUT_KEY padKey{
pad->GetPosition(), effectiveSize,
2004 static_cast<int>( padShape ),
pad->GetOrientation() };
2006 if( !processedPads.insert( padKey ).second )
2010 knockoutPadClearance(
pad );
2015 auto knockoutTrackClearance =
2018 if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
2020 bool sameNet = aTrack->GetNetCode() == aZone->
GetNetCode();
2042 if(
via->FlashLayer( aLayer ) && gap > 0 )
2044 via->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
m_maxError,
2063 if(
via->IsBackdrilledOrPostMachined( aLayer ) )
2074 pmSize = std::max( pmSize, frontPM.
size );
2080 pmSize = std::max( pmSize, backPM.
size );
2086 bdSize = secDrill.
size.
x;
2088 int knockoutSize = std::max( pmSize, bdSize );
2090 if( knockoutSize > 0 )
2092 int clearance = std::max( gap, 0 ) + extra_margin;
2103 aTrack->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
m_maxError,
2112 if( !track->IsOnLayer( aLayer ) )
2122 int viaEffectiveSize = std::max(
via->GetDrillValue(),
via->GetWidth( aLayer ) );
2123 VIA_KNOCKOUT_KEY viaKey{
via->GetPosition(), viaEffectiveSize };
2125 if( !processedVias.insert( viaKey ).second )
2130 TRACK_KNOCKOUT_KEY trackKey( track->GetStart(), track->GetEnd(), track->GetWidth() );
2132 if( !processedTracks.insert( trackKey ).second )
2136 knockoutTrackClearance( track );
2141 auto knockoutGraphicClearance =
2147 shapeNet =
static_cast<PCB_SHAPE*
>( aItem )->GetNetCode();
2149 bool sameNet = shapeNet == aZone->
GetNetCode();
2155 if( aItem->IsOnLayer( aLayer )
2157 || aItem->IsOnLayer(
Margin ) )
2159 if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
2161 bool ignoreLineWidths =
false;
2164 if( aItem->IsOnLayer( aLayer ) && !sameNet )
2168 else if( aItem->IsOnLayer(
Edge_Cuts ) )
2171 ignoreLineWidths =
true;
2173 else if( aItem->IsOnLayer(
Margin ) )
2180 gap += extra_margin;
2181 addKnockout( aItem, aLayer, gap, ignoreLineWidths, aHoles );
2187 auto knockoutCourtyardClearance =
2190 if( aFootprint->GetBoundingBox().Intersects( zone_boundingbox ) )
2196 aHoles.
Append( aFootprint->GetCourtyard( aLayer ) );
2209 knockoutCourtyardClearance( footprint );
2210 knockoutGraphicClearance( &footprint->Reference() );
2211 knockoutGraphicClearance( &footprint->Value() );
2213 std::set<PAD*> allowedNetTiePads;
2217 if( footprint->IsNetTie() )
2219 for(
PAD*
pad : footprint->Pads() )
2228 if(
pad->IsOnLayer( aLayer ) )
2229 allowedNetTiePads.insert(
pad );
2231 for(
PAD* other : footprint->GetNetTiePads(
pad ) )
2233 if( other->IsOnLayer( aLayer ) )
2234 allowedNetTiePads.insert( other );
2240 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
2245 BOX2I itemBBox = item->GetBoundingBox();
2247 if( !zone_boundingbox.
Intersects( itemBBox ) )
2250 bool skipItem =
false;
2252 if( item->IsOnLayer( aLayer ) )
2254 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape();
2256 for(
PAD*
pad : allowedNetTiePads )
2258 if(
pad->GetBoundingBox().Intersects( itemBBox )
2259 &&
pad->GetEffectiveShape( aLayer )->Collide( itemShape.get() ) )
2268 knockoutGraphicClearance( item );
2277 knockoutGraphicClearance( item );
2282 auto knockoutZoneClearance =
2283 [&](
ZONE* aKnockout )
2286 if( !aKnockout->GetLayerSet().test( aLayer ) )
2289 if( aKnockout->GetBoundingBox().Intersects( zone_boundingbox ) )
2291 if( aKnockout->GetIsRuleArea() )
2293 if( aKnockout->GetDoNotAllowZoneFills() && !aZone->
IsTeardropArea() )
2302 if( aKnockout->HigherPriority( aZone ) && !aKnockout->SameNet( aZone ) )
2314 aKnockout->TransformShapeToPolygon( poly, aLayer, gap + extra_margin,
m_maxError,
2322 if( aIncludeZoneClearances )
2329 knockoutZoneClearance( otherZone );
2334 for(
ZONE* otherZone : footprint->Zones() )
2339 knockoutZoneClearance( otherZone );
2360 auto evalRulesForItems =
2372 auto knockoutZoneClearance =
2373 [&](
ZONE* aKnockout )
2375 if( !aKnockout->GetLayerSet().test( aLayer ) )
2378 if( aKnockout->GetBoundingBox().Intersects( zone_boundingbox ) )
2380 if( aKnockout->GetIsRuleArea() )
2382 if( aKnockout->GetDoNotAllowZoneFills() && !aZone->
IsTeardropArea() )
2390 if( aKnockout->HigherPriority( aZone ) && !aKnockout->SameNet( aZone ) )
2402 aKnockout->TransformShapeToPolygon( poly, aLayer, gap + extra_margin,
m_maxError,
2411 knockoutZoneClearance( otherZone );
2415 for(
ZONE* otherZone : footprint->Zones() )
2416 knockoutZoneClearance( otherZone );
2431 auto knockoutZoneOutline =
2432 [&](
ZONE* aKnockout )
2435 if( !aKnockout->GetLayerSet().test( aLayer ) )
2438 if( aKnockout->GetBoundingBox().Intersects( zoneBBox ) )
2454 if( otherZone->SameNet( aZone )
2458 if( !otherZone->IsTeardropArea() )
2459 knockoutZoneOutline( otherZone );
2465 for(
ZONE* otherZone : footprint->Zones() )
2467 if( otherZone->SameNet( aZone ) && otherZone->HigherPriority( aZone ) )
2470 if( !otherZone->IsTeardropArea() )
2471 knockoutZoneOutline( otherZone );
2489 std::map<int, std::vector<std::pair<int, VECTOR2I>>> insertion_points;
2501 insertion_points[
result.m_outline1].push_back( {
result.m_vertex1, pt1 } );
2502 insertion_points[
result.m_outline1].push_back( {
result.m_vertex1, pt2 } );
2505 for(
auto& [outline, vertices] : insertion_points )
2509 if( vertices.empty() )
2514 std::stable_sort( vertices.begin(), vertices.end(),
2515 [](
const std::pair<int, VECTOR2I>& a,
const std::pair<int, VECTOR2I>& b )
2517 return a.first < b.first;
2520 std::vector<VECTOR2I> new_points;
2521 new_points.reserve( line.
PointCount() + vertices.size() );
2523 size_t vertex_idx = 0;
2527 new_points.push_back( line.
CPoint( i ) );
2530 while( vertex_idx < vertices.size() && vertices[vertex_idx].first == i )
2532 new_points.push_back( vertices[vertex_idx].second );
2539 for(
const auto& pt : new_points )
2545#define DUMP_POLYS_TO_COPPER_LAYER( a, b, c ) \
2546 { if( m_debugZoneFiller && aDebugLayer == b ) \
2548 m_board->SetLayerName( b, c ); \
2549 SHAPE_POLY_SET d = a; \
2589 std::vector<BOARD_ITEM*> thermalConnectionPads;
2590 std::vector<PAD*> noConnectionPads;
2591 std::deque<SHAPE_LINE_CHAIN> thermalSpokes;
2594 aFillPolys = aSmoothedOutline;
2621 aFillPolys, thermalRings );
2654 static const bool USE_BBOX_CACHES =
true;
2681 const VECTOR2I& testPt = spoke.CPoint( 3 );
2684 if( testAreas.
Contains( testPt, -1, 1, USE_BBOX_CACHES ) )
2693 if( interval++ > 400 )
2706 if( &other != &spoke
2707 && other.PointInside( testPt, 1, USE_BBOX_CACHES )
2708 && spoke.PointInside( other.CPoint( 3 ), 1, USE_BBOX_CACHES ) )
2744 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
2746 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
2747 BOX2I islandExtents;
2749 for(
const VECTOR2I& pt : island.front().CPoints() )
2751 islandExtents.
Merge( pt );
2772 || !
m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill ) )
2816 for(
BOARD_ITEM* item : thermalConnectionPads )
2830 if( iterativeRefill )
2840 wxT(
"Cached pre-knockout fill for zone %s layer %d: %d outlines, area %.0f, "
2841 "bbox (%d,%d)-(%d,%d)" ),
2842 aZone->
GetNetname(),
static_cast<int>( aLayer ),
2874 auto checkForCancel =
2877 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
2880 auto knockoutGraphicItem =
2883 if( aItem->IsKnockout() && aItem->IsOnLayer( aLayer )
2884 && aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
2886 addKnockout( aItem, aLayer, 0,
true, clearanceHoles );
2895 knockoutGraphicItem( &footprint->Reference() );
2896 knockoutGraphicItem( &footprint->Value() );
2898 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
2899 knockoutGraphicItem( item );
2907 knockoutGraphicItem( item );
2910 aFillPolys = aSmoothedOutline;
2913 auto subtractKeepout =
2914 [&](
ZONE* candidate )
2916 if( !candidate->GetIsRuleArea() )
2919 if( !candidate->HasKeepoutParametersSet() )
2922 if( candidate->GetDoNotAllowZoneFills() && candidate->IsOnLayer( aLayer ) )
2924 if( candidate->GetBoundingBox().Intersects( zone_boundingbox ) )
2926 if( candidate->Outline()->ArcCount() == 0 )
2945 subtractKeepout( keepout );
2953 for(
ZONE* keepout : footprint->Zones() )
2954 subtractKeepout( keepout );
2997 debugLayer = aLayer;
3001 if( !aZone->
BuildSmoothedPoly( maxExtents, aLayer, boardOutline, &smoothedPoly ) )
3009 if(
fillCopperZone( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aFillPolys ) )
3026 const std::vector<BOARD_ITEM*>& aSpokedPadsList,
3027 std::deque<SHAPE_LINE_CHAIN>& aSpokesList )
3046 if( !item->IsOnLayer( aLayer ) )
3049 int thermalReliefGap = 0;
3053 bool circular =
false;
3057 pad =
static_cast<PAD*
>( item );
3087 int spoke_max_allowed_w = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
3088 spoke_w = std::clamp( spoke_w, constraint.
Value().
Min(), constraint.
Value().
Max() );
3089 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
3091 if( spoke_w < aZone->GetMinThickness() )
3104 spoke_w = std::min( spoke_w,
via->GetWidth( aLayer ) );
3106 if( spoke_w < aZone->GetMinThickness() )
3125 int spoke_max_allowed_w = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
3127 spoke_w = std::clamp( spoke_w, constraint.
Value().
Min(), constraint.
Value().
Max() );
3130 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
3133 if( spoke_w < aZone->GetMinThickness() )
3142 int spoke_half_w = spoke_w / 2;
3145 BOX2I itemBB = item->GetBoundingBox();
3151 bool customSpokes =
false;
3155 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
3157 if( primitive->IsProxyItem() && primitive->GetShape() ==
SHAPE_T::SEGMENT )
3159 customSpokes =
true;
3170 auto buildSpokesFromOrigin =
3177 auto intersectBBox =
3180 double dx = spokeAngle.
Cos();
3181 double dy = spokeAngle.
Sin();
3187 *spoke_side =
VECTOR2I( spoke_half_w, 0 );
3188 return KiROUND( 0.0, dy * half_size.
y );
3192 *spoke_side =
VECTOR2I( 0, spoke_half_w );
3193 return KiROUND( dx * half_size.
x, 0.0 );
3198 double dist_x = half_size.
x /
std::abs( dx );
3199 double dist_y = half_size.
y /
std::abs( dy );
3201 if( dist_x < dist_y )
3203 *spoke_side =
KiROUND( 0.0, spoke_half_w / (
ANGLE_90 - spokeAngle ).Sin() );
3204 return KiROUND( dx * dist_x, dy * dist_x );
3208 *spoke_side =
KiROUND( spoke_half_w / spokeAngle.
Sin(), 0.0 );
3209 return KiROUND( dx * dist_y, dy * dist_y );
3222 for(
const EDA_ANGLE& spokeAngle : angles )
3225 VECTOR2I intersection = intersectBBox( spokeAngle, &spoke_side );
3234 aSpokesList.push_back( std::move( spoke ) );
3246 thermalOutline = thermalPoly.
Outline( 0 );
3250 auto trimToOutline = [&](
SEG& aSegment )
3254 if( padOutline.
Intersect( aSegment, intersections ) )
3256 intersections.clear();
3259 if( thermalOutline.
Intersect( aSegment, intersections ) )
3261 aSegment.B = intersections.front().p;
3268 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
3270 if( primitive->IsProxyItem() && primitive->GetShape() ==
SHAPE_T::SEGMENT )
3272 SEG seg( primitive->GetStart(), primitive->GetEnd() );
3277 seg.
A +=
pad->ShapePos( aLayer );
3278 seg.
B +=
pad->ShapePos( aLayer );
3292 if( trimToOutline( seg ) )
3294 VECTOR2I direction = ( seg.
B - seg.
A ).Resize( spoke_half_w );
3298 SEG segL( seg.
A - direction - offset, seg.
B + direction - offset );
3299 SEG segR( seg.
A - direction + offset, seg.
B + direction + offset );
3302 if( trimToOutline( segL ) && trimToOutline( segR ) )
3310 spoke.
Append( seg.
A + offset );
3311 spoke.
Append( seg.
A - offset );
3313 spoke.
Append( segL.
B + direction );
3314 spoke.
Append( seg.
B + direction );
3315 spoke.
Append( segR.
B + direction );
3318 aSpokesList.push_back( std::move( spoke ) );
3331 thermalSpokeAngle =
pad->GetThermalSpokeAngle();
3350 position =
pad->ShapePos( aLayer );
3351 orientation =
pad->GetOrientation();
3359 position =
via->GetPosition();
3364 spokesBox.
Inflate( thermalReliefGap +
epsilon + zone_half_width );
3371 buildSpokesFromOrigin( spokesBox,
ANGLE_0 );
3373 if( thermalSpokeAngle !=
ANGLE_0 )
3376 for(
auto it = aSpokesList.rbegin(); it != aSpokesList.rbegin() + 4; ++it )
3377 it->Rotate( thermalSpokeAngle );
3382 buildSpokesFromOrigin( spokesBox, thermalSpokeAngle );
3385 auto spokeIter = aSpokesList.rbegin();
3387 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
3389 spokeIter->Rotate( orientation );
3390 spokeIter->Move( position );
3395 for(
size_t ii = 0; ii < aSpokesList.size(); ++ii )
3396 aSpokesList[ii].GenerateBBoxCache();
3402 const std::vector<BOARD_ITEM*>& aThermalConnectionPads,
3409 for(
BOARD_ITEM* item : aThermalConnectionPads )
3411 if( !item->IsOnLayer( aLayer ) )
3416 bool isCircular =
false;
3424 pad =
static_cast<PAD*
>( item );
3426 position =
pad->ShapePos( aLayer );
3432 padRadius = std::max( padSize.
x, padSize.
y ) / 2;
3441 int spokeMaxWidth = std::min( padSize.
x, padSize.
y );
3442 spokeWidth = std::min( spokeWidth, spokeMaxWidth );
3447 position =
via->GetPosition();
3449 padRadius =
via->GetWidth( aLayer ) / 2;
3458 spokeWidth = std::min( spokeWidth, padRadius * 2 );
3466 if( spokeWidth < aZone->GetMinThickness() )
3476 int ringInnerRadius = padRadius + thermalGap;
3477 int ringWidth = spokeWidth;
3490 pad->TransformShapeToPolygon( outerShape, aLayer, thermalGap + spokeWidth,
3494 pad->TransformShapeToPolygon( innerShape, aLayer, thermalGap,
3497 thermalRing = outerShape;
3529 int maxError =
m_board->GetDesignSettings().m_MaxError;
3545 hole_base.
Append( corner );
3546 corner.
x += hole_size;
3547 hole_base.
Append( corner );
3548 corner.
y += hole_size;
3549 hole_base.
Append( corner );
3551 hole_base.
Append( corner );
3571 #define SMOOTH_MIN_VAL_MM 0.02
3572 #define SMOOTH_SMALL_VAL_MM 0.04
3588 smooth_value = std::min( smooth_value, aZone->
GetHatchGap() / 2 );
3591 maxError = std::max( maxError * 2, smooth_value / 20 );
3593 switch( smooth_level )
3605 hole_base = smooth_hole.
Fillet( smooth_value, maxError ).
Outline( 0 );
3617 auto& defaultOffsets =
m_board->GetDesignSettings().m_ZoneLayerProperties;
3620 VECTOR2I offset = defaultOffsets[aLayer].hatching_offset.value_or(
VECTOR2I() );
3622 if( localOffsets.contains( aLayer ) && localOffsets.at( aLayer ).hatching_offset.has_value() )
3623 offset = localOffsets.at( aLayer ).hatching_offset.value();
3625 int x_offset = bbox.
GetX() - ( bbox.
GetX() ) % gridsize - gridsize;
3626 int y_offset = bbox.
GetY() - ( bbox.
GetY() ) % gridsize - gridsize;
3629 for(
int xx = x_offset; xx <= bbox.
GetRight(); xx += gridsize )
3631 for(
int yy = y_offset; yy <= bbox.
GetBottom(); yy += gridsize )
3642 hole.
Move(
VECTOR2I( offset.
x % gridsize, offset.
y % gridsize ) );
3655 deflated_thickness = std::max( deflated_thickness, maxError * 2 );
3677 if( area < minimal_hole_area )
3688 BOX2I thermalBBox = aThermalRings.
BBox();
3691 for(
int holeIdx = holes.
OutlineCount() - 1; holeIdx >= 0; holeIdx-- )
3701 for(
int ringIdx = 0; ringIdx < aThermalRings.
OutlineCount(); ringIdx++ )
3708 if( !holeBBox.
Contains( ringBBox ) )
3724 if( intersections.empty() )
3745 auto cacheKey = std::make_pair(
static_cast<const ZONE*
>( aZone ), aLayer );
3753 wxLogTrace(
traceZoneFiller, wxT(
"Cache miss for zone %s layer %d (cache size: %zu)" ),
3758 wxLogTrace(
traceZoneFiller, wxT(
"Cache hit for zone %s layer %d: pre-knockout %d outlines" ),
3759 aZone->
GetNetname(),
static_cast<int>( aLayer ), it->second.OutlineCount() );
3762 aFillPolys = it->second;
3775 auto evalRulesForItems =
3787 auto knockoutZoneFill =
3788 [&](
ZONE* otherZone )
3790 if( otherZone == aZone )
3793 if( !otherZone->GetLayerSet().test( aLayer ) )
3796 if( otherZone->IsTeardropArea() )
3799 if( !otherZone->HigherPriority( aZone ) )
3802 if( !otherZone->GetBoundingBox().Intersects( zoneBBox ) )
3805 if( !otherZone->HasFilledPolysForLayer( aLayer ) )
3808 std::shared_ptr<SHAPE_POLY_SET> otherFill = otherZone->GetFilledPolysList( aLayer );
3810 if( !otherFill || otherFill->OutlineCount() == 0 )
3813 if( otherZone->SameNet( aZone ) )
3820 aZone, otherZone, aLayer ) );
3823 otherZone, aLayer ) );
3836 knockoutZoneFill( otherZone );
3840 for(
ZONE* otherZone : footprint->Zones() )
3841 knockoutZoneFill( otherZone );
3845 auto subtractKeepout =
3846 [&](
ZONE* candidate )
3848 if( !candidate->GetIsRuleArea() )
3851 if( !candidate->HasKeepoutParametersSet() )
3854 if( candidate->GetDoNotAllowZoneFills() && candidate->IsOnLayer( aLayer ) )
3856 if( candidate->GetBoundingBox().Intersects( zoneBBox ) )
3858 if( candidate->Outline()->ArcCount() == 0 )
3873 subtractKeepout( keepout );
3877 for(
ZONE* keepout : footprint->Zones() )
3878 subtractKeepout( keepout );
bool operator==(const wxAuiPaneInfo &aLhs, const wxAuiPaneInfo &aRhs)
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 Vec Centre() 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 bool Contains(const Vec &aPoint) 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)
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const override
Check if point aP lies inside a closed shape.
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
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
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.
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.
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
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 buildHatchZoneThermalRings(const ZONE *aZone, PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aSmoothedOutline, const std::vector< BOARD_ITEM * > &aThermalConnectionPads, SHAPE_POLY_SET &aFillPolys, SHAPE_POLY_SET &aThermalRings)
Build thermal rings for pads in hatch zones.
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
std::map< std::pair< const ZONE *, PCB_LAYER_ID >, SHAPE_POLY_SET > m_preKnockoutFillCache
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 addHatchFillTypeOnZone(const ZONE *aZone, PCB_LAYER_ID aLayer, PCB_LAYER_ID aDebugLayer, SHAPE_POLY_SET &aFillPolys, const SHAPE_POLY_SET &aThermalRings)
for zones having the ZONE_FILL_MODE::ZONE_FILL_MODE::HATCH_PATTERN, create a grid pattern in filled a...
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.
static constexpr std::size_t hash_val(const Types &... args)
@ 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.
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
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