30#include <unordered_map>
31#include <unordered_set>
68 RESULTS(
int aOutline1,
int aOutline2,
int aVertex1,
int aVertex2 ) :
115 SEG::ecoord min_dist = std::numeric_limits<SEG::ecoord>::max();
118 auto check_pt = [&](
VERTEX* p )
120 VECTOR2D diff( p->x - aPt->
x, p->y - aPt->
y );
123 if( dist2 > 0 && dist2 < limit2 && dist2 < min_dist && p->isEar(
true ) )
132 while( p && p->
z <= maxZ )
140 while( p && p->
z >= minZ )
155 std::set<VERTEX*> visited;
168 if( ( visited.empty() || !visited.contains( p ) ) && ( q =
getPoint( p ) ) )
172 if( !visited.contains( q ) &&
174 p->
i, q->
i ).second )
178 visited.insert( p->
prev );
180 visited.insert( p->
next );
183 visited.insert( q->
prev );
185 visited.insert( q->
next );
220struct PAD_KNOCKOUT_KEY
228 bool operator==(
const PAD_KNOCKOUT_KEY& other )
const
230 return position == other.position && effectiveSize == other.effectiveSize
231 && shape == other.shape && orientation == other.orientation
232 && netCode == other.netCode;
236struct PAD_KNOCKOUT_KEY_HASH
238 size_t operator()(
const PAD_KNOCKOUT_KEY& key )
const
240 return hash_val( key.position.
x, key.position.
y, key.effectiveSize.
x, key.effectiveSize.
y,
241 key.shape, key.orientation.
AsDegrees(), key.netCode );
248struct VIA_KNOCKOUT_KEY
254 bool operator==(
const VIA_KNOCKOUT_KEY& other )
const
256 return position == other.position && effectiveSize == other.effectiveSize
257 && netCode == other.netCode;
261struct VIA_KNOCKOUT_KEY_HASH
263 size_t operator()(
const VIA_KNOCKOUT_KEY& key )
const
265 return hash_val( key.position.
x, key.position.
y, key.effectiveSize, key.netCode );
271struct TRACK_KNOCKOUT_KEY
277 TRACK_KNOCKOUT_KEY(
const VECTOR2I& aStart,
const VECTOR2I& aEnd,
int aWidth ) :
281 if( aStart.
x < aEnd.
x || ( aStart.
x == aEnd.
x && aStart.
y <= aEnd.
y ) )
293 bool operator==(
const TRACK_KNOCKOUT_KEY& other )
const
295 return start == other.start && end == other.end && width == other.width;
299struct TRACK_KNOCKOUT_KEY_HASH
301 size_t operator()(
const TRACK_KNOCKOUT_KEY& key )
const
303 return hash_val( key.start.
x, key.start.
y, key.end.
x, key.end.
y, key.width );
307template<
typename Func>
308void forEachBoardAndFootprintZone(
BOARD* aBoard, Func&& aFunc )
315 for(
ZONE* zone : footprint->Zones() )
382 std::lock_guard<KISPINLOCK> lock(
m_board->GetConnectivity()->GetLock() );
384 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
385 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
HASH_128> oldFillHashes;
386 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> isolatedIslandsMap;
388 std::shared_ptr<CONNECTIVITY_DATA> connectivity =
m_board->GetConnectivity();
395 connectivity->ClearRatsnest();
403 :
_(
"Building zone fills..." ) );
416 zone->CacheBoundingBox();
420 for(
PAD*
pad : footprint->Pads() )
424 pad->BuildEffectiveShapes();
429 for(
ZONE* zone : footprint->Zones() )
430 zone->CacheBoundingBox();
433 footprint->BuildCourtyardCaches();
434 footprint->BuildNetTieCache();
441 std::unordered_map<const ZONE*, POLY_YSTRIPES_INDEX> zoneOutlineIndices;
445 if( zone->GetNumCorners() <= 2 )
448 zoneOutlineIndices[zone].Build( *zone->Outline() );
451 auto findHighestPriorityZone =
453 const std::function<bool(
const ZONE* )>& testFn ) ->
ZONE*
455 unsigned highestPriority = 0;
456 ZONE* highestPriorityZone =
nullptr;
461 if( zone->GetIsRuleArea() )
464 if( zone->GetAssignedPriority() < highestPriority )
467 if( !zone->IsOnLayer( itemLayer ) )
471 if( zone->GetNumCorners() <= 2 )
474 if( !zone->GetBoundingBox().Intersects( bbox ) )
477 if( !testFn( zone ) )
481 if( zone->GetAssignedPriority() > highestPriority
482 || zone->GetNetCode() == netcode )
484 highestPriority = zone->GetAssignedPriority();
485 highestPriorityZone = zone;
489 return highestPriorityZone;
492 auto isInPourKeepoutArea =
497 if( !zone->GetIsRuleArea() )
500 if( !zone->HasKeepoutParametersSet() )
503 if( !zone->GetDoNotAllowZoneFills() )
506 if( !zone->IsOnLayer( itemLayer ) )
510 if( zone->GetNumCorners() <= 2 )
513 if( !zone->GetBoundingBox().Intersects( bbox ) )
516 auto it = zoneOutlineIndices.find( zone );
518 if( it != zoneOutlineIndices.end() && it->second.Contains( testPoint ) )
535 via->ClearZoneLayerOverrides();
537 if( !
via->GetRemoveUnconnected() )
542 int holeRadius =
via->GetDrillValue() / 2 + 1;
543 int netcode =
via->GetNetCode();
544 LSET layers =
via->GetLayerSet() & boardCuMask;
548 [&](
const ZONE* aZone ) ->
bool
555 if( !
via->ConditionallyFlashed( layer ) )
558 if( isInPourKeepoutArea( bbox, layer,
center ) )
564 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, viaTestFn );
569 || layer == padstack.
Drill().
end ) )
585 for(
PAD*
pad : footprint->Pads() )
587 pad->ClearZoneLayerOverrides();
589 if( !
pad->GetRemoveUnconnected() )
594 int netcode =
pad->GetNetCode();
595 LSET layers =
pad->GetLayerSet() & boardCuMask;
598 [&](
const ZONE* aZone ) ->
bool
600 auto it = zoneOutlineIndices.find( aZone );
602 if( it != zoneOutlineIndices.end() )
603 return it->second.Contains(
center );
610 if( !
pad->ConditionallyFlashed( layer ) )
613 if( isInPourKeepoutArea( bbox, layer,
center ) )
619 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, padTestFn );
630 for(
ZONE* zone : aZones )
633 if( zone->GetIsRuleArea() )
637 if( zone->GetNumCorners() <= 2 )
647 zone->BuildHashValue( layer );
648 oldFillHashes[ { zone, layer } ] = zone->GetHashValue( layer );
651 toFill.emplace_back( std::make_pair( zone, layer ) );
656 if( !zone->IsCopperThieving() )
664 auto zone_fill_dependency =
666 bool aRequireCompletedOtherFill ) ->
bool
673 if( aRequireCompletedOtherFill && aOtherZone->GetFillFlag( aLayer ) )
678 if( aOtherZone->GetIsRuleArea() )
682 if( aOtherZone->GetNumCorners() <= 2 )
686 if( !aOtherZone->GetLayerSet().test( aLayer ) )
693 if( aOtherZone->SameNet( aZone ) )
701 if( !inflatedBBox.
Intersects( aOtherZone->GetBoundingBox() ) )
707 auto check_fill_dependency =
710 return zone_fill_dependency( aZone, aLayer, aOtherZone,
true );
713 auto fill_item_dependency =
714 [&](
const std::pair<ZONE*, PCB_LAYER_ID>& aWaiter,
715 const std::pair<ZONE*, PCB_LAYER_ID>& aDependency ) ->
bool
717 if( aWaiter.first == aDependency.first || aWaiter.second != aDependency.second )
720 return check_fill_dependency( aWaiter.first, aWaiter.second, aDependency.first );
724 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
730 ZONE* zone = aFillItem.first;
745 auto tesselate_lambda =
746 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
752 ZONE* zone = aFillItem.first;
761 std::atomic<bool> cancelled =
false;
763 auto waitForFutures =
764 [&]( std::vector<std::future<int>>& aFutures, std::vector<int>* aResults = nullptr )
769 for(
auto& future : aFutures )
771 while( future.wait_for( std::chrono::milliseconds( 100 ) )
772 != std::future_status::ready )
783 int result = future.get();
786 aResults->push_back(
result );
792 std::vector<std::vector<size_t>> successors;
793 std::vector<int> inDegree;
794 std::vector<size_t> currentWave;
797 auto build_fill_dag = [&](
const std::vector<std::pair<ZONE*, PCB_LAYER_ID>>& aFillItems,
auto&& aHasDependency,
798 bool aAnyDependencies ) -> FILL_DAG
802 dag.successors.resize( aFillItems.size() );
803 dag.inDegree.assign( aFillItems.size(), 0 );
804 dag.currentWave.reserve( aFillItems.size() );
808 if( aAnyDependencies )
810 for(
size_t i = 0; i < aFillItems.size(); ++i )
812 for(
size_t j = 0; j < aFillItems.size(); ++j )
817 if( aHasDependency( aFillItems[j], aFillItems[i] ) )
819 dag.successors[i].push_back( j );
826 for(
size_t i = 0; i < aFillItems.size(); ++i )
828 if( dag.inDegree[i] == 0 )
829 dag.currentWave.push_back( i );
835 auto run_fill_waves = [&](
const std::vector<std::pair<ZONE*, PCB_LAYER_ID>>& aFillItems,
auto&& aFillFn,
836 auto&& aTessFn,
auto&& aHasDependency,
bool aAnyDependencies )
838 FILL_DAG dag = build_fill_dag( aFillItems, aHasDependency, aAnyDependencies );
840 while( !dag.currentWave.empty() && !cancelled.load() )
842 std::vector<std::future<int>> fillFutures;
843 std::vector<int> fillResults;
845 fillFutures.reserve( dag.currentWave.size() );
847 for(
size_t idx : dag.currentWave )
849 fillFutures.emplace_back(
tp.submit_task(
850 [&aFillFn, &aFillItems, idx]()
852 return aFillFn( aFillItems[idx] );
856 waitForFutures( fillFutures, &fillResults );
858 std::vector<std::future<int>> tessFutures;
860 tessFutures.reserve( dag.currentWave.size() );
862 for(
size_t ii = 0; ii < fillResults.size(); ++ii )
864 if( fillResults[ii] == 0 )
867 size_t idx = dag.currentWave[ii];
869 tessFutures.emplace_back(
tp.submit_task(
870 [&aTessFn, &aFillItems, idx]()
872 return aTessFn( aFillItems[idx] );
876 waitForFutures( tessFutures );
878 if( cancelled.load() )
881 std::vector<size_t> nextWave;
883 for(
size_t idx : dag.currentWave )
885 for(
size_t succ : dag.successors[idx] )
887 if( --dag.inDegree[succ] == 0 )
888 nextWave.push_back( succ );
892 dag.currentWave = std::move( nextWave );
896 run_fill_waves( toFill, fill_lambda, tesselate_lambda, fill_item_dependency,
true );
911 connectivity->FillIsolatedIslandsMap( isolatedIslandsMap );
912 connectivity->SetProgressReporter(
nullptr );
917 for(
ZONE* zone : aZones )
920 if( zone->GetIsRuleArea() )
923 zone->SetIsFilled(
true );
932 std::set<std::pair<ZONE*, PCB_LAYER_ID>> zonesWithRemovedIslandLayers;
939 std::set<std::pair<ZONE*, PCB_LAYER_ID>> initiallyFullyIsolatedLayers;
941 for(
const auto& [ zone, zoneIslands ] : isolatedIslandsMap )
945 bool allLayersFullyIsolated =
true;
947 for(
const auto& [ layer, layerIslands ] : zoneIslands )
949 bool layerFullyIsolated = ( layerIslands.m_IsolatedOutlines.size()
950 ==
static_cast<size_t>( zone->GetFilledPolysList( layer )->OutlineCount() ) );
952 if( layerFullyIsolated )
953 initiallyFullyIsolatedLayers.insert( { zone, layer } );
955 allLayersFullyIsolated =
false;
958 if( allLayersFullyIsolated )
961 for(
const auto& [ layer, layerIslands ] : zoneIslands )
966 if( layerIslands.m_IsolatedOutlines.empty() )
969 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
973 std::sort( islands.begin(), islands.end(), std::greater<int>() );
975 std::shared_ptr<SHAPE_POLY_SET> poly = zone->GetFilledPolysList( layer );
976 long long int minArea = zone->GetMinIslandArea();
979 for(
int idx : islands )
985 poly->DeletePolygonAndTriangulationData( idx,
false );
986 zonesWithRemovedIslandLayers.insert( { zone, layer } );
990 poly->DeletePolygonAndTriangulationData( idx,
false );
991 zonesWithRemovedIslandLayers.insert( { zone, layer } );
995 zone->SetIsIsland( layer, idx );
999 poly->UpdateTriangulationDataHash();
1000 zone->CalculateFilledArea();
1017 if( iterativeRefill && !zonesWithRemovedIslandLayers.empty() )
1019 const int maxIterations = 8;
1020 bool progressReported =
false;
1021 bool hitIterationLimit =
false;
1024 std::set<std::pair<ZONE*, PCB_LAYER_ID>> changedZoneLayers( zonesWithRemovedIslandLayers );
1026 auto cached_refill_tessellate_lambda = [&](
const std::pair<ZONE*, PCB_LAYER_ID>& aFillItem ) ->
int
1028 ZONE* zone = aFillItem.first;
1035 auto no_dependency = [](
const std::pair<ZONE*, PCB_LAYER_ID>&,
const std::pair<ZONE*, PCB_LAYER_ID>& ) ->
bool
1040 for(
int iteration = 0; iteration < maxIterations; ++iteration )
1045 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zonesToRefill;
1046 std::set<std::pair<ZONE*, PCB_LAYER_ID>> zonesToRefillSet;
1048 for(
const auto& [changedZone, changedLayer] : changedZoneLayers )
1050 BOX2I bbox = changedZone->GetBoundingBox();
1053 for(
ZONE* zone : aZones )
1055 if( zone->GetIsRuleArea() )
1058 if( !zone->GetLayerSet().test( changedLayer ) )
1074 if( zone != changedZone && !changedZone->HigherPriority( zone ) && !changedZone->SameNet( zone ) )
1079 if( !zone->GetBoundingBox().Intersects( bbox ) )
1082 auto fillItem = std::make_pair( zone, changedLayer );
1084 if( zonesToRefillSet.insert( fillItem ).second )
1085 zonesToRefill.push_back( fillItem );
1089 if( zonesToRefill.empty() )
1092 if( !progressReported )
1101 progressReported =
true;
1107 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
HASH_128> iterHashes;
1109 for(
const auto& fillItem : zonesToRefill )
1111 fillItem.first->BuildHashValue( fillItem.second );
1112 iterHashes[fillItem] = fillItem.first->GetHashValue( fillItem.second );
1123 LSET snapshotLayers;
1125 for(
const auto& [zone, layer] : zonesToRefill )
1126 snapshotLayers.
set( layer );
1130 forEachBoardAndFootprintZone(
m_board,
1147 if( sp && sp->OutlineCount() > 0 )
1148 snapshot[{ zone, layer }] = sp->CloneDropTriangulation();
1152 auto cached_refill_fill_lambda =
1153 [&](
const std::pair<ZONE*, PCB_LAYER_ID>& aFillItem ) ->
int
1155 ZONE* zone = aFillItem.first;
1167 run_fill_waves( zonesToRefill, cached_refill_fill_lambda, cached_refill_tessellate_lambda, no_dependency,
1173 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> refillIslandsMap;
1175 for(
const auto& [zone, layer] : zonesToRefill )
1189 connectivity->FillIsolatedIslandsMap( refillIslandsMap );
1191 for(
const auto& [zone, zoneIslands] : refillIslandsMap )
1193 for(
const auto& [layer, layerIslands] : zoneIslands )
1198 if( layerIslands.m_IsolatedOutlines.empty() )
1203 if( initiallyFullyIsolatedLayers.count( { zone, layer } ) > 0 )
1205 if( layerIslands.m_IsolatedOutlines.size()
1212 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
1213 std::sort( islands.begin(), islands.end(), std::greater<int>() );
1219 for(
int idx : islands )
1224 poly->DeletePolygonAndTriangulationData( idx,
false );
1226 poly->DeletePolygonAndTriangulationData( idx,
false );
1231 poly->UpdateTriangulationDataHash();
1239 changedZoneLayers.clear();
1241 for(
const auto& fillItem : zonesToRefill )
1243 fillItem.first->BuildHashValue( fillItem.second );
1245 auto hashIt = iterHashes.find( fillItem );
1246 HASH_128 oldHash = ( hashIt != iterHashes.end() ) ? hashIt->second :
HASH_128{};
1248 if( fillItem.first->GetHashValue( fillItem.second ) != oldHash )
1249 changedZoneLayers.insert( fillItem );
1252 if( changedZoneLayers.empty() )
1255 if( iteration + 1 >= maxIterations )
1257 hitIterationLimit =
true;
1262 if( hitIterationLimit )
1264 wxString msg = wxString::Format(
_(
"Zone fills may be incorrect: iterative refill did not converge "
1265 "after %d passes.\n\n"
1266 "This can happen with complex overlapping zones. "
1267 "Consider simplifying your zones." ),
1272 KIDIALOG dlg( aParent, msg,
_(
"Warning" ), wxOK | wxICON_WARNING );
1278 wxLogWarning( msg );
1285 using island_check_return = std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
int>>;
1287 std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
double>> polys_to_check;
1290 polys_to_check.reserve(
m_board->GetCopperLayerCount() * aZones.size() );
1292 for(
ZONE* zone : aZones )
1302 double minArea = (double) zone->GetMinThickness() * zone->GetMinThickness() * 3;
1309 polys_to_check.emplace_back( zone->GetFilledPolysList( layer ), minArea );
1313 auto island_lambda =
1314 [&](
int aStart,
int aEnd ) -> island_check_return
1316 island_check_return retval;
1318 for(
int ii = aStart; ii < aEnd && !cancelled.load(); ++ii )
1320 auto [poly, minArea] = polys_to_check[ii];
1322 for(
int jj = poly->OutlineCount() - 1; jj >= 0; jj-- )
1327 double island_area = test_poly.
Area();
1329 if( island_area < minArea )
1341 if( intersection.
Area() < island_area / 2.0 )
1342 retval.emplace_back( poly, jj );
1349 auto island_returns =
tp.submit_blocks( 0, polys_to_check.size(), island_lambda );
1353 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
1355 std::future<island_check_return>& ret = island_returns[ii];
1359 std::future_status status = ret.wait_for( std::chrono::seconds( 0 ) );
1361 while( status != std::future_status::ready )
1371 status = ret.wait_for( std::chrono::milliseconds( 100 ) );
1376 if( cancelled.load() )
1379 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
1381 std::future<island_check_return>& ret = island_returns[ii];
1385 for(
auto& action_item : ret.get() )
1386 action_item.first->DeletePolygonAndTriangulationData( action_item.second,
true );
1390 for(
ZONE* zone : aZones )
1391 zone->CalculateFilledArea();
1404 std::unique_ptr<POLY_YSTRIPES_INDEX>
index;
1407 struct NET_LAYER_HASH
1409 size_t operator()(
const std::pair<int, PCB_LAYER_ID>& k )
const
1411 return std::hash<int>()( k.first ) ^ ( std::hash<int>()( k.second ) << 16 );
1415 std::unordered_map<std::pair<int, PCB_LAYER_ID>, std::vector<INDEXED_ZONE>, NET_LAYER_HASH>
1416 filledZonesByNetLayer;
1420 if( zone->GetIsRuleArea() )
1425 if( !zone->HasFilledPolysForLayer( layer ) )
1428 const std::shared_ptr<SHAPE_POLY_SET>& fill = zone->GetFilledPolysList( layer );
1430 if( fill->IsEmpty() )
1434 iz.bbox = fill->BBox();
1435 iz.index = std::make_unique<POLY_YSTRIPES_INDEX>();
1436 iz.index->Build( *fill );
1437 filledZonesByNetLayer[{ zone->GetNetCode(), layer }].push_back( std::move( iz ) );
1441 auto zoneReachesPoint =
1444 auto it = filledZonesByNetLayer.find( { aNetcode, aLayer } );
1446 if( it == filledZonesByNetLayer.end() )
1449 for(
const INDEXED_ZONE& iz : it->second )
1451 if( !iz.bbox.GetInflated( aRadius ).Contains( aCenter ) )
1454 if( iz.index->Contains( aCenter, aRadius ) )
1468 int holeRadius =
via->GetDrillValue() / 2;
1469 int netcode =
via->GetNetCode();
1470 LSET layers =
via->GetLayerSet() & boardCuMask;
1477 if( !zoneReachesPoint( netcode, layer,
center, holeRadius ) )
1484 for(
PAD*
pad : footprint->Pads() )
1487 int netcode =
pad->GetNetCode();
1488 LSET layers =
pad->GetLayerSet() & boardCuMask;
1492 if(
pad->HasHole() )
1493 holeRadius = std::min(
pad->GetDrillSizeX(),
pad->GetDrillSizeY() ) / 2;
1500 if( !zoneReachesPoint( netcode, layer,
center, holeRadius ) )
1508 bool outOfDate =
false;
1510 for(
ZONE* zone : aZones )
1513 if( zone->GetIsRuleArea() )
1518 zone->BuildHashValue( layer );
1520 if( oldFillHashes[ { zone, layer } ] != zone->GetHashValue( layer ) )
1526 &&
m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill ) )
1528 KIDIALOG dlg( aParent,
_(
"Prototype zone fill enabled. Disable setting and refill?" ),
_(
"Confirmation" ),
1529 wxOK | wxCANCEL | wxICON_WARNING );
1535 m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill =
false;
1537 else if( !outOfDate )
1545 KIDIALOG dlg( aParent,
_(
"Zone fills are out-of-date. Refill?" ),
_(
"Confirmation" ),
1546 wxOK | wxCANCEL | wxICON_WARNING );
1589 std::vector<VECTOR2I> convex_hull;
1594 for(
const VECTOR2I& pt : convex_hull )
1626 switch( aItem->
Type() )
1633 if(
text->IsVisible() )
1635 if(
text->IsKnockout() )
1691 std::vector<BOARD_ITEM*>& aThermalConnectionPads,
1692 std::vector<PAD*>& aNoConnectionPads )
1698 std::shared_ptr<SHAPE> padShape;
1703 std::unordered_set<PAD_KNOCKOUT_KEY, PAD_KNOCKOUT_KEY_HASH> processedPads;
1704 std::unordered_set<VIA_KNOCKOUT_KEY, VIA_KNOCKOUT_KEY_HASH> processedVias;
1708 for(
PAD*
pad : footprint->Pads() )
1714 &&
pad->GetDrillSize().x > 0;
1716 if( !
pad->IsOnLayer( aLayer ) && !npthWithHole )
1719 BOX2I padBBox =
pad->GetBoundingBox();
1736 int drill = std::max(
pad->GetDrillSize().x,
pad->GetDrillSize().y );
1737 int maxDim = std::max( { padSize.
x, padSize.
y, drill } );
1738 effectiveSize =
VECTOR2I( maxDim, maxDim );
1742 effectiveSize = padSize;
1745 PAD_KNOCKOUT_KEY padKey{
pad->GetPosition(), effectiveSize,
1746 static_cast<int>( padShapeType ),
1747 pad->GetOrientation(),
pad->GetNetCode() };
1749 if( !processedPads.insert( padKey ).second )
1753 bool noConnection =
pad->GetNetCode() != aZone->
GetNetCode();
1760 noConnection =
true;
1765 if(
pad->IsBackdrilledOrPostMachined( aLayer ) )
1766 noConnection =
true;
1771 aNoConnectionPads.push_back(
pad );
1786 switch( connection )
1792 if( aFill.
Collide( padShape.get(), 0 ) )
1800 aThermalConnectionPads.push_back(
pad );
1809 aNoConnectionPads.push_back(
pad );
1834 switch( connection )
1839 if( aFill.
Collide( padShape.get(), 0 ) )
1844 aThermalConnectionPads.push_back(
pad );
1858 if(
pad->FlashLayer( aLayer ) )
1862 else if(
pad->GetDrillSize().x > 0 )
1869 holeClearance = padClearance;
1895 if( !
via->IsOnLayer( aLayer ) )
1898 BOX2I viaBBox =
via->GetBoundingBox();
1905 int viaEffectiveSize = std::max(
via->GetDrillValue(),
via->GetWidth( aLayer ) );
1906 VIA_KNOCKOUT_KEY viaKey{
via->GetPosition(), viaEffectiveSize,
via->GetNetCode() };
1908 if( !processedVias.insert( viaKey ).second )
1911 bool noConnection =
via->GetNetCode() != aZone->
GetNetCode()
1913 && aLayer !=
via->Padstack().Drill().start
1914 && aLayer !=
via->Padstack().Drill().end );
1917 noConnection =
true;
1920 if(
via->IsBackdrilledOrPostMachined( aLayer ) )
1922 noConnection =
true;
1934 pmSize = std::max( pmSize, frontPM.
size );
1940 pmSize = std::max( pmSize, backPM.
size );
1946 bdSize = secDrill.
size.
x;
1948 int knockoutSize = std::max( pmSize, bdSize );
1950 if( knockoutSize > 0 )
1965 switch( connection )
1975 if( thermalGap > 0 )
1977 aThermalConnectionPads.push_back(
via );
2005 const std::vector<PAD*>& aNoConnectionPads,
2007 bool aIncludeZoneClearances )
2013 std::unordered_set<PAD_KNOCKOUT_KEY, PAD_KNOCKOUT_KEY_HASH> processedPads;
2014 std::unordered_set<VIA_KNOCKOUT_KEY, VIA_KNOCKOUT_KEY_HASH> processedVias;
2015 std::unordered_set<TRACK_KNOCKOUT_KEY, TRACK_KNOCKOUT_KEY_HASH> processedTracks;
2017 auto checkForCancel =
2020 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
2033 auto evalRulesForItems =
2047 auto knockoutPadClearance =
2052 bool hasHole = aPad->GetDrillSize().x > 0;
2053 bool flashLayer = aPad->FlashLayer( aLayer );
2056 if( flashLayer || platedHole )
2061 if( flashLayer && gap >= 0 )
2062 addKnockout( aPad, aLayer, gap + extra_margin, aHoles );
2077 && aPad->GetDrillSize().x != aPad->GetDrillSize().y )
2088 if( aPad->IsBackdrilledOrPostMachined( aLayer ) )
2099 pmSize = std::max( pmSize, frontPM.
size );
2105 pmSize = std::max( pmSize, backPM.
size );
2111 bdSize = secDrill.
size.
x;
2113 int knockoutSize = std::max( pmSize, bdSize );
2115 if( knockoutSize > 0 )
2117 int clearance = std::max( gap, 0 ) + extra_margin;
2125 for(
PAD*
pad : aNoConnectionPads )
2141 int drill = std::max(
pad->GetDrillSize().x,
pad->GetDrillSize().y );
2142 int maxDim = std::max( { padSize.
x, padSize.
y, drill } );
2143 effectiveSize =
VECTOR2I( maxDim, maxDim );
2147 effectiveSize = padSize;
2150 PAD_KNOCKOUT_KEY padKey{
pad->GetPosition(), effectiveSize,
2151 static_cast<int>( padShape ),
pad->GetOrientation(),
2152 pad->GetNetCode() };
2154 if( !processedPads.insert( padKey ).second )
2158 knockoutPadClearance(
pad );
2163 auto knockoutTrackClearance =
2166 if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
2168 bool sameNet = aTrack->GetNetCode() == aZone->
GetNetCode();
2190 if(
via->FlashLayer( aLayer ) && gap > 0 )
2192 via->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
m_maxError,
2211 if(
via->IsBackdrilledOrPostMachined( aLayer ) )
2222 pmSize = std::max( pmSize, frontPM.
size );
2228 pmSize = std::max( pmSize, backPM.
size );
2234 bdSize = secDrill.
size.
x;
2236 int knockoutSize = std::max( pmSize, bdSize );
2238 if( knockoutSize > 0 )
2240 int clearance = std::max( gap, 0 ) + extra_margin;
2251 aTrack->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
m_maxError,
2260 if( !track->IsOnLayer( aLayer ) )
2270 int viaEffectiveSize = std::max(
via->GetDrillValue(),
via->GetWidth( aLayer ) );
2271 VIA_KNOCKOUT_KEY viaKey{
via->GetPosition(), viaEffectiveSize,
via->GetNetCode() };
2273 if( !processedVias.insert( viaKey ).second )
2278 TRACK_KNOCKOUT_KEY trackKey( track->GetStart(), track->GetEnd(), track->GetWidth() );
2280 if( !processedTracks.insert( trackKey ).second )
2284 knockoutTrackClearance( track );
2289 auto knockoutGraphicClearance =
2295 shapeNet =
static_cast<PCB_SHAPE*
>( aItem )->GetNetCode();
2297 bool sameNet = shapeNet == aZone->
GetNetCode();
2303 if( aItem->IsOnLayer( aLayer )
2305 || aItem->IsOnLayer(
Margin ) )
2307 if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
2309 bool ignoreLineWidths =
false;
2312 if( aItem->IsOnLayer( aLayer ) && !sameNet )
2316 else if( aItem->IsOnLayer(
Edge_Cuts ) )
2319 ignoreLineWidths =
true;
2321 else if( aItem->IsOnLayer(
Margin ) )
2328 gap += extra_margin;
2329 addKnockout( aItem, aLayer, gap, ignoreLineWidths, aHoles );
2335 auto knockoutCourtyardClearance =
2338 if( aFootprint->GetBoundingBox().Intersects( zone_boundingbox ) )
2349 aHoles.
Append( aFootprint->GetCourtyard( courtyardSide ) );
2362 knockoutCourtyardClearance( footprint );
2363 knockoutGraphicClearance( &footprint->Reference() );
2364 knockoutGraphicClearance( &footprint->Value() );
2366 std::set<PAD*> allowedNetTiePads;
2370 if( footprint->IsNetTie() )
2372 for(
PAD*
pad : footprint->Pads() )
2381 if(
pad->IsOnLayer( aLayer ) )
2382 allowedNetTiePads.insert(
pad );
2384 for(
PAD* other : footprint->GetNetTiePads(
pad ) )
2386 if( other->IsOnLayer( aLayer ) )
2387 allowedNetTiePads.insert( other );
2393 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
2398 BOX2I itemBBox = item->GetBoundingBox();
2400 if( !zone_boundingbox.
Intersects( itemBBox ) )
2403 bool skipItem =
false;
2405 if( item->IsOnLayer( aLayer ) )
2407 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape();
2409 for(
PAD*
pad : allowedNetTiePads )
2411 if(
pad->GetBoundingBox().Intersects( itemBBox )
2412 &&
pad->GetEffectiveShape( aLayer )->Collide( itemShape.get() ) )
2421 knockoutGraphicClearance( item );
2430 knockoutGraphicClearance( item );
2435 auto knockoutZoneClearance =
2436 [&](
ZONE* aKnockout )
2439 if( !aKnockout->GetLayerSet().test( aLayer ) )
2442 if( aKnockout->GetBoundingBox().Intersects( zone_boundingbox ) )
2444 if( aKnockout->GetIsRuleArea() )
2446 if( aKnockout->GetDoNotAllowZoneFills() && !aZone->
IsTeardropArea() )
2455 if( aKnockout->HigherPriority( aZone ) && !aKnockout->SameNet( aZone ) )
2467 aKnockout->TransformShapeToPolygon( poly, aLayer, gap + extra_margin,
m_maxError,
2475 if( aIncludeZoneClearances )
2482 knockoutZoneClearance( otherZone );
2487 for(
ZONE* otherZone : footprint->Zones() )
2492 knockoutZoneClearance( otherZone );
2513 auto evalRulesForItems =
2529 auto knockoutZoneClearance =
2530 [&](
ZONE* aKnockout )
2532 if( aKnockout->GetIsRuleArea() )
2535 if( !aKnockout->GetLayerSet().test( aLayer ) )
2538 if( aKnockout->GetBoundingBox().Intersects( zone_boundingbox ) )
2540 if( aKnockout->HigherPriority( aZone ) && !aKnockout->SameNet( aZone ) )
2543 aZone, aKnockout, aLayer ) );
2546 aKnockout, aLayer ) );
2552 aKnockout->TransformShapeToPolygon( poly, aLayer, gap + extra_margin,
2559 forEachBoardAndFootprintZone(
m_board, knockoutZoneClearance );
2575 auto collectZoneOutline =
2576 [&](
ZONE* aKnockout )
2578 if( !aKnockout->GetLayerSet().test( aLayer ) )
2581 if( aKnockout->GetBoundingBox().Intersects( zoneBBox ) )
2582 appendZoneOutlineWithoutArcs( aKnockout, knockouts );
2585 forEachBoardAndFootprintZone(
2587 [&](
ZONE* otherZone )
2591 bool higherPrioritySameNet =
2596 collectZoneOutline( otherZone );
2615 std::map<int, std::vector<std::pair<int, VECTOR2I>>> insertion_points;
2627 insertion_points[
result.m_outline1].push_back( {
result.m_vertex1, pt1 } );
2628 insertion_points[
result.m_outline1].push_back( {
result.m_vertex1, pt2 } );
2631 for(
auto& [outline, vertices] : insertion_points )
2639 std::stable_sort( vertices.begin(), vertices.end(),
2640 [](
const std::pair<int, VECTOR2I>& a,
const std::pair<int, VECTOR2I>& b )
2642 return a.first > b.first;
2645 for(
const auto& [vertex, pt] : vertices )
2646 line.
Insert( vertex + 1, pt );
2667 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
2669 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
2670 BOX2I islandExtents;
2672 for(
const VECTOR2I& pt : island.front().CPoints() )
2674 islandExtents.
Merge( pt );
2690#define DUMP_POLYS_TO_COPPER_LAYER( a, b, c ) \
2691 { if( m_debugZoneFiller && aDebugLayer == b ) \
2693 m_board->SetLayerName( b, c ); \
2694 SHAPE_POLY_SET d = a; \
2734 std::vector<BOARD_ITEM*> thermalConnectionPads;
2735 std::vector<PAD*> noConnectionPads;
2736 std::deque<SHAPE_LINE_CHAIN> thermalSpokes;
2739 aFillPolys = aSmoothedOutline;
2766 aFillPolys, thermalRings );
2788 if( iterativeRefill )
2791 bool addedKeepoutHoles =
false;
2793 auto collectKeepoutHoles =
2794 [&](
ZONE* candidate )
2799 if( !isZoneFillKeepout( candidate, aLayer, zone_boundingbox ) )
2802 candidate->TransformSmoothedOutlineToPolygon( clearanceHoles, 0,
m_maxError,
2804 addedKeepoutHoles =
true;
2807 forEachBoardAndFootprintZone(
m_board, collectKeepoutHoles );
2809 if( addedKeepoutHoles )
2838 if( iterativeRefill )
2864 spokeTestIndex.
Build( testAreas );
2871 const VECTOR2I& testPt = spoke.CPoint( 3 );
2874 if( spokeTestIndex.
Contains( testPt, 1 ) )
2883 if( interval++ > 400 )
2896 if( &other != &spoke
2897 && other.PointInside( testPt, 1 )
2898 && spoke.PointInside( other.CPoint( 3 ), 1 ) )
2934 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
2936 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
2937 BOX2I islandExtents;
2939 for(
const VECTOR2I& pt : island.front().CPoints() )
2941 islandExtents.
Merge( pt );
2962 || !
m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill ) )
3011 for(
BOARD_ITEM* item : thermalConnectionPads )
3025 bool knockoutsApplied =
false;
3027 if( iterativeRefill )
3038 knockoutsApplied =
true;
3051 if( knockoutsApplied )
3076 auto checkForCancel =
3079 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
3082 auto knockoutGraphicItem =
3085 if( aItem->IsKnockout() && aItem->IsOnLayer( aLayer )
3086 && aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
3088 addKnockout( aItem, aLayer, 0,
true, clearanceHoles );
3097 knockoutGraphicItem( &footprint->Reference() );
3098 knockoutGraphicItem( &footprint->Value() );
3100 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
3101 knockoutGraphicItem( item );
3109 knockoutGraphicItem( item );
3112 aFillPolys = aSmoothedOutline;
3117 auto collectKeepout =
3118 [&](
ZONE* candidate )
3120 if( !isZoneFillKeepout( candidate, aLayer, zone_boundingbox ) )
3123 appendZoneOutlineWithoutArcs( candidate, keepoutHoles );
3126 bool cancelledKeepoutScan =
false;
3128 forEachBoardAndFootprintZone(
3130 [&](
ZONE* keepout )
3132 if( cancelledKeepoutScan )
3137 cancelledKeepoutScan =
true;
3141 collectKeepout( keepout );
3144 if( cancelledKeepoutScan )
3195 debugLayer = aLayer;
3199 if( !aZone->
BuildSmoothedPoly( maxExtents, aLayer, boardOutline, &smoothedPoly ) )
3207 if(
fillCopperZone( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aFillPolys ) )
3224 const std::vector<BOARD_ITEM*>& aSpokedPadsList,
3225 std::deque<SHAPE_LINE_CHAIN>& aSpokesList )
3244 if( !item->IsOnLayer( aLayer ) )
3247 int thermalReliefGap = 0;
3251 bool circular =
false;
3255 pad =
static_cast<PAD*
>( item );
3285 int spoke_max_allowed_w = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
3286 spoke_w = std::clamp( spoke_w, constraint.
Value().
Min(), constraint.
Value().
Max() );
3287 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
3289 if( spoke_w < aZone->GetMinThickness() )
3302 spoke_w = std::min( spoke_w,
via->GetWidth( aLayer ) );
3304 if( spoke_w < aZone->GetMinThickness() )
3323 int spoke_max_allowed_w = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
3325 spoke_w = std::clamp( spoke_w, constraint.
Value().
Min(), constraint.
Value().
Max() );
3328 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
3331 if( spoke_w < aZone->GetMinThickness() )
3340 int spoke_half_w = spoke_w / 2;
3343 BOX2I itemBB = item->GetBoundingBox();
3349 bool customSpokes =
false;
3353 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
3355 if( primitive->IsProxyItem() && primitive->GetShape() ==
SHAPE_T::SEGMENT )
3357 customSpokes =
true;
3368 auto buildSpokesFromOrigin =
3375 auto intersectBBox =
3378 double dx = spokeAngle.
Cos();
3379 double dy = spokeAngle.
Sin();
3385 *spoke_side =
VECTOR2I( spoke_half_w, 0 );
3386 return KiROUND( 0.0, dy * half_size.
y );
3390 *spoke_side =
VECTOR2I( 0, spoke_half_w );
3391 return KiROUND( dx * half_size.
x, 0.0 );
3396 double dist_x = half_size.
x /
std::abs( dx );
3397 double dist_y = half_size.
y /
std::abs( dy );
3399 if( dist_x < dist_y )
3401 *spoke_side =
KiROUND( 0.0, spoke_half_w / (
ANGLE_90 - spokeAngle ).Sin() );
3402 return KiROUND( dx * dist_x, dy * dist_x );
3406 *spoke_side =
KiROUND( spoke_half_w / spokeAngle.
Sin(), 0.0 );
3407 return KiROUND( dx * dist_y, dy * dist_y );
3420 for(
const EDA_ANGLE& spokeAngle : angles )
3423 VECTOR2I intersection = intersectBBox( spokeAngle, &spoke_side );
3432 aSpokesList.push_back( std::move( spoke ) );
3444 thermalOutline = thermalPoly.
Outline( 0 );
3448 auto trimToOutline = [&](
SEG& aSegment )
3452 if( padOutline.
Intersect( aSegment, intersections ) )
3454 intersections.clear();
3457 if( thermalOutline.
Intersect( aSegment, intersections ) )
3459 aSegment.B = intersections.front().p;
3466 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
3468 if( primitive->IsProxyItem() && primitive->GetShape() ==
SHAPE_T::SEGMENT )
3470 SEG seg( primitive->GetStart(), primitive->GetEnd() );
3475 seg.
A +=
pad->ShapePos( aLayer );
3476 seg.
B +=
pad->ShapePos( aLayer );
3490 if( trimToOutline( seg ) )
3492 VECTOR2I direction = ( seg.
B - seg.
A ).Resize( spoke_half_w );
3496 SEG segL( seg.
A - direction - offset, seg.
B + direction - offset );
3497 SEG segR( seg.
A - direction + offset, seg.
B + direction + offset );
3500 if( trimToOutline( segL ) && trimToOutline( segR ) )
3508 spoke.
Append( seg.
A + offset );
3509 spoke.
Append( seg.
A - offset );
3511 spoke.
Append( segL.
B + direction );
3512 spoke.
Append( seg.
B + direction );
3513 spoke.
Append( segR.
B + direction );
3516 aSpokesList.push_back( std::move( spoke ) );
3529 thermalSpokeAngle =
pad->GetThermalSpokeAngle();
3548 position =
pad->ShapePos( aLayer );
3549 orientation =
pad->GetOrientation();
3557 position =
via->GetPosition();
3562 spokesBox.
Inflate( thermalReliefGap +
epsilon + zone_half_width );
3569 buildSpokesFromOrigin( spokesBox,
ANGLE_0 );
3571 if( thermalSpokeAngle !=
ANGLE_0 )
3574 for(
auto it = aSpokesList.rbegin(); it != aSpokesList.rbegin() + 4; ++it )
3575 it->Rotate( thermalSpokeAngle );
3580 buildSpokesFromOrigin( spokesBox, thermalSpokeAngle );
3583 auto spokeIter = aSpokesList.rbegin();
3585 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
3587 spokeIter->Rotate( orientation );
3588 spokeIter->Move( position );
3593 for(
size_t ii = 0; ii < aSpokesList.size(); ++ii )
3594 aSpokesList[ii].GenerateBBoxCache();
3600 const std::vector<BOARD_ITEM*>& aThermalConnectionPads,
3607 for(
BOARD_ITEM* item : aThermalConnectionPads )
3609 if( !item->IsOnLayer( aLayer ) )
3614 bool isCircular =
false;
3622 pad =
static_cast<PAD*
>( item );
3624 position =
pad->ShapePos( aLayer );
3630 padRadius = std::max( padSize.
x, padSize.
y ) / 2;
3639 int spokeMaxWidth = std::min( padSize.
x, padSize.
y );
3640 spokeWidth = std::min( spokeWidth, spokeMaxWidth );
3645 position =
via->GetPosition();
3647 padRadius =
via->GetWidth( aLayer ) / 2;
3656 spokeWidth = std::min( spokeWidth, padRadius * 2 );
3664 if( spokeWidth < aZone->GetMinThickness() )
3674 int ringInnerRadius = padRadius + thermalGap;
3675 int ringWidth = spokeWidth;
3688 pad->TransformShapeToPolygon( outerShape, aLayer, thermalGap + spokeWidth,
3692 pad->TransformShapeToPolygon( innerShape, aLayer, thermalGap,
3695 thermalRing = outerShape;
3725 if( settings.
gap <= 0
3727 || ( needsLineWidth && settings.
line_width <= 0 ) )
3754 const auto& defaultOffsets =
m_board->GetDesignSettings().m_ZoneLayerProperties;
3758 if(
auto it = defaultOffsets.find( aLayer ); it != defaultOffsets.end() )
3759 offset = it->second.hatching_offset.value_or(
VECTOR2I() );
3761 if( localOffsets.contains( aLayer ) && localOffsets.at( aLayer ).hatching_offset.has_value() )
3762 offset = localOffsets.at( aLayer ).hatching_offset.value();
3777 const int dotRadius = std::max( settings.
element_size / 2 - halfMinWidth, 1 );
3778 const int maxError =
m_board->GetDesignSettings().m_MaxError;
3784 int xStart = bbox.
GetLeft() - ( bbox.
GetLeft() % dotStride ) + offset.
x;
3785 int yStart = bbox.
GetTop() - ( bbox.
GetTop() % dotStride ) + offset.
y;
3787 while( xStart > bbox.
GetLeft() )
3788 xStart -= dotStride;
3790 while( yStart > bbox.
GetTop() )
3791 yStart -= dotStride;
3820 int xVoid = bbox.
GetLeft() - ( bbox.
GetLeft() % lineStride ) + offset.
x
3822 int yVoid = bbox.
GetTop() - ( bbox.
GetTop() % lineStride ) + offset.
y
3825 while( xVoid - voidSize / 2 > bbox.
GetLeft() )
3826 xVoid -= lineStride;
3828 while( yVoid - voidSize / 2 > bbox.
GetTop() )
3829 yVoid -= lineStride;
3833 for(
int yy = yVoid; yy <= bbox.
GetBottom() + voidSize; yy += lineStride )
3835 for(
int xx = xVoid; xx <= bbox.
GetRight() + voidSize; xx += lineStride )
3838 rect.
Append( xx - voidSize / 2, yy - voidSize / 2 );
3839 rect.
Append( xx + voidSize / 2, yy - voidSize / 2 );
3840 rect.
Append( xx + voidSize / 2, yy + voidSize / 2 );
3841 rect.
Append( xx - voidSize / 2, yy + voidSize / 2 );
3866 const VECTOR2I squareSize( sideLen, sideLen );
3868 const int containmentInset =
3883 for(
int yy = yStart; yy <= bbox.
GetBottom() + dotRadius; yy += dotStride )
3885 const int rowOffset = ( settings.
stagger && ( rowIndex & 1 ) ) ? dotStride / 2 : 0;
3887 for(
int xx = xStart + rowOffset; xx <= bbox.
GetRight() + dotRadius; xx += dotStride )
3891 if( !filledRegion.
Contains( centre, -1, 0,
true ) )
3911 aFillPolys = stamps;
3932 int maxError =
m_board->GetDesignSettings().m_MaxError;
3948 hole_base.
Append( corner );
3949 corner.
x += hole_size;
3950 hole_base.
Append( corner );
3951 corner.
y += hole_size;
3952 hole_base.
Append( corner );
3954 hole_base.
Append( corner );
3974 #define SMOOTH_MIN_VAL_MM 0.02
3975 #define SMOOTH_SMALL_VAL_MM 0.04
3991 smooth_value = std::min( smooth_value, aZone->
GetHatchGap() / 2 );
3994 maxError = std::max( maxError * 2, smooth_value / 20 );
3996 switch( smooth_level )
4008 hole_base = smooth_hole.
Fillet( smooth_value, maxError ).
Outline( 0 );
4020 const auto& defaultOffsets =
m_board->GetDesignSettings().m_ZoneLayerProperties;
4025 if(
auto it = defaultOffsets.find( aLayer ); it != defaultOffsets.end() )
4026 offset = it->second.hatching_offset.value_or(
VECTOR2I() );
4028 if( localOffsets.contains( aLayer ) && localOffsets.at( aLayer ).hatching_offset.has_value() )
4029 offset = localOffsets.at( aLayer ).hatching_offset.value();
4031 int x_offset = bbox.
GetX() - ( bbox.
GetX() ) % gridsize - gridsize;
4032 int y_offset = bbox.
GetY() - ( bbox.
GetY() ) % gridsize - gridsize;
4035 for(
int xx = x_offset; xx <= bbox.
GetRight(); xx += gridsize )
4037 for(
int yy = y_offset; yy <= bbox.
GetBottom(); yy += gridsize )
4048 hole.
Move(
VECTOR2I( offset.
x % gridsize, offset.
y % gridsize ) );
4061 deflated_thickness = std::max( deflated_thickness, maxError * 2 );
4083 if( area < minimal_hole_area )
4094 BOX2I thermalBBox = aThermalRings.
BBox();
4097 for(
int holeIdx = holes.
OutlineCount() - 1; holeIdx >= 0; holeIdx-- )
4107 for(
int ringIdx = 0; ringIdx < aThermalRings.
OutlineCount(); ringIdx++ )
4114 if( !holeBBox.
Contains( ringBBox ) )
4130 if( intersections.empty() )
4152 auto cacheKey = std::make_pair(
static_cast<const ZONE*
>( aZone ), aLayer );
4162 aFillPolys = it->second;
4175 auto evalRulesForItems =
4187 bool knockoutsApplied =
false;
4191 auto collectZoneKnockout =
4192 [&](
ZONE* otherZone )
4194 if( otherZone == aZone )
4197 if( !otherZone->GetLayerSet().test( aLayer ) )
4200 if( otherZone->IsTeardropArea() && otherZone->SameNet( aZone ) )
4203 if( !otherZone->HigherPriority( aZone ) )
4206 if( !otherZone->GetBoundingBox().Intersects( zoneBBox ) )
4213 std::shared_ptr<SHAPE_POLY_SET> fillShared;
4217 auto it = aSnapshot->find( {
static_cast<const ZONE*
>( otherZone ), aLayer } );
4219 if( it == aSnapshot->end() )
4222 fillPtr = &it->second;
4226 if( !otherZone->HasFilledPolysForLayer( aLayer ) )
4229 fillShared = otherZone->GetFilledPolysList( aLayer );
4234 fillPtr = fillShared.get();
4240 if( otherZone->SameNet( aZone ) )
4242 sameNetKnockouts.
Append( *fillPtr );
4247 aZone, otherZone, aLayer ) );
4250 otherZone, aLayer ) );
4258 diffNetKnockouts.
Append( inflatedFill );
4259 knockoutsApplied =
true;
4263 forEachBoardAndFootprintZone(
m_board, collectZoneKnockout );
4277 if( knockoutsApplied )
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 );
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.
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 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 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 refillZoneFromCache(ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aFillPolys, const FillSnapshot *aSnapshot=nullptr)
Refill a zone from cached pre-knockout 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
SHAPE_POLY_SET * Outline()
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
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.
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