28#include <wx/filename.h>
32#include <unordered_map>
33#include <unordered_set>
70 RESULTS(
int aOutline1,
int aOutline2,
int aVertex1,
int aVertex2 ) :
107 distances.reserve( outline.
PointCount() + 1 );
108 distances.push_back( 0.0 );
110 for(
int j = 0; j < outline.
PointCount(); j++ )
112 distances.push_back( distances.back()
117 tail =
createList( outline, tail, (
void*)( intptr_t )( i ) );
133 SEG::ecoord min_dist = std::numeric_limits<SEG::ecoord>::max();
136 auto check_pt = [&](
VERTEX* p )
142 const std::vector<double>& distances =
144 double directDistance =
std::abs( distances[p->i] - distances[aPt->
i] );
145 double contourDistance =
146 std::min( directDistance, distances.back() - directDistance );
148 if( contourDistance <
m_dist )
152 VECTOR2D diff( p->x - aPt->
x, p->y - aPt->
y );
155 if( dist2 > 0 && dist2 < limit2 && dist2 < min_dist && p->isEar(
true ) )
164 while( p && p->
z <= maxZ )
172 while( p && p->
z >= minZ )
187 std::set<VERTEX*> visited;
200 if( ( visited.empty() || !visited.contains( p ) ) && ( q =
getPoint( p ) ) )
204 if( !visited.contains( q ) &&
206 p->
i, q->
i ).second )
210 visited.insert( p->
prev );
212 visited.insert( p->
next );
215 visited.insert( q->
prev );
217 visited.insert( q->
next );
253struct PAD_KNOCKOUT_KEY
261 bool operator==(
const PAD_KNOCKOUT_KEY& other )
const
263 return position == other.position && effectiveSize == other.effectiveSize
264 && shape == other.shape && orientation == other.orientation
265 && netCode == other.netCode;
269struct PAD_KNOCKOUT_KEY_HASH
271 size_t operator()(
const PAD_KNOCKOUT_KEY& key )
const
273 return hash_val( key.position.
x, key.position.
y, key.effectiveSize.
x, key.effectiveSize.
y,
274 key.shape, key.orientation.
AsDegrees(), key.netCode );
281struct VIA_KNOCKOUT_KEY
287 bool operator==(
const VIA_KNOCKOUT_KEY& other )
const
289 return position == other.position && effectiveSize == other.effectiveSize
290 && netCode == other.netCode;
294struct VIA_KNOCKOUT_KEY_HASH
296 size_t operator()(
const VIA_KNOCKOUT_KEY& key )
const
298 return hash_val( key.position.
x, key.position.
y, key.effectiveSize, key.netCode );
304struct TRACK_KNOCKOUT_KEY
310 TRACK_KNOCKOUT_KEY(
const VECTOR2I& aStart,
const VECTOR2I& aEnd,
int aWidth ) :
314 if( aStart.
x < aEnd.
x || ( aStart.
x == aEnd.
x && aStart.
y <= aEnd.
y ) )
326 bool operator==(
const TRACK_KNOCKOUT_KEY& other )
const
328 return start == other.start && end == other.end && width == other.width;
332struct TRACK_KNOCKOUT_KEY_HASH
334 size_t operator()(
const TRACK_KNOCKOUT_KEY& key )
const
336 return hash_val( key.start.
x, key.start.
y, key.end.
x, key.end.
y, key.width );
340template<
typename Func>
341void forEachBoardAndFootprintZone(
BOARD* aBoard, Func&& aFunc )
348 for(
ZONE* zone : footprint->Zones() )
407 if(
m_board->GetDesignSettings().m_ZoneKeepExternalFillets )
409 for(
const ZONE* zone : { aZone, aKnockout } )
414 reach += (int) zone->GetCornerRadius();
428 return zoneOutline.
Collide( &knockoutOutline, reach );
444 std::lock_guard<KISPINLOCK> lock(
m_board->GetConnectivity()->GetLock() );
459 std::shared_ptr<DRC_ENGINE> drcEngine = std::make_shared<DRC_ENGINE>(
m_board, &bds );
463 drcEngine->InitEngine( wxFileName(
m_board->GetDesignRulesPath() ) );
476 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
477 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
HASH_128> oldFillHashes;
478 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> isolatedIslandsMap;
480 std::shared_ptr<CONNECTIVITY_DATA> connectivity =
m_board->GetConnectivity();
487 connectivity->ClearRatsnest();
495 :
_(
"Building zone fills..." ) );
508 zone->CacheBoundingBox();
512 for(
PAD*
pad : footprint->Pads() )
516 pad->BuildEffectiveShapes();
521 for(
ZONE* zone : footprint->Zones() )
522 zone->CacheBoundingBox();
525 footprint->BuildCourtyardCaches();
526 footprint->BuildNetTieCache();
533 std::unordered_map<const ZONE*, POLY_YSTRIPES_INDEX> zoneOutlineIndices;
537 if( zone->GetNumCorners() <= 2 )
540 zoneOutlineIndices[zone].Build( zone->GetBoardOutline() );
547 auto findHighestPriorityZone =
549 const std::function<bool(
const ZONE* )>& testFn ) ->
ZONE*
551 unsigned highestSameNetPriority = 0;
552 ZONE* highestSameNetZone =
nullptr;
553 unsigned highestPriority = 0;
554 ZONE* highestPriorityZone =
nullptr;
559 if( zone->GetIsRuleArea() )
562 if( !zone->IsOnLayer( itemLayer ) )
565 const unsigned priority = zone->GetAssignedPriority();
566 const bool sameNet = zone->GetNetCode() == netcode;
571 if( highestSameNetZone && priority < highestSameNetPriority )
574 else if( highestPriorityZone && priority < highestPriority )
580 if( zone->GetNumCorners() <= 2 )
583 if( !zone->GetBoundingBox().Intersects( bbox ) )
586 if( !testFn( zone ) )
590 && ( !highestSameNetZone || priority > highestSameNetPriority ) )
592 highestSameNetPriority = priority;
593 highestSameNetZone = zone;
596 if( !highestPriorityZone || priority > highestPriority )
598 highestPriority = priority;
599 highestPriorityZone = zone;
603 return highestSameNetZone ? highestSameNetZone : highestPriorityZone;
606 auto isInPourKeepoutArea =
611 if( !zone->GetIsRuleArea() )
614 if( !zone->HasKeepoutParametersSet() )
617 if( !zone->GetDoNotAllowZoneFills() )
620 if( !zone->IsOnLayer( itemLayer ) )
624 if( zone->GetNumCorners() <= 2 )
627 if( !zone->GetBoundingBox().Intersects( bbox ) )
630 auto it = zoneOutlineIndices.find( zone );
632 if( it != zoneOutlineIndices.end() && it->second.Contains( testPoint ) )
649 via->ClearZoneLayerOverrides();
651 if( !
via->GetRemoveUnconnected() )
656 int holeRadius =
via->GetDrillValue() / 2 + 1;
657 int netcode =
via->GetNetCode();
658 LSET layers =
via->GetLayerSet() & boardCuMask;
661 auto viaTestFn = [&](
const ZONE* aZone ) ->
bool
668 if( !
via->ConditionallyFlashed( layer ) )
671 if( isInPourKeepoutArea( bbox, layer,
center ) )
677 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, viaTestFn );
682 || layer == padstack.
Drill().
end ) )
698 for(
PAD*
pad : footprint->Pads() )
700 pad->ClearZoneLayerOverrides();
702 if( !
pad->GetRemoveUnconnected() )
707 int netcode =
pad->GetNetCode();
708 LSET layers =
pad->GetLayerSet() & boardCuMask;
711 [&](
const ZONE* aZone ) ->
bool
713 auto it = zoneOutlineIndices.find( aZone );
715 if( it != zoneOutlineIndices.end() )
716 return it->second.Contains(
center );
723 if( !
pad->ConditionallyFlashed( layer ) )
726 if( isInPourKeepoutArea( bbox, layer,
center ) )
732 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, padTestFn );
743 for(
ZONE* zone : aZones )
746 if( zone->GetIsRuleArea() )
750 if( zone->GetNumCorners() <= 2 )
760 zone->BuildHashValue( layer );
761 oldFillHashes[ { zone, layer } ] = zone->GetHashValue( layer );
764 toFill.emplace_back( std::make_pair( zone, layer ) );
769 if( !zone->IsCopperThieving() )
777 auto zone_fill_dependency =
779 bool aRequireCompletedOtherFill ) ->
bool
786 if( aRequireCompletedOtherFill && aOtherZone->GetFillFlag( aLayer ) )
791 if( aOtherZone->GetIsRuleArea() )
795 if( aOtherZone->GetNumCorners() <= 2 )
799 if( !aOtherZone->GetLayerSet().test( aLayer ) )
806 if( aOtherZone->SameNet( aZone ) )
813 auto check_fill_dependency =
816 return zone_fill_dependency( aZone, aLayer, aOtherZone,
true );
819 auto fill_item_dependency =
820 [&](
const std::pair<ZONE*, PCB_LAYER_ID>& aWaiter,
821 const std::pair<ZONE*, PCB_LAYER_ID>& aDependency ) ->
bool
823 if( aWaiter.first == aDependency.first || aWaiter.second != aDependency.second )
826 return check_fill_dependency( aWaiter.first, aWaiter.second, aDependency.first );
830 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
836 ZONE* zone = aFillItem.first;
851 auto tesselate_lambda =
852 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
858 ZONE* zone = aFillItem.first;
867 std::atomic<bool> cancelled =
false;
873 auto run_fill_waves =
874 [&](
const std::vector<std::pair<ZONE*, PCB_LAYER_ID>>& aFillItems,
auto&& aFillFn,
875 auto&& aTessFn,
auto&& aHasDependency,
bool aAnyDependencies )
877 const size_t count = aFillItems.size();
882 std::vector<std::vector<size_t>> successors( count );
883 std::vector<std::atomic<int>> inDegree( count );
885 for(
size_t i = 0; i < count; ++i )
886 inDegree[i].store( 0, std::memory_order_relaxed );
889 if( aAnyDependencies )
891 for(
size_t i = 0; i < count; ++i )
893 for(
size_t j = 0; j < count; ++j )
898 if( aHasDependency( aFillItems[j], aFillItems[i] ) )
900 successors[i].push_back( j );
901 inDegree[j].fetch_add( 1, std::memory_order_relaxed );
907 std::atomic<int> remaining( (
int) count );
909 std::function<void(
size_t )>
process;
913 int filled = aFillFn( aFillItems[idx] );
916 for(
size_t succ : successors[idx] )
918 if( inDegree[succ].fetch_sub( 1, std::memory_order_acq_rel ) == 1 )
922 if( filled != 0 && !cancelled.load() )
923 aTessFn( aFillItems[idx] );
925 remaining.fetch_sub( 1, std::memory_order_acq_rel );
929 for(
size_t i = 0; i < count; ++i )
931 if( inDegree[i].load( std::memory_order_relaxed ) == 0 )
936 while( remaining.load( std::memory_order_acquire ) > 0 )
946 std::this_thread::sleep_for( std::chrono::milliseconds( 20 ) );
956 run_fill_waves( toFill, fill_lambda, tesselate_lambda, fill_item_dependency,
true );
971 connectivity->FillIsolatedIslandsMap( isolatedIslandsMap );
972 connectivity->SetProgressReporter(
nullptr );
977 for(
ZONE* zone : aZones )
980 if( zone->GetIsRuleArea() )
983 zone->SetIsFilled(
true );
992 std::set<std::pair<ZONE*, PCB_LAYER_ID>> zonesWithRemovedIslandLayers;
999 std::set<std::pair<ZONE*, PCB_LAYER_ID>> initiallyFullyIsolatedLayers;
1001 for(
const auto& [ zone, zoneIslands ] : isolatedIslandsMap )
1005 bool allLayersFullyIsolated =
true;
1007 for(
const auto& [ layer, layerIslands ] : zoneIslands )
1009 bool layerFullyIsolated = ( layerIslands.m_IsolatedOutlines.size()
1010 ==
static_cast<size_t>( zone->GetFilledPolysList( layer )->OutlineCount() ) );
1012 if( layerFullyIsolated )
1013 initiallyFullyIsolatedLayers.insert( { zone, layer } );
1015 allLayersFullyIsolated =
false;
1018 if( allLayersFullyIsolated )
1021 for(
const auto& [ layer, layerIslands ] : zoneIslands )
1026 if( layerIslands.m_IsolatedOutlines.empty() )
1029 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
1033 std::sort( islands.begin(), islands.end(), std::greater<int>() );
1035 std::shared_ptr<SHAPE_POLY_SET> poly = zone->GetFilledPolysList( layer );
1036 long long int minArea = zone->GetMinIslandArea();
1039 for(
int idx : islands )
1045 poly->DeletePolygonAndTriangulationData( idx,
false );
1046 zonesWithRemovedIslandLayers.insert( { zone, layer } );
1050 poly->DeletePolygonAndTriangulationData( idx,
false );
1051 zonesWithRemovedIslandLayers.insert( { zone, layer } );
1055 zone->SetIsIsland( layer, idx );
1059 poly->UpdateTriangulationDataHash();
1060 zone->CalculateFilledArea();
1080 std::set<std::pair<ZONE*, PCB_LAYER_ID>> sameNetOverlapSeeds;
1082 if( iterativeRefill )
1087 std::map<int, std::vector<ZONE*>> zonesByNet;
1089 forEachBoardAndFootprintZone(
1094 zonesByNet[zone->
GetNetCode()].push_back( zone );
1097 for(
ZONE* lowerZone : aZones )
1099 if( lowerZone->GetIsRuleArea() || lowerZone->IsTeardropArea() )
1102 auto netIt = zonesByNet.find( lowerZone->GetNetCode() );
1104 if( netIt == zonesByNet.end() )
1107 LSET lowerLayers = lowerZone->GetLayerSet() & boardCu;
1109 for(
ZONE* higherZone : netIt->second )
1111 if( higherZone == lowerZone
1115 if( !lowerZone->GetBoundingBox().Intersects( higherZone->
GetBoundingBox() ) )
1124 if( lowerZone->HasFilledPolysForLayer( layer )
1127 sameNetOverlapSeeds.insert( { lowerZone, layer } );
1135 && ( !zonesWithRemovedIslandLayers.empty() || !sameNetOverlapSeeds.empty() ) )
1137 const int maxIterations = 8;
1138 bool progressReported =
false;
1139 bool hitIterationLimit =
false;
1142 std::set<std::pair<ZONE*, PCB_LAYER_ID>> changedZoneLayers( zonesWithRemovedIslandLayers );
1143 changedZoneLayers.insert( sameNetOverlapSeeds.begin(), sameNetOverlapSeeds.end() );
1145 auto cached_refill_tessellate_lambda = [&](
const std::pair<ZONE*, PCB_LAYER_ID>& aFillItem ) ->
int
1147 ZONE* zone = aFillItem.first;
1154 auto no_dependency = [](
const std::pair<ZONE*, PCB_LAYER_ID>&,
const std::pair<ZONE*, PCB_LAYER_ID>& ) ->
bool
1159 for(
int iteration = 0; iteration < maxIterations; ++iteration )
1164 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zonesToRefill;
1165 std::set<std::pair<ZONE*, PCB_LAYER_ID>> zonesToRefillSet;
1167 for(
const auto& [changedZone, changedLayer] : changedZoneLayers )
1169 BOX2I bbox = changedZone->GetBoundingBox();
1172 for(
ZONE* zone : aZones )
1174 if( zone->GetIsRuleArea() )
1177 if( !zone->GetLayerSet().test( changedLayer ) )
1193 if( zone != changedZone && !changedZone->HigherPriority( zone ) && !changedZone->SameNet( zone ) )
1200 if( zone != changedZone && !changedZone->SameNet( zone ) )
1205 else if( !zone->GetBoundingBox().Intersects( bbox ) )
1210 auto fillItem = std::make_pair( zone, changedLayer );
1212 if( zonesToRefillSet.insert( fillItem ).second )
1213 zonesToRefill.push_back( fillItem );
1217 if( zonesToRefill.empty() )
1220 if( !progressReported )
1229 progressReported =
true;
1235 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
HASH_128> iterHashes;
1237 for(
const auto& fillItem : zonesToRefill )
1239 fillItem.first->BuildHashValue( fillItem.second );
1240 iterHashes[fillItem] = fillItem.first->GetHashValue( fillItem.second );
1251 LSET snapshotLayers;
1253 for(
const auto& [zone, layer] : zonesToRefill )
1254 snapshotLayers.
set( layer );
1258 forEachBoardAndFootprintZone(
m_board,
1275 if( sp && sp->OutlineCount() > 0 )
1276 snapshot[{ zone, layer }] = sp->CloneDropTriangulation();
1280 auto cached_refill_fill_lambda =
1281 [&](
const std::pair<ZONE*, PCB_LAYER_ID>& aFillItem ) ->
int
1283 ZONE* zone = aFillItem.first;
1295 run_fill_waves( zonesToRefill, cached_refill_fill_lambda, cached_refill_tessellate_lambda, no_dependency,
1301 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> refillIslandsMap;
1303 for(
const auto& [zone, layer] : zonesToRefill )
1317 connectivity->FillIsolatedIslandsMap( refillIslandsMap );
1319 for(
const auto& [zone, zoneIslands] : refillIslandsMap )
1321 for(
const auto& [layer, layerIslands] : zoneIslands )
1326 if( layerIslands.m_IsolatedOutlines.empty() )
1331 if( initiallyFullyIsolatedLayers.count( { zone, layer } ) > 0 )
1333 if( layerIslands.m_IsolatedOutlines.size()
1340 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
1341 std::sort( islands.begin(), islands.end(), std::greater<int>() );
1347 for(
int idx : islands )
1352 poly->DeletePolygonAndTriangulationData( idx,
false );
1354 poly->DeletePolygonAndTriangulationData( idx,
false );
1359 poly->UpdateTriangulationDataHash();
1367 changedZoneLayers.clear();
1369 for(
const auto& fillItem : zonesToRefill )
1371 fillItem.first->BuildHashValue( fillItem.second );
1373 auto hashIt = iterHashes.find( fillItem );
1374 HASH_128 oldHash = ( hashIt != iterHashes.end() ) ? hashIt->second :
HASH_128{};
1376 if( fillItem.first->GetHashValue( fillItem.second ) != oldHash )
1377 changedZoneLayers.insert( fillItem );
1380 if( changedZoneLayers.empty() )
1383 if( iteration + 1 >= maxIterations )
1385 hitIterationLimit =
true;
1390 if( hitIterationLimit )
1392 wxString msg = wxString::Format(
_(
"Zone fills may be incorrect: iterative refill did not converge "
1393 "after %d passes.\n\n"
1394 "This can happen with complex overlapping zones. "
1395 "Consider simplifying your zones." ),
1400 KIDIALOG dlg( aParent, msg,
_(
"Warning" ), wxOK | wxICON_WARNING );
1406 wxLogWarning( msg );
1413 using island_check_return = std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
int>>;
1415 std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
double>> polys_to_check;
1418 polys_to_check.reserve(
m_board->GetCopperLayerCount() * aZones.size() );
1420 for(
ZONE* zone : aZones )
1430 double minArea = (double) zone->GetMinThickness() * zone->GetMinThickness() * 3;
1437 polys_to_check.emplace_back( zone->GetFilledPolysList( layer ), minArea );
1441 auto island_lambda =
1442 [&](
int aStart,
int aEnd ) -> island_check_return
1444 island_check_return retval;
1446 for(
int ii = aStart; ii < aEnd && !cancelled.load(); ++ii )
1448 auto [poly, minArea] = polys_to_check[ii];
1450 for(
int jj = poly->OutlineCount() - 1; jj >= 0; jj-- )
1455 double island_area = test_poly.
Area();
1457 if( island_area < minArea )
1469 if( intersection.
Area() < island_area / 2.0 )
1470 retval.emplace_back( poly, jj );
1477 auto island_returns =
tp.submit_blocks( 0, polys_to_check.size(), island_lambda );
1481 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
1483 std::future<island_check_return>& ret = island_returns[ii];
1487 std::future_status status = ret.wait_for( std::chrono::seconds( 0 ) );
1489 while( status != std::future_status::ready )
1499 status = ret.wait_for( std::chrono::milliseconds( 100 ) );
1504 if( cancelled.load() )
1507 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
1509 std::future<island_check_return>& ret = island_returns[ii];
1513 for(
auto& action_item : ret.get() )
1514 action_item.first->DeletePolygonAndTriangulationData( action_item.second,
true );
1518 for(
ZONE* zone : aZones )
1519 zone->CalculateFilledArea();
1532 std::unique_ptr<POLY_YSTRIPES_INDEX>
index;
1535 struct NET_LAYER_HASH
1537 size_t operator()(
const std::pair<int, PCB_LAYER_ID>& k )
const
1539 return std::hash<int>()( k.first ) ^ ( std::hash<int>()( k.second ) << 16 );
1543 std::unordered_map<std::pair<int, PCB_LAYER_ID>, std::vector<INDEXED_ZONE>, NET_LAYER_HASH>
1544 filledZonesByNetLayer;
1548 if( zone->GetIsRuleArea() )
1553 if( !zone->HasFilledPolysForLayer( layer ) )
1556 const std::shared_ptr<SHAPE_POLY_SET>& fill = zone->GetFilledPolysList( layer );
1558 if( fill->IsEmpty() )
1562 iz.bbox = fill->BBox();
1563 iz.index = std::make_unique<POLY_YSTRIPES_INDEX>();
1564 iz.index->Build( *fill );
1565 filledZonesByNetLayer[{ zone->GetNetCode(), layer }].push_back( std::move( iz ) );
1569 auto zoneReachesPoint =
1572 auto it = filledZonesByNetLayer.find( { aNetcode, aLayer } );
1574 if( it == filledZonesByNetLayer.end() )
1577 for(
const INDEXED_ZONE& iz : it->second )
1579 if( !iz.bbox.GetInflated( aRadius ).Contains( aCenter ) )
1582 if( iz.index->Contains( aCenter, aRadius ) )
1596 int holeRadius =
via->GetDrillValue() / 2;
1597 int netcode =
via->GetNetCode();
1598 LSET layers =
via->GetLayerSet() & boardCuMask;
1605 int reach = std::max( holeRadius,
via->GetWidth( layer ) / 2 );
1607 if( !zoneReachesPoint( netcode, layer,
center, reach ) )
1614 for(
PAD*
pad : footprint->Pads() )
1617 int netcode =
pad->GetNetCode();
1618 LSET layers =
pad->GetLayerSet() & boardCuMask;
1622 if(
pad->HasHole() )
1623 holeRadius = std::min(
pad->GetDrillSizeX(),
pad->GetDrillSizeY() ) / 2;
1634 int reach = std::max( holeRadius, std::min( padSize.
x, padSize.
y ) / 2 );
1636 if( !zoneReachesPoint( netcode, layer,
center, reach ) )
1644 bool outOfDate =
false;
1646 for(
ZONE* zone : aZones )
1649 if( zone->GetIsRuleArea() )
1654 zone->BuildHashValue( layer );
1656 if( oldFillHashes[ { zone, layer } ] != zone->GetHashValue( layer ) )
1662 &&
m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill ) )
1664 KIDIALOG dlg( aParent,
_(
"Prototype zone fill enabled. Disable setting and refill?" ),
_(
"Confirmation" ),
1665 wxOK | wxCANCEL | wxICON_WARNING );
1671 m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill =
false;
1673 else if( !outOfDate )
1681 KIDIALOG dlg( aParent,
_(
"Zone fills are out-of-date. Refill?" ),
_(
"Confirmation" ),
1682 wxOK | wxCANCEL | wxICON_WARNING );
1725 std::vector<VECTOR2I> convex_hull;
1730 for(
const VECTOR2I& pt : convex_hull )
1762 switch( aItem->
Type() )
1769 if(
text->IsVisible() )
1771 if(
text->IsKnockout() )
1826 std::vector<BOARD_ITEM*>& aThermalConnectionPads,
1827 std::vector<PAD*>& aNoConnectionPads,
1828 std::vector<BOARD_ITEM*>& aSolidConnectionItems )
1834 std::shared_ptr<SHAPE> padShape;
1839 std::unordered_set<PAD_KNOCKOUT_KEY, PAD_KNOCKOUT_KEY_HASH> processedPads;
1840 std::unordered_set<VIA_KNOCKOUT_KEY, VIA_KNOCKOUT_KEY_HASH> processedVias;
1844 for(
PAD*
pad : footprint->Pads() )
1850 &&
pad->GetDrillSize().x > 0;
1852 if( !
pad->IsOnLayer( aLayer ) && !npthWithHole )
1855 BOX2I padBBox =
pad->GetBoundingBox();
1872 int drill = std::max(
pad->GetDrillSize().x,
pad->GetDrillSize().y );
1873 int maxDim = std::max( { padSize.
x, padSize.
y, drill } );
1874 effectiveSize =
VECTOR2I( maxDim, maxDim );
1878 effectiveSize = padSize;
1881 PAD_KNOCKOUT_KEY padKey{
pad->GetPosition(), effectiveSize,
1882 static_cast<int>( padShapeType ),
1883 pad->GetOrientation(),
pad->GetNetCode() };
1885 if( !processedPads.insert( padKey ).second )
1889 bool noConnection =
pad->GetNetCode() != aZone->
GetNetCode();
1896 noConnection =
true;
1901 if(
pad->IsBackdrilledOrPostMachined( aLayer ) )
1902 noConnection =
true;
1907 aNoConnectionPads.push_back(
pad );
1922 switch( connection )
1928 if( aFill.
Collide( padShape.get(), 0 ) )
1936 aThermalConnectionPads.push_back(
pad );
1945 aNoConnectionPads.push_back(
pad );
1970 switch( connection )
1975 if( aFill.
Collide( padShape.get(), 0 ) )
1980 aThermalConnectionPads.push_back(
pad );
1994 if(
pad->FlashLayer( aLayer ) )
1998 else if(
pad->GetDrillSize().x > 0 )
2005 holeClearance = padClearance;
2031 if( !
via->IsOnLayer( aLayer ) )
2034 BOX2I viaBBox =
via->GetBoundingBox();
2041 int viaEffectiveSize = std::max(
via->GetDrillValue(),
via->GetWidth( aLayer ) );
2042 VIA_KNOCKOUT_KEY viaKey{
via->GetPosition(), viaEffectiveSize,
via->GetNetCode() };
2044 if( !processedVias.insert( viaKey ).second )
2047 bool noConnection =
via->GetNetCode() != aZone->
GetNetCode()
2049 && aLayer !=
via->Padstack().Drill().start
2050 && aLayer !=
via->Padstack().Drill().end );
2053 noConnection =
true;
2056 if(
via->IsBackdrilledOrPostMachined( aLayer ) )
2058 noConnection =
true;
2070 pmSize = std::max( pmSize, frontPM.
size );
2076 pmSize = std::max( pmSize, backPM.
size );
2082 bdSize = secDrill.
size.
x;
2084 int knockoutSize = std::max( pmSize, bdSize );
2086 if( knockoutSize > 0 )
2101 switch( connection )
2111 if( thermalGap > 0 )
2113 aThermalConnectionPads.push_back(
via );
2128 aSolidConnectionItems.push_back(
via );
2143 const std::vector<PAD*>& aNoConnectionPads,
2145 bool aIncludeZoneClearances )
2151 std::unordered_set<PAD_KNOCKOUT_KEY, PAD_KNOCKOUT_KEY_HASH> processedPads;
2152 std::unordered_set<VIA_KNOCKOUT_KEY, VIA_KNOCKOUT_KEY_HASH> processedVias;
2153 std::unordered_set<TRACK_KNOCKOUT_KEY, TRACK_KNOCKOUT_KEY_HASH> processedTracks;
2155 auto checkForCancel =
2158 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
2171 auto evalRulesForItems =
2185 auto knockoutPadClearance =
2190 bool hasHole = aPad->GetDrillSize().x > 0;
2191 bool flashLayer = aPad->FlashLayer( aLayer );
2194 if( flashLayer || platedHole )
2199 if( flashLayer && gap >= 0 )
2200 addKnockout( aPad, aLayer, gap + extra_margin, aHoles );
2217 if( aPad->IsBackdrilledOrPostMachined( aLayer ) )
2228 pmSize = std::max( pmSize, frontPM.
size );
2234 pmSize = std::max( pmSize, backPM.
size );
2240 bdSize = secDrill.
size.
x;
2242 int knockoutSize = std::max( pmSize, bdSize );
2244 if( knockoutSize > 0 )
2246 int clearance = std::max( gap, 0 ) + extra_margin;
2254 for(
PAD*
pad : aNoConnectionPads )
2270 int drill = std::max(
pad->GetDrillSize().x,
pad->GetDrillSize().y );
2271 int maxDim = std::max( { padSize.
x, padSize.
y, drill } );
2272 effectiveSize =
VECTOR2I( maxDim, maxDim );
2276 effectiveSize = padSize;
2279 PAD_KNOCKOUT_KEY padKey{
pad->GetPosition(), effectiveSize,
2280 static_cast<int>( padShape ),
pad->GetOrientation(),
2281 pad->GetNetCode() };
2283 if( !processedPads.insert( padKey ).second )
2287 knockoutPadClearance(
pad );
2292 auto knockoutTrackClearance =
2295 if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
2297 bool sameNet = aTrack->GetNetCode() == aZone->
GetNetCode();
2319 if(
via->FlashLayer( aLayer ) && gap > 0 )
2321 via->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
m_maxError,
2340 if(
via->IsBackdrilledOrPostMachined( aLayer ) )
2351 pmSize = std::max( pmSize, frontPM.
size );
2357 pmSize = std::max( pmSize, backPM.
size );
2363 bdSize = secDrill.
size.
x;
2365 int knockoutSize = std::max( pmSize, bdSize );
2367 if( knockoutSize > 0 )
2369 int clearance = std::max( gap, 0 ) + extra_margin;
2380 aTrack->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
m_maxError,
2389 if( !track->IsOnLayer( aLayer ) )
2399 int viaEffectiveSize = std::max(
via->GetDrillValue(),
via->GetWidth( aLayer ) );
2400 VIA_KNOCKOUT_KEY viaKey{
via->GetPosition(), viaEffectiveSize,
via->GetNetCode() };
2402 if( !processedVias.insert( viaKey ).second )
2407 TRACK_KNOCKOUT_KEY trackKey( track->GetStart(), track->GetEnd(), track->GetWidth() );
2409 if( !processedTracks.insert( trackKey ).second )
2413 knockoutTrackClearance( track );
2418 auto knockoutGraphicClearance =
2424 shapeNet =
static_cast<PCB_SHAPE*
>( aItem )->GetNetCode();
2426 bool sameNet = shapeNet == aZone->
GetNetCode();
2432 if( aItem->IsOnLayer( aLayer )
2434 || aItem->IsOnLayer(
Margin ) )
2436 if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
2438 bool ignoreLineWidths =
false;
2441 if( aItem->IsOnLayer( aLayer ) && !sameNet )
2445 else if( aItem->IsOnLayer(
Edge_Cuts ) )
2448 ignoreLineWidths =
true;
2450 else if( aItem->IsOnLayer(
Margin ) )
2457 gap += extra_margin;
2458 addKnockout( aItem, aLayer, gap, ignoreLineWidths, aHoles );
2464 auto knockoutCourtyardClearance =
2467 if( aFootprint->GetBoundingBox().Intersects( zone_boundingbox ) )
2478 aHoles.
Append( aFootprint->GetCourtyard( courtyardSide ) );
2491 knockoutCourtyardClearance( footprint );
2492 knockoutGraphicClearance( &footprint->Reference() );
2493 knockoutGraphicClearance( &footprint->Value() );
2495 std::set<PAD*> allowedNetTiePads;
2499 if( footprint->IsNetTie() )
2501 for(
PAD*
pad : footprint->Pads() )
2510 if(
pad->IsOnLayer( aLayer ) )
2511 allowedNetTiePads.insert(
pad );
2513 for(
PAD* other : footprint->GetNetTiePads(
pad ) )
2515 if( other->IsOnLayer( aLayer ) )
2516 allowedNetTiePads.insert( other );
2522 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
2527 BOX2I itemBBox = item->GetBoundingBox();
2529 if( !zone_boundingbox.
Intersects( itemBBox ) )
2532 bool skipItem =
false;
2534 if( item->IsOnLayer( aLayer ) )
2536 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape();
2538 for(
PAD*
pad : allowedNetTiePads )
2540 if(
pad->GetBoundingBox().Intersects( itemBBox )
2541 &&
pad->GetEffectiveShape( aLayer )->Collide( itemShape.get() ) )
2550 knockoutGraphicClearance( item );
2559 knockoutGraphicClearance( item );
2564 auto knockoutZoneClearance =
2565 [&](
ZONE* aKnockout )
2568 if( !aKnockout->GetLayerSet().test( aLayer ) )
2571 if( aKnockout->GetIsRuleArea() )
2573 if( aKnockout->GetBoundingBox().Intersects( zone_boundingbox )
2574 && aKnockout->GetDoNotAllowZoneFills() && !aZone->
IsTeardropArea() )
2581 else if( aKnockout->HigherPriority( aZone ) && !aKnockout->SameNet( aZone )
2594 aKnockout->TransformShapeToPolygon( poly, aLayer, gap + extra_margin,
m_maxError,
2600 if( aIncludeZoneClearances )
2607 knockoutZoneClearance( otherZone );
2612 for(
ZONE* otherZone : footprint->Zones() )
2617 knockoutZoneClearance( otherZone );
2635 auto evalRulesForItems =
2651 auto knockoutZoneClearance =
2652 [&](
ZONE* aKnockout )
2654 if( aKnockout->GetIsRuleArea() )
2657 if( !aKnockout->GetLayerSet().test( aLayer ) )
2660 if( aKnockout->HigherPriority( aZone ) && !aKnockout->SameNet( aZone )
2664 aZone, aKnockout, aLayer ) );
2667 aKnockout, aLayer ) );
2673 aKnockout->TransformShapeToPolygon( poly, aLayer, gap + extra_margin,
2679 forEachBoardAndFootprintZone(
m_board, knockoutZoneClearance );
2695 auto collectZoneOutline =
2696 [&](
ZONE* aKnockout )
2698 if( !aKnockout->GetLayerSet().test( aLayer ) )
2701 if( aKnockout->GetBoundingBox().Intersects( zoneBBox ) )
2702 appendZoneOutlineWithoutArcs( aKnockout, knockouts );
2705 forEachBoardAndFootprintZone(
2707 [&](
ZONE* otherZone )
2711 bool higherPrioritySameNet =
2716 collectZoneOutline( otherZone );
2735 std::map<int, std::vector<std::pair<int, VECTOR2I>>> insertion_points;
2747 insertion_points[
result.m_outline1].push_back( {
result.m_vertex1, pt1 } );
2748 insertion_points[
result.m_outline1].push_back( {
result.m_vertex1, pt2 } );
2751 for(
auto& [outline, vertices] : insertion_points )
2759 std::stable_sort( vertices.begin(), vertices.end(),
2760 [](
const std::pair<int, VECTOR2I>& a,
const std::pair<int, VECTOR2I>& b )
2762 return a.first > b.first;
2765 for(
const auto& [vertex, pt] : vertices )
2766 line.
Insert( vertex + 1, pt );
2787 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
2789 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
2790 BOX2I islandExtents;
2792 for(
const VECTOR2I& pt : island.front().CPoints() )
2794 islandExtents.
Merge( pt );
2810#define DUMP_POLYS_TO_COPPER_LAYER( a, b, c ) \
2811 { if( m_debugZoneFiller && aDebugLayer == b ) \
2813 m_board->SetLayerName( b, c ); \
2814 SHAPE_POLY_SET d = a; \
2854 std::vector<BOARD_ITEM*> thermalConnectionPads;
2855 std::vector<PAD*> noConnectionPads;
2856 std::vector<BOARD_ITEM*> solidConnectionItems;
2857 std::deque<SHAPE_LINE_CHAIN> thermalSpokes;
2860 aFillPolys = aSmoothedOutline;
2870 knockoutThermalReliefs( aZone, aLayer, aFillPolys, thermalConnectionPads, noConnectionPads, solidConnectionItems );
2887 aFillPolys, thermalRings );
2909 if( iterativeRefill )
2912 bool addedKeepoutHoles =
false;
2914 auto collectKeepoutHoles =
2915 [&](
ZONE* candidate )
2920 if( !isZoneFillKeepout( candidate, aLayer, zone_boundingbox ) )
2923 candidate->TransformSmoothedOutlineToPolygon( clearanceHoles, 0,
m_maxError,
2925 addedKeepoutHoles =
true;
2928 forEachBoardAndFootprintZone(
m_board, collectKeepoutHoles );
2930 if( addedKeepoutHoles )
2959 if( iterativeRefill )
2985 spokeTestIndex.
Build( testAreas );
2992 const VECTOR2I& testPt = spoke.CPoint( 3 );
2995 if( spokeTestIndex.
Contains( testPt, 1 ) )
3004 if( interval++ > 400 )
3017 if( &other != &spoke
3018 && other.PointInside( testPt, 1 )
3019 && spoke.PointInside( other.CPoint( 3 ), 1 ) )
3055 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
3057 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
3058 BOX2I islandExtents;
3060 for(
const VECTOR2I& pt : island.front().CPoints() )
3062 islandExtents.
Merge( pt );
3083 || !
m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill ) )
3092 for(
BOARD_ITEM* item : solidConnectionItems )
3094 if( item->Type() !=
PCB_VIA_T || !item->IsOnLayer( aLayer ) )
3163 for(
BOARD_ITEM* item : thermalConnectionPads )
3177 bool knockoutsApplied =
false;
3179 if( iterativeRefill )
3190 knockoutsApplied =
true;
3203 if( knockoutsApplied )
3228 auto checkForCancel =
3231 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
3234 auto knockoutGraphicItem =
3237 if( aItem->IsKnockout() && aItem->IsOnLayer( aLayer )
3238 && aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
3240 addKnockout( aItem, aLayer, 0,
true, clearanceHoles );
3249 knockoutGraphicItem( &footprint->Reference() );
3250 knockoutGraphicItem( &footprint->Value() );
3252 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
3253 knockoutGraphicItem( item );
3261 knockoutGraphicItem( item );
3264 aFillPolys = aSmoothedOutline;
3269 auto collectKeepout =
3270 [&](
ZONE* candidate )
3272 if( !isZoneFillKeepout( candidate, aLayer, zone_boundingbox ) )
3275 appendZoneOutlineWithoutArcs( candidate, keepoutHoles );
3278 bool cancelledKeepoutScan =
false;
3280 forEachBoardAndFootprintZone(
3282 [&](
ZONE* keepout )
3284 if( cancelledKeepoutScan )
3289 cancelledKeepoutScan =
true;
3293 collectKeepout( keepout );
3296 if( cancelledKeepoutScan )
3347 debugLayer = aLayer;
3351 if( !aZone->
BuildSmoothedPoly( maxExtents, aLayer, boardOutline, &smoothedPoly ) )
3359 if(
fillCopperZone( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aFillPolys ) )
3376 const std::vector<BOARD_ITEM*>& aSpokedPadsList,
3377 std::deque<SHAPE_LINE_CHAIN>& aSpokesList )
3396 if( !item->IsOnLayer( aLayer ) )
3399 int thermalReliefGap = 0;
3403 bool circular =
false;
3407 pad =
static_cast<PAD*
>( item );
3437 int spoke_max_allowed_w = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
3438 spoke_w = std::clamp( spoke_w, constraint.
Value().
Min(), constraint.
Value().
Max() );
3439 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
3441 if( spoke_w < aZone->GetMinThickness() )
3454 spoke_w = std::min( spoke_w,
via->GetWidth( aLayer ) );
3456 if( spoke_w < aZone->GetMinThickness() )
3475 int spoke_max_allowed_w = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
3477 spoke_w = std::clamp( spoke_w, constraint.
Value().
Min(), constraint.
Value().
Max() );
3480 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
3483 if( spoke_w < aZone->GetMinThickness() )
3492 int spoke_half_w = spoke_w / 2;
3495 BOX2I itemBB = item->GetBoundingBox();
3501 bool customSpokes =
false;
3505 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
3507 if( primitive->IsProxyItem() && primitive->GetShape() ==
SHAPE_T::SEGMENT )
3509 customSpokes =
true;
3520 auto buildSpokesFromOrigin =
3527 auto intersectBBox =
3530 double dx = spokeAngle.
Cos();
3531 double dy = spokeAngle.
Sin();
3537 *spoke_side =
VECTOR2I( spoke_half_w, 0 );
3538 return KiROUND( 0.0, dy * half_size.
y );
3542 *spoke_side =
VECTOR2I( 0, spoke_half_w );
3543 return KiROUND( dx * half_size.
x, 0.0 );
3548 double dist_x = half_size.
x /
std::abs( dx );
3549 double dist_y = half_size.
y /
std::abs( dy );
3551 if( dist_x < dist_y )
3553 *spoke_side =
KiROUND( 0.0, spoke_half_w / (
ANGLE_90 - spokeAngle ).Sin() );
3554 return KiROUND( dx * dist_x, dy * dist_x );
3558 *spoke_side =
KiROUND( spoke_half_w / spokeAngle.
Sin(), 0.0 );
3559 return KiROUND( dx * dist_y, dy * dist_y );
3572 for(
const EDA_ANGLE& spokeAngle : angles )
3575 VECTOR2I intersection = intersectBBox( spokeAngle, &spoke_side );
3584 aSpokesList.push_back( std::move( spoke ) );
3596 thermalOutline = thermalPoly.
Outline( 0 );
3600 auto trimToOutline = [&](
SEG& aSegment )
3604 if( padOutline.
Intersect( aSegment, intersections ) )
3606 intersections.clear();
3609 if( thermalOutline.
Intersect( aSegment, intersections ) )
3611 aSegment.B = intersections.front().p;
3618 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
3620 if( primitive->IsProxyItem() && primitive->GetShape() ==
SHAPE_T::SEGMENT )
3622 SEG seg( primitive->GetStart(), primitive->GetEnd() );
3627 seg.
A +=
pad->ShapePos( aLayer );
3628 seg.
B +=
pad->ShapePos( aLayer );
3642 if( trimToOutline( seg ) )
3644 VECTOR2I direction = ( seg.
B - seg.
A ).Resize( spoke_half_w );
3648 SEG segL( seg.
A - direction - offset, seg.
B + direction - offset );
3649 SEG segR( seg.
A - direction + offset, seg.
B + direction + offset );
3652 if( trimToOutline( segL ) && trimToOutline( segR ) )
3660 spoke.
Append( seg.
A + offset );
3661 spoke.
Append( seg.
A - offset );
3663 spoke.
Append( segL.
B + direction );
3664 spoke.
Append( seg.
B + direction );
3665 spoke.
Append( segR.
B + direction );
3668 aSpokesList.push_back( std::move( spoke ) );
3681 thermalSpokeAngle =
pad->GetThermalSpokeAngle();
3700 position =
pad->ShapePos( aLayer );
3701 orientation =
pad->GetOrientation();
3709 position =
via->GetPosition();
3714 spokesBox.
Inflate( thermalReliefGap +
epsilon + zone_half_width );
3721 buildSpokesFromOrigin( spokesBox,
ANGLE_0 );
3723 if( thermalSpokeAngle !=
ANGLE_0 )
3726 for(
auto it = aSpokesList.rbegin(); it != aSpokesList.rbegin() + 4; ++it )
3727 it->Rotate( thermalSpokeAngle );
3732 buildSpokesFromOrigin( spokesBox, thermalSpokeAngle );
3735 auto spokeIter = aSpokesList.rbegin();
3737 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
3739 spokeIter->Rotate( orientation );
3740 spokeIter->Move( position );
3745 for(
size_t ii = 0; ii < aSpokesList.size(); ++ii )
3746 aSpokesList[ii].GenerateBBoxCache();
3752 const std::vector<BOARD_ITEM*>& aThermalConnectionPads,
3759 for(
BOARD_ITEM* item : aThermalConnectionPads )
3761 if( !item->IsOnLayer( aLayer ) )
3766 bool isCircular =
false;
3774 pad =
static_cast<PAD*
>( item );
3776 position =
pad->ShapePos( aLayer );
3782 padRadius = std::max( padSize.
x, padSize.
y ) / 2;
3791 int spokeMaxWidth = std::min( padSize.
x, padSize.
y );
3792 spokeWidth = std::min( spokeWidth, spokeMaxWidth );
3797 position =
via->GetPosition();
3799 padRadius =
via->GetWidth( aLayer ) / 2;
3808 spokeWidth = std::min( spokeWidth, padRadius * 2 );
3816 if( spokeWidth < aZone->GetMinThickness() )
3826 int ringInnerRadius = padRadius + thermalGap;
3827 int ringWidth = spokeWidth;
3840 pad->TransformShapeToPolygon( outerShape, aLayer, thermalGap + spokeWidth,
3844 pad->TransformShapeToPolygon( innerShape, aLayer, thermalGap,
3847 thermalRing = outerShape;
3877 if( settings.
gap <= 0
3879 || ( needsLineWidth && settings.
line_width <= 0 ) )
3906 const auto& defaultOffsets =
m_board->GetDesignSettings().m_ZoneLayerProperties;
3910 if(
auto it = defaultOffsets.find( aLayer ); it != defaultOffsets.end() )
3911 offset = it->second.hatching_offset.value_or(
VECTOR2I() );
3913 if( localOffsets.contains( aLayer ) && localOffsets.at( aLayer ).hatching_offset.has_value() )
3914 offset = localOffsets.at( aLayer ).hatching_offset.value();
3929 const int dotRadius = std::max( settings.
element_size / 2 - halfMinWidth, 1 );
3930 const int maxError =
m_board->GetDesignSettings().m_MaxError;
3936 int xStart = bbox.
GetLeft() - ( bbox.
GetLeft() % dotStride ) + offset.
x;
3937 int yStart = bbox.
GetTop() - ( bbox.
GetTop() % dotStride ) + offset.
y;
3939 while( xStart > bbox.
GetLeft() )
3940 xStart -= dotStride;
3942 while( yStart > bbox.
GetTop() )
3943 yStart -= dotStride;
3972 int xVoid = bbox.
GetLeft() - ( bbox.
GetLeft() % lineStride ) + offset.
x
3974 int yVoid = bbox.
GetTop() - ( bbox.
GetTop() % lineStride ) + offset.
y
3977 while( xVoid - voidSize / 2 > bbox.
GetLeft() )
3978 xVoid -= lineStride;
3980 while( yVoid - voidSize / 2 > bbox.
GetTop() )
3981 yVoid -= lineStride;
3985 for(
int yy = yVoid; yy <= bbox.
GetBottom() + voidSize; yy += lineStride )
3987 for(
int xx = xVoid; xx <= bbox.
GetRight() + voidSize; xx += lineStride )
3990 rect.
Append( xx - voidSize / 2, yy - voidSize / 2 );
3991 rect.
Append( xx + voidSize / 2, yy - voidSize / 2 );
3992 rect.
Append( xx + voidSize / 2, yy + voidSize / 2 );
3993 rect.
Append( xx - voidSize / 2, yy + voidSize / 2 );
4018 const VECTOR2I squareSize( sideLen, sideLen );
4020 const int containmentInset =
4035 for(
int yy = yStart; yy <= bbox.
GetBottom() + dotRadius; yy += dotStride )
4037 const int rowOffset = ( settings.
stagger && ( rowIndex & 1 ) ) ? dotStride / 2 : 0;
4039 for(
int xx = xStart + rowOffset; xx <= bbox.
GetRight() + dotRadius; xx += dotStride )
4043 if( !filledRegion.
Contains( centre, -1, 0,
true ) )
4063 aFillPolys = stamps;
4084 int maxError =
m_board->GetDesignSettings().m_MaxError;
4100 hole_base.
Append( corner );
4101 corner.
x += hole_size;
4102 hole_base.
Append( corner );
4103 corner.
y += hole_size;
4104 hole_base.
Append( corner );
4106 hole_base.
Append( corner );
4126 #define SMOOTH_MIN_VAL_MM 0.02
4127 #define SMOOTH_SMALL_VAL_MM 0.04
4143 smooth_value = std::min( smooth_value, aZone->
GetHatchGap() / 2 );
4146 maxError = std::max( maxError * 2, smooth_value / 20 );
4148 switch( smooth_level )
4160 hole_base = smooth_hole.
Fillet( smooth_value, maxError ).
Outline( 0 );
4172 const auto& defaultOffsets =
m_board->GetDesignSettings().m_ZoneLayerProperties;
4177 if(
auto it = defaultOffsets.find( aLayer ); it != defaultOffsets.end() )
4178 offset = it->second.hatching_offset.value_or(
VECTOR2I() );
4180 if( localOffsets.contains( aLayer ) && localOffsets.at( aLayer ).hatching_offset.has_value() )
4181 offset = localOffsets.at( aLayer ).hatching_offset.value();
4183 int x_offset = bbox.
GetX() - ( bbox.
GetX() ) % gridsize - gridsize;
4184 int y_offset = bbox.
GetY() - ( bbox.
GetY() ) % gridsize - gridsize;
4187 for(
int xx = x_offset; xx <= bbox.
GetRight(); xx += gridsize )
4189 for(
int yy = y_offset; yy <= bbox.
GetBottom(); yy += gridsize )
4200 hole.
Move(
VECTOR2I( offset.
x % gridsize, offset.
y % gridsize ) );
4213 deflated_thickness = std::max( deflated_thickness, maxError * 2 );
4235 if( area < minimal_hole_area )
4246 BOX2I thermalBBox = aThermalRings.
BBox();
4249 for(
int holeIdx = holes.
OutlineCount() - 1; holeIdx >= 0; holeIdx-- )
4259 for(
int ringIdx = 0; ringIdx < aThermalRings.
OutlineCount(); ringIdx++ )
4266 if( !holeBBox.
Contains( ringBBox ) )
4282 if( intersections.empty() )
4304 auto cacheKey = std::make_pair(
static_cast<const ZONE*
>( aZone ), aLayer );
4314 aFillPolys = it->second;
4327 auto evalRulesForItems =
4339 bool knockoutsApplied =
false;
4343 auto collectZoneKnockout =
4344 [&](
ZONE* otherZone )
4346 if( otherZone == aZone )
4349 if( !otherZone->GetLayerSet().test( aLayer ) )
4352 if( otherZone->IsTeardropArea() && otherZone->SameNet( aZone ) )
4355 if( !otherZone->HigherPriority( aZone ) )
4360 if( otherZone->SameNet( aZone ) )
4362 if( !otherZone->GetBoundingBox().Intersects( zoneBBox ) )
4374 std::shared_ptr<SHAPE_POLY_SET> fillShared;
4378 auto it = aSnapshot->find( {
static_cast<const ZONE*
>( otherZone ), aLayer } );
4380 if( it == aSnapshot->end() )
4383 fillPtr = &it->second;
4387 if( !otherZone->HasFilledPolysForLayer( aLayer ) )
4390 fillShared = otherZone->GetFilledPolysList( aLayer );
4395 fillPtr = fillShared.get();
4401 if( otherZone->SameNet( aZone ) )
4409 appendZoneOutlineWithoutArcs( otherZone, sameNetKnockouts );
4411 sameNetKnockouts.
Append( *fillPtr );
4416 aZone, otherZone, aLayer ) );
4419 otherZone, aLayer ) );
4427 diffNetKnockouts.
Append( inflatedFill );
4428 knockoutsApplied =
true;
4432 forEachBoardAndFootprintZone(
m_board, collectZoneKnockout );
4441 refillHash.
addData(
reinterpret_cast<const uint8_t*
>( diffNetHash.
Value64 ),
4442 sizeof( diffNetHash.
Value64 ) );
4443 refillHash.
addData(
reinterpret_cast<const uint8_t*
>( sameNetHash.
Value64 ),
4444 sizeof( sameNetHash.
Value64 ) );
4453 aFillPolys = it->second.second;
4470 if( knockoutsApplied )
4487 solidExtent = sit->second;
4491 knockouts.
Append( sameNetKnockouts );
bool operator==(const wxAuiPaneInfo &aLhs, const wxAuiPaneInfo &aRhs)
constexpr EDA_IU_SCALE pcbIUScale
@ ZLO_FORCE_NO_ZONE_CONNECTION
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
BASE_SET & set(size_t pos)
Container for design settings for a BOARD object.
std::shared_ptr< DRC_ENGINE > m_DRCEngine
int GetBiggestClearanceValue() const
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const
Convert the item shape to a closed polygon.
virtual void SetIsKnockout(bool aKnockout)
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Information pertinent to a Pcbnew printed circuit board.
const ZONES & Zones() const
int GetCopperLayerCount() const
const FOOTPRINTS & Footprints() const
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
constexpr int GetSizeMax() const
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
constexpr coord_type GetY() const
constexpr size_type GetWidth() const
constexpr Vec Centre() const
constexpr coord_type GetX() const
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
constexpr const Vec GetCenter() const
constexpr size_type GetHeight() const
constexpr coord_type GetLeft() const
constexpr bool Contains(const Vec &aPoint) const
constexpr coord_type GetRight() const
constexpr coord_type GetTop() const
constexpr bool Intersects(const BOX2< Vec > &aRect) const
constexpr coord_type GetBottom() const
Represent a set of changes (additions, deletions or modifications) of a data model (e....
MINOPTMAX< int > & Value()
const MINOPTMAX< int > & GetValue() const
ZONE_CONNECTION m_ZoneConnection
DRC_CONSTRAINT EvalRules(DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
DRC_CONSTRAINT EvalZoneConnection(const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
KICAD_T Type() const
Returns the type of object.
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
bool SetOKCancelLabels(const ButtonLabel &ok, const ButtonLabel &cancel) override
LSET is a set of PCB_LAYER_IDs.
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
static const LSET & InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
A streaming C++ equivalent for MurmurHash3_x64_128.
FORCE_INLINE void addData(const uint8_t *data, size_t length)
FORCE_INLINE HASH_128 digest()
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
UNCONNECTED_LAYER_MODE UnconnectedLayerMode() const
const BOX2I GetBoundingBox() const override
The bounding box is cached, so this will be efficient most of the time.
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
void SetOffset(PCB_LAYER_ID aLayer, const VECTOR2I &aOffset)
void SetPosition(const VECTOR2I &aPos) override
void SetOrientation(const EDA_ANGLE &aAngle)
Set the rotation angle of the pad.
bool TransformHoleToPolygon(SHAPE_POLY_SET &aBuffer, int aClearance, int aError, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Build the corner list of the polygonal drill shape in the board coordinate system.
void GetBoundingHull(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth=false) const override
Convert the item shape to a closed polygon.
void TransformTextToPolySet(SHAPE_POLY_SET &aBuffer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc) const
Function TransformTextToPolySet Convert the text to a polygonSet describing the actual character stro...
void SetPosition(const VECTOR2I &aPoint) override
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Y-stripe spatial index for efficient point-in-polygon containment testing.
bool Contains(const VECTOR2I &aPt, int aAccuracy=0) const
Test whether a point is inside the indexed polygon set.
void Build(const SHAPE_POLY_SET &aPolySet)
Build the spatial index from a SHAPE_POLY_SET's outlines and holes.
A progress reporter interface for use in multi-threaded environments.
RESULTS(int aOutline1, int aOutline2, int aVertex1, int aVertex2)
bool operator<(const RESULTS &aOther) const
VECTOR2I::extended_type ecoord
static SEG::ecoord Square(int a)
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void Move(const VECTOR2I &aVector) override
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int Intersect(const SEG &aSeg, INTERSECTIONS &aIp) const
Find all intersection points between our line chain and the segment aSeg.
int PointCount() const
Return the number of points (vertices) in this line chain.
double Area(bool aAbsolute=true) const
Return the area of this chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
void Insert(size_t aVertex, const VECTOR2I &aP)
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const override
Check if point aP lies inside a closed shape.
std::vector< INTERSECTION > INTERSECTIONS
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
Represent a set of closed polygons.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
void RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
SHAPE_POLY_SET Chamfer(int aDistance)
Return a chamfered version of the polygon set.
void BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
void DeletePolygon(int aIdx)
Delete aIdx-th polygon from the set.
double Area()
Return the area of this poly set.
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
POLYGON & Polygon(int aIndex)
Return the aIndex-th subpolygon in the set.
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
int ArcCount() const
Count the number of arc shapes present.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
void Deflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError)
void BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
void BuildBBoxCaches() const
Construct BBoxCaches for Contains(), below.
int OutlineCount() const
Return the number of outlines in the set.
SHAPE_POLY_SET Fillet(int aRadius, int aErrorMax)
Return a filleted version of the polygon set.
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
SHAPE_POLY_SET CloneDropTriangulation() const
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
const BOX2I BBoxFromCaches() const
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
constexpr extended_type SquaredEuclideanNorm() const
Compute the squared euclidean norm of the vector, which is defined as (x ** 2 + y ** 2).
constexpr VECTOR2< T > Perpendicular() const
Compute the perpendicular vector.
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
VERTEX * getPoint(VERTEX *aPt) const
std::set< RESULTS > GetResults() const
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.
void buildCopperItemClearances(const ZONE *aZone, PCB_LAYER_ID aLayer, const std::vector< PAD * > &aNoConnectionPads, SHAPE_POLY_SET &aHoles, bool aIncludeZoneClearances=true)
Removes clearance from the shape for copper items which share the zone's layer but are not connected ...
void buildHatchZoneThermalRings(const ZONE *aZone, PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aSmoothedOutline, const std::vector< BOARD_ITEM * > &aThermalConnectionPads, SHAPE_POLY_SET &aFillPolys, SHAPE_POLY_SET &aThermalRings)
Build thermal rings for pads in hatch zones.
void connect_nearby_polys(SHAPE_POLY_SET &aPolys, double aDistance)
Create strands of zero-width between elements of SHAPE_POLY_SET that are within aDistance of each oth...
void knockoutThermalReliefs(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aFill, std::vector< BOARD_ITEM * > &aThermalConnectionPads, std::vector< PAD * > &aNoConnectionPads, std::vector< BOARD_ITEM * > &aSolidConnectionItems)
Removes thermal reliefs from the shape for any pads connected to the zone.
void buildThermalSpokes(const ZONE *box, PCB_LAYER_ID aLayer, const std::vector< BOARD_ITEM * > &aSpokedPadsList, std::deque< SHAPE_LINE_CHAIN > &aSpokes)
Function buildThermalSpokes Constructs a list of all thermal spokes for the given zone.
void buildDifferentNetZoneClearances(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aHoles)
Build clearance knockout holes for higher-priority zones on different nets.
std::map< std::pair< const ZONE *, PCB_LAYER_ID >, SHAPE_POLY_SET > FillSnapshot
Snapshot of zone fill polygons captured before an iterative refill wave.
ZONE_FILLER(BOARD *aBoard, COMMIT *aCommit)
void subtractHigherPriorityZones(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aRawFill)
Removes the outlines of higher-proirity zones with the same net.
void addKnockout(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer, int aGap, SHAPE_POLY_SET &aHoles)
Add a knockout for a pad or via.
SHAPE_POLY_SET m_boardOutline
std::map< std::pair< const ZONE *, PCB_LAYER_ID >, SHAPE_POLY_SET > m_preKnockoutFillCache
void SetProgressReporter(PROGRESS_REPORTER *aReporter)
std::map< std::pair< const ZONE *, PCB_LAYER_ID >, SHAPE_POLY_SET > m_preHatchSolidFillCache
std::map< std::pair< const ZONE *, PCB_LAYER_ID >, std::pair< HASH_128, SHAPE_POLY_SET > > m_refillResultCache
PROGRESS_REPORTER * m_progressReporter
bool refillZoneFromCache(ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aFillPolys, const FillSnapshot *aSnapshot=nullptr)
Refill a zone from cached pre-knockout fill.
bool zoneKnockoutMayInteract(const ZONE *aZone, const ZONE *aKnockout) const
Test whether aKnockout's fill can knock out any part of aZone's fill.
bool addCopperThievingPattern(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aFillPolys)
Stamp a regular grid of pattern shapes onto a zone's filled area for copper thieving.
bool fillCopperZone(const ZONE *aZone, PCB_LAYER_ID aLayer, PCB_LAYER_ID aDebugLayer, const SHAPE_POLY_SET &aSmoothedOutline, const SHAPE_POLY_SET &aMaxExtents, SHAPE_POLY_SET &aFillPolys)
Function fillCopperZone Add non copper areas polygons (pads and tracks with clearance) to a filled co...
void addHoleKnockout(PAD *aPad, int aGap, SHAPE_POLY_SET &aHoles)
Add a knockout for a pad's hole.
bool fillNonCopperZone(const ZONE *candidate, PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aSmoothedOutline, SHAPE_POLY_SET &aFillPolys)
void postKnockoutMinWidthPrune(const ZONE *aZone, SHAPE_POLY_SET &aFillPolys)
Remove minimum-width violations introduced by zone-to-zone knockouts.
bool addHatchFillTypeOnZone(const ZONE *aZone, PCB_LAYER_ID aLayer, PCB_LAYER_ID aDebugLayer, SHAPE_POLY_SET &aFillPolys, const SHAPE_POLY_SET &aThermalRings)
for zones having the ZONE_FILL_MODE::ZONE_FILL_MODE::HATCH_PATTERN, create a grid pattern in filled a...
bool fillSingleZone(ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aFillPolys)
Build the filled solid areas polygons from zone outlines (stored in m_Poly) The solid areas can be mo...
bool Fill(const std::vector< ZONE * > &aZones, bool aCheck=false, wxWindow *aParent=nullptr)
Fills the given list of zones.
Handle a list of polygons defining a copper zone.
void CacheTriangulation(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, const SHAPE_POLY_SET::TASK_SUBMITTER &aSubmitter={})
Create a list of triangles that "fill" the solid areas used for instance to draw these solid areas on...
void SetNeedRefill(bool aNeedRefill)
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
std::optional< int > GetLocalClearance() const override
const THIEVING_SETTINGS & GetThievingSettings() const
ZONE_LAYER_PROPERTIES & LayerProperties(PCB_LAYER_ID aLayer)
std::shared_ptr< SHAPE_POLY_SET > GetFilledPolysList(PCB_LAYER_ID aLayer) const
const BOX2I GetBoundingBox() const override
ISLAND_REMOVAL_MODE GetIslandRemovalMode() const
void SetFillFlag(PCB_LAYER_ID aLayer, bool aFlag)
bool IsCopperThieving() const
long long int GetMinIslandArea() const
void SetFilledPolysList(PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPolysList)
Set the list of filled polygons.
int GetMinThickness() const
SHAPE_POLY_SET GetBoardOutline() const
bool HigherPriority(const ZONE *aOther) const
bool HasFilledPolysForLayer(PCB_LAYER_ID aLayer) const
int GetHatchThickness() const
double GetHatchHoleMinArea() const
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
bool IsTeardropArea() const
EDA_ANGLE GetHatchOrientation() const
bool BuildSmoothedPoly(SHAPE_POLY_SET &aSmoothedPoly, PCB_LAYER_ID aLayer, SHAPE_POLY_SET *aBoardOutline, SHAPE_POLY_SET *aSmoothedPolyWithApron=nullptr) const
ZONE_FILL_MODE GetFillMode() const
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
bool HasKeepoutParametersSet() const
Accessor to determine if any keepout parameters are set.
double GetHatchSmoothingValue() const
bool GetDoNotAllowZoneFills() const
int GetHatchSmoothingLevel() const
void SetIsIsland(PCB_LAYER_ID aLayer, int aPolyIdx)
bool IsOnCopperLayer() const override
double CalculateFilledArea()
Compute the area currently occupied by the zone fill.
unsigned GetAssignedPriority() const
bool SameNet(const ZONE *aOther) const
void TransformRingToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aCentre, int aRadius, int aWidth, int aError, ERROR_LOC aErrorLoc)
Convert arcs to multiple straight segments.
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void TransformTrapezoidToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aPosition, const VECTOR2I &aSize, const EDA_ANGLE &aRotation, int aDeltaX, int aDeltaY, int aInflate, int aError, ERROR_LOC aErrorLoc)
Convert a rectangle or trapezoid to a polygon.
void BuildConvexHull(std::vector< VECTOR2I > &aResult, const std::vector< VECTOR2I > &aPoly)
Calculate the convex hull of a list of points in counter-clockwise order.
CORNER_STRATEGY
define how inflate transform build inflated polygon
@ CHAMFER_ALL_CORNERS
All angles are chamfered.
@ ROUND_ALL_CORNERS
All angles are rounded.
@ EDGE_CLEARANCE_CONSTRAINT
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
@ THERMAL_SPOKE_WIDTH_CONSTRAINT
@ THERMAL_RELIEF_GAP_CONSTRAINT
@ HOLE_CLEARANCE_CONSTRAINT
@ PHYSICAL_CLEARANCE_CONSTRAINT
static constexpr EDA_ANGLE ANGLE_0
static constexpr EDA_ANGLE ANGLE_90
a few functions useful in geometry calculations.
bool m_ZoneFillIterativeRefill
Enable iterative zone filling to handle isolated islands in higher priority zones.
bool m_DebugZoneFiller
A mode that dumps the various stages of a F_Cu fill into In1_Cu through In9_Cu.
static constexpr std::size_t hash_val(const Types &... args)
@ ALWAYS_FLASHED
Always flashed for connectivity.
bool IsInnerCopperLayer(int aLayerId)
Test whether a layer is an inner (In1_Cu to In30_Cu) copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
@ PTH
Plated through hole pad.
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
BARCODE class definition.
static PGM_BASE * process
A storage class for 128-bit hash value.
A struct recording the isolated and single-pad islands within a zone.
! The properties of a padstack drill. Drill position is always the pad position (origin).
VECTOR2I size
Drill diameter (x == y) or slot dimensions (x != y)
std::optional< PAD_DRILL_POST_MACHINING_MODE > mode
Parameters that drive copper-thieving fill generation.
wxString result
Test unit parsing edge cases and error handling.
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::priority_thread_pool thread_pool
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
@ PCB_PAD_T
class PAD, a pad in a footprint
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D
#define SMOOTH_MIN_VAL_MM
#define DUMP_POLYS_TO_COPPER_LAYER(a, b, c)
#define SMOOTH_SMALL_VAL_MM
ISLAND_REMOVAL_MODE
Whether or not to remove isolated islands from a zone.
ZONE_CONNECTION
How pads are covered by copper in zone.
@ THERMAL
Use thermal relief for pads.
@ NONE
Pads are not covered.
@ FULL
pads are covered by copper