24#include <wx/filename.h>
27#include <unordered_map>
28#include <unordered_set>
65 RESULTS(
int aOutline1,
int aOutline2,
int aVertex1,
int aVertex2 ) :
112 SEG::ecoord min_dist = std::numeric_limits<SEG::ecoord>::max();
115 auto check_pt = [&](
VERTEX* p )
117 VECTOR2D diff( p->x - aPt->
x, p->y - aPt->
y );
120 if( dist2 > 0 && dist2 < limit2 && dist2 < min_dist && p->isEar(
true ) )
129 while( p && p->
z <= maxZ )
137 while( p && p->
z >= minZ )
152 std::set<VERTEX*> visited;
165 if( ( visited.empty() || !visited.contains( p ) ) && ( q =
getPoint( p ) ) )
169 if( !visited.contains( q ) &&
171 p->
i, q->
i ).second )
175 visited.insert( p->
prev );
177 visited.insert( p->
next );
180 visited.insert( q->
prev );
182 visited.insert( q->
next );
217struct PAD_KNOCKOUT_KEY
225 bool operator==(
const PAD_KNOCKOUT_KEY& other )
const
227 return position == other.position && effectiveSize == other.effectiveSize
228 && shape == other.shape && orientation == other.orientation
229 && netCode == other.netCode;
233struct PAD_KNOCKOUT_KEY_HASH
235 size_t operator()(
const PAD_KNOCKOUT_KEY& key )
const
237 return hash_val( key.position.
x, key.position.
y, key.effectiveSize.
x, key.effectiveSize.
y,
238 key.shape, key.orientation.
AsDegrees(), key.netCode );
245struct VIA_KNOCKOUT_KEY
251 bool operator==(
const VIA_KNOCKOUT_KEY& other )
const
253 return position == other.position && effectiveSize == other.effectiveSize
254 && netCode == other.netCode;
258struct VIA_KNOCKOUT_KEY_HASH
260 size_t operator()(
const VIA_KNOCKOUT_KEY& key )
const
262 return hash_val( key.position.
x, key.position.
y, key.effectiveSize, key.netCode );
268struct TRACK_KNOCKOUT_KEY
274 TRACK_KNOCKOUT_KEY(
const VECTOR2I& aStart,
const VECTOR2I& aEnd,
int aWidth ) :
278 if( aStart.
x < aEnd.
x || ( aStart.
x == aEnd.
x && aStart.
y <= aEnd.
y ) )
290 bool operator==(
const TRACK_KNOCKOUT_KEY& other )
const
292 return start == other.start && end == other.end && width == other.width;
296struct TRACK_KNOCKOUT_KEY_HASH
298 size_t operator()(
const TRACK_KNOCKOUT_KEY& key )
const
300 return hash_val( key.start.
x, key.start.
y, key.end.
x, key.end.
y, key.width );
304template<
typename Func>
305void forEachBoardAndFootprintZone(
BOARD* aBoard, Func&& aFunc )
312 for(
ZONE* zone : footprint->Zones() )
376 std::lock_guard<KISPINLOCK> lock(
m_board->GetConnectivity()->GetLock() );
386 std::shared_ptr<DRC_ENGINE> drcEngine = std::make_shared<DRC_ENGINE>(
m_board, &bds );
390 drcEngine->InitEngine( wxFileName(
m_board->GetDesignRulesPath() ) );
403 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
404 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
HASH_128> oldFillHashes;
405 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> isolatedIslandsMap;
407 std::shared_ptr<CONNECTIVITY_DATA> connectivity =
m_board->GetConnectivity();
414 connectivity->ClearRatsnest();
422 :
_(
"Building zone fills..." ) );
435 zone->CacheBoundingBox();
439 for(
PAD*
pad : footprint->Pads() )
443 pad->BuildEffectiveShapes();
448 for(
ZONE* zone : footprint->Zones() )
449 zone->CacheBoundingBox();
452 footprint->BuildCourtyardCaches();
453 footprint->BuildNetTieCache();
460 std::unordered_map<const ZONE*, POLY_YSTRIPES_INDEX> zoneOutlineIndices;
464 if( zone->GetNumCorners() <= 2 )
467 zoneOutlineIndices[zone].Build( zone->GetBoardOutline() );
474 auto findHighestPriorityZone =
476 const std::function<bool(
const ZONE* )>& testFn ) ->
ZONE*
478 unsigned highestSameNetPriority = 0;
479 ZONE* highestSameNetZone =
nullptr;
480 unsigned highestPriority = 0;
481 ZONE* highestPriorityZone =
nullptr;
486 if( zone->GetIsRuleArea() )
489 if( !zone->IsOnLayer( itemLayer ) )
492 const unsigned priority = zone->GetAssignedPriority();
493 const bool sameNet = zone->GetNetCode() == netcode;
498 if( highestSameNetZone && priority < highestSameNetPriority )
501 else if( highestPriorityZone && priority < highestPriority )
507 if( zone->GetNumCorners() <= 2 )
510 if( !zone->GetBoundingBox().Intersects( bbox ) )
513 if( !testFn( zone ) )
517 && ( !highestSameNetZone || priority > highestSameNetPriority ) )
519 highestSameNetPriority = priority;
520 highestSameNetZone = zone;
523 if( !highestPriorityZone || priority > highestPriority )
525 highestPriority = priority;
526 highestPriorityZone = zone;
530 return highestSameNetZone ? highestSameNetZone : highestPriorityZone;
533 auto isInPourKeepoutArea =
538 if( !zone->GetIsRuleArea() )
541 if( !zone->HasKeepoutParametersSet() )
544 if( !zone->GetDoNotAllowZoneFills() )
547 if( !zone->IsOnLayer( itemLayer ) )
551 if( zone->GetNumCorners() <= 2 )
554 if( !zone->GetBoundingBox().Intersects( bbox ) )
557 auto it = zoneOutlineIndices.find( zone );
559 if( it != zoneOutlineIndices.end() && it->second.Contains( testPoint ) )
576 via->ClearZoneLayerOverrides();
578 if( !
via->GetRemoveUnconnected() )
583 int holeRadius =
via->GetDrillValue() / 2 + 1;
584 int netcode =
via->GetNetCode();
585 LSET layers =
via->GetLayerSet() & boardCuMask;
588 auto viaTestFn = [&](
const ZONE* aZone ) ->
bool
595 if( !
via->ConditionallyFlashed( layer ) )
598 if( isInPourKeepoutArea( bbox, layer,
center ) )
604 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, viaTestFn );
609 || layer == padstack.
Drill().
end ) )
625 for(
PAD*
pad : footprint->Pads() )
627 pad->ClearZoneLayerOverrides();
629 if( !
pad->GetRemoveUnconnected() )
634 int netcode =
pad->GetNetCode();
635 LSET layers =
pad->GetLayerSet() & boardCuMask;
638 [&](
const ZONE* aZone ) ->
bool
640 auto it = zoneOutlineIndices.find( aZone );
642 if( it != zoneOutlineIndices.end() )
643 return it->second.Contains(
center );
650 if( !
pad->ConditionallyFlashed( layer ) )
653 if( isInPourKeepoutArea( bbox, layer,
center ) )
659 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, padTestFn );
670 for(
ZONE* zone : aZones )
673 if( zone->GetIsRuleArea() )
677 if( zone->GetNumCorners() <= 2 )
687 zone->BuildHashValue( layer );
688 oldFillHashes[ { zone, layer } ] = zone->GetHashValue( layer );
691 toFill.emplace_back( std::make_pair( zone, layer ) );
696 if( !zone->IsCopperThieving() )
704 auto zone_fill_dependency =
706 bool aRequireCompletedOtherFill ) ->
bool
713 if( aRequireCompletedOtherFill && aOtherZone->GetFillFlag( aLayer ) )
718 if( aOtherZone->GetIsRuleArea() )
722 if( aOtherZone->GetNumCorners() <= 2 )
726 if( !aOtherZone->GetLayerSet().test( aLayer ) )
733 if( aOtherZone->SameNet( aZone ) )
741 if( !inflatedBBox.
Intersects( aOtherZone->GetBoundingBox() ) )
749 auto check_fill_dependency =
752 return zone_fill_dependency( aZone, aLayer, aOtherZone,
true );
755 auto fill_item_dependency =
756 [&](
const std::pair<ZONE*, PCB_LAYER_ID>& aWaiter,
757 const std::pair<ZONE*, PCB_LAYER_ID>& aDependency ) ->
bool
759 if( aWaiter.first == aDependency.first || aWaiter.second != aDependency.second )
762 return check_fill_dependency( aWaiter.first, aWaiter.second, aDependency.first );
766 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
772 ZONE* zone = aFillItem.first;
787 auto tesselate_lambda =
788 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
794 ZONE* zone = aFillItem.first;
803 std::atomic<bool> cancelled =
false;
805 auto waitForFutures =
806 [&]( std::vector<std::future<int>>& aFutures, std::vector<int>* aResults = nullptr )
811 for(
auto& future : aFutures )
813 while( future.wait_for( std::chrono::milliseconds( 100 ) )
814 != std::future_status::ready )
825 int result = future.get();
828 aResults->push_back(
result );
834 std::vector<std::vector<size_t>> successors;
835 std::vector<int> inDegree;
836 std::vector<size_t> currentWave;
839 auto build_fill_dag = [&](
const std::vector<std::pair<ZONE*, PCB_LAYER_ID>>& aFillItems,
auto&& aHasDependency,
840 bool aAnyDependencies ) -> FILL_DAG
844 dag.successors.resize( aFillItems.size() );
845 dag.inDegree.assign( aFillItems.size(), 0 );
846 dag.currentWave.reserve( aFillItems.size() );
850 if( aAnyDependencies )
852 for(
size_t i = 0; i < aFillItems.size(); ++i )
854 for(
size_t j = 0; j < aFillItems.size(); ++j )
859 if( aHasDependency( aFillItems[j], aFillItems[i] ) )
861 dag.successors[i].push_back( j );
868 for(
size_t i = 0; i < aFillItems.size(); ++i )
870 if( dag.inDegree[i] == 0 )
871 dag.currentWave.push_back( i );
877 auto run_fill_waves = [&](
const std::vector<std::pair<ZONE*, PCB_LAYER_ID>>& aFillItems,
auto&& aFillFn,
878 auto&& aTessFn,
auto&& aHasDependency,
bool aAnyDependencies )
880 FILL_DAG dag = build_fill_dag( aFillItems, aHasDependency, aAnyDependencies );
882 while( !dag.currentWave.empty() && !cancelled.load() )
884 std::vector<std::future<int>> fillFutures;
885 std::vector<int> fillResults;
887 fillFutures.reserve( dag.currentWave.size() );
889 for(
size_t idx : dag.currentWave )
891 fillFutures.emplace_back(
tp.submit_task(
892 [&aFillFn, &aFillItems, idx]()
894 return aFillFn( aFillItems[idx] );
898 waitForFutures( fillFutures, &fillResults );
900 std::vector<std::future<int>> tessFutures;
902 tessFutures.reserve( dag.currentWave.size() );
904 for(
size_t ii = 0; ii < fillResults.size(); ++ii )
906 if( fillResults[ii] == 0 )
909 size_t idx = dag.currentWave[ii];
911 tessFutures.emplace_back(
tp.submit_task(
912 [&aTessFn, &aFillItems, idx]()
914 return aTessFn( aFillItems[idx] );
918 waitForFutures( tessFutures );
920 if( cancelled.load() )
923 std::vector<size_t> nextWave;
925 for(
size_t idx : dag.currentWave )
927 for(
size_t succ : dag.successors[idx] )
929 if( --dag.inDegree[succ] == 0 )
930 nextWave.push_back( succ );
934 dag.currentWave = std::move( nextWave );
938 run_fill_waves( toFill, fill_lambda, tesselate_lambda, fill_item_dependency,
true );
953 connectivity->FillIsolatedIslandsMap( isolatedIslandsMap );
954 connectivity->SetProgressReporter(
nullptr );
959 for(
ZONE* zone : aZones )
962 if( zone->GetIsRuleArea() )
965 zone->SetIsFilled(
true );
974 std::set<std::pair<ZONE*, PCB_LAYER_ID>> zonesWithRemovedIslandLayers;
981 std::set<std::pair<ZONE*, PCB_LAYER_ID>> initiallyFullyIsolatedLayers;
983 for(
const auto& [ zone, zoneIslands ] : isolatedIslandsMap )
987 bool allLayersFullyIsolated =
true;
989 for(
const auto& [ layer, layerIslands ] : zoneIslands )
991 bool layerFullyIsolated = ( layerIslands.m_IsolatedOutlines.size()
992 ==
static_cast<size_t>( zone->GetFilledPolysList( layer )->OutlineCount() ) );
994 if( layerFullyIsolated )
995 initiallyFullyIsolatedLayers.insert( { zone, layer } );
997 allLayersFullyIsolated =
false;
1000 if( allLayersFullyIsolated )
1003 for(
const auto& [ layer, layerIslands ] : zoneIslands )
1008 if( layerIslands.m_IsolatedOutlines.empty() )
1011 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
1015 std::sort( islands.begin(), islands.end(), std::greater<int>() );
1017 std::shared_ptr<SHAPE_POLY_SET> poly = zone->GetFilledPolysList( layer );
1018 long long int minArea = zone->GetMinIslandArea();
1021 for(
int idx : islands )
1027 poly->DeletePolygonAndTriangulationData( idx,
false );
1028 zonesWithRemovedIslandLayers.insert( { zone, layer } );
1032 poly->DeletePolygonAndTriangulationData( idx,
false );
1033 zonesWithRemovedIslandLayers.insert( { zone, layer } );
1037 zone->SetIsIsland( layer, idx );
1041 poly->UpdateTriangulationDataHash();
1042 zone->CalculateFilledArea();
1062 std::set<std::pair<ZONE*, PCB_LAYER_ID>> sameNetOverlapSeeds;
1064 if( iterativeRefill )
1069 std::map<int, std::vector<ZONE*>> zonesByNet;
1071 forEachBoardAndFootprintZone(
1076 zonesByNet[zone->
GetNetCode()].push_back( zone );
1079 for(
ZONE* lowerZone : aZones )
1081 if( lowerZone->GetIsRuleArea() || lowerZone->IsTeardropArea() )
1084 auto netIt = zonesByNet.find( lowerZone->GetNetCode() );
1086 if( netIt == zonesByNet.end() )
1089 LSET lowerLayers = lowerZone->GetLayerSet() & boardCu;
1091 for(
ZONE* higherZone : netIt->second )
1093 if( higherZone == lowerZone
1097 if( !lowerZone->GetBoundingBox().Intersects( higherZone->
GetBoundingBox() ) )
1106 if( lowerZone->HasFilledPolysForLayer( layer )
1109 sameNetOverlapSeeds.insert( { lowerZone, layer } );
1117 && ( !zonesWithRemovedIslandLayers.empty() || !sameNetOverlapSeeds.empty() ) )
1119 const int maxIterations = 8;
1120 bool progressReported =
false;
1121 bool hitIterationLimit =
false;
1124 std::set<std::pair<ZONE*, PCB_LAYER_ID>> changedZoneLayers( zonesWithRemovedIslandLayers );
1125 changedZoneLayers.insert( sameNetOverlapSeeds.begin(), sameNetOverlapSeeds.end() );
1127 auto cached_refill_tessellate_lambda = [&](
const std::pair<ZONE*, PCB_LAYER_ID>& aFillItem ) ->
int
1129 ZONE* zone = aFillItem.first;
1136 auto no_dependency = [](
const std::pair<ZONE*, PCB_LAYER_ID>&,
const std::pair<ZONE*, PCB_LAYER_ID>& ) ->
bool
1141 for(
int iteration = 0; iteration < maxIterations; ++iteration )
1146 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zonesToRefill;
1147 std::set<std::pair<ZONE*, PCB_LAYER_ID>> zonesToRefillSet;
1149 for(
const auto& [changedZone, changedLayer] : changedZoneLayers )
1151 BOX2I bbox = changedZone->GetBoundingBox();
1154 for(
ZONE* zone : aZones )
1156 if( zone->GetIsRuleArea() )
1159 if( !zone->GetLayerSet().test( changedLayer ) )
1175 if( zone != changedZone && !changedZone->HigherPriority( zone ) && !changedZone->SameNet( zone ) )
1180 if( !zone->GetBoundingBox().Intersects( bbox ) )
1183 auto fillItem = std::make_pair( zone, changedLayer );
1185 if( zonesToRefillSet.insert( fillItem ).second )
1186 zonesToRefill.push_back( fillItem );
1190 if( zonesToRefill.empty() )
1193 if( !progressReported )
1202 progressReported =
true;
1208 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
HASH_128> iterHashes;
1210 for(
const auto& fillItem : zonesToRefill )
1212 fillItem.first->BuildHashValue( fillItem.second );
1213 iterHashes[fillItem] = fillItem.first->GetHashValue( fillItem.second );
1224 LSET snapshotLayers;
1226 for(
const auto& [zone, layer] : zonesToRefill )
1227 snapshotLayers.
set( layer );
1231 forEachBoardAndFootprintZone(
m_board,
1248 if( sp && sp->OutlineCount() > 0 )
1249 snapshot[{ zone, layer }] = sp->CloneDropTriangulation();
1253 auto cached_refill_fill_lambda =
1254 [&](
const std::pair<ZONE*, PCB_LAYER_ID>& aFillItem ) ->
int
1256 ZONE* zone = aFillItem.first;
1268 run_fill_waves( zonesToRefill, cached_refill_fill_lambda, cached_refill_tessellate_lambda, no_dependency,
1274 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> refillIslandsMap;
1276 for(
const auto& [zone, layer] : zonesToRefill )
1290 connectivity->FillIsolatedIslandsMap( refillIslandsMap );
1292 for(
const auto& [zone, zoneIslands] : refillIslandsMap )
1294 for(
const auto& [layer, layerIslands] : zoneIslands )
1299 if( layerIslands.m_IsolatedOutlines.empty() )
1304 if( initiallyFullyIsolatedLayers.count( { zone, layer } ) > 0 )
1306 if( layerIslands.m_IsolatedOutlines.size()
1313 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
1314 std::sort( islands.begin(), islands.end(), std::greater<int>() );
1320 for(
int idx : islands )
1325 poly->DeletePolygonAndTriangulationData( idx,
false );
1327 poly->DeletePolygonAndTriangulationData( idx,
false );
1332 poly->UpdateTriangulationDataHash();
1340 changedZoneLayers.clear();
1342 for(
const auto& fillItem : zonesToRefill )
1344 fillItem.first->BuildHashValue( fillItem.second );
1346 auto hashIt = iterHashes.find( fillItem );
1347 HASH_128 oldHash = ( hashIt != iterHashes.end() ) ? hashIt->second :
HASH_128{};
1349 if( fillItem.first->GetHashValue( fillItem.second ) != oldHash )
1350 changedZoneLayers.insert( fillItem );
1353 if( changedZoneLayers.empty() )
1356 if( iteration + 1 >= maxIterations )
1358 hitIterationLimit =
true;
1363 if( hitIterationLimit )
1365 wxString msg = wxString::Format(
_(
"Zone fills may be incorrect: iterative refill did not converge "
1366 "after %d passes.\n\n"
1367 "This can happen with complex overlapping zones. "
1368 "Consider simplifying your zones." ),
1373 KIDIALOG dlg( aParent, msg,
_(
"Warning" ), wxOK | wxICON_WARNING );
1379 wxLogWarning( msg );
1386 using island_check_return = std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
int>>;
1388 std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
double>> polys_to_check;
1391 polys_to_check.reserve(
m_board->GetCopperLayerCount() * aZones.size() );
1393 for(
ZONE* zone : aZones )
1403 double minArea = (double) zone->GetMinThickness() * zone->GetMinThickness() * 3;
1410 polys_to_check.emplace_back( zone->GetFilledPolysList( layer ), minArea );
1414 auto island_lambda =
1415 [&](
int aStart,
int aEnd ) -> island_check_return
1417 island_check_return retval;
1419 for(
int ii = aStart; ii < aEnd && !cancelled.load(); ++ii )
1421 auto [poly, minArea] = polys_to_check[ii];
1423 for(
int jj = poly->OutlineCount() - 1; jj >= 0; jj-- )
1428 double island_area = test_poly.
Area();
1430 if( island_area < minArea )
1442 if( intersection.
Area() < island_area / 2.0 )
1443 retval.emplace_back( poly, jj );
1450 auto island_returns =
tp.submit_blocks( 0, polys_to_check.size(), island_lambda );
1454 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
1456 std::future<island_check_return>& ret = island_returns[ii];
1460 std::future_status status = ret.wait_for( std::chrono::seconds( 0 ) );
1462 while( status != std::future_status::ready )
1472 status = ret.wait_for( std::chrono::milliseconds( 100 ) );
1477 if( cancelled.load() )
1480 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
1482 std::future<island_check_return>& ret = island_returns[ii];
1486 for(
auto& action_item : ret.get() )
1487 action_item.first->DeletePolygonAndTriangulationData( action_item.second,
true );
1491 for(
ZONE* zone : aZones )
1492 zone->CalculateFilledArea();
1505 std::unique_ptr<POLY_YSTRIPES_INDEX>
index;
1508 struct NET_LAYER_HASH
1510 size_t operator()(
const std::pair<int, PCB_LAYER_ID>& k )
const
1512 return std::hash<int>()( k.first ) ^ ( std::hash<int>()( k.second ) << 16 );
1516 std::unordered_map<std::pair<int, PCB_LAYER_ID>, std::vector<INDEXED_ZONE>, NET_LAYER_HASH>
1517 filledZonesByNetLayer;
1521 if( zone->GetIsRuleArea() )
1526 if( !zone->HasFilledPolysForLayer( layer ) )
1529 const std::shared_ptr<SHAPE_POLY_SET>& fill = zone->GetFilledPolysList( layer );
1531 if( fill->IsEmpty() )
1535 iz.bbox = fill->BBox();
1536 iz.index = std::make_unique<POLY_YSTRIPES_INDEX>();
1537 iz.index->Build( *fill );
1538 filledZonesByNetLayer[{ zone->GetNetCode(), layer }].push_back( std::move( iz ) );
1542 auto zoneReachesPoint =
1545 auto it = filledZonesByNetLayer.find( { aNetcode, aLayer } );
1547 if( it == filledZonesByNetLayer.end() )
1550 for(
const INDEXED_ZONE& iz : it->second )
1552 if( !iz.bbox.GetInflated( aRadius ).Contains( aCenter ) )
1555 if( iz.index->Contains( aCenter, aRadius ) )
1569 int holeRadius =
via->GetDrillValue() / 2;
1570 int netcode =
via->GetNetCode();
1571 LSET layers =
via->GetLayerSet() & boardCuMask;
1578 if( !zoneReachesPoint( netcode, layer,
center, holeRadius ) )
1585 for(
PAD*
pad : footprint->Pads() )
1588 int netcode =
pad->GetNetCode();
1589 LSET layers =
pad->GetLayerSet() & boardCuMask;
1593 if(
pad->HasHole() )
1594 holeRadius = std::min(
pad->GetDrillSizeX(),
pad->GetDrillSizeY() ) / 2;
1601 if( !zoneReachesPoint( netcode, layer,
center, holeRadius ) )
1609 bool outOfDate =
false;
1611 for(
ZONE* zone : aZones )
1614 if( zone->GetIsRuleArea() )
1619 zone->BuildHashValue( layer );
1621 if( oldFillHashes[ { zone, layer } ] != zone->GetHashValue( layer ) )
1627 &&
m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill ) )
1629 KIDIALOG dlg( aParent,
_(
"Prototype zone fill enabled. Disable setting and refill?" ),
_(
"Confirmation" ),
1630 wxOK | wxCANCEL | wxICON_WARNING );
1636 m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill =
false;
1638 else if( !outOfDate )
1646 KIDIALOG dlg( aParent,
_(
"Zone fills are out-of-date. Refill?" ),
_(
"Confirmation" ),
1647 wxOK | wxCANCEL | wxICON_WARNING );
1690 std::vector<VECTOR2I> convex_hull;
1695 for(
const VECTOR2I& pt : convex_hull )
1727 switch( aItem->
Type() )
1734 if(
text->IsVisible() )
1736 if(
text->IsKnockout() )
1791 std::vector<BOARD_ITEM*>& aThermalConnectionPads,
1792 std::vector<PAD*>& aNoConnectionPads,
1793 std::vector<BOARD_ITEM*>& aSolidConnectionItems )
1799 std::shared_ptr<SHAPE> padShape;
1804 std::unordered_set<PAD_KNOCKOUT_KEY, PAD_KNOCKOUT_KEY_HASH> processedPads;
1805 std::unordered_set<VIA_KNOCKOUT_KEY, VIA_KNOCKOUT_KEY_HASH> processedVias;
1809 for(
PAD*
pad : footprint->Pads() )
1815 &&
pad->GetDrillSize().x > 0;
1817 if( !
pad->IsOnLayer( aLayer ) && !npthWithHole )
1820 BOX2I padBBox =
pad->GetBoundingBox();
1837 int drill = std::max(
pad->GetDrillSize().x,
pad->GetDrillSize().y );
1838 int maxDim = std::max( { padSize.
x, padSize.
y, drill } );
1839 effectiveSize =
VECTOR2I( maxDim, maxDim );
1843 effectiveSize = padSize;
1846 PAD_KNOCKOUT_KEY padKey{
pad->GetPosition(), effectiveSize,
1847 static_cast<int>( padShapeType ),
1848 pad->GetOrientation(),
pad->GetNetCode() };
1850 if( !processedPads.insert( padKey ).second )
1854 bool noConnection =
pad->GetNetCode() != aZone->
GetNetCode();
1861 noConnection =
true;
1866 if(
pad->IsBackdrilledOrPostMachined( aLayer ) )
1867 noConnection =
true;
1872 aNoConnectionPads.push_back(
pad );
1887 switch( connection )
1893 if( aFill.
Collide( padShape.get(), 0 ) )
1901 aThermalConnectionPads.push_back(
pad );
1910 aNoConnectionPads.push_back(
pad );
1935 switch( connection )
1940 if( aFill.
Collide( padShape.get(), 0 ) )
1945 aThermalConnectionPads.push_back(
pad );
1959 if(
pad->FlashLayer( aLayer ) )
1963 else if(
pad->GetDrillSize().x > 0 )
1970 holeClearance = padClearance;
1996 if( !
via->IsOnLayer( aLayer ) )
1999 BOX2I viaBBox =
via->GetBoundingBox();
2006 int viaEffectiveSize = std::max(
via->GetDrillValue(),
via->GetWidth( aLayer ) );
2007 VIA_KNOCKOUT_KEY viaKey{
via->GetPosition(), viaEffectiveSize,
via->GetNetCode() };
2009 if( !processedVias.insert( viaKey ).second )
2012 bool noConnection =
via->GetNetCode() != aZone->
GetNetCode()
2014 && aLayer !=
via->Padstack().Drill().start
2015 && aLayer !=
via->Padstack().Drill().end );
2018 noConnection =
true;
2021 if(
via->IsBackdrilledOrPostMachined( aLayer ) )
2023 noConnection =
true;
2035 pmSize = std::max( pmSize, frontPM.
size );
2041 pmSize = std::max( pmSize, backPM.
size );
2047 bdSize = secDrill.
size.
x;
2049 int knockoutSize = std::max( pmSize, bdSize );
2051 if( knockoutSize > 0 )
2066 switch( connection )
2076 if( thermalGap > 0 )
2078 aThermalConnectionPads.push_back(
via );
2093 aSolidConnectionItems.push_back(
via );
2108 const std::vector<PAD*>& aNoConnectionPads,
2110 bool aIncludeZoneClearances )
2116 std::unordered_set<PAD_KNOCKOUT_KEY, PAD_KNOCKOUT_KEY_HASH> processedPads;
2117 std::unordered_set<VIA_KNOCKOUT_KEY, VIA_KNOCKOUT_KEY_HASH> processedVias;
2118 std::unordered_set<TRACK_KNOCKOUT_KEY, TRACK_KNOCKOUT_KEY_HASH> processedTracks;
2120 auto checkForCancel =
2123 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
2136 auto evalRulesForItems =
2150 auto knockoutPadClearance =
2155 bool hasHole = aPad->GetDrillSize().x > 0;
2156 bool flashLayer = aPad->FlashLayer( aLayer );
2159 if( flashLayer || platedHole )
2164 if( flashLayer && gap >= 0 )
2165 addKnockout( aPad, aLayer, gap + extra_margin, aHoles );
2180 && aPad->GetDrillSize().x != aPad->GetDrillSize().y )
2191 if( aPad->IsBackdrilledOrPostMachined( aLayer ) )
2202 pmSize = std::max( pmSize, frontPM.
size );
2208 pmSize = std::max( pmSize, backPM.
size );
2214 bdSize = secDrill.
size.
x;
2216 int knockoutSize = std::max( pmSize, bdSize );
2218 if( knockoutSize > 0 )
2220 int clearance = std::max( gap, 0 ) + extra_margin;
2228 for(
PAD*
pad : aNoConnectionPads )
2244 int drill = std::max(
pad->GetDrillSize().x,
pad->GetDrillSize().y );
2245 int maxDim = std::max( { padSize.
x, padSize.
y, drill } );
2246 effectiveSize =
VECTOR2I( maxDim, maxDim );
2250 effectiveSize = padSize;
2253 PAD_KNOCKOUT_KEY padKey{
pad->GetPosition(), effectiveSize,
2254 static_cast<int>( padShape ),
pad->GetOrientation(),
2255 pad->GetNetCode() };
2257 if( !processedPads.insert( padKey ).second )
2261 knockoutPadClearance(
pad );
2266 auto knockoutTrackClearance =
2269 if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
2271 bool sameNet = aTrack->GetNetCode() == aZone->
GetNetCode();
2293 if(
via->FlashLayer( aLayer ) && gap > 0 )
2295 via->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
m_maxError,
2314 if(
via->IsBackdrilledOrPostMachined( aLayer ) )
2325 pmSize = std::max( pmSize, frontPM.
size );
2331 pmSize = std::max( pmSize, backPM.
size );
2337 bdSize = secDrill.
size.
x;
2339 int knockoutSize = std::max( pmSize, bdSize );
2341 if( knockoutSize > 0 )
2343 int clearance = std::max( gap, 0 ) + extra_margin;
2354 aTrack->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
m_maxError,
2363 if( !track->IsOnLayer( aLayer ) )
2373 int viaEffectiveSize = std::max(
via->GetDrillValue(),
via->GetWidth( aLayer ) );
2374 VIA_KNOCKOUT_KEY viaKey{
via->GetPosition(), viaEffectiveSize,
via->GetNetCode() };
2376 if( !processedVias.insert( viaKey ).second )
2381 TRACK_KNOCKOUT_KEY trackKey( track->GetStart(), track->GetEnd(), track->GetWidth() );
2383 if( !processedTracks.insert( trackKey ).second )
2387 knockoutTrackClearance( track );
2392 auto knockoutGraphicClearance =
2398 shapeNet =
static_cast<PCB_SHAPE*
>( aItem )->GetNetCode();
2400 bool sameNet = shapeNet == aZone->
GetNetCode();
2406 if( aItem->IsOnLayer( aLayer )
2408 || aItem->IsOnLayer(
Margin ) )
2410 if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
2412 bool ignoreLineWidths =
false;
2415 if( aItem->IsOnLayer( aLayer ) && !sameNet )
2419 else if( aItem->IsOnLayer(
Edge_Cuts ) )
2422 ignoreLineWidths =
true;
2424 else if( aItem->IsOnLayer(
Margin ) )
2431 gap += extra_margin;
2432 addKnockout( aItem, aLayer, gap, ignoreLineWidths, aHoles );
2438 auto knockoutCourtyardClearance =
2441 if( aFootprint->GetBoundingBox().Intersects( zone_boundingbox ) )
2452 aHoles.
Append( aFootprint->GetCourtyard( courtyardSide ) );
2465 knockoutCourtyardClearance( footprint );
2466 knockoutGraphicClearance( &footprint->Reference() );
2467 knockoutGraphicClearance( &footprint->Value() );
2469 std::set<PAD*> allowedNetTiePads;
2473 if( footprint->IsNetTie() )
2475 for(
PAD*
pad : footprint->Pads() )
2484 if(
pad->IsOnLayer( aLayer ) )
2485 allowedNetTiePads.insert(
pad );
2487 for(
PAD* other : footprint->GetNetTiePads(
pad ) )
2489 if( other->IsOnLayer( aLayer ) )
2490 allowedNetTiePads.insert( other );
2496 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
2501 BOX2I itemBBox = item->GetBoundingBox();
2503 if( !zone_boundingbox.
Intersects( itemBBox ) )
2506 bool skipItem =
false;
2508 if( item->IsOnLayer( aLayer ) )
2510 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape();
2512 for(
PAD*
pad : allowedNetTiePads )
2514 if(
pad->GetBoundingBox().Intersects( itemBBox )
2515 &&
pad->GetEffectiveShape( aLayer )->Collide( itemShape.get() ) )
2524 knockoutGraphicClearance( item );
2533 knockoutGraphicClearance( item );
2538 auto knockoutZoneClearance =
2539 [&](
ZONE* aKnockout )
2542 if( !aKnockout->GetLayerSet().test( aLayer ) )
2545 if( aKnockout->GetBoundingBox().Intersects( zone_boundingbox ) )
2547 if( aKnockout->GetIsRuleArea() )
2549 if( aKnockout->GetDoNotAllowZoneFills() && !aZone->
IsTeardropArea() )
2558 if( aKnockout->HigherPriority( aZone ) && !aKnockout->SameNet( aZone ) )
2570 aKnockout->TransformShapeToPolygon( poly, aLayer, gap + extra_margin,
m_maxError,
2578 if( aIncludeZoneClearances )
2585 knockoutZoneClearance( otherZone );
2590 for(
ZONE* otherZone : footprint->Zones() )
2595 knockoutZoneClearance( otherZone );
2616 auto evalRulesForItems =
2632 auto knockoutZoneClearance =
2633 [&](
ZONE* aKnockout )
2635 if( aKnockout->GetIsRuleArea() )
2638 if( !aKnockout->GetLayerSet().test( aLayer ) )
2641 if( aKnockout->GetBoundingBox().Intersects( zone_boundingbox ) )
2643 if( aKnockout->HigherPriority( aZone ) && !aKnockout->SameNet( aZone ) )
2646 aZone, aKnockout, aLayer ) );
2649 aKnockout, aLayer ) );
2655 aKnockout->TransformShapeToPolygon( poly, aLayer, gap + extra_margin,
2662 forEachBoardAndFootprintZone(
m_board, knockoutZoneClearance );
2678 auto collectZoneOutline =
2679 [&](
ZONE* aKnockout )
2681 if( !aKnockout->GetLayerSet().test( aLayer ) )
2684 if( aKnockout->GetBoundingBox().Intersects( zoneBBox ) )
2685 appendZoneOutlineWithoutArcs( aKnockout, knockouts );
2688 forEachBoardAndFootprintZone(
2690 [&](
ZONE* otherZone )
2694 bool higherPrioritySameNet =
2699 collectZoneOutline( otherZone );
2718 std::map<int, std::vector<std::pair<int, VECTOR2I>>> insertion_points;
2730 insertion_points[
result.m_outline1].push_back( {
result.m_vertex1, pt1 } );
2731 insertion_points[
result.m_outline1].push_back( {
result.m_vertex1, pt2 } );
2734 for(
auto& [outline, vertices] : insertion_points )
2742 std::stable_sort( vertices.begin(), vertices.end(),
2743 [](
const std::pair<int, VECTOR2I>& a,
const std::pair<int, VECTOR2I>& b )
2745 return a.first > b.first;
2748 for(
const auto& [vertex, pt] : vertices )
2749 line.
Insert( vertex + 1, pt );
2770 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
2772 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
2773 BOX2I islandExtents;
2775 for(
const VECTOR2I& pt : island.front().CPoints() )
2777 islandExtents.
Merge( pt );
2793#define DUMP_POLYS_TO_COPPER_LAYER( a, b, c ) \
2794 { if( m_debugZoneFiller && aDebugLayer == b ) \
2796 m_board->SetLayerName( b, c ); \
2797 SHAPE_POLY_SET d = a; \
2837 std::vector<BOARD_ITEM*> thermalConnectionPads;
2838 std::vector<PAD*> noConnectionPads;
2839 std::vector<BOARD_ITEM*> solidConnectionItems;
2840 std::deque<SHAPE_LINE_CHAIN> thermalSpokes;
2843 aFillPolys = aSmoothedOutline;
2853 knockoutThermalReliefs( aZone, aLayer, aFillPolys, thermalConnectionPads, noConnectionPads, solidConnectionItems );
2870 aFillPolys, thermalRings );
2892 if( iterativeRefill )
2895 bool addedKeepoutHoles =
false;
2897 auto collectKeepoutHoles =
2898 [&](
ZONE* candidate )
2903 if( !isZoneFillKeepout( candidate, aLayer, zone_boundingbox ) )
2906 candidate->TransformSmoothedOutlineToPolygon( clearanceHoles, 0,
m_maxError,
2908 addedKeepoutHoles =
true;
2911 forEachBoardAndFootprintZone(
m_board, collectKeepoutHoles );
2913 if( addedKeepoutHoles )
2942 if( iterativeRefill )
2968 spokeTestIndex.
Build( testAreas );
2975 const VECTOR2I& testPt = spoke.CPoint( 3 );
2978 if( spokeTestIndex.
Contains( testPt, 1 ) )
2987 if( interval++ > 400 )
3000 if( &other != &spoke
3001 && other.PointInside( testPt, 1 )
3002 && spoke.PointInside( other.CPoint( 3 ), 1 ) )
3038 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
3040 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
3041 BOX2I islandExtents;
3043 for(
const VECTOR2I& pt : island.front().CPoints() )
3045 islandExtents.
Merge( pt );
3066 || !
m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill ) )
3075 for(
BOARD_ITEM* item : solidConnectionItems )
3077 if( item->Type() !=
PCB_VIA_T || !item->IsOnLayer( aLayer ) )
3131 for(
BOARD_ITEM* item : thermalConnectionPads )
3145 bool knockoutsApplied =
false;
3147 if( iterativeRefill )
3158 knockoutsApplied =
true;
3171 if( knockoutsApplied )
3196 auto checkForCancel =
3199 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
3202 auto knockoutGraphicItem =
3205 if( aItem->IsKnockout() && aItem->IsOnLayer( aLayer )
3206 && aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
3208 addKnockout( aItem, aLayer, 0,
true, clearanceHoles );
3217 knockoutGraphicItem( &footprint->Reference() );
3218 knockoutGraphicItem( &footprint->Value() );
3220 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
3221 knockoutGraphicItem( item );
3229 knockoutGraphicItem( item );
3232 aFillPolys = aSmoothedOutline;
3237 auto collectKeepout =
3238 [&](
ZONE* candidate )
3240 if( !isZoneFillKeepout( candidate, aLayer, zone_boundingbox ) )
3243 appendZoneOutlineWithoutArcs( candidate, keepoutHoles );
3246 bool cancelledKeepoutScan =
false;
3248 forEachBoardAndFootprintZone(
3250 [&](
ZONE* keepout )
3252 if( cancelledKeepoutScan )
3257 cancelledKeepoutScan =
true;
3261 collectKeepout( keepout );
3264 if( cancelledKeepoutScan )
3315 debugLayer = aLayer;
3319 if( !aZone->
BuildSmoothedPoly( maxExtents, aLayer, boardOutline, &smoothedPoly ) )
3327 if(
fillCopperZone( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aFillPolys ) )
3344 const std::vector<BOARD_ITEM*>& aSpokedPadsList,
3345 std::deque<SHAPE_LINE_CHAIN>& aSpokesList )
3364 if( !item->IsOnLayer( aLayer ) )
3367 int thermalReliefGap = 0;
3371 bool circular =
false;
3375 pad =
static_cast<PAD*
>( item );
3405 int spoke_max_allowed_w = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
3406 spoke_w = std::clamp( spoke_w, constraint.
Value().
Min(), constraint.
Value().
Max() );
3407 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
3409 if( spoke_w < aZone->GetMinThickness() )
3422 spoke_w = std::min( spoke_w,
via->GetWidth( aLayer ) );
3424 if( spoke_w < aZone->GetMinThickness() )
3443 int spoke_max_allowed_w = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
3445 spoke_w = std::clamp( spoke_w, constraint.
Value().
Min(), constraint.
Value().
Max() );
3448 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
3451 if( spoke_w < aZone->GetMinThickness() )
3460 int spoke_half_w = spoke_w / 2;
3463 BOX2I itemBB = item->GetBoundingBox();
3469 bool customSpokes =
false;
3473 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
3475 if( primitive->IsProxyItem() && primitive->GetShape() ==
SHAPE_T::SEGMENT )
3477 customSpokes =
true;
3488 auto buildSpokesFromOrigin =
3495 auto intersectBBox =
3498 double dx = spokeAngle.
Cos();
3499 double dy = spokeAngle.
Sin();
3505 *spoke_side =
VECTOR2I( spoke_half_w, 0 );
3506 return KiROUND( 0.0, dy * half_size.
y );
3510 *spoke_side =
VECTOR2I( 0, spoke_half_w );
3511 return KiROUND( dx * half_size.
x, 0.0 );
3516 double dist_x = half_size.
x /
std::abs( dx );
3517 double dist_y = half_size.
y /
std::abs( dy );
3519 if( dist_x < dist_y )
3521 *spoke_side =
KiROUND( 0.0, spoke_half_w / (
ANGLE_90 - spokeAngle ).Sin() );
3522 return KiROUND( dx * dist_x, dy * dist_x );
3526 *spoke_side =
KiROUND( spoke_half_w / spokeAngle.
Sin(), 0.0 );
3527 return KiROUND( dx * dist_y, dy * dist_y );
3540 for(
const EDA_ANGLE& spokeAngle : angles )
3543 VECTOR2I intersection = intersectBBox( spokeAngle, &spoke_side );
3552 aSpokesList.push_back( std::move( spoke ) );
3564 thermalOutline = thermalPoly.
Outline( 0 );
3568 auto trimToOutline = [&](
SEG& aSegment )
3572 if( padOutline.
Intersect( aSegment, intersections ) )
3574 intersections.clear();
3577 if( thermalOutline.
Intersect( aSegment, intersections ) )
3579 aSegment.B = intersections.front().p;
3586 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
3588 if( primitive->IsProxyItem() && primitive->GetShape() ==
SHAPE_T::SEGMENT )
3590 SEG seg( primitive->GetStart(), primitive->GetEnd() );
3595 seg.
A +=
pad->ShapePos( aLayer );
3596 seg.
B +=
pad->ShapePos( aLayer );
3610 if( trimToOutline( seg ) )
3612 VECTOR2I direction = ( seg.
B - seg.
A ).Resize( spoke_half_w );
3616 SEG segL( seg.
A - direction - offset, seg.
B + direction - offset );
3617 SEG segR( seg.
A - direction + offset, seg.
B + direction + offset );
3620 if( trimToOutline( segL ) && trimToOutline( segR ) )
3628 spoke.
Append( seg.
A + offset );
3629 spoke.
Append( seg.
A - offset );
3631 spoke.
Append( segL.
B + direction );
3632 spoke.
Append( seg.
B + direction );
3633 spoke.
Append( segR.
B + direction );
3636 aSpokesList.push_back( std::move( spoke ) );
3649 thermalSpokeAngle =
pad->GetThermalSpokeAngle();
3668 position =
pad->ShapePos( aLayer );
3669 orientation =
pad->GetOrientation();
3677 position =
via->GetPosition();
3682 spokesBox.
Inflate( thermalReliefGap +
epsilon + zone_half_width );
3689 buildSpokesFromOrigin( spokesBox,
ANGLE_0 );
3691 if( thermalSpokeAngle !=
ANGLE_0 )
3694 for(
auto it = aSpokesList.rbegin(); it != aSpokesList.rbegin() + 4; ++it )
3695 it->Rotate( thermalSpokeAngle );
3700 buildSpokesFromOrigin( spokesBox, thermalSpokeAngle );
3703 auto spokeIter = aSpokesList.rbegin();
3705 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
3707 spokeIter->Rotate( orientation );
3708 spokeIter->Move( position );
3713 for(
size_t ii = 0; ii < aSpokesList.size(); ++ii )
3714 aSpokesList[ii].GenerateBBoxCache();
3720 const std::vector<BOARD_ITEM*>& aThermalConnectionPads,
3727 for(
BOARD_ITEM* item : aThermalConnectionPads )
3729 if( !item->IsOnLayer( aLayer ) )
3734 bool isCircular =
false;
3742 pad =
static_cast<PAD*
>( item );
3744 position =
pad->ShapePos( aLayer );
3750 padRadius = std::max( padSize.
x, padSize.
y ) / 2;
3759 int spokeMaxWidth = std::min( padSize.
x, padSize.
y );
3760 spokeWidth = std::min( spokeWidth, spokeMaxWidth );
3765 position =
via->GetPosition();
3767 padRadius =
via->GetWidth( aLayer ) / 2;
3776 spokeWidth = std::min( spokeWidth, padRadius * 2 );
3784 if( spokeWidth < aZone->GetMinThickness() )
3794 int ringInnerRadius = padRadius + thermalGap;
3795 int ringWidth = spokeWidth;
3808 pad->TransformShapeToPolygon( outerShape, aLayer, thermalGap + spokeWidth,
3812 pad->TransformShapeToPolygon( innerShape, aLayer, thermalGap,
3815 thermalRing = outerShape;
3845 if( settings.
gap <= 0
3847 || ( needsLineWidth && settings.
line_width <= 0 ) )
3874 const auto& defaultOffsets =
m_board->GetDesignSettings().m_ZoneLayerProperties;
3878 if(
auto it = defaultOffsets.find( aLayer ); it != defaultOffsets.end() )
3879 offset = it->second.hatching_offset.value_or(
VECTOR2I() );
3881 if( localOffsets.contains( aLayer ) && localOffsets.at( aLayer ).hatching_offset.has_value() )
3882 offset = localOffsets.at( aLayer ).hatching_offset.value();
3897 const int dotRadius = std::max( settings.
element_size / 2 - halfMinWidth, 1 );
3898 const int maxError =
m_board->GetDesignSettings().m_MaxError;
3904 int xStart = bbox.
GetLeft() - ( bbox.
GetLeft() % dotStride ) + offset.
x;
3905 int yStart = bbox.
GetTop() - ( bbox.
GetTop() % dotStride ) + offset.
y;
3907 while( xStart > bbox.
GetLeft() )
3908 xStart -= dotStride;
3910 while( yStart > bbox.
GetTop() )
3911 yStart -= dotStride;
3940 int xVoid = bbox.
GetLeft() - ( bbox.
GetLeft() % lineStride ) + offset.
x
3942 int yVoid = bbox.
GetTop() - ( bbox.
GetTop() % lineStride ) + offset.
y
3945 while( xVoid - voidSize / 2 > bbox.
GetLeft() )
3946 xVoid -= lineStride;
3948 while( yVoid - voidSize / 2 > bbox.
GetTop() )
3949 yVoid -= lineStride;
3953 for(
int yy = yVoid; yy <= bbox.
GetBottom() + voidSize; yy += lineStride )
3955 for(
int xx = xVoid; xx <= bbox.
GetRight() + voidSize; xx += lineStride )
3958 rect.
Append( xx - voidSize / 2, yy - voidSize / 2 );
3959 rect.
Append( xx + voidSize / 2, yy - voidSize / 2 );
3960 rect.
Append( xx + voidSize / 2, yy + voidSize / 2 );
3961 rect.
Append( xx - voidSize / 2, yy + voidSize / 2 );
3986 const VECTOR2I squareSize( sideLen, sideLen );
3988 const int containmentInset =
4003 for(
int yy = yStart; yy <= bbox.
GetBottom() + dotRadius; yy += dotStride )
4005 const int rowOffset = ( settings.
stagger && ( rowIndex & 1 ) ) ? dotStride / 2 : 0;
4007 for(
int xx = xStart + rowOffset; xx <= bbox.
GetRight() + dotRadius; xx += dotStride )
4011 if( !filledRegion.
Contains( centre, -1, 0,
true ) )
4031 aFillPolys = stamps;
4052 int maxError =
m_board->GetDesignSettings().m_MaxError;
4068 hole_base.
Append( corner );
4069 corner.
x += hole_size;
4070 hole_base.
Append( corner );
4071 corner.
y += hole_size;
4072 hole_base.
Append( corner );
4074 hole_base.
Append( corner );
4094 #define SMOOTH_MIN_VAL_MM 0.02
4095 #define SMOOTH_SMALL_VAL_MM 0.04
4111 smooth_value = std::min( smooth_value, aZone->
GetHatchGap() / 2 );
4114 maxError = std::max( maxError * 2, smooth_value / 20 );
4116 switch( smooth_level )
4128 hole_base = smooth_hole.
Fillet( smooth_value, maxError ).
Outline( 0 );
4140 const auto& defaultOffsets =
m_board->GetDesignSettings().m_ZoneLayerProperties;
4145 if(
auto it = defaultOffsets.find( aLayer ); it != defaultOffsets.end() )
4146 offset = it->second.hatching_offset.value_or(
VECTOR2I() );
4148 if( localOffsets.contains( aLayer ) && localOffsets.at( aLayer ).hatching_offset.has_value() )
4149 offset = localOffsets.at( aLayer ).hatching_offset.value();
4151 int x_offset = bbox.
GetX() - ( bbox.
GetX() ) % gridsize - gridsize;
4152 int y_offset = bbox.
GetY() - ( bbox.
GetY() ) % gridsize - gridsize;
4155 for(
int xx = x_offset; xx <= bbox.
GetRight(); xx += gridsize )
4157 for(
int yy = y_offset; yy <= bbox.
GetBottom(); yy += gridsize )
4168 hole.
Move(
VECTOR2I( offset.
x % gridsize, offset.
y % gridsize ) );
4181 deflated_thickness = std::max( deflated_thickness, maxError * 2 );
4203 if( area < minimal_hole_area )
4214 BOX2I thermalBBox = aThermalRings.
BBox();
4217 for(
int holeIdx = holes.
OutlineCount() - 1; holeIdx >= 0; holeIdx-- )
4227 for(
int ringIdx = 0; ringIdx < aThermalRings.
OutlineCount(); ringIdx++ )
4234 if( !holeBBox.
Contains( ringBBox ) )
4250 if( intersections.empty() )
4272 auto cacheKey = std::make_pair(
static_cast<const ZONE*
>( aZone ), aLayer );
4282 aFillPolys = it->second;
4295 auto evalRulesForItems =
4307 bool knockoutsApplied =
false;
4311 auto collectZoneKnockout =
4312 [&](
ZONE* otherZone )
4314 if( otherZone == aZone )
4317 if( !otherZone->GetLayerSet().test( aLayer ) )
4320 if( otherZone->IsTeardropArea() && otherZone->SameNet( aZone ) )
4323 if( !otherZone->HigherPriority( aZone ) )
4326 if( !otherZone->GetBoundingBox().Intersects( zoneBBox ) )
4333 std::shared_ptr<SHAPE_POLY_SET> fillShared;
4337 auto it = aSnapshot->find( {
static_cast<const ZONE*
>( otherZone ), aLayer } );
4339 if( it == aSnapshot->end() )
4342 fillPtr = &it->second;
4346 if( !otherZone->HasFilledPolysForLayer( aLayer ) )
4349 fillShared = otherZone->GetFilledPolysList( aLayer );
4354 fillPtr = fillShared.get();
4360 if( otherZone->SameNet( aZone ) )
4362 sameNetKnockouts.
Append( *fillPtr );
4367 aZone, otherZone, aLayer ) );
4370 otherZone, aLayer ) );
4378 diffNetKnockouts.
Append( inflatedFill );
4379 knockoutsApplied =
true;
4383 forEachBoardAndFootprintZone(
m_board, collectZoneKnockout );
4397 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 );
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 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)
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
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.
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