28#include <wx/filename.h>
32#include <unordered_map>
33#include <unordered_set>
71 RESULTS(
int aOutline1,
int aOutline2,
int aVertex1,
int aVertex2 ) :
108 distances.reserve( outline.
PointCount() + 1 );
109 distances.push_back( 0.0 );
111 for(
int j = 0; j < outline.
PointCount(); j++ )
113 distances.push_back( distances.back()
118 tail =
createList( outline, tail, (
void*)( intptr_t )( i ) );
134 SEG::ecoord min_dist = std::numeric_limits<SEG::ecoord>::max();
137 auto check_pt = [&](
VERTEX* p )
143 const std::vector<double>& distances =
145 double directDistance =
std::abs( distances[p->i] - distances[aPt->
i] );
146 double contourDistance =
147 std::min( directDistance, distances.back() - directDistance );
149 if( contourDistance <
m_dist )
153 VECTOR2D diff( p->x - aPt->
x, p->y - aPt->
y );
156 if( dist2 > 0 && dist2 < limit2 && dist2 < min_dist && p->isEar(
true ) )
165 while( p && p->
z <= maxZ )
173 while( p && p->
z >= minZ )
188 std::set<VERTEX*> visited;
201 if( ( visited.empty() || !visited.contains( p ) ) && ( q =
getPoint( p ) ) )
205 if( !visited.contains( q ) &&
207 p->
i, q->
i ).second )
211 visited.insert( p->
prev );
213 visited.insert( p->
next );
216 visited.insert( q->
prev );
218 visited.insert( q->
next );
254struct PAD_KNOCKOUT_KEY
262 bool operator==(
const PAD_KNOCKOUT_KEY& other )
const
264 return position == other.position && effectiveSize == other.effectiveSize
265 && shape == other.shape && orientation == other.orientation
266 && netCode == other.netCode;
270struct PAD_KNOCKOUT_KEY_HASH
272 size_t operator()(
const PAD_KNOCKOUT_KEY& key )
const
274 return hash_val( key.position.
x, key.position.
y, key.effectiveSize.
x, key.effectiveSize.
y,
275 key.shape, key.orientation.
AsDegrees(), key.netCode );
282struct VIA_KNOCKOUT_KEY
288 bool operator==(
const VIA_KNOCKOUT_KEY& other )
const
290 return position == other.position && effectiveSize == other.effectiveSize
291 && netCode == other.netCode;
295struct VIA_KNOCKOUT_KEY_HASH
297 size_t operator()(
const VIA_KNOCKOUT_KEY& key )
const
299 return hash_val( key.position.
x, key.position.
y, key.effectiveSize, key.netCode );
305struct TRACK_KNOCKOUT_KEY
311 TRACK_KNOCKOUT_KEY(
const VECTOR2I& aStart,
const VECTOR2I& aEnd,
int aWidth ) :
315 if( aStart.
x < aEnd.
x || ( aStart.
x == aEnd.
x && aStart.
y <= aEnd.
y ) )
327 bool operator==(
const TRACK_KNOCKOUT_KEY& other )
const
329 return start == other.start && end == other.end && width == other.width;
333struct TRACK_KNOCKOUT_KEY_HASH
335 size_t operator()(
const TRACK_KNOCKOUT_KEY& key )
const
337 return hash_val( key.start.
x, key.start.
y, key.end.
x, key.end.
y, key.width );
341template<
typename Func>
342void forEachBoardAndFootprintZone(
BOARD* aBoard, Func&& aFunc )
349 for(
ZONE* zone : footprint->Zones() )
404 std::vector<INDEXED_ITEM>& aResult )
417 aResult.push_back( aEntry );
421 aIndex.
Search( min, max, visitor );
423 std::sort( aResult.begin(), aResult.end(),
426 return a.m_seq < b.m_seq;
436 BOX2I bbox = aItem->GetBoundingBox();
440 aBuilder.Add( min, max,
INDEXED_ITEM{ aItem, aOwner, aSeq } );
445 forEachBoardAndFootprintZone(
m_board,
452 ITEM_RTREE::Builder graphics;
453 ITEM_RTREE::Builder footprints;
454 ITEM_RTREE::Builder pads;
461 add( footprints, footprint, footprint, seq );
462 add( graphics, &footprint->Reference(), footprint, seq++ );
463 add( graphics, &footprint->Value(), footprint, seq++ );
465 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
466 add( graphics, item, footprint, seq++ );
468 for(
PAD*
pad : footprint->Pads() )
469 add( pads,
pad, footprint, padSeq++ );
473 add( graphics, item,
nullptr, seq++ );
481 std::map<PCB_LAYER_ID, ITEM_RTREE::Builder> tracks;
486 LSET trackLayers = track->GetLayerSet() & boardCu;
489 add( tracks[layer], track,
nullptr, seq );
496 for(
auto& [layer, builder] : tracks )
499 std::map<PCB_LAYER_ID, ITEM_RTREE::Builder> zones;
502 forEachBoardAndFootprintZone(
m_board,
506 add( zones[layer], zone,
nullptr, seq );
513 for(
auto& [layer, builder] : zones )
538 if(
m_board->GetDesignSettings().m_ZoneKeepExternalFillets )
553 if(
m_board->GetDesignSettings().m_ZoneKeepExternalFillets )
555 for(
const ZONE* zone : { aZone, aKnockout } )
560 reach += (int) zone->GetCornerRadius();
574 return zoneOutline.
Collide( &knockoutOutline, reach );
590 std::lock_guard<KISPINLOCK> lock(
m_board->GetConnectivity()->GetLock() );
606 std::shared_ptr<DRC_ENGINE> drcEngine = std::make_shared<DRC_ENGINE>(
m_board, &bds );
610 drcEngine->InitEngine( wxFileName(
m_board->GetDesignRulesPath() ) );
623 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
624 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
HASH_128> oldFillHashes;
625 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> isolatedIslandsMap;
627 std::shared_ptr<CONNECTIVITY_DATA> connectivity =
m_board->GetConnectivity();
634 connectivity->ClearRatsnest();
642 :
_(
"Building zone fills..." ) );
655 zone->CacheBoundingBox();
659 for(
PAD*
pad : footprint->Pads() )
663 pad->BuildEffectiveShapes();
668 for(
ZONE* zone : footprint->Zones() )
669 zone->CacheBoundingBox();
672 footprint->BuildCourtyardCaches();
673 footprint->BuildNetTieCache();
682 std::unordered_map<const ZONE*, POLY_YSTRIPES_INDEX> zoneOutlineIndices;
686 if( zone->GetNumCorners() <= 2 )
689 zoneOutlineIndices[zone].Build( zone->GetBoardOutline() );
696 auto findHighestPriorityZone =
698 const std::function<bool(
const ZONE* )>& testFn ) ->
ZONE*
700 unsigned highestSameNetPriority = 0;
701 ZONE* highestSameNetZone =
nullptr;
702 unsigned highestPriority = 0;
703 ZONE* highestPriorityZone =
nullptr;
708 if( zone->GetIsRuleArea() )
711 if( !zone->IsOnLayer( itemLayer ) )
714 const unsigned priority = zone->GetAssignedPriority();
715 const bool sameNet = zone->GetNetCode() == netcode;
720 if( highestSameNetZone && priority < highestSameNetPriority )
723 else if( highestPriorityZone && priority < highestPriority )
729 if( zone->GetNumCorners() <= 2 )
732 if( !zone->GetBoundingBox().Intersects( bbox ) )
735 if( !testFn( zone ) )
739 && ( !highestSameNetZone || priority > highestSameNetPriority ) )
741 highestSameNetPriority = priority;
742 highestSameNetZone = zone;
745 if( !highestPriorityZone || priority > highestPriority )
747 highestPriority = priority;
748 highestPriorityZone = zone;
752 return highestSameNetZone ? highestSameNetZone : highestPriorityZone;
755 auto isInPourKeepoutArea =
760 if( !zone->GetIsRuleArea() )
763 if( !zone->HasKeepoutParametersSet() )
766 if( !zone->GetDoNotAllowZoneFills() )
769 if( !zone->IsOnLayer( itemLayer ) )
773 if( zone->GetNumCorners() <= 2 )
776 if( !zone->GetBoundingBox().Intersects( bbox ) )
779 auto it = zoneOutlineIndices.find( zone );
781 if( it != zoneOutlineIndices.end() && it->second.Contains( testPoint ) )
798 via->ClearZoneLayerOverrides();
800 if( !
via->GetRemoveUnconnected() )
805 int holeRadius =
via->GetDrillValue() / 2 + 1;
806 int netcode =
via->GetNetCode();
807 LSET layers =
via->GetLayerSet() & boardCuMask;
811 [&](
const ZONE* aZone ) ->
bool
818 if( !
via->ConditionallyFlashed( layer ) )
821 if( isInPourKeepoutArea( bbox, layer,
center ) )
827 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, viaTestFn );
832 || layer == padstack.
Drill().
end ) )
848 for(
PAD*
pad : footprint->Pads() )
850 pad->ClearZoneLayerOverrides();
852 if( !
pad->GetRemoveUnconnected() )
857 int netcode =
pad->GetNetCode();
858 LSET layers =
pad->GetLayerSet() & boardCuMask;
861 [&](
const ZONE* aZone ) ->
bool
863 auto it = zoneOutlineIndices.find( aZone );
865 if( it != zoneOutlineIndices.end() )
866 return it->second.Contains(
center );
873 if( !
pad->ConditionallyFlashed( layer ) )
876 if( isInPourKeepoutArea( bbox, layer,
center ) )
882 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, padTestFn );
893 for(
ZONE* zone : aZones )
896 if( zone->GetIsRuleArea() )
900 if( zone->GetNumCorners() <= 2 )
910 zone->BuildHashValue( layer );
911 oldFillHashes[ { zone, layer } ] = zone->GetHashValue( layer );
914 toFill.emplace_back( std::make_pair( zone, layer ) );
920 if( !zone->IsCopperThieving() && !zone->IsTeardropArea() )
928 auto zone_fill_dependency =
930 bool aRequireCompletedOtherFill ) ->
bool
937 if( aRequireCompletedOtherFill && aOtherZone->GetFillFlag( aLayer ) )
942 if( aOtherZone->GetIsRuleArea() )
946 if( aOtherZone->GetNumCorners() <= 2 )
950 if( !aOtherZone->GetLayerSet().test( aLayer ) )
957 if( aOtherZone->SameNet( aZone ) )
964 auto check_fill_dependency =
967 return zone_fill_dependency( aZone, aLayer, aOtherZone,
true );
970 auto fill_item_dependency =
971 [&](
const std::pair<ZONE*, PCB_LAYER_ID>& aWaiter,
972 const std::pair<ZONE*, PCB_LAYER_ID>& aDependency ) ->
bool
974 if( aWaiter.first == aDependency.first || aWaiter.second != aDependency.second )
977 return check_fill_dependency( aWaiter.first, aWaiter.second, aDependency.first );
981 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
987 ZONE* zone = aFillItem.first;
1002 auto tesselate_lambda =
1003 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
1009 ZONE* zone = aFillItem.first;
1018 std::atomic<bool> cancelled =
false;
1024 auto run_fill_waves =
1025 [&](
const std::vector<std::pair<ZONE*, PCB_LAYER_ID>>& aFillItems,
auto&& aFillFn,
1026 auto&& aTessFn,
auto&& aHasDependency,
bool aAnyDependencies )
1028 const size_t count = aFillItems.size();
1033 std::vector<std::vector<size_t>> successors( count );
1034 std::vector<std::atomic<int>> inDegree( count );
1036 for(
size_t i = 0; i < count; ++i )
1037 inDegree[i].store( 0, std::memory_order_relaxed );
1040 if( aAnyDependencies )
1043 std::map<PCB_LAYER_ID, std::vector<size_t>> byLayer;
1045 for(
size_t i = 0; i < count; ++i )
1046 byLayer[aFillItems[i].second].push_back( i );
1048 for(
const auto& [layer, items] : byLayer )
1050 for(
size_t i : items )
1052 for(
size_t j : items )
1057 if( aHasDependency( aFillItems[j], aFillItems[i] ) )
1059 successors[i].push_back( j );
1060 inDegree[j].fetch_add( 1, std::memory_order_relaxed );
1067 std::atomic<int> remaining( (
int) count );
1071 std::atomic<int> inFlight( 0 );
1073 std::function<void(
size_t )>
process;
1078 inFlight.fetch_add( 1, std::memory_order_relaxed );
1084 inFlight.fetch_sub( 1, std::memory_order_acq_rel );
1091 int filled = aFillFn( aFillItems[idx] );
1094 for(
size_t succ : successors[idx] )
1096 if( inDegree[succ].fetch_sub( 1, std::memory_order_acq_rel ) == 1 )
1100 if( filled != 0 && !cancelled.load() )
1101 aTessFn( aFillItems[idx] );
1103 remaining.fetch_sub( 1, std::memory_order_acq_rel );
1106 std::vector<size_t> roots;
1109 for(
size_t i = 0; i < count; ++i )
1111 if( inDegree[i].load( std::memory_order_relaxed ) == 0 )
1112 roots.push_back( i );
1115 for(
size_t idx : roots )
1119 while( remaining.load( std::memory_order_acquire ) > 0 )
1129 std::this_thread::sleep_for( std::chrono::milliseconds( 20 ) );
1136 while( inFlight.load( std::memory_order_acquire ) > 0 )
1137 std::this_thread::sleep_for( std::chrono::milliseconds( 1 ) );
1140 run_fill_waves( toFill, fill_lambda, tesselate_lambda, fill_item_dependency,
true );
1156 for(
ZONE* zone : aZones )
1158 if( zone->IsTeardropArea() )
1159 connectivity->Update( zone );
1163 connectivity->FillIsolatedIslandsMap( isolatedIslandsMap );
1164 connectivity->SetProgressReporter(
nullptr );
1169 for(
ZONE* zone : aZones )
1172 if( zone->GetIsRuleArea() )
1175 zone->SetIsFilled(
true );
1184 std::set<std::pair<ZONE*, PCB_LAYER_ID>> zonesWithRemovedIslandLayers;
1191 std::set<std::pair<ZONE*, PCB_LAYER_ID>> initiallyFullyIsolatedLayers;
1193 for(
const auto& [ zone, zoneIslands ] : isolatedIslandsMap )
1197 bool allLayersFullyIsolated =
true;
1199 for(
const auto& [ layer, layerIslands ] : zoneIslands )
1201 bool layerFullyIsolated = ( layerIslands.m_IsolatedOutlines.size()
1202 ==
static_cast<size_t>( zone->GetFilledPolysList( layer )->OutlineCount() ) );
1204 if( layerFullyIsolated )
1205 initiallyFullyIsolatedLayers.insert( { zone, layer } );
1207 allLayersFullyIsolated =
false;
1210 if( allLayersFullyIsolated )
1213 for(
const auto& [ layer, layerIslands ] : zoneIslands )
1218 if( layerIslands.m_IsolatedOutlines.empty() )
1221 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
1225 std::sort( islands.begin(), islands.end(), std::greater<int>() );
1227 std::shared_ptr<SHAPE_POLY_SET> poly = zone->GetFilledPolysList( layer );
1228 long long int minArea = zone->GetMinIslandArea();
1231 for(
int idx : islands )
1237 poly->DeletePolygonAndTriangulationData( idx,
false );
1238 zonesWithRemovedIslandLayers.insert( { zone, layer } );
1242 poly->DeletePolygonAndTriangulationData( idx,
false );
1243 zonesWithRemovedIslandLayers.insert( { zone, layer } );
1247 zone->SetIsIsland( layer, idx );
1251 poly->UpdateTriangulationDataHash();
1252 zone->CalculateFilledArea();
1272 std::set<std::pair<ZONE*, PCB_LAYER_ID>> sameNetOverlapSeeds;
1274 if( iterativeRefill )
1279 std::map<int, std::vector<ZONE*>> zonesByNet;
1281 forEachBoardAndFootprintZone(
1286 zonesByNet[zone->
GetNetCode()].push_back( zone );
1289 for(
ZONE* lowerZone : aZones )
1291 if( lowerZone->GetIsRuleArea() || lowerZone->IsTeardropArea() )
1294 auto netIt = zonesByNet.find( lowerZone->GetNetCode() );
1296 if( netIt == zonesByNet.end() )
1299 LSET lowerLayers = lowerZone->GetLayerSet() & boardCu;
1301 for(
ZONE* higherZone : netIt->second )
1303 if( higherZone == lowerZone
1307 if( !lowerZone->GetBoundingBox().Intersects( higherZone->
GetBoundingBox() ) )
1316 if( lowerZone->HasFilledPolysForLayer( layer )
1319 sameNetOverlapSeeds.insert( { lowerZone, layer } );
1327 && ( !zonesWithRemovedIslandLayers.empty() || !sameNetOverlapSeeds.empty() ) )
1329 const int maxIterations = 8;
1330 bool progressReported =
false;
1331 bool hitIterationLimit =
false;
1334 std::set<std::pair<ZONE*, PCB_LAYER_ID>> changedZoneLayers( zonesWithRemovedIslandLayers );
1335 changedZoneLayers.insert( sameNetOverlapSeeds.begin(), sameNetOverlapSeeds.end() );
1337 auto cached_refill_tessellate_lambda = [&](
const std::pair<ZONE*, PCB_LAYER_ID>& aFillItem ) ->
int
1339 ZONE* zone = aFillItem.first;
1346 auto no_dependency = [](
const std::pair<ZONE*, PCB_LAYER_ID>&,
const std::pair<ZONE*, PCB_LAYER_ID>& ) ->
bool
1351 for(
int iteration = 0; iteration < maxIterations; ++iteration )
1356 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zonesToRefill;
1357 std::set<std::pair<ZONE*, PCB_LAYER_ID>> zonesToRefillSet;
1359 for(
const auto& [changedZone, changedLayer] : changedZoneLayers )
1361 BOX2I bbox = changedZone->GetBoundingBox();
1364 for(
ZONE* zone : aZones )
1366 if( zone->GetIsRuleArea() )
1371 if( zone->IsTeardropArea() )
1374 if( !zone->GetLayerSet().test( changedLayer ) )
1390 if( zone != changedZone && !changedZone->HigherPriority( zone ) && !changedZone->SameNet( zone ) )
1397 if( zone != changedZone && !changedZone->SameNet( zone ) )
1402 else if( !zone->GetBoundingBox().Intersects( bbox ) )
1407 auto fillItem = std::make_pair( zone, changedLayer );
1409 if( zonesToRefillSet.insert( fillItem ).second )
1410 zonesToRefill.push_back( fillItem );
1414 if( zonesToRefill.empty() )
1417 if( !progressReported )
1426 progressReported =
true;
1432 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
HASH_128> iterHashes;
1434 for(
const auto& fillItem : zonesToRefill )
1436 fillItem.first->BuildHashValue( fillItem.second );
1437 iterHashes[fillItem] = fillItem.first->GetHashValue( fillItem.second );
1448 LSET snapshotLayers;
1450 for(
const auto& [zone, layer] : zonesToRefill )
1451 snapshotLayers.
set( layer );
1455 forEachBoardAndFootprintZone(
m_board,
1472 if( sp && sp->OutlineCount() > 0 )
1473 snapshot[{ zone, layer }] = sp->CloneDropTriangulation();
1477 auto cached_refill_fill_lambda =
1478 [&](
const std::pair<ZONE*, PCB_LAYER_ID>& aFillItem ) ->
int
1480 ZONE* zone = aFillItem.first;
1492 run_fill_waves( zonesToRefill, cached_refill_fill_lambda, cached_refill_tessellate_lambda, no_dependency,
1498 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> refillIslandsMap;
1500 for(
const auto& [zone, layer] : zonesToRefill )
1512 connectivity->FillIsolatedIslandsMap( refillIslandsMap );
1514 for(
const auto& [zone, zoneIslands] : refillIslandsMap )
1516 for(
const auto& [layer, layerIslands] : zoneIslands )
1521 if( layerIslands.m_IsolatedOutlines.empty() )
1526 if( initiallyFullyIsolatedLayers.count( { zone, layer } ) > 0 )
1528 if( layerIslands.m_IsolatedOutlines.size()
1535 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
1536 std::sort( islands.begin(), islands.end(), std::greater<int>() );
1542 for(
int idx : islands )
1547 poly->DeletePolygonAndTriangulationData( idx,
false );
1549 poly->DeletePolygonAndTriangulationData( idx,
false );
1554 poly->UpdateTriangulationDataHash();
1562 changedZoneLayers.clear();
1564 for(
const auto& fillItem : zonesToRefill )
1566 fillItem.first->BuildHashValue( fillItem.second );
1568 auto hashIt = iterHashes.find( fillItem );
1569 HASH_128 oldHash = ( hashIt != iterHashes.end() ) ? hashIt->second :
HASH_128{};
1571 if( fillItem.first->GetHashValue( fillItem.second ) != oldHash )
1572 changedZoneLayers.insert( fillItem );
1575 if( changedZoneLayers.empty() )
1578 if( iteration + 1 >= maxIterations )
1580 hitIterationLimit =
true;
1585 if( hitIterationLimit )
1587 wxString msg = wxString::Format(
_(
"Zone fills may be incorrect: iterative refill did not converge "
1588 "after %d passes.\n\n"
1589 "This can happen with complex overlapping zones. "
1590 "Consider simplifying your zones." ),
1595 KIDIALOG dlg( aParent, msg,
_(
"Warning" ), wxOK | wxICON_WARNING );
1601 wxLogWarning( msg );
1608 using island_check_return = std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
int>>;
1610 std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
double>> polys_to_check;
1613 polys_to_check.reserve(
m_board->GetCopperLayerCount() * aZones.size() );
1615 for(
ZONE* zone : aZones )
1628 double minArea = (double) zone->GetMinThickness() * zone->GetMinThickness() * 3;
1635 polys_to_check.emplace_back( zone->GetFilledPolysList( layer ), minArea );
1639 auto island_lambda =
1640 [&](
int aStart,
int aEnd ) -> island_check_return
1642 island_check_return retval;
1644 for(
int ii = aStart; ii < aEnd && !cancelled.load(); ++ii )
1646 auto [poly, minArea] = polys_to_check[ii];
1648 for(
int jj = poly->OutlineCount() - 1; jj >= 0; jj-- )
1653 double island_area = test_poly.
Area();
1655 if( island_area < minArea )
1667 if( intersection.
Area() < island_area / 2.0 )
1668 retval.emplace_back( poly, jj );
1675 auto island_returns =
tp.submit_blocks( 0, polys_to_check.size(), island_lambda );
1679 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
1681 std::future<island_check_return>& ret = island_returns[ii];
1685 std::future_status status = ret.wait_for( std::chrono::seconds( 0 ) );
1687 while( status != std::future_status::ready )
1697 status = ret.wait_for( std::chrono::milliseconds( 100 ) );
1702 if( cancelled.load() )
1705 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
1707 std::future<island_check_return>& ret = island_returns[ii];
1711 for(
auto& action_item : ret.get() )
1712 action_item.first->DeletePolygonAndTriangulationData( action_item.second,
true );
1716 for(
ZONE* zone : aZones )
1717 zone->CalculateFilledArea();
1730 std::unique_ptr<POLY_YSTRIPES_INDEX>
index;
1733 struct NET_LAYER_HASH
1735 size_t operator()(
const std::pair<int, PCB_LAYER_ID>& k )
const
1737 return std::hash<int>()( k.first ) ^ ( std::hash<int>()( k.second ) << 16 );
1741 std::unordered_map<std::pair<int, PCB_LAYER_ID>, std::vector<INDEXED_ZONE>, NET_LAYER_HASH>
1742 filledZonesByNetLayer;
1746 if( zone->GetIsRuleArea() )
1751 if( !zone->HasFilledPolysForLayer( layer ) )
1754 const std::shared_ptr<SHAPE_POLY_SET>& fill = zone->GetFilledPolysList( layer );
1756 if( fill->IsEmpty() )
1760 iz.bbox = fill->BBox();
1761 iz.index = std::make_unique<POLY_YSTRIPES_INDEX>();
1762 iz.index->Build( *fill );
1763 filledZonesByNetLayer[{ zone->GetNetCode(), layer }].push_back( std::move( iz ) );
1767 auto zoneReachesPoint =
1770 auto it = filledZonesByNetLayer.find( { aNetcode, aLayer } );
1772 if( it == filledZonesByNetLayer.end() )
1775 for(
const INDEXED_ZONE& iz : it->second )
1777 if( !iz.bbox.GetInflated( aRadius ).Contains( aCenter ) )
1780 if( iz.index->Contains( aCenter, aRadius ) )
1794 int holeRadius =
via->GetDrillValue() / 2;
1795 int netcode =
via->GetNetCode();
1796 LSET layers =
via->GetLayerSet() & boardCuMask;
1803 int reach = std::max( holeRadius,
via->GetWidth( layer ) / 2 );
1805 if( !zoneReachesPoint( netcode, layer,
center, reach ) )
1812 for(
PAD*
pad : footprint->Pads() )
1815 int netcode =
pad->GetNetCode();
1816 LSET layers =
pad->GetLayerSet() & boardCuMask;
1820 if(
pad->HasHole() )
1821 holeRadius = std::min(
pad->GetDrillSizeX(),
pad->GetDrillSizeY() ) / 2;
1832 int reach = std::max( holeRadius, std::min( padSize.
x, padSize.
y ) / 2 );
1834 if( !zoneReachesPoint( netcode, layer,
center, reach ) )
1842 bool outOfDate =
false;
1844 for(
ZONE* zone : aZones )
1847 if( zone->GetIsRuleArea() )
1852 zone->BuildHashValue( layer );
1854 if( oldFillHashes[ { zone, layer } ] != zone->GetHashValue( layer ) )
1860 &&
m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill ) )
1862 KIDIALOG dlg( aParent,
_(
"Prototype zone fill enabled. Disable setting and refill?" ),
_(
"Confirmation" ),
1863 wxOK | wxCANCEL | wxICON_WARNING );
1869 m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill =
false;
1871 else if( !outOfDate )
1879 KIDIALOG dlg( aParent,
_(
"Zone fills are out-of-date. Refill?" ),
_(
"Confirmation" ),
1880 wxOK | wxCANCEL | wxICON_WARNING );
1923 std::vector<VECTOR2I> convex_hull;
1928 for(
const VECTOR2I& pt : convex_hull )
1960 switch( aItem->
Type() )
1967 if(
text->IsVisible() )
1969 if(
text->IsKnockout() )
2032 std::vector<BOARD_ITEM*>& aThermalConnectionPads,
2033 std::vector<PAD*>& aNoConnectionPads,
2034 std::vector<BOARD_ITEM*>& aSolidConnectionItems )
2040 std::shared_ptr<SHAPE> padShape;
2045 std::unordered_set<PAD_KNOCKOUT_KEY, PAD_KNOCKOUT_KEY_HASH> processedPads;
2046 std::unordered_set<VIA_KNOCKOUT_KEY, VIA_KNOCKOUT_KEY_HASH> processedVias;
2052 std::vector<INDEXED_ITEM> padHits;
2058 PAD*
pad =
static_cast<PAD*
>( padHit.m_item );
2064 &&
pad->GetDrillSize().x > 0;
2066 if( !
pad->IsOnLayer( aLayer ) && !npthWithHole )
2069 BOX2I padBBox =
pad->GetBoundingBox();
2086 int drill = std::max(
pad->GetDrillSize().x,
pad->GetDrillSize().y );
2087 int maxDim = std::max( { padSize.
x, padSize.
y, drill } );
2088 effectiveSize =
VECTOR2I( maxDim, maxDim );
2092 effectiveSize = padSize;
2095 PAD_KNOCKOUT_KEY padKey{
pad->GetPosition(), effectiveSize,
2096 static_cast<int>( padShapeType ),
2097 pad->GetOrientation(),
pad->GetNetCode() };
2099 if( !processedPads.insert( padKey ).second )
2103 bool noConnection =
pad->GetNetCode() != aZone->
GetNetCode();
2110 noConnection =
true;
2115 if(
pad->IsBackdrilledOrPostMachined( aLayer ) )
2116 noConnection =
true;
2121 aNoConnectionPads.push_back(
pad );
2136 switch( connection )
2142 if( aFill.
Collide( padShape.get(), 0 ) )
2150 aThermalConnectionPads.push_back(
pad );
2159 aNoConnectionPads.push_back(
pad );
2184 switch( connection )
2189 if( aFill.
Collide( padShape.get(), 0 ) )
2194 aThermalConnectionPads.push_back(
pad );
2208 if(
pad->FlashLayer( aLayer ) )
2212 else if(
pad->GetDrillSize().x > 0 )
2219 holeClearance = padClearance;
2245 if( !
via->IsOnLayer( aLayer ) )
2248 BOX2I viaBBox =
via->GetBoundingBox();
2255 int viaEffectiveSize = std::max(
via->GetDrillValue(),
via->GetWidth( aLayer ) );
2256 VIA_KNOCKOUT_KEY viaKey{
via->GetPosition(), viaEffectiveSize,
via->GetNetCode() };
2258 if( !processedVias.insert( viaKey ).second )
2261 bool noConnection =
via->GetNetCode() != aZone->
GetNetCode()
2263 && aLayer !=
via->Padstack().Drill().start
2264 && aLayer !=
via->Padstack().Drill().end );
2267 noConnection =
true;
2270 if(
via->IsBackdrilledOrPostMachined( aLayer ) )
2272 noConnection =
true;
2284 pmSize = std::max( pmSize, frontPM.
size );
2290 pmSize = std::max( pmSize, backPM.
size );
2296 bdSize = secDrill.
size.
x;
2298 int knockoutSize = std::max( pmSize, bdSize );
2300 if( knockoutSize > 0 )
2315 switch( connection )
2325 if( thermalGap > 0 )
2327 aThermalConnectionPads.push_back(
via );
2342 aSolidConnectionItems.push_back(
via );
2357 const std::vector<PAD*>& aNoConnectionPads,
2359 bool aIncludeZoneClearances )
2365 std::unordered_set<PAD_KNOCKOUT_KEY, PAD_KNOCKOUT_KEY_HASH> processedPads;
2366 std::unordered_set<VIA_KNOCKOUT_KEY, VIA_KNOCKOUT_KEY_HASH> processedVias;
2367 std::unordered_set<TRACK_KNOCKOUT_KEY, TRACK_KNOCKOUT_KEY_HASH> processedTracks;
2369 auto checkForCancel =
2372 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
2385 auto evalRulesForItems =
2399 auto knockoutPadClearance =
2404 bool hasHole = aPad->GetDrillSize().x > 0;
2406 bool flashLayer = aPad->FlashLayer( aLayer );
2409 if( flashLayer || platedHole )
2412 if( flashLayer && gap >= 0 )
2413 addKnockout( aPad, aLayer, gap + extra_margin, aHoles );
2424 gap = std::max( gap, holeGap );
2431 if( aPad->IsBackdrilledOrPostMachined( aLayer ) )
2433 int knockoutSize = aPad->Padstack().GetMaxHoleSize();
2435 if( knockoutSize > 0 )
2437 int clearance = std::max( holeGap, 0 ) + extra_margin;
2445 for(
PAD*
pad : aNoConnectionPads )
2461 int drill = std::max(
pad->GetDrillSize().x,
pad->GetDrillSize().y );
2462 int maxDim = std::max( { padSize.
x, padSize.
y, drill } );
2463 effectiveSize =
VECTOR2I( maxDim, maxDim );
2467 effectiveSize = padSize;
2470 PAD_KNOCKOUT_KEY padKey{
pad->GetPosition(), effectiveSize,
static_cast<int>( padShape ),
2471 pad->GetOrientation(),
pad->GetNetCode() };
2473 if( !processedPads.insert( padKey ).second )
2477 knockoutPadClearance(
pad );
2482 auto knockoutTrackClearance =
2485 if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
2487 bool sameNet = aTrack->GetNetCode() == aZone->
GetNetCode();
2509 if(
via->FlashLayer( aLayer ) && gap > 0 )
2511 via->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
m_maxError,
2523 gap = std::max( gap, holeGap );
2534 if(
via->IsBackdrilledOrPostMachined( aLayer ) )
2536 int knockoutSize =
via->Padstack().GetMaxHoleSize();
2538 if( knockoutSize > 0 )
2540 int clearance = std::max( holeGap, 0 ) + extra_margin;
2551 aTrack->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
m_maxError,
2558 std::vector<INDEXED_ITEM> hits;
2561 queryIndex( trackIt->second, zone_boundingbox, hits );
2577 int viaEffectiveSize = std::max(
via->GetDrillValue(),
via->GetWidth( aLayer ) );
2578 VIA_KNOCKOUT_KEY viaKey{
via->GetPosition(), viaEffectiveSize,
via->GetNetCode() };
2580 if( !processedVias.insert( viaKey ).second )
2587 if( !processedTracks.insert( trackKey ).second )
2591 knockoutTrackClearance( track );
2596 auto knockoutGraphicClearance =
2602 shapeNet =
static_cast<PCB_SHAPE*
>( aItem )->GetNetCode();
2604 bool sameNet = shapeNet == aZone->
GetNetCode();
2610 if( aItem->IsOnLayer( aLayer )
2612 || aItem->IsOnLayer(
Margin ) )
2614 if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
2616 bool ignoreLineWidths =
false;
2619 if( aItem->IsOnLayer( aLayer ) && !sameNet )
2623 else if( aItem->IsOnLayer(
Edge_Cuts ) )
2626 ignoreLineWidths =
true;
2628 else if( aItem->IsOnLayer(
Margin ) )
2635 gap += extra_margin;
2636 addKnockout( aItem, aLayer, gap, ignoreLineWidths, aHoles );
2642 auto knockoutCourtyardClearance =
2645 if( aFootprint->GetBoundingBox().Intersects( zone_boundingbox ) )
2656 aHoles.
Append( aFootprint->GetCourtyard( courtyardSide ) );
2669 std::map<FOOTPRINT*, std::set<PAD*>> netTiePads;
2671 auto allowedNetTiePads =
2672 [&](
FOOTPRINT* aFootprint ) ->
const std::set<PAD*>&
2674 auto [it, inserted] = netTiePads.try_emplace( aFootprint );
2676 if( !inserted || !aFootprint->IsNetTie() )
2679 for(
PAD*
pad : aFootprint->Pads() )
2688 if(
pad->IsOnLayer( aLayer ) )
2689 it->second.insert(
pad );
2691 for(
PAD* other : aFootprint->GetNetTiePads(
pad ) )
2693 if( other->IsOnLayer( aLayer ) )
2694 it->second.insert( other );
2702 std::vector<INDEXED_ITEM> gfxHits;
2703 std::vector<INDEXED_ITEM> fpHits;
2712 while( gi < gfxHits.size() || fi < fpHits.size() )
2717 if( fi < fpHits.size() && ( gi >= gfxHits.size() || fpHits[fi].m_seq <= gfxHits[gi].m_seq ) )
2719 knockoutCourtyardClearance(
static_cast<FOOTPRINT*
>( fpHits[fi++].m_item ) );
2726 bool skipItem =
false;
2729 if( owner && item != &owner->
Reference() && item != &owner->
Value()
2732 const std::set<PAD*>& allowed = allowedNetTiePads( owner );
2734 if( !allowed.empty() )
2739 for(
PAD*
pad : allowed )
2741 if(
pad->GetBoundingBox().Intersects( itemBBox )
2742 &&
pad->GetEffectiveShape( aLayer )->Collide( itemShape.get() ) )
2752 knockoutGraphicClearance( item );
2757 auto knockoutZoneClearance =
2758 [&](
ZONE* aKnockout )
2761 if( !aKnockout->GetLayerSet().test( aLayer ) )
2764 if( aKnockout->GetIsRuleArea() )
2766 if( aKnockout->GetBoundingBox().Intersects( zone_boundingbox )
2767 && aKnockout->GetDoNotAllowZoneFills() && !aZone->
IsTeardropArea() )
2774 else if( aKnockout->HigherPriority( aZone ) && !aKnockout->SameNet( aZone )
2800 ZONE* otherZone =
static_cast<ZONE*
>( hit.m_item );
2807 knockoutZoneClearance( otherZone );
2824 auto evalRulesForItems =
2840 auto knockoutZoneClearance =
2841 [&](
ZONE* aKnockout )
2843 if( aKnockout->GetIsRuleArea() )
2847 if( aKnockout->IsTeardropArea() )
2850 if( !aKnockout->GetLayerSet().test( aLayer ) )
2853 if( aKnockout->HigherPriority( aZone )
2854 && !aKnockout->SameNet( aZone )
2871 std::vector<INDEXED_ITEM> hits;
2875 knockoutZoneClearance(
static_cast<ZONE*
>( hit.m_item ) );
2891 auto collectZoneOutline =
2892 [&](
ZONE* aKnockout )
2894 if( !aKnockout->GetLayerSet().test( aLayer ) )
2897 if( aKnockout->GetBoundingBox().Intersects( zoneBBox ) )
2898 appendZoneOutlineWithoutArcs( aKnockout, knockouts );
2903 std::vector<INDEXED_ITEM> hits;
2908 ZONE* otherZone =
static_cast<ZONE*
>( hit.m_item );
2912 bool higherPrioritySameNet =
2917 collectZoneOutline( otherZone );
2937 std::map<int, std::vector<std::pair<int, VECTOR2I>>> insertion_points;
2949 insertion_points[
result.m_outline1].push_back( {
result.m_vertex1, pt1 } );
2950 insertion_points[
result.m_outline1].push_back( {
result.m_vertex1, pt2 } );
2953 for(
auto& [outline, vertices] : insertion_points )
2961 std::stable_sort( vertices.begin(), vertices.end(),
2962 [](
const std::pair<int, VECTOR2I>& a,
const std::pair<int, VECTOR2I>& b )
2964 return a.first > b.first;
2967 for(
const auto& [vertex, pt] : vertices )
2968 line.
Insert( vertex + 1, pt );
2977 const double noiseArea = (double) aMaxError * aMaxError;
2979 for(
int ii = aPolys.
OutlineCount() - 1; ii >= 0; ii-- )
3008 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
3010 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
3011 BOX2I islandExtents;
3013 for(
const VECTOR2I& pt : island.front().CPoints() )
3015 islandExtents.
Merge( pt );
3031#define DUMP_POLYS_TO_COPPER_LAYER( a, b, c ) \
3032 { if( m_debugZoneFiller && aDebugLayer == b ) \
3034 m_board->SetLayerName( b, c ); \
3035 SHAPE_POLY_SET d = a; \
3075 std::vector<BOARD_ITEM*> thermalConnectionPads;
3076 std::vector<PAD*> noConnectionPads;
3077 std::vector<BOARD_ITEM*> solidConnectionItems;
3078 std::deque<SHAPE_LINE_CHAIN> thermalSpokes;
3081 aFillPolys = aSmoothedOutline;
3091 knockoutThermalReliefs( aZone, aLayer, aFillPolys, thermalConnectionPads, noConnectionPads, solidConnectionItems );
3108 aFillPolys, thermalRings );
3130 if( iterativeRefill )
3133 bool addedKeepoutHoles =
false;
3135 auto collectKeepoutHoles =
3136 [&](
ZONE* candidate )
3141 if( !isZoneFillKeepout( candidate, aLayer, zone_boundingbox ) )
3146 addedKeepoutHoles =
true;
3149 forEachBoardAndFootprintZone(
m_board, collectKeepoutHoles );
3151 if( addedKeepoutHoles )
3175 if( iterativeRefill )
3210 spokeTestIndex.
Build( testAreas );
3215 const VECTOR2I& testPt = spoke.CPoint( 3 );
3218 if( spokeTestIndex.
Contains( testPt, 1 ) )
3227 if( interval++ > 400 )
3240 if( &other != &spoke
3241 && other.PointInside( testPt, 1 )
3242 && spoke.PointInside( other.CPoint( 3 ), 1 ) )
3279 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
3281 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
3282 BOX2I islandExtents;
3284 for(
const VECTOR2I& pt : island.front().CPoints() )
3286 islandExtents.
Merge( pt );
3307 || !
m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill ) )
3316 for(
BOARD_ITEM* item : solidConnectionItems )
3318 if( item->Type() !=
PCB_VIA_T || !item->IsOnLayer( aLayer ) )
3387 for(
BOARD_ITEM* item : thermalConnectionPads )
3401 bool knockoutsApplied =
false;
3404 if( iterativeRefill )
3423 knockoutsApplied =
true;
3436 if( knockoutsApplied )
3463 auto checkForCancel =
3466 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
3469 auto knockoutGraphicItem =
3472 if( aItem->IsKnockout() && aItem->IsOnLayer( aLayer )
3473 && aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
3475 addKnockout( aItem, aLayer, 0,
true, clearanceHoles );
3484 knockoutGraphicItem( &footprint->Reference() );
3485 knockoutGraphicItem( &footprint->Value() );
3487 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
3488 knockoutGraphicItem( item );
3496 knockoutGraphicItem( item );
3499 aFillPolys = aSmoothedOutline;
3504 auto collectKeepout =
3505 [&](
ZONE* candidate )
3507 if( !isZoneFillKeepout( candidate, aLayer, zone_boundingbox ) )
3510 appendZoneOutlineWithoutArcs( candidate, keepoutHoles );
3513 bool cancelledKeepoutScan =
false;
3515 forEachBoardAndFootprintZone(
3517 [&](
ZONE* keepout )
3519 if( cancelledKeepoutScan )
3524 cancelledKeepoutScan =
true;
3528 collectKeepout( keepout );
3531 if( cancelledKeepoutScan )
3582 debugLayer = aLayer;
3586 if( !aZone->
BuildSmoothedPoly( maxExtents, aLayer, boardOutline, &smoothedPoly ) )
3594 if(
fillCopperZone( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aFillPolys ) )
3611 const std::vector<BOARD_ITEM*>& aSpokedPadsList,
3612 std::deque<SHAPE_LINE_CHAIN>& aSpokesList )
3631 if( !item->IsOnLayer( aLayer ) )
3634 int thermalReliefGap = 0;
3638 bool circular =
false;
3642 pad =
static_cast<PAD*
>( item );
3672 int spoke_max_allowed_w = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
3673 spoke_w = std::clamp( spoke_w, constraint.
Value().
Min(), constraint.
Value().
Max() );
3674 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
3676 if( spoke_w < aZone->GetMinThickness() )
3689 spoke_w = std::min( spoke_w,
via->GetWidth( aLayer ) );
3691 if( spoke_w < aZone->GetMinThickness() )
3710 int spoke_max_allowed_w = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
3712 spoke_w = std::clamp( spoke_w, constraint.
Value().
Min(), constraint.
Value().
Max() );
3715 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
3718 if( spoke_w < aZone->GetMinThickness() )
3727 int spoke_half_w = spoke_w / 2;
3730 BOX2I itemBB = item->GetBoundingBox();
3736 bool customSpokes =
false;
3740 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
3742 if( primitive->IsProxyItem() && primitive->GetShape() ==
SHAPE_T::SEGMENT )
3744 customSpokes =
true;
3755 auto buildSpokesFromOrigin =
3762 auto intersectBBox =
3765 double dx = spokeAngle.
Cos();
3766 double dy = spokeAngle.
Sin();
3772 *spoke_side =
VECTOR2I( spoke_half_w, 0 );
3773 return KiROUND( 0.0, dy * half_size.
y );
3777 *spoke_side =
VECTOR2I( 0, spoke_half_w );
3778 return KiROUND( dx * half_size.
x, 0.0 );
3783 double dist_x = half_size.
x /
std::abs( dx );
3784 double dist_y = half_size.
y /
std::abs( dy );
3786 if( dist_x < dist_y )
3788 *spoke_side =
KiROUND( 0.0, spoke_half_w / (
ANGLE_90 - spokeAngle ).Sin() );
3789 return KiROUND( dx * dist_x, dy * dist_x );
3793 *spoke_side =
KiROUND( spoke_half_w / spokeAngle.
Sin(), 0.0 );
3794 return KiROUND( dx * dist_y, dy * dist_y );
3807 for(
const EDA_ANGLE& spokeAngle : angles )
3810 VECTOR2I intersection = intersectBBox( spokeAngle, &spoke_side );
3819 aSpokesList.push_back( std::move( spoke ) );
3831 thermalOutline = thermalPoly.
Outline( 0 );
3835 auto trimToOutline = [&](
SEG& aSegment )
3839 if( padOutline.
Intersect( aSegment, intersections ) )
3841 intersections.clear();
3844 if( thermalOutline.
Intersect( aSegment, intersections ) )
3846 aSegment.B = intersections.front().p;
3853 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
3855 if( primitive->IsProxyItem() && primitive->GetShape() ==
SHAPE_T::SEGMENT )
3857 SEG seg( primitive->GetStart(), primitive->GetEnd() );
3862 seg.
A +=
pad->ShapePos( aLayer );
3863 seg.
B +=
pad->ShapePos( aLayer );
3877 if( trimToOutline( seg ) )
3879 VECTOR2I direction = ( seg.
B - seg.
A ).Resize( spoke_half_w );
3883 SEG segL( seg.
A - direction - offset, seg.
B + direction - offset );
3884 SEG segR( seg.
A - direction + offset, seg.
B + direction + offset );
3887 if( trimToOutline( segL ) && trimToOutline( segR ) )
3895 spoke.
Append( seg.
A + offset );
3896 spoke.
Append( seg.
A - offset );
3898 spoke.
Append( segL.
B + direction );
3899 spoke.
Append( seg.
B + direction );
3900 spoke.
Append( segR.
B + direction );
3903 aSpokesList.push_back( std::move( spoke ) );
3916 thermalSpokeAngle =
pad->GetThermalSpokeAngle();
3935 position =
pad->ShapePos( aLayer );
3936 orientation =
pad->GetOrientation();
3944 position =
via->GetPosition();
3949 spokesBox.
Inflate( thermalReliefGap +
epsilon + zone_half_width );
3956 buildSpokesFromOrigin( spokesBox,
ANGLE_0 );
3958 if( thermalSpokeAngle !=
ANGLE_0 )
3961 for(
auto it = aSpokesList.rbegin(); it != aSpokesList.rbegin() + 4; ++it )
3962 it->Rotate( thermalSpokeAngle );
3967 buildSpokesFromOrigin( spokesBox, thermalSpokeAngle );
3970 auto spokeIter = aSpokesList.rbegin();
3972 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
3974 spokeIter->Rotate( orientation );
3975 spokeIter->Move( position );
3980 for(
size_t ii = 0; ii < aSpokesList.size(); ++ii )
3981 aSpokesList[ii].GenerateBBoxCache();
3987 const std::vector<BOARD_ITEM*>& aThermalConnectionPads,
3994 for(
BOARD_ITEM* item : aThermalConnectionPads )
3996 if( !item->IsOnLayer( aLayer ) )
4001 bool isCircular =
false;
4009 pad =
static_cast<PAD*
>( item );
4011 position =
pad->ShapePos( aLayer );
4017 padRadius = std::max( padSize.
x, padSize.
y ) / 2;
4026 int spokeMaxWidth = std::min( padSize.
x, padSize.
y );
4027 spokeWidth = std::min( spokeWidth, spokeMaxWidth );
4032 position =
via->GetPosition();
4034 padRadius =
via->GetWidth( aLayer ) / 2;
4043 spokeWidth = std::min( spokeWidth, padRadius * 2 );
4051 if( spokeWidth < aZone->GetMinThickness() )
4061 int ringInnerRadius = padRadius + thermalGap;
4062 int ringWidth = spokeWidth;
4075 pad->TransformShapeToPolygon( outerShape, aLayer, thermalGap + spokeWidth,
4079 pad->TransformShapeToPolygon( innerShape, aLayer, thermalGap,
4082 thermalRing = outerShape;
4112 if( settings.
gap <= 0
4114 || ( needsLineWidth && settings.
line_width <= 0 ) )
4141 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();
4164 const int dotRadius = std::max( settings.
element_size / 2 - halfMinWidth, 1 );
4165 const int maxError =
m_board->GetDesignSettings().m_MaxError;
4171 int xStart = bbox.
GetLeft() - ( bbox.
GetLeft() % dotStride ) + offset.
x;
4172 int yStart = bbox.
GetTop() - ( bbox.
GetTop() % dotStride ) + offset.
y;
4174 while( xStart > bbox.
GetLeft() )
4175 xStart -= dotStride;
4177 while( yStart > bbox.
GetTop() )
4178 yStart -= dotStride;
4207 int xVoid = bbox.
GetLeft() - ( bbox.
GetLeft() % lineStride ) + offset.
x
4209 int yVoid = bbox.
GetTop() - ( bbox.
GetTop() % lineStride ) + offset.
y
4212 while( xVoid - voidSize / 2 > bbox.
GetLeft() )
4213 xVoid -= lineStride;
4215 while( yVoid - voidSize / 2 > bbox.
GetTop() )
4216 yVoid -= lineStride;
4220 for(
int yy = yVoid; yy <= bbox.
GetBottom() + voidSize; yy += lineStride )
4222 for(
int xx = xVoid; xx <= bbox.
GetRight() + voidSize; xx += lineStride )
4225 rect.
Append( xx - voidSize / 2, yy - voidSize / 2 );
4226 rect.
Append( xx + voidSize / 2, yy - voidSize / 2 );
4227 rect.
Append( xx + voidSize / 2, yy + voidSize / 2 );
4228 rect.
Append( xx - voidSize / 2, yy + voidSize / 2 );
4253 const VECTOR2I squareSize( sideLen, sideLen );
4255 const int containmentInset =
4270 for(
int yy = yStart; yy <= bbox.
GetBottom() + dotRadius; yy += dotStride )
4272 const int rowOffset = ( settings.
stagger && ( rowIndex & 1 ) ) ? dotStride / 2 : 0;
4274 for(
int xx = xStart + rowOffset; xx <= bbox.
GetRight() + dotRadius; xx += dotStride )
4278 if( !filledRegion.
Contains( centre, -1, 0,
true ) )
4298 aFillPolys = stamps;
4319 int maxError =
m_board->GetDesignSettings().m_MaxError;
4335 hole_base.
Append( corner );
4336 corner.
x += hole_size;
4337 hole_base.
Append( corner );
4338 corner.
y += hole_size;
4339 hole_base.
Append( corner );
4341 hole_base.
Append( corner );
4361 #define SMOOTH_MIN_VAL_MM 0.02
4362 #define SMOOTH_SMALL_VAL_MM 0.04
4378 smooth_value = std::min( smooth_value, aZone->
GetHatchGap() / 2 );
4381 maxError = std::max( maxError * 2, smooth_value / 20 );
4383 switch( smooth_level )
4395 hole_base = smooth_hole.
Fillet( smooth_value, maxError ).
Outline( 0 );
4407 const auto& defaultOffsets =
m_board->GetDesignSettings().m_ZoneLayerProperties;
4412 if(
auto it = defaultOffsets.find( aLayer ); it != defaultOffsets.end() )
4413 offset = it->second.hatching_offset.value_or(
VECTOR2I() );
4415 if( localOffsets.contains( aLayer ) && localOffsets.at( aLayer ).hatching_offset.has_value() )
4416 offset = localOffsets.at( aLayer ).hatching_offset.value();
4418 int x_offset = bbox.
GetX() - ( bbox.
GetX() ) % gridsize - gridsize;
4419 int y_offset = bbox.
GetY() - ( bbox.
GetY() ) % gridsize - gridsize;
4422 for(
int xx = x_offset; xx <= bbox.
GetRight(); xx += gridsize )
4424 for(
int yy = y_offset; yy <= bbox.
GetBottom(); yy += gridsize )
4435 hole.
Move(
VECTOR2I( offset.
x % gridsize, offset.
y % gridsize ) );
4448 deflated_thickness = std::max( deflated_thickness, maxError * 2 );
4470 if( area < minimal_hole_area )
4481 BOX2I thermalBBox = aThermalRings.
BBox();
4484 for(
int holeIdx = holes.
OutlineCount() - 1; holeIdx >= 0; holeIdx-- )
4494 for(
int ringIdx = 0; ringIdx < aThermalRings.
OutlineCount(); ringIdx++ )
4501 if( !holeBBox.
Contains( ringBBox ) )
4517 if( intersections.empty() )
4539 auto cacheKey = std::make_pair(
static_cast<const ZONE*
>( aZone ), aLayer );
4549 aFillPolys = it->second;
4562 auto evalRulesForItems =
4574 bool knockoutsApplied =
false;
4578 auto collectZoneKnockout =
4579 [&](
ZONE* otherZone )
4581 if( otherZone == aZone )
4584 if( !otherZone->GetLayerSet().test( aLayer ) )
4588 if( otherZone->IsTeardropArea() )
4591 if( !otherZone->HigherPriority( aZone ) )
4596 if( otherZone->SameNet( aZone ) )
4598 if( !otherZone->GetBoundingBox().Intersects( zoneBBox ) )
4610 std::shared_ptr<SHAPE_POLY_SET> fillShared;
4614 auto it = aSnapshot->find( {
static_cast<const ZONE*
>( otherZone ), aLayer } );
4616 if( it == aSnapshot->end() )
4619 fillPtr = &it->second;
4623 if( !otherZone->HasFilledPolysForLayer( aLayer ) )
4626 fillShared = otherZone->GetFilledPolysList( aLayer );
4631 fillPtr = fillShared.get();
4637 if( otherZone->SameNet( aZone ) )
4645 appendZoneOutlineWithoutArcs( otherZone, sameNetKnockouts );
4647 sameNetKnockouts.
Append( *fillPtr );
4660 diffNetKnockouts.
Append( inflatedFill );
4661 knockoutsApplied =
true;
4667 std::vector<INDEXED_ITEM> hits;
4671 collectZoneKnockout(
static_cast<ZONE*
>( hit.m_item ) );
4681 refillHash.
addData(
reinterpret_cast<const uint8_t*
>( diffNetHash.
Value64 ),
4682 sizeof( diffNetHash.
Value64 ) );
4683 refillHash.
addData(
reinterpret_cast<const uint8_t*
>( sameNetHash.
Value64 ),
4684 sizeof( sameNetHash.
Value64 ) );
4693 aFillPolys = it->second.second;
4709 if( knockoutsApplied )
4718 sameNetApron = ait->second;
4742 solidExtent = sit->second;
4746 knockouts.
Append( sameNetKnockouts );
bool operator==(const wxAuiPaneInfo &aLhs, const wxAuiPaneInfo &aRhs)
constexpr EDA_IU_SCALE pcbIUScale
@ ZLO_FORCE_NO_ZONE_CONNECTION
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
BASE_SET & set(size_t pos)
Container for design settings for a BOARD object.
std::shared_ptr< DRC_ENGINE > m_DRCEngine
int GetBiggestClearanceValue() const
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const
Convert the item shape to a closed polygon.
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
virtual void SetIsKnockout(bool aKnockout)
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
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)
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
KICAD_T Type() const
Returns the type of object.
void TransformWithLineEndingsToPolygon(SHAPE_POLY_SET &aBuffer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const
Convert the shape body shortened for line endings plus line-ending geometry to polygons.
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
int Search(const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], VISITOR &aVisitor) const
Search for all items whose bounding boxes overlap the query rectangle.
LSET is a set of PCB_LAYER_IDs.
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
static const LSET & InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
A streaming C++ equivalent for MurmurHash3_x64_128.
FORCE_INLINE void addData(const uint8_t *data, size_t length)
FORCE_INLINE HASH_128 digest()
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
UNCONNECTED_LAYER_MODE UnconnectedLayerMode() const
const BOX2I GetBoundingBox() const override
The bounding box is cached, so this will be efficient most of the time.
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
void SetOffset(PCB_LAYER_ID aLayer, const VECTOR2I &aOffset)
void SetPosition(const VECTOR2I &aPos) override
void SetOrientation(const EDA_ANGLE &aAngle)
Set the rotation angle of the pad.
bool TransformHoleToPolygon(SHAPE_POLY_SET &aBuffer, int aClearance, int aError, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Build the corner list of the polygonal drill shape in the board coordinate system.
void GetBoundingHull(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth=false) const override
Convert the item shape to a closed polygon.
void TransformTextToPolySet(SHAPE_POLY_SET &aBuffer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc) const
Function TransformTextToPolySet Convert the text to a polygonSet describing the actual character stro...
const VECTOR2I & GetStart() const
const VECTOR2I & GetEnd() const
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
virtual int GetWidth() const
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
std::vector< std::vector< double > > m_outlineDistances
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.
ITEM_RTREE m_footprintIndex
void buildItemIndexes()
Index the static board items once per fill.
std::map< std::pair< const ZONE *, PCB_LAYER_ID >, SHAPE_POLY_SET > m_sameNetApronCache
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 ...
BOX2I zoneKnockoutQueryBox(const ZONE *aZone) const
A window that holds every zone zoneKnockoutMayInteract() can accept for aZone.
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...
std::map< PCB_LAYER_ID, ITEM_RTREE > m_zoneIndex
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 postKnockoutMinWidthPrune(const ZONE *aZone, SHAPE_POLY_SET &aFillPolys, const SHAPE_POLY_SET &aSameNetApron)
Remove minimum-width violations introduced by zone-to-zone knockouts.
std::map< PCB_LAYER_ID, ITEM_RTREE > m_trackIndex
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.
static void queryIndex(const ITEM_RTREE &aIndex, const BOX2I &aBBox, std::vector< INDEXED_ITEM > &aResult)
Collect the items whose bounding box overlaps aBBox, in board order.
ZONE_FILLER(BOARD *aBoard, COMMIT *aCommit)
void subtractHigherPriorityZones(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aRawFill)
Removes the outlines of higher-proirity zones with the same net.
void addKnockout(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer, int aGap, SHAPE_POLY_SET &aHoles)
Add a knockout for a pad or via.
SHAPE_POLY_SET m_boardOutline
std::map< std::pair< const ZONE *, PCB_LAYER_ID >, SHAPE_POLY_SET > m_preKnockoutFillCache
void SetProgressReporter(PROGRESS_REPORTER *aReporter)
std::map< std::pair< const ZONE *, PCB_LAYER_ID >, SHAPE_POLY_SET > m_preHatchSolidFillCache
KIRTREE::PACKED_RTREE< INDEXED_ITEM, int, 2 > ITEM_RTREE
std::map< std::pair< const ZONE *, PCB_LAYER_ID >, std::pair< HASH_128, SHAPE_POLY_SET > > m_refillResultCache
PROGRESS_REPORTER * m_progressReporter
bool refillZoneFromCache(ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aFillPolys, const FillSnapshot *aSnapshot=nullptr)
Refill a zone from cached pre-knockout fill.
bool zoneKnockoutMayInteract(const ZONE *aZone, const ZONE *aKnockout) const
Test whether aKnockout's fill can knock out any part of aZone's fill.
bool mayHoldOutOfBoardCopper(const ZONE *aZone) const
True if the fill of aZone can reach outside the board outline.
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)
ITEM_RTREE m_graphicIndex
int m_maxZoneCornerRadius
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
ZONE_SETTINGS::CORNER_SMOOTHING GetCornerSmoothingType() 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
unsigned int GetCornerRadius() const
void SetIsIsland(PCB_LAYER_ID aLayer, int aPolyIdx)
bool IsOnCopperLayer() const override
double CalculateFilledArea()
Compute the area currently occupied by the zone fill.
unsigned GetAssignedPriority() const
bool SameNet(const ZONE *aOther) const
void TransformRingToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aCentre, int aRadius, int aWidth, int aError, ERROR_LOC aErrorLoc)
Convert arcs to multiple straight segments.
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void TransformTrapezoidToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aPosition, const VECTOR2I &aSize, const EDA_ANGLE &aRotation, int aDeltaX, int aDeltaY, int aInflate, int aError, ERROR_LOC aErrorLoc)
Convert a rectangle or trapezoid to a polygon.
void BuildConvexHull(std::vector< VECTOR2I > &aResult, const std::vector< VECTOR2I > &aPoly)
Calculate the convex hull of a list of points in counter-clockwise order.
CORNER_STRATEGY
define how inflate transform build inflated polygon
@ CHAMFER_ALL_CORNERS
All angles are chamfered.
@ ROUND_ALL_CORNERS
All angles are rounded.
@ EDGE_CLEARANCE_CONSTRAINT
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
@ THERMAL_SPOKE_WIDTH_CONSTRAINT
@ THERMAL_RELIEF_GAP_CONSTRAINT
@ HOLE_CLEARANCE_CONSTRAINT
@ PHYSICAL_CLEARANCE_CONSTRAINT
static constexpr EDA_ANGLE ANGLE_0
static constexpr EDA_ANGLE ANGLE_90
a few functions useful in geometry calculations.
bool m_ZoneFillIterativeRefill
Enable iterative zone filling to handle isolated islands in higher priority zones.
bool m_DebugZoneFiller
A mode that dumps the various stages of a F_Cu fill into In1_Cu through In9_Cu.
static constexpr std::size_t hash_val(const Types &... args)
@ ALWAYS_FLASHED
Always flashed for connectivity.
bool IsInnerCopperLayer(int aLayerId)
Test whether a layer is an inner (In1_Cu to In30_Cu) copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
@ PTH
Plated through hole pad.
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
BARCODE class definition.
static PGM_BASE * process
A storage class for 128-bit hash value.
A struct recording the isolated and single-pad islands within a zone.
The properties of a padstack drill.
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.
An item in one of the fill indexes.
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
@ PCB_DRILL_CHART_T
class PCB_DRILL_CHART, a live drill chart derived from PCB_TABLE
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D
#define SMOOTH_MIN_VAL_MM
static void dropSubResolutionOutlines(SHAPE_POLY_SET &aPolys, int aMaxError)
#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