28#include <wx/filename.h>
32#include <unordered_map>
33#include <unordered_set>
72 RESULTS(
int aOutline1,
int aOutline2,
int aVertex1,
int aVertex2 ) :
109 distances.reserve( outline.
PointCount() + 1 );
110 distances.push_back( 0.0 );
112 for(
int j = 0; j < outline.
PointCount(); j++ )
114 distances.push_back( distances.back()
119 tail =
createList( outline, tail, (
void*)( intptr_t )( i ) );
135 SEG::ecoord min_dist = std::numeric_limits<SEG::ecoord>::max();
138 auto check_pt = [&](
VERTEX* p )
144 const std::vector<double>& distances =
146 double directDistance =
std::abs( distances[p->i] - distances[aPt->
i] );
147 double contourDistance =
148 std::min( directDistance, distances.back() - directDistance );
150 if( contourDistance <
m_dist )
154 VECTOR2D diff( p->x - aPt->
x, p->y - aPt->
y );
157 if( dist2 > 0 && dist2 < limit2 && dist2 < min_dist && p->isEar(
true ) )
166 while( p && p->
z <= maxZ )
174 while( p && p->
z >= minZ )
189 std::set<VERTEX*> visited;
202 if( ( visited.empty() || !visited.contains( p ) ) && ( q =
getPoint( p ) ) )
206 if( !visited.contains( q ) &&
208 p->
i, q->
i ).second )
212 visited.insert( p->
prev );
214 visited.insert( p->
next );
217 visited.insert( q->
prev );
219 visited.insert( q->
next );
255struct PAD_KNOCKOUT_KEY
263 bool operator==(
const PAD_KNOCKOUT_KEY& other )
const
265 return position == other.position && effectiveSize == other.effectiveSize
266 && shape == other.shape && orientation == other.orientation
267 && netCode == other.netCode;
271struct PAD_KNOCKOUT_KEY_HASH
273 size_t operator()(
const PAD_KNOCKOUT_KEY& key )
const
275 return hash_val( key.position.
x, key.position.
y, key.effectiveSize.
x, key.effectiveSize.
y,
276 key.shape, key.orientation.
AsDegrees(), key.netCode );
283struct VIA_KNOCKOUT_KEY
289 bool operator==(
const VIA_KNOCKOUT_KEY& other )
const
291 return position == other.position && effectiveSize == other.effectiveSize
292 && netCode == other.netCode;
296struct VIA_KNOCKOUT_KEY_HASH
298 size_t operator()(
const VIA_KNOCKOUT_KEY& key )
const
300 return hash_val( key.position.
x, key.position.
y, key.effectiveSize, key.netCode );
306struct TRACK_KNOCKOUT_KEY
312 TRACK_KNOCKOUT_KEY(
const VECTOR2I& aStart,
const VECTOR2I& aEnd,
int aWidth ) :
316 if( aStart.
x < aEnd.
x || ( aStart.
x == aEnd.
x && aStart.
y <= aEnd.
y ) )
328 bool operator==(
const TRACK_KNOCKOUT_KEY& other )
const
330 return start == other.start && end == other.end && width == other.width;
334struct TRACK_KNOCKOUT_KEY_HASH
336 size_t operator()(
const TRACK_KNOCKOUT_KEY& key )
const
338 return hash_val( key.start.
x, key.start.
y, key.end.
x, key.end.
y, key.width );
342template<
typename Func>
343void forEachBoardAndFootprintZone(
BOARD* aBoard, Func&& aFunc )
350 for(
ZONE* zone : footprint->Zones() )
405 std::vector<INDEXED_ITEM>& aResult )
418 aResult.push_back( aEntry );
422 aIndex.
Search( min, max, visitor );
424 std::sort( aResult.begin(), aResult.end(),
427 return a.m_seq < b.m_seq;
437 BOX2I bbox = aItem->GetBoundingBox();
441 aBuilder.Add( min, max,
INDEXED_ITEM{ aItem, aOwner, aSeq } );
446 forEachBoardAndFootprintZone(
m_board,
453 ITEM_RTREE::Builder graphics;
454 ITEM_RTREE::Builder footprints;
455 ITEM_RTREE::Builder pads;
462 add( footprints, footprint, footprint, seq );
463 add( graphics, &footprint->Reference(), footprint, seq++ );
464 add( graphics, &footprint->Value(), footprint, seq++ );
466 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
467 add( graphics, item, footprint, seq++ );
469 for(
PAD*
pad : footprint->Pads() )
470 add( pads,
pad, footprint, padSeq++ );
474 add( graphics, item,
nullptr, seq++ );
482 std::map<PCB_LAYER_ID, ITEM_RTREE::Builder> tracks;
487 LSET trackLayers = track->GetLayerSet() & boardCu;
490 add( tracks[layer], track,
nullptr, seq );
497 for(
auto& [layer, builder] : tracks )
500 std::map<PCB_LAYER_ID, ITEM_RTREE::Builder> zones;
503 forEachBoardAndFootprintZone(
m_board,
507 add( zones[layer], zone,
nullptr, seq );
514 for(
auto& [layer, builder] : zones )
540 if(
m_board->GetDesignSettings().m_ZoneKeepExternalFillets )
555 if(
m_board->GetDesignSettings().m_ZoneKeepExternalFillets )
557 for(
const ZONE* zone : { aZone, aKnockout } )
562 reach += (int) zone->GetCornerRadius();
576 return zoneOutline.
Collide( &knockoutOutline, reach );
592 std::lock_guard<KISPINLOCK> lock(
m_board->GetConnectivity()->GetLock() );
608 std::shared_ptr<DRC_ENGINE> drcEngine = std::make_shared<DRC_ENGINE>(
m_board, &bds );
612 drcEngine->InitEngine( wxFileName(
m_board->GetDesignRulesPath() ) );
625 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
626 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
HASH_128> oldFillHashes;
627 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> isolatedIslandsMap;
629 std::shared_ptr<CONNECTIVITY_DATA> connectivity =
m_board->GetConnectivity();
636 connectivity->ClearRatsnest();
644 :
_(
"Building zone fills..." ) );
657 zone->CacheBoundingBox();
661 for(
PAD*
pad : footprint->Pads() )
665 pad->BuildEffectiveShapes();
670 for(
ZONE* zone : footprint->Zones() )
671 zone->CacheBoundingBox();
674 footprint->BuildCourtyardCaches();
675 footprint->BuildNetTieCache();
684 std::unordered_map<const ZONE*, POLY_YSTRIPES_INDEX> zoneOutlineIndices;
688 if( zone->GetNumCorners() <= 2 )
691 zoneOutlineIndices[zone].Build( zone->GetBoardOutline() );
698 auto findHighestPriorityZone =
700 const std::function<bool(
const ZONE* )>& testFn ) ->
ZONE*
702 unsigned highestSameNetPriority = 0;
703 ZONE* highestSameNetZone =
nullptr;
704 unsigned highestPriority = 0;
705 ZONE* highestPriorityZone =
nullptr;
710 if( zone->GetIsRuleArea() )
713 if( !zone->IsOnLayer( itemLayer ) )
716 const unsigned priority = zone->GetAssignedPriority();
717 const bool sameNet = zone->GetNetCode() == netcode;
722 if( highestSameNetZone && priority < highestSameNetPriority )
725 else if( highestPriorityZone && priority < highestPriority )
731 if( zone->GetNumCorners() <= 2 )
734 if( !zone->GetBoundingBox().Intersects( bbox ) )
737 if( !testFn( zone ) )
741 && ( !highestSameNetZone || priority > highestSameNetPriority ) )
743 highestSameNetPriority = priority;
744 highestSameNetZone = zone;
747 if( !highestPriorityZone || priority > highestPriority )
749 highestPriority = priority;
750 highestPriorityZone = zone;
754 return highestSameNetZone ? highestSameNetZone : highestPriorityZone;
757 auto isInPourKeepoutArea =
762 if( !zone->GetIsRuleArea() )
765 if( !zone->HasKeepoutParametersSet() )
768 if( !zone->GetDoNotAllowZoneFills() )
771 if( !zone->IsOnLayer( itemLayer ) )
775 if( zone->GetNumCorners() <= 2 )
778 if( !zone->GetBoundingBox().Intersects( bbox ) )
781 auto it = zoneOutlineIndices.find( zone );
783 if( it != zoneOutlineIndices.end() && it->second.Contains( testPoint ) )
800 via->ClearZoneLayerOverrides();
802 if( !
via->GetRemoveUnconnected() )
807 int holeRadius =
via->GetDrillValue() / 2 + 1;
808 int netcode =
via->GetNetCode();
809 LSET layers =
via->GetLayerSet() & boardCuMask;
813 [&](
const ZONE* aZone ) ->
bool
820 if( !
via->ConditionallyFlashed( layer ) )
823 if( isInPourKeepoutArea( bbox, layer,
center ) )
829 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, viaTestFn );
834 || layer == padstack.
Drill().
end ) )
850 for(
PAD*
pad : footprint->Pads() )
852 pad->ClearZoneLayerOverrides();
854 if( !
pad->GetRemoveUnconnected() )
859 int netcode =
pad->GetNetCode();
860 LSET layers =
pad->GetLayerSet() & boardCuMask;
863 [&](
const ZONE* aZone ) ->
bool
865 auto it = zoneOutlineIndices.find( aZone );
867 if( it != zoneOutlineIndices.end() )
868 return it->second.Contains(
center );
875 if( !
pad->ConditionallyFlashed( layer ) )
878 if( isInPourKeepoutArea( bbox, layer,
center ) )
884 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, padTestFn );
895 for(
ZONE* zone : aZones )
898 if( zone->GetIsRuleArea() )
902 if( zone->GetNumCorners() <= 2 )
912 zone->BuildHashValue( layer );
913 oldFillHashes[ { zone, layer } ] = zone->GetHashValue( layer );
916 toFill.emplace_back( std::make_pair( zone, layer ) );
922 if( !zone->IsCopperThieving() && !zone->IsTeardropArea() )
930 auto zone_fill_dependency =
932 bool aRequireCompletedOtherFill ) ->
bool
939 if( aRequireCompletedOtherFill && aOtherZone->GetFillFlag( aLayer ) )
944 if( aOtherZone->GetIsRuleArea() )
948 if( aOtherZone->GetNumCorners() <= 2 )
952 if( !aOtherZone->GetLayerSet().test( aLayer ) )
959 if( aOtherZone->SameNet( aZone ) )
966 auto check_fill_dependency =
969 return zone_fill_dependency( aZone, aLayer, aOtherZone,
true );
972 auto fill_item_dependency =
973 [&](
const std::pair<ZONE*, PCB_LAYER_ID>& aWaiter,
974 const std::pair<ZONE*, PCB_LAYER_ID>& aDependency ) ->
bool
976 if( aWaiter.first == aDependency.first || aWaiter.second != aDependency.second )
979 return check_fill_dependency( aWaiter.first, aWaiter.second, aDependency.first );
983 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
989 ZONE* zone = aFillItem.first;
1004 auto tesselate_lambda =
1005 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
1011 ZONE* zone = aFillItem.first;
1020 std::atomic<bool> cancelled =
false;
1026 auto run_fill_waves =
1027 [&](
const std::vector<std::pair<ZONE*, PCB_LAYER_ID>>& aFillItems,
auto&& aFillFn,
1028 auto&& aTessFn,
auto&& aHasDependency,
bool aAnyDependencies )
1030 const size_t count = aFillItems.size();
1035 std::vector<std::vector<size_t>> successors( count );
1036 std::vector<std::atomic<int>> inDegree( count );
1038 for(
size_t i = 0; i < count; ++i )
1039 inDegree[i].store( 0, std::memory_order_relaxed );
1042 if( aAnyDependencies )
1044 struct LAYER_FILL_ITEMS
1046 std::unordered_map<ZONE*, std::vector<size_t>> indices;
1047 std::unordered_set<ZONE*> indexed;
1048 std::vector<size_t> unindexed;
1051 std::unordered_map<PCB_LAYER_ID, LAYER_FILL_ITEMS> fillItemsByLayer;
1056 auto& indexed = fillItemsByLayer[layer].indexed;
1059 indexed.insert(
static_cast<ZONE*
>( item.m_item ) );
1062 for(
size_t i = 0; i < count; ++i )
1064 const auto& [zone, layer] = aFillItems[i];
1065 LAYER_FILL_ITEMS& items = fillItemsByLayer[layer];
1066 items.indices[zone].push_back( i );
1068 if( !items.indexed.contains( zone ) )
1069 items.unindexed.push_back( i );
1072 std::vector<size_t> lastSeen( count, count );
1075 for(
size_t j = 0; j < count; ++j )
1077 const auto& [zone, layer] = aFillItems[j];
1078 const LAYER_FILL_ITEMS& layerItems = fillItemsByLayer.at( layer );
1079 auto addDependency =
1083 if( i == j || lastSeen[i] == j )
1088 if( aHasDependency( aFillItems[j], aFillItems[i] ) )
1090 successors[i].push_back( j );
1091 inDegree[j].fetch_add( 1, std::memory_order_relaxed );
1095 for(
size_t i : layerItems.unindexed )
1106 auto items = layerItems.indices.find(
static_cast<ZONE*
>( hit.m_item ) );
1108 if( items != layerItems.indices.end() )
1110 for(
size_t i : items->second )
1117 index->second.Search( min, max, visitor );
1122 std::atomic<int> remaining( (
int) count );
1126 std::atomic<int> inFlight( 0 );
1128 std::function<void(
size_t )>
process;
1133 inFlight.fetch_add( 1, std::memory_order_relaxed );
1139 inFlight.fetch_sub( 1, std::memory_order_acq_rel );
1146 int filled = aFillFn( aFillItems[idx] );
1149 for(
size_t succ : successors[idx] )
1151 if( inDegree[succ].fetch_sub( 1, std::memory_order_acq_rel ) == 1 )
1155 if( filled != 0 && !cancelled.load() )
1156 aTessFn( aFillItems[idx] );
1158 remaining.fetch_sub( 1, std::memory_order_acq_rel );
1161 std::vector<size_t> roots;
1164 for(
size_t i = 0; i < count; ++i )
1166 if( inDegree[i].load( std::memory_order_relaxed ) == 0 )
1167 roots.push_back( i );
1170 for(
size_t idx : roots )
1174 while( remaining.load( std::memory_order_acquire ) > 0 )
1184 std::this_thread::sleep_for( std::chrono::milliseconds( 20 ) );
1191 while( inFlight.load( std::memory_order_acquire ) > 0 )
1192 std::this_thread::sleep_for( std::chrono::milliseconds( 1 ) );
1195 run_fill_waves( toFill, fill_lambda, tesselate_lambda, fill_item_dependency,
true );
1211 for(
ZONE* zone : aZones )
1213 if( zone->IsTeardropArea() )
1214 connectivity->Update( zone );
1218 connectivity->FillIsolatedIslandsMap( isolatedIslandsMap );
1219 connectivity->SetProgressReporter(
nullptr );
1224 for(
ZONE* zone : aZones )
1227 if( zone->GetIsRuleArea() )
1230 zone->SetIsFilled(
true );
1239 std::set<std::pair<ZONE*, PCB_LAYER_ID>> zonesWithRemovedIslandLayers;
1246 std::set<std::pair<ZONE*, PCB_LAYER_ID>> initiallyFullyIsolatedLayers;
1248 for(
const auto& [ zone, zoneIslands ] : isolatedIslandsMap )
1252 bool allLayersFullyIsolated =
true;
1254 for(
const auto& [ layer, layerIslands ] : zoneIslands )
1256 bool layerFullyIsolated = ( layerIslands.m_IsolatedOutlines.size()
1257 ==
static_cast<size_t>( zone->GetFilledPolysList( layer )->OutlineCount() ) );
1259 if( layerFullyIsolated )
1260 initiallyFullyIsolatedLayers.insert( { zone, layer } );
1262 allLayersFullyIsolated =
false;
1265 if( allLayersFullyIsolated )
1268 for(
const auto& [ layer, layerIslands ] : zoneIslands )
1273 if( layerIslands.m_IsolatedOutlines.empty() )
1276 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
1280 std::sort( islands.begin(), islands.end(), std::greater<int>() );
1282 std::shared_ptr<SHAPE_POLY_SET> poly = zone->GetFilledPolysList( layer );
1283 long long int minArea = zone->GetMinIslandArea();
1286 for(
int idx : islands )
1292 poly->DeletePolygonAndTriangulationData( idx,
false );
1293 zonesWithRemovedIslandLayers.insert( { zone, layer } );
1297 poly->DeletePolygonAndTriangulationData( idx,
false );
1298 zonesWithRemovedIslandLayers.insert( { zone, layer } );
1302 zone->SetIsIsland( layer, idx );
1306 poly->UpdateTriangulationDataHash();
1307 zone->CalculateFilledArea();
1327 std::set<std::pair<ZONE*, PCB_LAYER_ID>> sameNetOverlapSeeds;
1329 if( iterativeRefill )
1334 std::map<int, std::vector<ZONE*>> zonesByNet;
1336 forEachBoardAndFootprintZone(
1341 zonesByNet[zone->
GetNetCode()].push_back( zone );
1344 for(
ZONE* lowerZone : aZones )
1346 if( lowerZone->GetIsRuleArea() || lowerZone->IsTeardropArea() )
1349 auto netIt = zonesByNet.find( lowerZone->GetNetCode() );
1351 if( netIt == zonesByNet.end() )
1354 LSET lowerLayers = lowerZone->GetLayerSet() & boardCu;
1356 for(
ZONE* higherZone : netIt->second )
1358 if( higherZone == lowerZone
1362 if( !lowerZone->GetBoundingBox().Intersects( higherZone->
GetBoundingBox() ) )
1371 if( lowerZone->HasFilledPolysForLayer( layer )
1374 sameNetOverlapSeeds.insert( { lowerZone, layer } );
1382 && ( !zonesWithRemovedIslandLayers.empty() || !sameNetOverlapSeeds.empty() ) )
1384 const int maxIterations = 8;
1385 bool progressReported =
false;
1386 bool hitIterationLimit =
false;
1389 std::set<std::pair<ZONE*, PCB_LAYER_ID>> changedZoneLayers( zonesWithRemovedIslandLayers );
1390 changedZoneLayers.insert( sameNetOverlapSeeds.begin(), sameNetOverlapSeeds.end() );
1392 auto cached_refill_tessellate_lambda = [&](
const std::pair<ZONE*, PCB_LAYER_ID>& aFillItem ) ->
int
1394 ZONE* zone = aFillItem.first;
1401 auto no_dependency = [](
const std::pair<ZONE*, PCB_LAYER_ID>&,
const std::pair<ZONE*, PCB_LAYER_ID>& ) ->
bool
1406 for(
int iteration = 0; iteration < maxIterations; ++iteration )
1411 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zonesToRefill;
1412 std::set<std::pair<ZONE*, PCB_LAYER_ID>> zonesToRefillSet;
1414 for(
const auto& [changedZone, changedLayer] : changedZoneLayers )
1416 BOX2I bbox = changedZone->GetBoundingBox();
1419 for(
ZONE* zone : aZones )
1421 if( zone->GetIsRuleArea() )
1426 if( zone->IsTeardropArea() )
1429 if( !zone->GetLayerSet().test( changedLayer ) )
1445 if( zone != changedZone && !changedZone->HigherPriority( zone ) && !changedZone->SameNet( zone ) )
1452 if( zone != changedZone && !changedZone->SameNet( zone ) )
1457 else if( !zone->GetBoundingBox().Intersects( bbox ) )
1462 auto fillItem = std::make_pair( zone, changedLayer );
1464 if( zonesToRefillSet.insert( fillItem ).second )
1465 zonesToRefill.push_back( fillItem );
1469 if( zonesToRefill.empty() )
1472 if( !progressReported )
1481 progressReported =
true;
1487 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
HASH_128> iterHashes;
1489 for(
const auto& fillItem : zonesToRefill )
1491 fillItem.first->BuildHashValue( fillItem.second );
1492 iterHashes[fillItem] = fillItem.first->GetHashValue( fillItem.second );
1503 LSET snapshotLayers;
1505 for(
const auto& [zone, layer] : zonesToRefill )
1506 snapshotLayers.
set( layer );
1510 forEachBoardAndFootprintZone(
m_board,
1527 if( sp && sp->OutlineCount() > 0 )
1528 snapshot[{ zone, layer }] = sp->CloneDropTriangulation();
1532 auto cached_refill_fill_lambda =
1533 [&](
const std::pair<ZONE*, PCB_LAYER_ID>& aFillItem ) ->
int
1535 ZONE* zone = aFillItem.first;
1547 run_fill_waves( zonesToRefill, cached_refill_fill_lambda, cached_refill_tessellate_lambda, no_dependency,
1553 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> refillIslandsMap;
1555 for(
const auto& [zone, layer] : zonesToRefill )
1567 connectivity->FillIsolatedIslandsMap( refillIslandsMap );
1569 for(
const auto& [zone, zoneIslands] : refillIslandsMap )
1571 for(
const auto& [layer, layerIslands] : zoneIslands )
1576 if( layerIslands.m_IsolatedOutlines.empty() )
1581 if( initiallyFullyIsolatedLayers.count( { zone, layer } ) > 0 )
1583 if( layerIslands.m_IsolatedOutlines.size()
1590 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
1591 std::sort( islands.begin(), islands.end(), std::greater<int>() );
1597 for(
int idx : islands )
1602 poly->DeletePolygonAndTriangulationData( idx,
false );
1604 poly->DeletePolygonAndTriangulationData( idx,
false );
1609 poly->UpdateTriangulationDataHash();
1617 changedZoneLayers.clear();
1619 for(
const auto& fillItem : zonesToRefill )
1621 fillItem.first->BuildHashValue( fillItem.second );
1623 auto hashIt = iterHashes.find( fillItem );
1624 HASH_128 oldHash = ( hashIt != iterHashes.end() ) ? hashIt->second :
HASH_128{};
1626 if( fillItem.first->GetHashValue( fillItem.second ) != oldHash )
1627 changedZoneLayers.insert( fillItem );
1630 if( changedZoneLayers.empty() )
1633 if( iteration + 1 >= maxIterations )
1635 hitIterationLimit =
true;
1640 if( hitIterationLimit )
1642 wxString msg = wxString::Format(
_(
"Zone fills may be incorrect: iterative refill did not converge "
1643 "after %d passes.\n\n"
1644 "This can happen with complex overlapping zones. "
1645 "Consider simplifying your zones." ),
1650 KIDIALOG dlg( aParent, msg,
_(
"Warning" ), wxOK | wxICON_WARNING );
1656 wxLogWarning( msg );
1663 using island_check_return = std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
int>>;
1665 std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
double>> polys_to_check;
1668 polys_to_check.reserve(
m_board->GetCopperLayerCount() * aZones.size() );
1670 for(
ZONE* zone : aZones )
1683 double minArea = (double) zone->GetMinThickness() * zone->GetMinThickness() * 3;
1690 polys_to_check.emplace_back( zone->GetFilledPolysList( layer ), minArea );
1694 auto island_lambda =
1695 [&](
int aStart,
int aEnd ) -> island_check_return
1697 island_check_return retval;
1699 for(
int ii = aStart; ii < aEnd && !cancelled.load(); ++ii )
1701 auto [poly, minArea] = polys_to_check[ii];
1703 for(
int jj = poly->OutlineCount() - 1; jj >= 0; jj-- )
1708 double island_area = test_poly.
Area();
1710 if( island_area < minArea )
1721 const double inBoardArea = bboxInBoard.
Area();
1722 const double bboxArea =
static_cast<double>( bbox.
GetWidth() )
1723 *
static_cast<double>( bbox.
GetHeight() );
1724 const double outOfBoardArea = bboxArea - inBoardArea;
1726 if( outOfBoardArea < island_area / 2.0 )
1729 if( inBoardArea < island_area / 2.0 )
1731 retval.emplace_back( poly, jj );
1743 if( intersection.
Area() < island_area / 2.0 )
1744 retval.emplace_back( poly, jj );
1751 auto island_returns =
tp.submit_blocks( 0, polys_to_check.size(), island_lambda );
1755 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
1757 std::future<island_check_return>& ret = island_returns[ii];
1761 std::future_status status = ret.wait_for( std::chrono::seconds( 0 ) );
1763 while( status != std::future_status::ready )
1773 status = ret.wait_for( std::chrono::milliseconds( 100 ) );
1778 if( cancelled.load() )
1781 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
1783 std::future<island_check_return>& ret = island_returns[ii];
1787 for(
auto& action_item : ret.get() )
1788 action_item.first->DeletePolygonAndTriangulationData( action_item.second,
true );
1792 for(
ZONE* zone : aZones )
1793 zone->CalculateFilledArea();
1806 std::unique_ptr<POLY_YSTRIPES_INDEX>
index;
1809 struct NET_LAYER_HASH
1811 size_t operator()(
const std::pair<int, PCB_LAYER_ID>& k )
const
1813 return std::hash<int>()( k.first ) ^ ( std::hash<int>()( k.second ) << 16 );
1817 std::unordered_map<std::pair<int, PCB_LAYER_ID>, std::vector<INDEXED_ZONE>, NET_LAYER_HASH>
1818 filledZonesByNetLayer;
1822 if( zone->GetIsRuleArea() )
1827 if( !zone->HasFilledPolysForLayer( layer ) )
1830 const std::shared_ptr<SHAPE_POLY_SET>& fill = zone->GetFilledPolysList( layer );
1832 if( fill->IsEmpty() )
1836 iz.bbox = fill->BBox();
1837 iz.index = std::make_unique<POLY_YSTRIPES_INDEX>();
1838 iz.index->Build( *fill );
1839 filledZonesByNetLayer[{ zone->GetNetCode(), layer }].push_back( std::move( iz ) );
1843 auto zoneReachesPoint =
1846 auto it = filledZonesByNetLayer.find( { aNetcode, aLayer } );
1848 if( it == filledZonesByNetLayer.end() )
1851 for(
const INDEXED_ZONE& iz : it->second )
1853 if( !iz.bbox.GetInflated( aRadius ).Contains( aCenter ) )
1856 if( iz.index->Contains( aCenter, aRadius ) )
1870 int holeRadius =
via->GetDrillValue() / 2;
1871 int netcode =
via->GetNetCode();
1872 LSET layers =
via->GetLayerSet() & boardCuMask;
1879 int reach = std::max( holeRadius,
via->GetWidth( layer ) / 2 );
1881 if( !zoneReachesPoint( netcode, layer,
center, reach ) )
1888 for(
PAD*
pad : footprint->Pads() )
1891 int netcode =
pad->GetNetCode();
1892 LSET layers =
pad->GetLayerSet() & boardCuMask;
1896 if(
pad->HasHole() )
1897 holeRadius = std::min(
pad->GetDrillSizeX(),
pad->GetDrillSizeY() ) / 2;
1908 int reach = std::max( holeRadius, std::min( padSize.
x, padSize.
y ) / 2 );
1910 if( !zoneReachesPoint( netcode, layer,
center, reach ) )
1918 bool outOfDate =
false;
1920 for(
ZONE* zone : aZones )
1923 if( zone->GetIsRuleArea() )
1928 zone->BuildHashValue( layer );
1930 if( oldFillHashes[ { zone, layer } ] != zone->GetHashValue( layer ) )
1936 &&
m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill ) )
1938 KIDIALOG dlg( aParent,
_(
"Prototype zone fill enabled. Disable setting and refill?" ),
_(
"Confirmation" ),
1939 wxOK | wxCANCEL | wxICON_WARNING );
1945 m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill =
false;
1947 else if( !outOfDate )
1955 KIDIALOG dlg( aParent,
_(
"Zone fills are out-of-date. Refill?" ),
_(
"Confirmation" ),
1956 wxOK | wxCANCEL | wxICON_WARNING );
1999 std::vector<VECTOR2I> convex_hull;
2004 for(
const VECTOR2I& pt : convex_hull )
2036 switch( aItem->
Type() )
2043 if(
text->IsVisible() )
2045 if(
text->IsKnockout() )
2108 std::vector<BOARD_ITEM*>& aThermalConnectionPads,
2109 std::vector<PAD*>& aNoConnectionPads,
2110 std::vector<BOARD_ITEM*>& aSolidConnectionItems )
2116 std::shared_ptr<SHAPE> padShape;
2121 std::unordered_set<PAD_KNOCKOUT_KEY, PAD_KNOCKOUT_KEY_HASH> processedPads;
2122 std::unordered_set<VIA_KNOCKOUT_KEY, VIA_KNOCKOUT_KEY_HASH> processedVias;
2128 std::vector<INDEXED_ITEM> padHits;
2134 PAD*
pad =
static_cast<PAD*
>( padHit.m_item );
2140 &&
pad->GetDrillSize().x > 0;
2142 if( !
pad->IsOnLayer( aLayer ) && !npthWithHole )
2145 BOX2I padBBox =
pad->GetBoundingBox();
2162 int drill = std::max(
pad->GetDrillSize().x,
pad->GetDrillSize().y );
2163 int maxDim = std::max( { padSize.
x, padSize.
y, drill } );
2164 effectiveSize =
VECTOR2I( maxDim, maxDim );
2168 effectiveSize = padSize;
2171 PAD_KNOCKOUT_KEY padKey{
pad->GetPosition(), effectiveSize,
2172 static_cast<int>( padShapeType ),
2173 pad->GetOrientation(),
pad->GetNetCode() };
2175 if( !processedPads.insert( padKey ).second )
2179 bool noConnection =
pad->GetNetCode() != aZone->
GetNetCode();
2186 noConnection =
true;
2191 if(
pad->IsBackdrilledOrPostMachined( aLayer ) )
2192 noConnection =
true;
2197 aNoConnectionPads.push_back(
pad );
2212 switch( connection )
2218 if( aFill.
Collide( padShape.get(), 0 ) )
2226 aThermalConnectionPads.push_back(
pad );
2235 aNoConnectionPads.push_back(
pad );
2260 switch( connection )
2265 if( aFill.
Collide( padShape.get(), 0 ) )
2270 aThermalConnectionPads.push_back(
pad );
2284 if(
pad->FlashLayer( aLayer ) )
2288 else if(
pad->GetDrillSize().x > 0 )
2295 holeClearance = padClearance;
2321 if( !
via->IsOnLayer( aLayer ) )
2324 BOX2I viaBBox =
via->GetBoundingBox();
2331 int viaEffectiveSize = std::max(
via->GetDrillValue(),
via->GetWidth( aLayer ) );
2332 VIA_KNOCKOUT_KEY viaKey{
via->GetPosition(), viaEffectiveSize,
via->GetNetCode() };
2334 if( !processedVias.insert( viaKey ).second )
2337 bool noConnection =
via->GetNetCode() != aZone->
GetNetCode()
2339 && aLayer !=
via->Padstack().Drill().start
2340 && aLayer !=
via->Padstack().Drill().end );
2343 noConnection =
true;
2346 if(
via->IsBackdrilledOrPostMachined( aLayer ) )
2348 noConnection =
true;
2360 pmSize = std::max( pmSize, frontPM.
size );
2366 pmSize = std::max( pmSize, backPM.
size );
2372 bdSize = secDrill.
size.
x;
2374 int knockoutSize = std::max( pmSize, bdSize );
2376 if( knockoutSize > 0 )
2391 switch( connection )
2401 if( thermalGap > 0 )
2403 aThermalConnectionPads.push_back(
via );
2418 aSolidConnectionItems.push_back(
via );
2433 const std::vector<PAD*>& aNoConnectionPads,
2435 bool aIncludeZoneClearances )
2441 std::unordered_set<PAD_KNOCKOUT_KEY, PAD_KNOCKOUT_KEY_HASH> processedPads;
2442 std::unordered_set<VIA_KNOCKOUT_KEY, VIA_KNOCKOUT_KEY_HASH> processedVias;
2443 std::unordered_set<TRACK_KNOCKOUT_KEY, TRACK_KNOCKOUT_KEY_HASH> processedTracks;
2445 auto checkForCancel =
2448 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
2461 auto evalRulesForItems =
2475 auto knockoutPadClearance =
2480 bool hasHole = aPad->GetDrillSize().x > 0;
2482 bool flashLayer = aPad->FlashLayer( aLayer );
2485 if( flashLayer || platedHole )
2488 if( flashLayer && gap >= 0 )
2489 addKnockout( aPad, aLayer, gap + extra_margin, aHoles );
2500 gap = std::max( gap, holeGap );
2507 if( aPad->IsBackdrilledOrPostMachined( aLayer ) )
2509 int knockoutSize = aPad->Padstack().GetMaxHoleSize();
2511 if( knockoutSize > 0 )
2513 int clearance = std::max( holeGap, 0 ) + extra_margin;
2521 for(
PAD*
pad : aNoConnectionPads )
2537 int drill = std::max(
pad->GetDrillSize().x,
pad->GetDrillSize().y );
2538 int maxDim = std::max( { padSize.
x, padSize.
y, drill } );
2539 effectiveSize =
VECTOR2I( maxDim, maxDim );
2543 effectiveSize = padSize;
2546 PAD_KNOCKOUT_KEY padKey{
pad->GetPosition(), effectiveSize,
static_cast<int>( padShape ),
2547 pad->GetOrientation(),
pad->GetNetCode() };
2549 if( !processedPads.insert( padKey ).second )
2553 knockoutPadClearance(
pad );
2558 auto knockoutTrackClearance =
2561 if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
2563 bool sameNet = aTrack->GetNetCode() == aZone->
GetNetCode();
2585 if(
via->FlashLayer( aLayer ) && gap > 0 )
2587 via->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
m_maxError,
2599 gap = std::max( gap, holeGap );
2610 if(
via->IsBackdrilledOrPostMachined( aLayer ) )
2612 int knockoutSize =
via->Padstack().GetMaxHoleSize();
2614 if( knockoutSize > 0 )
2616 int clearance = std::max( holeGap, 0 ) + extra_margin;
2627 aTrack->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
m_maxError,
2634 std::vector<INDEXED_ITEM> hits;
2637 queryIndex( trackIt->second, zone_boundingbox, hits );
2653 int viaEffectiveSize = std::max(
via->GetDrillValue(),
via->GetWidth( aLayer ) );
2654 VIA_KNOCKOUT_KEY viaKey{
via->GetPosition(), viaEffectiveSize,
via->GetNetCode() };
2656 if( !processedVias.insert( viaKey ).second )
2663 if( !processedTracks.insert( trackKey ).second )
2667 knockoutTrackClearance( track );
2672 auto knockoutGraphicClearance =
2678 shapeNet =
static_cast<PCB_SHAPE*
>( aItem )->GetNetCode();
2680 bool sameNet = shapeNet == aZone->
GetNetCode();
2686 if( aItem->IsOnLayer( aLayer )
2688 || aItem->IsOnLayer(
Margin ) )
2690 if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
2692 bool ignoreLineWidths =
false;
2695 if( aItem->IsOnLayer( aLayer ) && !sameNet )
2699 else if( aItem->IsOnLayer(
Edge_Cuts ) )
2702 ignoreLineWidths =
true;
2704 else if( aItem->IsOnLayer(
Margin ) )
2711 gap += extra_margin;
2712 addKnockout( aItem, aLayer, gap, ignoreLineWidths, aHoles );
2718 auto knockoutCourtyardClearance =
2721 if( aFootprint->GetBoundingBox().Intersects( zone_boundingbox ) )
2732 aHoles.
Append( aFootprint->GetCourtyard( courtyardSide ) );
2745 std::map<FOOTPRINT*, std::set<PAD*>> netTiePads;
2747 auto allowedNetTiePads =
2748 [&](
FOOTPRINT* aFootprint ) ->
const std::set<PAD*>&
2750 auto [it, inserted] = netTiePads.try_emplace( aFootprint );
2752 if( !inserted || !aFootprint->IsNetTie() )
2755 for(
PAD*
pad : aFootprint->Pads() )
2764 if(
pad->IsOnLayer( aLayer ) )
2765 it->second.insert(
pad );
2767 for(
PAD* other : aFootprint->GetNetTiePads(
pad ) )
2769 if( other->IsOnLayer( aLayer ) )
2770 it->second.insert( other );
2778 std::vector<INDEXED_ITEM> gfxHits;
2779 std::vector<INDEXED_ITEM> fpHits;
2788 while( gi < gfxHits.size() || fi < fpHits.size() )
2793 if( fi < fpHits.size() && ( gi >= gfxHits.size() || fpHits[fi].m_seq <= gfxHits[gi].m_seq ) )
2795 knockoutCourtyardClearance(
static_cast<FOOTPRINT*
>( fpHits[fi++].m_item ) );
2802 bool skipItem =
false;
2805 if( owner && item != &owner->
Reference() && item != &owner->
Value()
2808 const std::set<PAD*>& allowed = allowedNetTiePads( owner );
2810 if( !allowed.empty() )
2815 for(
PAD*
pad : allowed )
2817 if(
pad->GetBoundingBox().Intersects( itemBBox )
2818 &&
pad->GetEffectiveShape( aLayer )->Collide( itemShape.get() ) )
2828 knockoutGraphicClearance( item );
2833 auto knockoutZoneClearance =
2834 [&](
ZONE* aKnockout )
2837 if( !aKnockout->GetLayerSet().test( aLayer ) )
2840 if( aKnockout->GetIsRuleArea() )
2842 if( aKnockout->GetBoundingBox().Intersects( zone_boundingbox )
2843 && aKnockout->GetDoNotAllowZoneFills() && !aZone->
IsTeardropArea() )
2850 else if( aKnockout->HigherPriority( aZone ) && !aKnockout->SameNet( aZone )
2876 ZONE* otherZone =
static_cast<ZONE*
>( hit.m_item );
2883 knockoutZoneClearance( otherZone );
2900 auto evalRulesForItems =
2916 auto knockoutZoneClearance =
2917 [&](
ZONE* aKnockout )
2919 if( aKnockout->GetIsRuleArea() )
2923 if( aKnockout->IsTeardropArea() )
2926 if( !aKnockout->GetLayerSet().test( aLayer ) )
2929 if( aKnockout->HigherPriority( aZone )
2930 && !aKnockout->SameNet( aZone )
2947 std::vector<INDEXED_ITEM> hits;
2951 knockoutZoneClearance(
static_cast<ZONE*
>( hit.m_item ) );
2967 auto collectZoneOutline =
2968 [&](
ZONE* aKnockout )
2970 if( !aKnockout->GetLayerSet().test( aLayer ) )
2973 if( aKnockout->GetBoundingBox().Intersects( zoneBBox ) )
2974 appendZoneOutlineWithoutArcs( aKnockout, knockouts );
2979 std::vector<INDEXED_ITEM> hits;
2984 ZONE* otherZone =
static_cast<ZONE*
>( hit.m_item );
2988 bool higherPrioritySameNet =
2993 collectZoneOutline( otherZone );
3013 std::map<int, std::vector<std::pair<int, VECTOR2I>>> insertion_points;
3025 insertion_points[
result.m_outline1].push_back( {
result.m_vertex1, pt1 } );
3026 insertion_points[
result.m_outline1].push_back( {
result.m_vertex1, pt2 } );
3029 for(
auto& [outline, vertices] : insertion_points )
3037 std::stable_sort( vertices.begin(), vertices.end(),
3038 [](
const std::pair<int, VECTOR2I>& a,
const std::pair<int, VECTOR2I>& b )
3040 return a.first > b.first;
3043 for(
const auto& [vertex, pt] : vertices )
3044 line.
Insert( vertex + 1, pt );
3053 const double noiseArea = (double) aMaxError * aMaxError;
3055 for(
int ii = aPolys.
OutlineCount() - 1; ii >= 0; ii-- )
3089 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
3091 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
3092 BOX2I islandExtents;
3094 for(
const VECTOR2I& pt : island.front().CPoints() )
3096 islandExtents.
Merge( pt );
3112#define DUMP_POLYS_TO_COPPER_LAYER( a, b, c ) \
3113 { if( m_debugZoneFiller && aDebugLayer == b ) \
3115 m_board->SetLayerName( b, c ); \
3116 SHAPE_POLY_SET d = a; \
3156 std::vector<BOARD_ITEM*> thermalConnectionPads;
3157 std::vector<PAD*> noConnectionPads;
3158 std::vector<BOARD_ITEM*> solidConnectionItems;
3159 std::deque<SHAPE_LINE_CHAIN> thermalSpokes;
3162 aFillPolys = aSmoothedOutline;
3172 knockoutThermalReliefs( aZone, aLayer, aFillPolys, thermalConnectionPads, noConnectionPads, solidConnectionItems );
3189 aFillPolys, thermalRings );
3211 if( iterativeRefill )
3214 bool addedKeepoutHoles =
false;
3216 auto collectKeepoutHoles =
3217 [&](
ZONE* candidate )
3222 if( !isZoneFillKeepout( candidate, aLayer, zone_boundingbox ) )
3227 addedKeepoutHoles =
true;
3230 forEachBoardAndFootprintZone(
m_board, collectKeepoutHoles );
3232 if( addedKeepoutHoles )
3256 if( iterativeRefill )
3291 spokeTestIndex.
Build( testAreas );
3296 const VECTOR2I& testPt = spoke.CPoint( 3 );
3299 if( spokeTestIndex.
Contains( testPt, 1 ) )
3308 if( interval++ > 400 )
3321 if( &other != &spoke
3322 && other.PointInside( testPt, 1 )
3323 && spoke.PointInside( other.CPoint( 3 ), 1 ) )
3360 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
3362 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
3363 BOX2I islandExtents;
3365 for(
const VECTOR2I& pt : island.front().CPoints() )
3367 islandExtents.
Merge( pt );
3388 || !
m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill ) )
3397 for(
BOARD_ITEM* item : solidConnectionItems )
3399 if( item->Type() !=
PCB_VIA_T || !item->IsOnLayer( aLayer ) )
3468 for(
BOARD_ITEM* item : thermalConnectionPads )
3482 bool knockoutsApplied =
false;
3485 if( iterativeRefill )
3504 knockoutsApplied =
true;
3517 if( knockoutsApplied )
3544 auto checkForCancel =
3547 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
3550 auto knockoutGraphicItem =
3553 if( aItem->IsKnockout() && aItem->IsOnLayer( aLayer )
3554 && aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
3556 addKnockout( aItem, aLayer, 0,
true, clearanceHoles );
3565 knockoutGraphicItem( &footprint->Reference() );
3566 knockoutGraphicItem( &footprint->Value() );
3568 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
3569 knockoutGraphicItem( item );
3577 knockoutGraphicItem( item );
3580 aFillPolys = aSmoothedOutline;
3585 auto collectKeepout =
3586 [&](
ZONE* candidate )
3588 if( !isZoneFillKeepout( candidate, aLayer, zone_boundingbox ) )
3591 appendZoneOutlineWithoutArcs( candidate, keepoutHoles );
3594 bool cancelledKeepoutScan =
false;
3596 forEachBoardAndFootprintZone(
3598 [&](
ZONE* keepout )
3600 if( cancelledKeepoutScan )
3605 cancelledKeepoutScan =
true;
3609 collectKeepout( keepout );
3612 if( cancelledKeepoutScan )
3663 debugLayer = aLayer;
3667 if( !aZone->
BuildSmoothedPoly( maxExtents, aLayer, boardOutline, &smoothedPoly ) )
3675 if(
fillCopperZone( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aFillPolys ) )
3692 const std::vector<BOARD_ITEM*>& aSpokedPadsList,
3693 std::deque<SHAPE_LINE_CHAIN>& aSpokesList )
3712 if( !item->IsOnLayer( aLayer ) )
3715 int thermalReliefGap = 0;
3719 bool circular =
false;
3723 pad =
static_cast<PAD*
>( item );
3753 int spoke_max_allowed_w = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
3754 spoke_w = std::clamp( spoke_w, constraint.
Value().
Min(), constraint.
Value().
Max() );
3755 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
3757 if( spoke_w < aZone->GetMinThickness() )
3770 spoke_w = std::min( spoke_w,
via->GetWidth( aLayer ) );
3772 if( spoke_w < aZone->GetMinThickness() )
3791 int spoke_max_allowed_w = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
3793 spoke_w = std::clamp( spoke_w, constraint.
Value().
Min(), constraint.
Value().
Max() );
3796 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
3799 if( spoke_w < aZone->GetMinThickness() )
3808 int spoke_half_w = spoke_w / 2;
3811 BOX2I itemBB = item->GetBoundingBox();
3817 bool customSpokes =
false;
3821 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
3823 if( primitive->IsProxyItem() && primitive->GetShape() ==
SHAPE_T::SEGMENT )
3825 customSpokes =
true;
3836 auto buildSpokesFromOrigin =
3843 auto intersectBBox =
3846 double dx = spokeAngle.
Cos();
3847 double dy = spokeAngle.
Sin();
3853 *spoke_side =
VECTOR2I( spoke_half_w, 0 );
3854 return KiROUND( 0.0, dy * half_size.
y );
3858 *spoke_side =
VECTOR2I( 0, spoke_half_w );
3859 return KiROUND( dx * half_size.
x, 0.0 );
3864 double dist_x = half_size.
x /
std::abs( dx );
3865 double dist_y = half_size.
y /
std::abs( dy );
3867 if( dist_x < dist_y )
3869 *spoke_side =
KiROUND( 0.0, spoke_half_w / (
ANGLE_90 - spokeAngle ).Sin() );
3870 return KiROUND( dx * dist_x, dy * dist_x );
3874 *spoke_side =
KiROUND( spoke_half_w / spokeAngle.
Sin(), 0.0 );
3875 return KiROUND( dx * dist_y, dy * dist_y );
3888 for(
const EDA_ANGLE& spokeAngle : angles )
3891 VECTOR2I intersection = intersectBBox( spokeAngle, &spoke_side );
3900 aSpokesList.push_back( std::move( spoke ) );
3912 thermalOutline = thermalPoly.
Outline( 0 );
3916 auto trimToOutline = [&](
SEG& aSegment )
3920 if( padOutline.
Intersect( aSegment, intersections ) )
3922 intersections.clear();
3925 if( thermalOutline.
Intersect( aSegment, intersections ) )
3927 aSegment.B = intersections.front().p;
3934 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
3936 if( primitive->IsProxyItem() && primitive->GetShape() ==
SHAPE_T::SEGMENT )
3938 SEG seg( primitive->GetStart(), primitive->GetEnd() );
3943 seg.
A +=
pad->ShapePos( aLayer );
3944 seg.
B +=
pad->ShapePos( aLayer );
3958 if( trimToOutline( seg ) )
3960 VECTOR2I direction = ( seg.
B - seg.
A ).Resize( spoke_half_w );
3964 SEG segL( seg.
A - direction - offset, seg.
B + direction - offset );
3965 SEG segR( seg.
A - direction + offset, seg.
B + direction + offset );
3968 if( trimToOutline( segL ) && trimToOutline( segR ) )
3976 spoke.
Append( seg.
A + offset );
3977 spoke.
Append( seg.
A - offset );
3979 spoke.
Append( segL.
B + direction );
3980 spoke.
Append( seg.
B + direction );
3981 spoke.
Append( segR.
B + direction );
3984 aSpokesList.push_back( std::move( spoke ) );
3997 thermalSpokeAngle =
pad->GetThermalSpokeAngle();
4016 position =
pad->ShapePos( aLayer );
4017 orientation =
pad->GetOrientation();
4025 position =
via->GetPosition();
4030 spokesBox.
Inflate( thermalReliefGap +
epsilon + zone_half_width );
4037 buildSpokesFromOrigin( spokesBox,
ANGLE_0 );
4039 if( thermalSpokeAngle !=
ANGLE_0 )
4042 for(
auto it = aSpokesList.rbegin(); it != aSpokesList.rbegin() + 4; ++it )
4043 it->Rotate( thermalSpokeAngle );
4048 buildSpokesFromOrigin( spokesBox, thermalSpokeAngle );
4051 auto spokeIter = aSpokesList.rbegin();
4053 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
4055 spokeIter->Rotate( orientation );
4056 spokeIter->Move( position );
4061 for(
size_t ii = 0; ii < aSpokesList.size(); ++ii )
4062 aSpokesList[ii].GenerateBBoxCache();
4068 const std::vector<BOARD_ITEM*>& aThermalConnectionPads,
4075 for(
BOARD_ITEM* item : aThermalConnectionPads )
4077 if( !item->IsOnLayer( aLayer ) )
4082 bool isCircular =
false;
4090 pad =
static_cast<PAD*
>( item );
4092 position =
pad->ShapePos( aLayer );
4098 padRadius = std::max( padSize.
x, padSize.
y ) / 2;
4107 int spokeMaxWidth = std::min( padSize.
x, padSize.
y );
4108 spokeWidth = std::min( spokeWidth, spokeMaxWidth );
4113 position =
via->GetPosition();
4115 padRadius =
via->GetWidth( aLayer ) / 2;
4124 spokeWidth = std::min( spokeWidth, padRadius * 2 );
4132 if( spokeWidth < aZone->GetMinThickness() )
4142 int ringInnerRadius = padRadius + thermalGap;
4143 int ringWidth = spokeWidth;
4156 pad->TransformShapeToPolygon( outerShape, aLayer, thermalGap + spokeWidth,
4160 pad->TransformShapeToPolygon( innerShape, aLayer, thermalGap,
4163 thermalRing = outerShape;
4193 if( settings.
gap <= 0
4195 || ( needsLineWidth && settings.
line_width <= 0 ) )
4222 const auto& defaultOffsets =
m_board->GetDesignSettings().m_ZoneLayerProperties;
4226 if(
auto it = defaultOffsets.find( aLayer ); it != defaultOffsets.end() )
4227 offset = it->second.hatching_offset.value_or(
VECTOR2I() );
4229 if( localOffsets.contains( aLayer ) && localOffsets.at( aLayer ).hatching_offset.has_value() )
4230 offset = localOffsets.at( aLayer ).hatching_offset.value();
4245 const int dotRadius = std::max( settings.
element_size / 2 - halfMinWidth, 1 );
4246 const int maxError =
m_board->GetDesignSettings().m_MaxError;
4252 int xStart = bbox.
GetLeft() - ( bbox.
GetLeft() % dotStride ) + offset.
x;
4253 int yStart = bbox.
GetTop() - ( bbox.
GetTop() % dotStride ) + offset.
y;
4255 while( xStart > bbox.
GetLeft() )
4256 xStart -= dotStride;
4258 while( yStart > bbox.
GetTop() )
4259 yStart -= dotStride;
4288 int xVoid = bbox.
GetLeft() - ( bbox.
GetLeft() % lineStride ) + offset.
x
4290 int yVoid = bbox.
GetTop() - ( bbox.
GetTop() % lineStride ) + offset.
y
4293 while( xVoid - voidSize / 2 > bbox.
GetLeft() )
4294 xVoid -= lineStride;
4296 while( yVoid - voidSize / 2 > bbox.
GetTop() )
4297 yVoid -= lineStride;
4301 for(
int yy = yVoid; yy <= bbox.
GetBottom() + voidSize; yy += lineStride )
4303 for(
int xx = xVoid; xx <= bbox.
GetRight() + voidSize; xx += lineStride )
4306 rect.
Append( xx - voidSize / 2, yy - voidSize / 2 );
4307 rect.
Append( xx + voidSize / 2, yy - voidSize / 2 );
4308 rect.
Append( xx + voidSize / 2, yy + voidSize / 2 );
4309 rect.
Append( xx - voidSize / 2, yy + voidSize / 2 );
4334 const VECTOR2I squareSize( sideLen, sideLen );
4336 const int containmentInset =
4351 for(
int yy = yStart; yy <= bbox.
GetBottom() + dotRadius; yy += dotStride )
4353 const int rowOffset = ( settings.
stagger && ( rowIndex & 1 ) ) ? dotStride / 2 : 0;
4355 for(
int xx = xStart + rowOffset; xx <= bbox.
GetRight() + dotRadius; xx += dotStride )
4359 if( !filledRegion.
Contains( centre, -1, 0,
true ) )
4379 aFillPolys = stamps;
4400 int maxError =
m_board->GetDesignSettings().m_MaxError;
4416 hole_base.
Append( corner );
4417 corner.
x += hole_size;
4418 hole_base.
Append( corner );
4419 corner.
y += hole_size;
4420 hole_base.
Append( corner );
4422 hole_base.
Append( corner );
4442 #define SMOOTH_MIN_VAL_MM 0.02
4443 #define SMOOTH_SMALL_VAL_MM 0.04
4459 smooth_value = std::min( smooth_value, aZone->
GetHatchGap() / 2 );
4462 maxError = std::max( maxError * 2, smooth_value / 20 );
4464 switch( smooth_level )
4476 hole_base = smooth_hole.
Fillet( smooth_value, maxError ).
Outline( 0 );
4488 const auto& defaultOffsets =
m_board->GetDesignSettings().m_ZoneLayerProperties;
4493 if(
auto it = defaultOffsets.find( aLayer ); it != defaultOffsets.end() )
4494 offset = it->second.hatching_offset.value_or(
VECTOR2I() );
4496 if( localOffsets.contains( aLayer ) && localOffsets.at( aLayer ).hatching_offset.has_value() )
4497 offset = localOffsets.at( aLayer ).hatching_offset.value();
4499 int x_offset = bbox.
GetX() - ( bbox.
GetX() ) % gridsize - gridsize;
4500 int y_offset = bbox.
GetY() - ( bbox.
GetY() ) % gridsize - gridsize;
4503 for(
int xx = x_offset; xx <= bbox.
GetRight(); xx += gridsize )
4505 for(
int yy = y_offset; yy <= bbox.
GetBottom(); yy += gridsize )
4516 hole.
Move(
VECTOR2I( offset.
x % gridsize, offset.
y % gridsize ) );
4529 deflated_thickness = std::max( deflated_thickness, maxError * 2 );
4551 if( area < minimal_hole_area )
4562 BOX2I thermalBBox = aThermalRings.
BBox();
4565 for(
int holeIdx = holes.
OutlineCount() - 1; holeIdx >= 0; holeIdx-- )
4575 for(
int ringIdx = 0; ringIdx < aThermalRings.
OutlineCount(); ringIdx++ )
4582 if( !holeBBox.
Contains( ringBBox ) )
4598 if( intersections.empty() )
4620 auto cacheKey = std::make_pair(
static_cast<const ZONE*
>( aZone ), aLayer );
4630 aFillPolys = it->second;
4643 auto evalRulesForItems =
4655 bool knockoutsApplied =
false;
4659 auto collectZoneKnockout =
4660 [&](
ZONE* otherZone )
4662 if( otherZone == aZone )
4665 if( !otherZone->GetLayerSet().test( aLayer ) )
4669 if( otherZone->IsTeardropArea() )
4672 if( !otherZone->HigherPriority( aZone ) )
4677 if( otherZone->SameNet( aZone ) )
4679 if( !otherZone->GetBoundingBox().Intersects( zoneBBox ) )
4691 std::shared_ptr<SHAPE_POLY_SET> fillShared;
4695 auto it = aSnapshot->find( {
static_cast<const ZONE*
>( otherZone ), aLayer } );
4697 if( it == aSnapshot->end() )
4700 fillPtr = &it->second;
4704 if( !otherZone->HasFilledPolysForLayer( aLayer ) )
4707 fillShared = otherZone->GetFilledPolysList( aLayer );
4712 fillPtr = fillShared.get();
4718 if( otherZone->SameNet( aZone ) )
4726 appendZoneOutlineWithoutArcs( otherZone, sameNetKnockouts );
4728 sameNetKnockouts.
Append( *fillPtr );
4741 diffNetKnockouts.
Append( inflatedFill );
4742 knockoutsApplied =
true;
4748 std::vector<INDEXED_ITEM> hits;
4752 collectZoneKnockout(
static_cast<ZONE*
>( hit.m_item ) );
4762 refillHash.
addData(
reinterpret_cast<const uint8_t*
>( diffNetHash.
Value64 ),
4763 sizeof( diffNetHash.
Value64 ) );
4764 refillHash.
addData(
reinterpret_cast<const uint8_t*
>( sameNetHash.
Value64 ),
4765 sizeof( sameNetHash.
Value64 ) );
4774 aFillPolys = it->second.second;
4790 if( knockoutsApplied )
4799 sameNetApron = ait->second;
4823 solidExtent = sit->second;
4827 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.
EDA_ANGLE GetAngle() const
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
Add two rectangular polygons separately bounding the barcode's symbol and the barcode's text.
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
Convert the text to a polygonSet describing the actual character strokes (one per segment).
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)
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)
Add non copper areas polygons (pads and tracks with clearance) to a filled copper area used in BuildF...
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={})
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:
SHAPE_LINE_CHAIN BoxToLineChain(const BOX2I &aBox)
Get a SHAPE_LINE_CHAIN representing the outline of a box.
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
Utility functions for working with shapes.
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.
EDA_ORIENTATION orientation
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