27#include <wx/filename.h>
31#include <unordered_map>
32#include <unordered_set>
69 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 );
222struct PAD_KNOCKOUT_KEY
230 bool operator==(
const PAD_KNOCKOUT_KEY& other )
const
232 return position == other.position && effectiveSize == other.effectiveSize
233 && shape == other.shape && orientation == other.orientation
234 && netCode == other.netCode;
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(), key.netCode );
250struct VIA_KNOCKOUT_KEY
256 bool operator==(
const VIA_KNOCKOUT_KEY& other )
const
258 return position == other.position && effectiveSize == other.effectiveSize
259 && netCode == other.netCode;
263struct VIA_KNOCKOUT_KEY_HASH
265 size_t operator()(
const VIA_KNOCKOUT_KEY& key )
const
267 return hash_val( key.position.
x, key.position.
y, key.effectiveSize, key.netCode );
273struct TRACK_KNOCKOUT_KEY
279 TRACK_KNOCKOUT_KEY(
const VECTOR2I& aStart,
const VECTOR2I& aEnd,
int aWidth ) :
283 if( aStart.
x < aEnd.
x || ( aStart.
x == aEnd.
x && aStart.
y <= aEnd.
y ) )
295 bool operator==(
const TRACK_KNOCKOUT_KEY& other )
const
297 return start == other.start && end == other.end && width == other.width;
301struct TRACK_KNOCKOUT_KEY_HASH
303 size_t operator()(
const TRACK_KNOCKOUT_KEY& key )
const
305 return hash_val( key.start.
x, key.start.
y, key.end.
x, key.end.
y, key.width );
309template<
typename Func>
310void forEachBoardAndFootprintZone(
BOARD* aBoard, Func&& aFunc )
317 for(
ZONE* zone : footprint->Zones() )
376 if(
m_board->GetDesignSettings().m_ZoneKeepExternalFillets )
378 for(
const ZONE* zone : { aZone, aKnockout } )
383 reach += (int) zone->GetCornerRadius();
397 return zoneOutline.
Collide( &knockoutOutline, reach );
413 std::lock_guard<KISPINLOCK> lock(
m_board->GetConnectivity()->GetLock() );
428 std::shared_ptr<DRC_ENGINE> drcEngine = std::make_shared<DRC_ENGINE>(
m_board, &bds );
432 drcEngine->InitEngine( wxFileName(
m_board->GetDesignRulesPath() ) );
445 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
446 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
HASH_128> oldFillHashes;
447 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> isolatedIslandsMap;
449 std::shared_ptr<CONNECTIVITY_DATA> connectivity =
m_board->GetConnectivity();
456 connectivity->ClearRatsnest();
464 :
_(
"Building zone fills..." ) );
477 zone->CacheBoundingBox();
481 for(
PAD*
pad : footprint->Pads() )
485 pad->BuildEffectiveShapes();
490 for(
ZONE* zone : footprint->Zones() )
491 zone->CacheBoundingBox();
494 footprint->BuildCourtyardCaches();
495 footprint->BuildNetTieCache();
502 std::unordered_map<const ZONE*, POLY_YSTRIPES_INDEX> zoneOutlineIndices;
506 if( zone->GetNumCorners() <= 2 )
509 zoneOutlineIndices[zone].Build( zone->GetBoardOutline() );
516 auto findHighestPriorityZone =
518 const std::function<bool(
const ZONE* )>& testFn ) ->
ZONE*
520 unsigned highestSameNetPriority = 0;
521 ZONE* highestSameNetZone =
nullptr;
522 unsigned highestPriority = 0;
523 ZONE* highestPriorityZone =
nullptr;
528 if( zone->GetIsRuleArea() )
531 if( !zone->IsOnLayer( itemLayer ) )
534 const unsigned priority = zone->GetAssignedPriority();
535 const bool sameNet = zone->GetNetCode() == netcode;
540 if( highestSameNetZone && priority < highestSameNetPriority )
543 else if( highestPriorityZone && priority < highestPriority )
549 if( zone->GetNumCorners() <= 2 )
552 if( !zone->GetBoundingBox().Intersects( bbox ) )
555 if( !testFn( zone ) )
559 && ( !highestSameNetZone || priority > highestSameNetPriority ) )
561 highestSameNetPriority = priority;
562 highestSameNetZone = zone;
565 if( !highestPriorityZone || priority > highestPriority )
567 highestPriority = priority;
568 highestPriorityZone = zone;
572 return highestSameNetZone ? highestSameNetZone : highestPriorityZone;
575 auto isInPourKeepoutArea =
580 if( !zone->GetIsRuleArea() )
583 if( !zone->HasKeepoutParametersSet() )
586 if( !zone->GetDoNotAllowZoneFills() )
589 if( !zone->IsOnLayer( itemLayer ) )
593 if( zone->GetNumCorners() <= 2 )
596 if( !zone->GetBoundingBox().Intersects( bbox ) )
599 auto it = zoneOutlineIndices.find( zone );
601 if( it != zoneOutlineIndices.end() && it->second.Contains( testPoint ) )
618 via->ClearZoneLayerOverrides();
620 if( !
via->GetRemoveUnconnected() )
625 int holeRadius =
via->GetDrillValue() / 2 + 1;
626 int netcode =
via->GetNetCode();
627 LSET layers =
via->GetLayerSet() & boardCuMask;
630 auto viaTestFn = [&](
const ZONE* aZone ) ->
bool
637 if( !
via->ConditionallyFlashed( layer ) )
640 if( isInPourKeepoutArea( bbox, layer,
center ) )
646 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, viaTestFn );
651 || layer == padstack.
Drill().
end ) )
667 for(
PAD*
pad : footprint->Pads() )
669 pad->ClearZoneLayerOverrides();
671 if( !
pad->GetRemoveUnconnected() )
676 int netcode =
pad->GetNetCode();
677 LSET layers =
pad->GetLayerSet() & boardCuMask;
680 [&](
const ZONE* aZone ) ->
bool
682 auto it = zoneOutlineIndices.find( aZone );
684 if( it != zoneOutlineIndices.end() )
685 return it->second.Contains(
center );
692 if( !
pad->ConditionallyFlashed( layer ) )
695 if( isInPourKeepoutArea( bbox, layer,
center ) )
701 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, padTestFn );
712 for(
ZONE* zone : aZones )
715 if( zone->GetIsRuleArea() )
719 if( zone->GetNumCorners() <= 2 )
729 zone->BuildHashValue( layer );
730 oldFillHashes[ { zone, layer } ] = zone->GetHashValue( layer );
733 toFill.emplace_back( std::make_pair( zone, layer ) );
738 if( !zone->IsCopperThieving() )
746 auto zone_fill_dependency =
748 bool aRequireCompletedOtherFill ) ->
bool
755 if( aRequireCompletedOtherFill && aOtherZone->GetFillFlag( aLayer ) )
760 if( aOtherZone->GetIsRuleArea() )
764 if( aOtherZone->GetNumCorners() <= 2 )
768 if( !aOtherZone->GetLayerSet().test( aLayer ) )
775 if( aOtherZone->SameNet( aZone ) )
782 auto check_fill_dependency =
785 return zone_fill_dependency( aZone, aLayer, aOtherZone,
true );
788 auto fill_item_dependency =
789 [&](
const std::pair<ZONE*, PCB_LAYER_ID>& aWaiter,
790 const std::pair<ZONE*, PCB_LAYER_ID>& aDependency ) ->
bool
792 if( aWaiter.first == aDependency.first || aWaiter.second != aDependency.second )
795 return check_fill_dependency( aWaiter.first, aWaiter.second, aDependency.first );
799 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
805 ZONE* zone = aFillItem.first;
820 auto tesselate_lambda =
821 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
827 ZONE* zone = aFillItem.first;
836 std::atomic<bool> cancelled =
false;
842 auto run_fill_waves =
843 [&](
const std::vector<std::pair<ZONE*, PCB_LAYER_ID>>& aFillItems,
auto&& aFillFn,
844 auto&& aTessFn,
auto&& aHasDependency,
bool aAnyDependencies )
846 const size_t count = aFillItems.size();
851 std::vector<std::vector<size_t>> successors( count );
852 std::vector<std::atomic<int>> inDegree( count );
854 for(
size_t i = 0; i < count; ++i )
855 inDegree[i].store( 0, std::memory_order_relaxed );
858 if( aAnyDependencies )
860 for(
size_t i = 0; i < count; ++i )
862 for(
size_t j = 0; j < count; ++j )
867 if( aHasDependency( aFillItems[j], aFillItems[i] ) )
869 successors[i].push_back( j );
870 inDegree[j].fetch_add( 1, std::memory_order_relaxed );
876 std::atomic<int> remaining( (
int) count );
878 std::function<void(
size_t )>
process;
882 int filled = aFillFn( aFillItems[idx] );
885 for(
size_t succ : successors[idx] )
887 if( inDegree[succ].fetch_sub( 1, std::memory_order_acq_rel ) == 1 )
891 if( filled != 0 && !cancelled.load() )
892 aTessFn( aFillItems[idx] );
894 remaining.fetch_sub( 1, std::memory_order_acq_rel );
898 for(
size_t i = 0; i < count; ++i )
900 if( inDegree[i].load( std::memory_order_relaxed ) == 0 )
905 while( remaining.load( std::memory_order_acquire ) > 0 )
915 std::this_thread::sleep_for( std::chrono::milliseconds( 20 ) );
925 run_fill_waves( toFill, fill_lambda, tesselate_lambda, fill_item_dependency,
true );
940 connectivity->FillIsolatedIslandsMap( isolatedIslandsMap );
941 connectivity->SetProgressReporter(
nullptr );
946 for(
ZONE* zone : aZones )
949 if( zone->GetIsRuleArea() )
952 zone->SetIsFilled(
true );
961 std::set<std::pair<ZONE*, PCB_LAYER_ID>> zonesWithRemovedIslandLayers;
968 std::set<std::pair<ZONE*, PCB_LAYER_ID>> initiallyFullyIsolatedLayers;
970 for(
const auto& [ zone, zoneIslands ] : isolatedIslandsMap )
974 bool allLayersFullyIsolated =
true;
976 for(
const auto& [ layer, layerIslands ] : zoneIslands )
978 bool layerFullyIsolated = ( layerIslands.m_IsolatedOutlines.size()
979 ==
static_cast<size_t>( zone->GetFilledPolysList( layer )->OutlineCount() ) );
981 if( layerFullyIsolated )
982 initiallyFullyIsolatedLayers.insert( { zone, layer } );
984 allLayersFullyIsolated =
false;
987 if( allLayersFullyIsolated )
990 for(
const auto& [ layer, layerIslands ] : zoneIslands )
995 if( layerIslands.m_IsolatedOutlines.empty() )
998 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
1002 std::sort( islands.begin(), islands.end(), std::greater<int>() );
1004 std::shared_ptr<SHAPE_POLY_SET> poly = zone->GetFilledPolysList( layer );
1005 long long int minArea = zone->GetMinIslandArea();
1008 for(
int idx : islands )
1014 poly->DeletePolygonAndTriangulationData( idx,
false );
1015 zonesWithRemovedIslandLayers.insert( { zone, layer } );
1019 poly->DeletePolygonAndTriangulationData( idx,
false );
1020 zonesWithRemovedIslandLayers.insert( { zone, layer } );
1024 zone->SetIsIsland( layer, idx );
1028 poly->UpdateTriangulationDataHash();
1029 zone->CalculateFilledArea();
1049 std::set<std::pair<ZONE*, PCB_LAYER_ID>> sameNetOverlapSeeds;
1051 if( iterativeRefill )
1056 std::map<int, std::vector<ZONE*>> zonesByNet;
1058 forEachBoardAndFootprintZone(
1063 zonesByNet[zone->
GetNetCode()].push_back( zone );
1066 for(
ZONE* lowerZone : aZones )
1068 if( lowerZone->GetIsRuleArea() || lowerZone->IsTeardropArea() )
1071 auto netIt = zonesByNet.find( lowerZone->GetNetCode() );
1073 if( netIt == zonesByNet.end() )
1076 LSET lowerLayers = lowerZone->GetLayerSet() & boardCu;
1078 for(
ZONE* higherZone : netIt->second )
1080 if( higherZone == lowerZone
1084 if( !lowerZone->GetBoundingBox().Intersects( higherZone->
GetBoundingBox() ) )
1093 if( lowerZone->HasFilledPolysForLayer( layer )
1096 sameNetOverlapSeeds.insert( { lowerZone, layer } );
1104 && ( !zonesWithRemovedIslandLayers.empty() || !sameNetOverlapSeeds.empty() ) )
1106 const int maxIterations = 8;
1107 bool progressReported =
false;
1108 bool hitIterationLimit =
false;
1111 std::set<std::pair<ZONE*, PCB_LAYER_ID>> changedZoneLayers( zonesWithRemovedIslandLayers );
1112 changedZoneLayers.insert( sameNetOverlapSeeds.begin(), sameNetOverlapSeeds.end() );
1114 auto cached_refill_tessellate_lambda = [&](
const std::pair<ZONE*, PCB_LAYER_ID>& aFillItem ) ->
int
1116 ZONE* zone = aFillItem.first;
1123 auto no_dependency = [](
const std::pair<ZONE*, PCB_LAYER_ID>&,
const std::pair<ZONE*, PCB_LAYER_ID>& ) ->
bool
1128 for(
int iteration = 0; iteration < maxIterations; ++iteration )
1133 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zonesToRefill;
1134 std::set<std::pair<ZONE*, PCB_LAYER_ID>> zonesToRefillSet;
1136 for(
const auto& [changedZone, changedLayer] : changedZoneLayers )
1138 BOX2I bbox = changedZone->GetBoundingBox();
1141 for(
ZONE* zone : aZones )
1143 if( zone->GetIsRuleArea() )
1146 if( !zone->GetLayerSet().test( changedLayer ) )
1162 if( zone != changedZone && !changedZone->HigherPriority( zone ) && !changedZone->SameNet( zone ) )
1169 if( zone != changedZone && !changedZone->SameNet( zone ) )
1174 else if( !zone->GetBoundingBox().Intersects( bbox ) )
1179 auto fillItem = std::make_pair( zone, changedLayer );
1181 if( zonesToRefillSet.insert( fillItem ).second )
1182 zonesToRefill.push_back( fillItem );
1186 if( zonesToRefill.empty() )
1189 if( !progressReported )
1198 progressReported =
true;
1204 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
HASH_128> iterHashes;
1206 for(
const auto& fillItem : zonesToRefill )
1208 fillItem.first->BuildHashValue( fillItem.second );
1209 iterHashes[fillItem] = fillItem.first->GetHashValue( fillItem.second );
1220 LSET snapshotLayers;
1222 for(
const auto& [zone, layer] : zonesToRefill )
1223 snapshotLayers.
set( layer );
1227 forEachBoardAndFootprintZone(
m_board,
1244 if( sp && sp->OutlineCount() > 0 )
1245 snapshot[{ zone, layer }] = sp->CloneDropTriangulation();
1249 auto cached_refill_fill_lambda =
1250 [&](
const std::pair<ZONE*, PCB_LAYER_ID>& aFillItem ) ->
int
1252 ZONE* zone = aFillItem.first;
1264 run_fill_waves( zonesToRefill, cached_refill_fill_lambda, cached_refill_tessellate_lambda, no_dependency,
1270 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> refillIslandsMap;
1272 for(
const auto& [zone, layer] : zonesToRefill )
1286 connectivity->FillIsolatedIslandsMap( refillIslandsMap );
1288 for(
const auto& [zone, zoneIslands] : refillIslandsMap )
1290 for(
const auto& [layer, layerIslands] : zoneIslands )
1295 if( layerIslands.m_IsolatedOutlines.empty() )
1300 if( initiallyFullyIsolatedLayers.count( { zone, layer } ) > 0 )
1302 if( layerIslands.m_IsolatedOutlines.size()
1309 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
1310 std::sort( islands.begin(), islands.end(), std::greater<int>() );
1316 for(
int idx : islands )
1321 poly->DeletePolygonAndTriangulationData( idx,
false );
1323 poly->DeletePolygonAndTriangulationData( idx,
false );
1328 poly->UpdateTriangulationDataHash();
1336 changedZoneLayers.clear();
1338 for(
const auto& fillItem : zonesToRefill )
1340 fillItem.first->BuildHashValue( fillItem.second );
1342 auto hashIt = iterHashes.find( fillItem );
1343 HASH_128 oldHash = ( hashIt != iterHashes.end() ) ? hashIt->second :
HASH_128{};
1345 if( fillItem.first->GetHashValue( fillItem.second ) != oldHash )
1346 changedZoneLayers.insert( fillItem );
1349 if( changedZoneLayers.empty() )
1352 if( iteration + 1 >= maxIterations )
1354 hitIterationLimit =
true;
1359 if( hitIterationLimit )
1361 wxString msg = wxString::Format(
_(
"Zone fills may be incorrect: iterative refill did not converge "
1362 "after %d passes.\n\n"
1363 "This can happen with complex overlapping zones. "
1364 "Consider simplifying your zones." ),
1369 KIDIALOG dlg( aParent, msg,
_(
"Warning" ), wxOK | wxICON_WARNING );
1375 wxLogWarning( msg );
1382 using island_check_return = std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
int>>;
1384 std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
double>> polys_to_check;
1387 polys_to_check.reserve(
m_board->GetCopperLayerCount() * aZones.size() );
1389 for(
ZONE* zone : aZones )
1399 double minArea = (double) zone->GetMinThickness() * zone->GetMinThickness() * 3;
1406 polys_to_check.emplace_back( zone->GetFilledPolysList( layer ), minArea );
1410 auto island_lambda =
1411 [&](
int aStart,
int aEnd ) -> island_check_return
1413 island_check_return retval;
1415 for(
int ii = aStart; ii < aEnd && !cancelled.load(); ++ii )
1417 auto [poly, minArea] = polys_to_check[ii];
1419 for(
int jj = poly->OutlineCount() - 1; jj >= 0; jj-- )
1424 double island_area = test_poly.
Area();
1426 if( island_area < minArea )
1438 if( intersection.
Area() < island_area / 2.0 )
1439 retval.emplace_back( poly, jj );
1446 auto island_returns =
tp.submit_blocks( 0, polys_to_check.size(), island_lambda );
1450 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
1452 std::future<island_check_return>& ret = island_returns[ii];
1456 std::future_status status = ret.wait_for( std::chrono::seconds( 0 ) );
1458 while( status != std::future_status::ready )
1468 status = ret.wait_for( std::chrono::milliseconds( 100 ) );
1473 if( cancelled.load() )
1476 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
1478 std::future<island_check_return>& ret = island_returns[ii];
1482 for(
auto& action_item : ret.get() )
1483 action_item.first->DeletePolygonAndTriangulationData( action_item.second,
true );
1487 for(
ZONE* zone : aZones )
1488 zone->CalculateFilledArea();
1501 std::unique_ptr<POLY_YSTRIPES_INDEX>
index;
1504 struct NET_LAYER_HASH
1506 size_t operator()(
const std::pair<int, PCB_LAYER_ID>& k )
const
1508 return std::hash<int>()( k.first ) ^ ( std::hash<int>()( k.second ) << 16 );
1512 std::unordered_map<std::pair<int, PCB_LAYER_ID>, std::vector<INDEXED_ZONE>, NET_LAYER_HASH>
1513 filledZonesByNetLayer;
1517 if( zone->GetIsRuleArea() )
1522 if( !zone->HasFilledPolysForLayer( layer ) )
1525 const std::shared_ptr<SHAPE_POLY_SET>& fill = zone->GetFilledPolysList( layer );
1527 if( fill->IsEmpty() )
1531 iz.bbox = fill->BBox();
1532 iz.index = std::make_unique<POLY_YSTRIPES_INDEX>();
1533 iz.index->Build( *fill );
1534 filledZonesByNetLayer[{ zone->GetNetCode(), layer }].push_back( std::move( iz ) );
1538 auto zoneReachesPoint =
1541 auto it = filledZonesByNetLayer.find( { aNetcode, aLayer } );
1543 if( it == filledZonesByNetLayer.end() )
1546 for(
const INDEXED_ZONE& iz : it->second )
1548 if( !iz.bbox.GetInflated( aRadius ).Contains( aCenter ) )
1551 if( iz.index->Contains( aCenter, aRadius ) )
1565 int holeRadius =
via->GetDrillValue() / 2;
1566 int netcode =
via->GetNetCode();
1567 LSET layers =
via->GetLayerSet() & boardCuMask;
1574 if( !zoneReachesPoint( netcode, layer,
center, holeRadius ) )
1581 for(
PAD*
pad : footprint->Pads() )
1584 int netcode =
pad->GetNetCode();
1585 LSET layers =
pad->GetLayerSet() & boardCuMask;
1589 if(
pad->HasHole() )
1590 holeRadius = std::min(
pad->GetDrillSizeX(),
pad->GetDrillSizeY() ) / 2;
1597 if( !zoneReachesPoint( netcode, layer,
center, holeRadius ) )
1605 bool outOfDate =
false;
1607 for(
ZONE* zone : aZones )
1610 if( zone->GetIsRuleArea() )
1615 zone->BuildHashValue( layer );
1617 if( oldFillHashes[ { zone, layer } ] != zone->GetHashValue( layer ) )
1623 &&
m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill ) )
1625 KIDIALOG dlg( aParent,
_(
"Prototype zone fill enabled. Disable setting and refill?" ),
_(
"Confirmation" ),
1626 wxOK | wxCANCEL | wxICON_WARNING );
1632 m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill =
false;
1634 else if( !outOfDate )
1642 KIDIALOG dlg( aParent,
_(
"Zone fills are out-of-date. Refill?" ),
_(
"Confirmation" ),
1643 wxOK | wxCANCEL | wxICON_WARNING );
1686 std::vector<VECTOR2I> convex_hull;
1691 for(
const VECTOR2I& pt : convex_hull )
1723 switch( aItem->
Type() )
1730 if(
text->IsVisible() )
1732 if(
text->IsKnockout() )
1787 std::vector<BOARD_ITEM*>& aThermalConnectionPads,
1788 std::vector<PAD*>& aNoConnectionPads,
1789 std::vector<BOARD_ITEM*>& aSolidConnectionItems )
1795 std::shared_ptr<SHAPE> padShape;
1800 std::unordered_set<PAD_KNOCKOUT_KEY, PAD_KNOCKOUT_KEY_HASH> processedPads;
1801 std::unordered_set<VIA_KNOCKOUT_KEY, VIA_KNOCKOUT_KEY_HASH> processedVias;
1805 for(
PAD*
pad : footprint->Pads() )
1811 &&
pad->GetDrillSize().x > 0;
1813 if( !
pad->IsOnLayer( aLayer ) && !npthWithHole )
1816 BOX2I padBBox =
pad->GetBoundingBox();
1833 int drill = std::max(
pad->GetDrillSize().x,
pad->GetDrillSize().y );
1834 int maxDim = std::max( { padSize.
x, padSize.
y, drill } );
1835 effectiveSize =
VECTOR2I( maxDim, maxDim );
1839 effectiveSize = padSize;
1842 PAD_KNOCKOUT_KEY padKey{
pad->GetPosition(), effectiveSize,
1843 static_cast<int>( padShapeType ),
1844 pad->GetOrientation(),
pad->GetNetCode() };
1846 if( !processedPads.insert( padKey ).second )
1850 bool noConnection =
pad->GetNetCode() != aZone->
GetNetCode();
1857 noConnection =
true;
1862 if(
pad->IsBackdrilledOrPostMachined( aLayer ) )
1863 noConnection =
true;
1868 aNoConnectionPads.push_back(
pad );
1883 switch( connection )
1889 if( aFill.
Collide( padShape.get(), 0 ) )
1897 aThermalConnectionPads.push_back(
pad );
1906 aNoConnectionPads.push_back(
pad );
1931 switch( connection )
1936 if( aFill.
Collide( padShape.get(), 0 ) )
1941 aThermalConnectionPads.push_back(
pad );
1955 if(
pad->FlashLayer( aLayer ) )
1959 else if(
pad->GetDrillSize().x > 0 )
1966 holeClearance = padClearance;
1992 if( !
via->IsOnLayer( aLayer ) )
1995 BOX2I viaBBox =
via->GetBoundingBox();
2002 int viaEffectiveSize = std::max(
via->GetDrillValue(),
via->GetWidth( aLayer ) );
2003 VIA_KNOCKOUT_KEY viaKey{
via->GetPosition(), viaEffectiveSize,
via->GetNetCode() };
2005 if( !processedVias.insert( viaKey ).second )
2008 bool noConnection =
via->GetNetCode() != aZone->
GetNetCode()
2010 && aLayer !=
via->Padstack().Drill().start
2011 && aLayer !=
via->Padstack().Drill().end );
2014 noConnection =
true;
2017 if(
via->IsBackdrilledOrPostMachined( aLayer ) )
2019 noConnection =
true;
2031 pmSize = std::max( pmSize, frontPM.
size );
2037 pmSize = std::max( pmSize, backPM.
size );
2043 bdSize = secDrill.
size.
x;
2045 int knockoutSize = std::max( pmSize, bdSize );
2047 if( knockoutSize > 0 )
2062 switch( connection )
2072 if( thermalGap > 0 )
2074 aThermalConnectionPads.push_back(
via );
2089 aSolidConnectionItems.push_back(
via );
2104 const std::vector<PAD*>& aNoConnectionPads,
2106 bool aIncludeZoneClearances )
2112 std::unordered_set<PAD_KNOCKOUT_KEY, PAD_KNOCKOUT_KEY_HASH> processedPads;
2113 std::unordered_set<VIA_KNOCKOUT_KEY, VIA_KNOCKOUT_KEY_HASH> processedVias;
2114 std::unordered_set<TRACK_KNOCKOUT_KEY, TRACK_KNOCKOUT_KEY_HASH> processedTracks;
2116 auto checkForCancel =
2119 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
2132 auto evalRulesForItems =
2146 auto knockoutPadClearance =
2151 bool hasHole = aPad->GetDrillSize().x > 0;
2152 bool flashLayer = aPad->FlashLayer( aLayer );
2155 if( flashLayer || platedHole )
2160 if( flashLayer && gap >= 0 )
2161 addKnockout( aPad, aLayer, gap + extra_margin, aHoles );
2176 && aPad->GetDrillSize().x != aPad->GetDrillSize().y )
2187 if( aPad->IsBackdrilledOrPostMachined( aLayer ) )
2198 pmSize = std::max( pmSize, frontPM.
size );
2204 pmSize = std::max( pmSize, backPM.
size );
2210 bdSize = secDrill.
size.
x;
2212 int knockoutSize = std::max( pmSize, bdSize );
2214 if( knockoutSize > 0 )
2216 int clearance = std::max( gap, 0 ) + extra_margin;
2224 for(
PAD*
pad : aNoConnectionPads )
2240 int drill = std::max(
pad->GetDrillSize().x,
pad->GetDrillSize().y );
2241 int maxDim = std::max( { padSize.
x, padSize.
y, drill } );
2242 effectiveSize =
VECTOR2I( maxDim, maxDim );
2246 effectiveSize = padSize;
2249 PAD_KNOCKOUT_KEY padKey{
pad->GetPosition(), effectiveSize,
2250 static_cast<int>( padShape ),
pad->GetOrientation(),
2251 pad->GetNetCode() };
2253 if( !processedPads.insert( padKey ).second )
2257 knockoutPadClearance(
pad );
2262 auto knockoutTrackClearance =
2265 if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
2267 bool sameNet = aTrack->GetNetCode() == aZone->
GetNetCode();
2289 if(
via->FlashLayer( aLayer ) && gap > 0 )
2291 via->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
m_maxError,
2310 if(
via->IsBackdrilledOrPostMachined( aLayer ) )
2321 pmSize = std::max( pmSize, frontPM.
size );
2327 pmSize = std::max( pmSize, backPM.
size );
2333 bdSize = secDrill.
size.
x;
2335 int knockoutSize = std::max( pmSize, bdSize );
2337 if( knockoutSize > 0 )
2339 int clearance = std::max( gap, 0 ) + extra_margin;
2350 aTrack->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
m_maxError,
2359 if( !track->IsOnLayer( aLayer ) )
2369 int viaEffectiveSize = std::max(
via->GetDrillValue(),
via->GetWidth( aLayer ) );
2370 VIA_KNOCKOUT_KEY viaKey{
via->GetPosition(), viaEffectiveSize,
via->GetNetCode() };
2372 if( !processedVias.insert( viaKey ).second )
2377 TRACK_KNOCKOUT_KEY trackKey( track->GetStart(), track->GetEnd(), track->GetWidth() );
2379 if( !processedTracks.insert( trackKey ).second )
2383 knockoutTrackClearance( track );
2388 auto knockoutGraphicClearance =
2394 shapeNet =
static_cast<PCB_SHAPE*
>( aItem )->GetNetCode();
2396 bool sameNet = shapeNet == aZone->
GetNetCode();
2402 if( aItem->IsOnLayer( aLayer )
2404 || aItem->IsOnLayer(
Margin ) )
2406 if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
2408 bool ignoreLineWidths =
false;
2411 if( aItem->IsOnLayer( aLayer ) && !sameNet )
2415 else if( aItem->IsOnLayer(
Edge_Cuts ) )
2418 ignoreLineWidths =
true;
2420 else if( aItem->IsOnLayer(
Margin ) )
2427 gap += extra_margin;
2428 addKnockout( aItem, aLayer, gap, ignoreLineWidths, aHoles );
2434 auto knockoutCourtyardClearance =
2437 if( aFootprint->GetBoundingBox().Intersects( zone_boundingbox ) )
2448 aHoles.
Append( aFootprint->GetCourtyard( courtyardSide ) );
2461 knockoutCourtyardClearance( footprint );
2462 knockoutGraphicClearance( &footprint->Reference() );
2463 knockoutGraphicClearance( &footprint->Value() );
2465 std::set<PAD*> allowedNetTiePads;
2469 if( footprint->IsNetTie() )
2471 for(
PAD*
pad : footprint->Pads() )
2480 if(
pad->IsOnLayer( aLayer ) )
2481 allowedNetTiePads.insert(
pad );
2483 for(
PAD* other : footprint->GetNetTiePads(
pad ) )
2485 if( other->IsOnLayer( aLayer ) )
2486 allowedNetTiePads.insert( other );
2492 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
2497 BOX2I itemBBox = item->GetBoundingBox();
2499 if( !zone_boundingbox.
Intersects( itemBBox ) )
2502 bool skipItem =
false;
2504 if( item->IsOnLayer( aLayer ) )
2506 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape();
2508 for(
PAD*
pad : allowedNetTiePads )
2510 if(
pad->GetBoundingBox().Intersects( itemBBox )
2511 &&
pad->GetEffectiveShape( aLayer )->Collide( itemShape.get() ) )
2520 knockoutGraphicClearance( item );
2529 knockoutGraphicClearance( item );
2534 auto knockoutZoneClearance =
2535 [&](
ZONE* aKnockout )
2538 if( !aKnockout->GetLayerSet().test( aLayer ) )
2541 if( aKnockout->GetIsRuleArea() )
2543 if( aKnockout->GetBoundingBox().Intersects( zone_boundingbox )
2544 && aKnockout->GetDoNotAllowZoneFills() && !aZone->
IsTeardropArea() )
2551 else if( aKnockout->HigherPriority( aZone ) && !aKnockout->SameNet( aZone )
2564 aKnockout->TransformShapeToPolygon( poly, aLayer, gap + extra_margin,
m_maxError,
2570 if( aIncludeZoneClearances )
2577 knockoutZoneClearance( otherZone );
2582 for(
ZONE* otherZone : footprint->Zones() )
2587 knockoutZoneClearance( otherZone );
2605 auto evalRulesForItems =
2621 auto knockoutZoneClearance =
2622 [&](
ZONE* aKnockout )
2624 if( aKnockout->GetIsRuleArea() )
2627 if( !aKnockout->GetLayerSet().test( aLayer ) )
2630 if( aKnockout->HigherPriority( aZone ) && !aKnockout->SameNet( aZone )
2634 aZone, aKnockout, aLayer ) );
2637 aKnockout, aLayer ) );
2643 aKnockout->TransformShapeToPolygon( poly, aLayer, gap + extra_margin,
2649 forEachBoardAndFootprintZone(
m_board, knockoutZoneClearance );
2665 auto collectZoneOutline =
2666 [&](
ZONE* aKnockout )
2668 if( !aKnockout->GetLayerSet().test( aLayer ) )
2671 if( aKnockout->GetBoundingBox().Intersects( zoneBBox ) )
2672 appendZoneOutlineWithoutArcs( aKnockout, knockouts );
2675 forEachBoardAndFootprintZone(
2677 [&](
ZONE* otherZone )
2681 bool higherPrioritySameNet =
2686 collectZoneOutline( otherZone );
2705 std::map<int, std::vector<std::pair<int, VECTOR2I>>> insertion_points;
2717 insertion_points[
result.m_outline1].push_back( {
result.m_vertex1, pt1 } );
2718 insertion_points[
result.m_outline1].push_back( {
result.m_vertex1, pt2 } );
2721 for(
auto& [outline, vertices] : insertion_points )
2729 std::stable_sort( vertices.begin(), vertices.end(),
2730 [](
const std::pair<int, VECTOR2I>& a,
const std::pair<int, VECTOR2I>& b )
2732 return a.first > b.first;
2735 for(
const auto& [vertex, pt] : vertices )
2736 line.
Insert( vertex + 1, pt );
2757 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
2759 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
2760 BOX2I islandExtents;
2762 for(
const VECTOR2I& pt : island.front().CPoints() )
2764 islandExtents.
Merge( pt );
2780#define DUMP_POLYS_TO_COPPER_LAYER( a, b, c ) \
2781 { if( m_debugZoneFiller && aDebugLayer == b ) \
2783 m_board->SetLayerName( b, c ); \
2784 SHAPE_POLY_SET d = a; \
2824 std::vector<BOARD_ITEM*> thermalConnectionPads;
2825 std::vector<PAD*> noConnectionPads;
2826 std::vector<BOARD_ITEM*> solidConnectionItems;
2827 std::deque<SHAPE_LINE_CHAIN> thermalSpokes;
2830 aFillPolys = aSmoothedOutline;
2840 knockoutThermalReliefs( aZone, aLayer, aFillPolys, thermalConnectionPads, noConnectionPads, solidConnectionItems );
2857 aFillPolys, thermalRings );
2879 if( iterativeRefill )
2882 bool addedKeepoutHoles =
false;
2884 auto collectKeepoutHoles =
2885 [&](
ZONE* candidate )
2890 if( !isZoneFillKeepout( candidate, aLayer, zone_boundingbox ) )
2893 candidate->TransformSmoothedOutlineToPolygon( clearanceHoles, 0,
m_maxError,
2895 addedKeepoutHoles =
true;
2898 forEachBoardAndFootprintZone(
m_board, collectKeepoutHoles );
2900 if( addedKeepoutHoles )
2929 if( iterativeRefill )
2955 spokeTestIndex.
Build( testAreas );
2962 const VECTOR2I& testPt = spoke.CPoint( 3 );
2965 if( spokeTestIndex.
Contains( testPt, 1 ) )
2974 if( interval++ > 400 )
2987 if( &other != &spoke
2988 && other.PointInside( testPt, 1 )
2989 && spoke.PointInside( other.CPoint( 3 ), 1 ) )
3025 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
3027 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
3028 BOX2I islandExtents;
3030 for(
const VECTOR2I& pt : island.front().CPoints() )
3032 islandExtents.
Merge( pt );
3053 || !
m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill ) )
3062 for(
BOARD_ITEM* item : solidConnectionItems )
3064 if( item->Type() !=
PCB_VIA_T || !item->IsOnLayer( aLayer ) )
3133 for(
BOARD_ITEM* item : thermalConnectionPads )
3147 bool knockoutsApplied =
false;
3149 if( iterativeRefill )
3160 knockoutsApplied =
true;
3173 if( knockoutsApplied )
3198 auto checkForCancel =
3201 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
3204 auto knockoutGraphicItem =
3207 if( aItem->IsKnockout() && aItem->IsOnLayer( aLayer )
3208 && aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
3210 addKnockout( aItem, aLayer, 0,
true, clearanceHoles );
3219 knockoutGraphicItem( &footprint->Reference() );
3220 knockoutGraphicItem( &footprint->Value() );
3222 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
3223 knockoutGraphicItem( item );
3231 knockoutGraphicItem( item );
3234 aFillPolys = aSmoothedOutline;
3239 auto collectKeepout =
3240 [&](
ZONE* candidate )
3242 if( !isZoneFillKeepout( candidate, aLayer, zone_boundingbox ) )
3245 appendZoneOutlineWithoutArcs( candidate, keepoutHoles );
3248 bool cancelledKeepoutScan =
false;
3250 forEachBoardAndFootprintZone(
3252 [&](
ZONE* keepout )
3254 if( cancelledKeepoutScan )
3259 cancelledKeepoutScan =
true;
3263 collectKeepout( keepout );
3266 if( cancelledKeepoutScan )
3317 debugLayer = aLayer;
3321 if( !aZone->
BuildSmoothedPoly( maxExtents, aLayer, boardOutline, &smoothedPoly ) )
3329 if(
fillCopperZone( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aFillPolys ) )
3346 const std::vector<BOARD_ITEM*>& aSpokedPadsList,
3347 std::deque<SHAPE_LINE_CHAIN>& aSpokesList )
3366 if( !item->IsOnLayer( aLayer ) )
3369 int thermalReliefGap = 0;
3373 bool circular =
false;
3377 pad =
static_cast<PAD*
>( item );
3407 int spoke_max_allowed_w = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
3408 spoke_w = std::clamp( spoke_w, constraint.
Value().
Min(), constraint.
Value().
Max() );
3409 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
3411 if( spoke_w < aZone->GetMinThickness() )
3424 spoke_w = std::min( spoke_w,
via->GetWidth( aLayer ) );
3426 if( spoke_w < aZone->GetMinThickness() )
3445 int spoke_max_allowed_w = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
3447 spoke_w = std::clamp( spoke_w, constraint.
Value().
Min(), constraint.
Value().
Max() );
3450 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
3453 if( spoke_w < aZone->GetMinThickness() )
3462 int spoke_half_w = spoke_w / 2;
3465 BOX2I itemBB = item->GetBoundingBox();
3471 bool customSpokes =
false;
3475 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
3477 if( primitive->IsProxyItem() && primitive->GetShape() ==
SHAPE_T::SEGMENT )
3479 customSpokes =
true;
3490 auto buildSpokesFromOrigin =
3497 auto intersectBBox =
3500 double dx = spokeAngle.
Cos();
3501 double dy = spokeAngle.
Sin();
3507 *spoke_side =
VECTOR2I( spoke_half_w, 0 );
3508 return KiROUND( 0.0, dy * half_size.
y );
3512 *spoke_side =
VECTOR2I( 0, spoke_half_w );
3513 return KiROUND( dx * half_size.
x, 0.0 );
3518 double dist_x = half_size.
x /
std::abs( dx );
3519 double dist_y = half_size.
y /
std::abs( dy );
3521 if( dist_x < dist_y )
3523 *spoke_side =
KiROUND( 0.0, spoke_half_w / (
ANGLE_90 - spokeAngle ).Sin() );
3524 return KiROUND( dx * dist_x, dy * dist_x );
3528 *spoke_side =
KiROUND( spoke_half_w / spokeAngle.
Sin(), 0.0 );
3529 return KiROUND( dx * dist_y, dy * dist_y );
3542 for(
const EDA_ANGLE& spokeAngle : angles )
3545 VECTOR2I intersection = intersectBBox( spokeAngle, &spoke_side );
3554 aSpokesList.push_back( std::move( spoke ) );
3566 thermalOutline = thermalPoly.
Outline( 0 );
3570 auto trimToOutline = [&](
SEG& aSegment )
3574 if( padOutline.
Intersect( aSegment, intersections ) )
3576 intersections.clear();
3579 if( thermalOutline.
Intersect( aSegment, intersections ) )
3581 aSegment.B = intersections.front().p;
3588 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
3590 if( primitive->IsProxyItem() && primitive->GetShape() ==
SHAPE_T::SEGMENT )
3592 SEG seg( primitive->GetStart(), primitive->GetEnd() );
3597 seg.
A +=
pad->ShapePos( aLayer );
3598 seg.
B +=
pad->ShapePos( aLayer );
3612 if( trimToOutline( seg ) )
3614 VECTOR2I direction = ( seg.
B - seg.
A ).Resize( spoke_half_w );
3618 SEG segL( seg.
A - direction - offset, seg.
B + direction - offset );
3619 SEG segR( seg.
A - direction + offset, seg.
B + direction + offset );
3622 if( trimToOutline( segL ) && trimToOutline( segR ) )
3630 spoke.
Append( seg.
A + offset );
3631 spoke.
Append( seg.
A - offset );
3633 spoke.
Append( segL.
B + direction );
3634 spoke.
Append( seg.
B + direction );
3635 spoke.
Append( segR.
B + direction );
3638 aSpokesList.push_back( std::move( spoke ) );
3651 thermalSpokeAngle =
pad->GetThermalSpokeAngle();
3670 position =
pad->ShapePos( aLayer );
3671 orientation =
pad->GetOrientation();
3679 position =
via->GetPosition();
3684 spokesBox.
Inflate( thermalReliefGap +
epsilon + zone_half_width );
3691 buildSpokesFromOrigin( spokesBox,
ANGLE_0 );
3693 if( thermalSpokeAngle !=
ANGLE_0 )
3696 for(
auto it = aSpokesList.rbegin(); it != aSpokesList.rbegin() + 4; ++it )
3697 it->Rotate( thermalSpokeAngle );
3702 buildSpokesFromOrigin( spokesBox, thermalSpokeAngle );
3705 auto spokeIter = aSpokesList.rbegin();
3707 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
3709 spokeIter->Rotate( orientation );
3710 spokeIter->Move( position );
3715 for(
size_t ii = 0; ii < aSpokesList.size(); ++ii )
3716 aSpokesList[ii].GenerateBBoxCache();
3722 const std::vector<BOARD_ITEM*>& aThermalConnectionPads,
3729 for(
BOARD_ITEM* item : aThermalConnectionPads )
3731 if( !item->IsOnLayer( aLayer ) )
3736 bool isCircular =
false;
3744 pad =
static_cast<PAD*
>( item );
3746 position =
pad->ShapePos( aLayer );
3752 padRadius = std::max( padSize.
x, padSize.
y ) / 2;
3761 int spokeMaxWidth = std::min( padSize.
x, padSize.
y );
3762 spokeWidth = std::min( spokeWidth, spokeMaxWidth );
3767 position =
via->GetPosition();
3769 padRadius =
via->GetWidth( aLayer ) / 2;
3778 spokeWidth = std::min( spokeWidth, padRadius * 2 );
3786 if( spokeWidth < aZone->GetMinThickness() )
3796 int ringInnerRadius = padRadius + thermalGap;
3797 int ringWidth = spokeWidth;
3810 pad->TransformShapeToPolygon( outerShape, aLayer, thermalGap + spokeWidth,
3814 pad->TransformShapeToPolygon( innerShape, aLayer, thermalGap,
3817 thermalRing = outerShape;
3847 if( settings.
gap <= 0
3849 || ( needsLineWidth && settings.
line_width <= 0 ) )
3876 const auto& defaultOffsets =
m_board->GetDesignSettings().m_ZoneLayerProperties;
3880 if(
auto it = defaultOffsets.find( aLayer ); it != defaultOffsets.end() )
3881 offset = it->second.hatching_offset.value_or(
VECTOR2I() );
3883 if( localOffsets.contains( aLayer ) && localOffsets.at( aLayer ).hatching_offset.has_value() )
3884 offset = localOffsets.at( aLayer ).hatching_offset.value();
3899 const int dotRadius = std::max( settings.
element_size / 2 - halfMinWidth, 1 );
3900 const int maxError =
m_board->GetDesignSettings().m_MaxError;
3906 int xStart = bbox.
GetLeft() - ( bbox.
GetLeft() % dotStride ) + offset.
x;
3907 int yStart = bbox.
GetTop() - ( bbox.
GetTop() % dotStride ) + offset.
y;
3909 while( xStart > bbox.
GetLeft() )
3910 xStart -= dotStride;
3912 while( yStart > bbox.
GetTop() )
3913 yStart -= dotStride;
3942 int xVoid = bbox.
GetLeft() - ( bbox.
GetLeft() % lineStride ) + offset.
x
3944 int yVoid = bbox.
GetTop() - ( bbox.
GetTop() % lineStride ) + offset.
y
3947 while( xVoid - voidSize / 2 > bbox.
GetLeft() )
3948 xVoid -= lineStride;
3950 while( yVoid - voidSize / 2 > bbox.
GetTop() )
3951 yVoid -= lineStride;
3955 for(
int yy = yVoid; yy <= bbox.
GetBottom() + voidSize; yy += lineStride )
3957 for(
int xx = xVoid; xx <= bbox.
GetRight() + voidSize; xx += lineStride )
3960 rect.
Append( xx - voidSize / 2, yy - voidSize / 2 );
3961 rect.
Append( xx + voidSize / 2, yy - voidSize / 2 );
3962 rect.
Append( xx + voidSize / 2, yy + voidSize / 2 );
3963 rect.
Append( xx - voidSize / 2, yy + voidSize / 2 );
3988 const VECTOR2I squareSize( sideLen, sideLen );
3990 const int containmentInset =
4005 for(
int yy = yStart; yy <= bbox.
GetBottom() + dotRadius; yy += dotStride )
4007 const int rowOffset = ( settings.
stagger && ( rowIndex & 1 ) ) ? dotStride / 2 : 0;
4009 for(
int xx = xStart + rowOffset; xx <= bbox.
GetRight() + dotRadius; xx += dotStride )
4013 if( !filledRegion.
Contains( centre, -1, 0,
true ) )
4033 aFillPolys = stamps;
4054 int maxError =
m_board->GetDesignSettings().m_MaxError;
4070 hole_base.
Append( corner );
4071 corner.
x += hole_size;
4072 hole_base.
Append( corner );
4073 corner.
y += hole_size;
4074 hole_base.
Append( corner );
4076 hole_base.
Append( corner );
4096 #define SMOOTH_MIN_VAL_MM 0.02
4097 #define SMOOTH_SMALL_VAL_MM 0.04
4113 smooth_value = std::min( smooth_value, aZone->
GetHatchGap() / 2 );
4116 maxError = std::max( maxError * 2, smooth_value / 20 );
4118 switch( smooth_level )
4130 hole_base = smooth_hole.
Fillet( smooth_value, maxError ).
Outline( 0 );
4142 const auto& defaultOffsets =
m_board->GetDesignSettings().m_ZoneLayerProperties;
4147 if(
auto it = defaultOffsets.find( aLayer ); it != defaultOffsets.end() )
4148 offset = it->second.hatching_offset.value_or(
VECTOR2I() );
4150 if( localOffsets.contains( aLayer ) && localOffsets.at( aLayer ).hatching_offset.has_value() )
4151 offset = localOffsets.at( aLayer ).hatching_offset.value();
4153 int x_offset = bbox.
GetX() - ( bbox.
GetX() ) % gridsize - gridsize;
4154 int y_offset = bbox.
GetY() - ( bbox.
GetY() ) % gridsize - gridsize;
4157 for(
int xx = x_offset; xx <= bbox.
GetRight(); xx += gridsize )
4159 for(
int yy = y_offset; yy <= bbox.
GetBottom(); yy += gridsize )
4170 hole.
Move(
VECTOR2I( offset.
x % gridsize, offset.
y % gridsize ) );
4183 deflated_thickness = std::max( deflated_thickness, maxError * 2 );
4205 if( area < minimal_hole_area )
4216 BOX2I thermalBBox = aThermalRings.
BBox();
4219 for(
int holeIdx = holes.
OutlineCount() - 1; holeIdx >= 0; holeIdx-- )
4229 for(
int ringIdx = 0; ringIdx < aThermalRings.
OutlineCount(); ringIdx++ )
4236 if( !holeBBox.
Contains( ringBBox ) )
4252 if( intersections.empty() )
4274 auto cacheKey = std::make_pair(
static_cast<const ZONE*
>( aZone ), aLayer );
4284 aFillPolys = it->second;
4297 auto evalRulesForItems =
4309 bool knockoutsApplied =
false;
4313 auto collectZoneKnockout =
4314 [&](
ZONE* otherZone )
4316 if( otherZone == aZone )
4319 if( !otherZone->GetLayerSet().test( aLayer ) )
4322 if( otherZone->IsTeardropArea() && otherZone->SameNet( aZone ) )
4325 if( !otherZone->HigherPriority( aZone ) )
4330 if( otherZone->SameNet( aZone ) )
4332 if( !otherZone->GetBoundingBox().Intersects( zoneBBox ) )
4344 std::shared_ptr<SHAPE_POLY_SET> fillShared;
4348 auto it = aSnapshot->find( {
static_cast<const ZONE*
>( otherZone ), aLayer } );
4350 if( it == aSnapshot->end() )
4353 fillPtr = &it->second;
4357 if( !otherZone->HasFilledPolysForLayer( aLayer ) )
4360 fillShared = otherZone->GetFilledPolysList( aLayer );
4365 fillPtr = fillShared.get();
4371 if( otherZone->SameNet( aZone ) )
4373 sameNetKnockouts.
Append( *fillPtr );
4378 aZone, otherZone, aLayer ) );
4381 otherZone, aLayer ) );
4389 diffNetKnockouts.
Append( inflatedFill );
4390 knockoutsApplied =
true;
4394 forEachBoardAndFootprintZone(
m_board, collectZoneKnockout );
4403 refillHash.
addData(
reinterpret_cast<const uint8_t*
>( diffNetHash.
Value64 ),
4404 sizeof( diffNetHash.
Value64 ) );
4405 refillHash.
addData(
reinterpret_cast<const uint8_t*
>( sameNetHash.
Value64 ),
4406 sizeof( sameNetHash.
Value64 ) );
4415 aFillPolys = it->second.second;
4432 if( knockoutsApplied )
4449 solidExtent = sit->second;
4453 knockouts.
Append( sameNetKnockouts );
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.
BASE_SET & set(size_t pos)
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.
const ZONES & Zones() const
int GetCopperLayerCount() const
const FOOTPRINTS & Footprints() 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 coord_type GetLeft() const
constexpr bool Contains(const Vec &aPoint) const
constexpr coord_type GetRight() const
constexpr coord_type GetTop() 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 const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
static const LSET & InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
A streaming C++ equivalent for MurmurHash3_x64_128.
FORCE_INLINE void addData(const uint8_t *data, size_t length)
FORCE_INLINE HASH_128 digest()
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.
Y-stripe spatial index for efficient point-in-polygon containment testing.
bool Contains(const VECTOR2I &aPt, int aAccuracy=0) const
Test whether a point is inside the indexed polygon set.
void Build(const SHAPE_POLY_SET &aPolySet)
Build the spatial index from a SHAPE_POLY_SET's outlines and holes.
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.
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.
void Insert(size_t aVertex, const VECTOR2I &aP)
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const override
Check if point aP lies inside a closed shape.
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.
void RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
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)
int ArcCount() const
Count the number of arc shapes present.
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.
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 knockoutThermalReliefs(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aFill, std::vector< BOARD_ITEM * > &aThermalConnectionPads, std::vector< PAD * > &aNoConnectionPads, std::vector< BOARD_ITEM * > &aSolidConnectionItems)
Removes thermal reliefs from the shape for any pads connected to the zone.
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.
std::map< std::pair< const ZONE *, PCB_LAYER_ID >, SHAPE_POLY_SET > FillSnapshot
Snapshot of zone fill polygons captured before an iterative refill wave.
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 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)
std::map< std::pair< const ZONE *, PCB_LAYER_ID >, SHAPE_POLY_SET > m_preHatchSolidFillCache
std::map< std::pair< const ZONE *, PCB_LAYER_ID >, std::pair< HASH_128, SHAPE_POLY_SET > > m_refillResultCache
PROGRESS_REPORTER * m_progressReporter
bool refillZoneFromCache(ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aFillPolys, const FillSnapshot *aSnapshot=nullptr)
Refill a zone from cached pre-knockout fill.
bool zoneKnockoutMayInteract(const ZONE *aZone, const ZONE *aKnockout) const
Test whether aKnockout's fill can knock out any part of aZone's fill.
bool addCopperThievingPattern(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aFillPolys)
Stamp a regular grid of pattern shapes onto a zone's filled area for copper thieving.
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)
void postKnockoutMinWidthPrune(const ZONE *aZone, SHAPE_POLY_SET &aFillPolys)
Remove minimum-width violations introduced by zone-to-zone knockouts.
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 CacheTriangulation(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, const SHAPE_POLY_SET::TASK_SUBMITTER &aSubmitter={})
Create a list of triangles that "fill" the solid areas used for instance to draw these solid areas on...
void SetNeedRefill(bool aNeedRefill)
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
std::optional< int > GetLocalClearance() const override
const THIEVING_SETTINGS & GetThievingSettings() const
ZONE_LAYER_PROPERTIES & LayerProperties(PCB_LAYER_ID aLayer)
std::shared_ptr< SHAPE_POLY_SET > GetFilledPolysList(PCB_LAYER_ID aLayer) const
const BOX2I GetBoundingBox() const override
ISLAND_REMOVAL_MODE GetIslandRemovalMode() const
void SetFillFlag(PCB_LAYER_ID aLayer, bool aFlag)
bool IsCopperThieving() const
long long int GetMinIslandArea() const
void SetFilledPolysList(PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPolysList)
Set the list of filled polygons.
int GetMinThickness() const
SHAPE_POLY_SET GetBoardOutline() const
bool HigherPriority(const ZONE *aOther) const
bool HasFilledPolysForLayer(PCB_LAYER_ID aLayer) const
int GetHatchThickness() const
double GetHatchHoleMinArea() const
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
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
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
bool HasKeepoutParametersSet() const
Accessor to determine if any keepout parameters are set.
double GetHatchSmoothingValue() const
bool GetDoNotAllowZoneFills() const
int GetHatchSmoothingLevel() const
void SetIsIsland(PCB_LAYER_ID aLayer, int aPolyIdx)
bool IsOnCopperLayer() const override
double CalculateFilledArea()
Compute the area currently occupied by the zone fill.
unsigned GetAssignedPriority() const
bool SameNet(const ZONE *aOther) 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 TransformTrapezoidToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aPosition, const VECTOR2I &aSize, const EDA_ANGLE &aRotation, int aDeltaX, int aDeltaY, int aInflate, int aError, ERROR_LOC aErrorLoc)
Convert a rectangle or trapezoid to a polygon.
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 constexpr std::size_t hash_val(const Types &... args)
@ ALWAYS_FLASHED
Always flashed for connectivity.
bool IsInnerCopperLayer(int aLayerId)
Test whether a layer is an inner (In1_Cu to In30_Cu) copper layer.
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.
static PGM_BASE * process
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
Parameters that drive copper-thieving fill generation.
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
#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