58 RESULTS(
int aOutline1,
int aOutline2,
int aVertex1,
int aVertex2 ) :
104 SEG::ecoord min_dist = std::numeric_limits<SEG::ecoord>::max();
107 auto check_pt = [&](
VERTEX* p )
109 VECTOR2D diff( p->x - aPt->
x, p->y - aPt->
y );
112 if( dist2 < limit2 && dist2 < min_dist
122 while( p && p->
z <= maxZ )
130 while( p && p->
z >= minZ )
142 std::set<VERTEX*> visited;
155 if( ( visited.empty() || !visited.contains( p ) ) && ( q =
getPoint( p ) ) )
159 if( !visited.contains( q ) &&
161 p->
i, q->
i ).second )
165 visited.insert( p->
prev );
167 visited.insert( p->
next );
170 visited.insert( q->
prev );
172 visited.insert( q->
next );
196 m_brdOutlinesValid( false ),
198 m_progressReporter( nullptr ),
200 m_worstClearance( 0 )
215 wxASSERT_MSG(
m_commit, wxT(
"ZONE_FILLER must have a valid commit to call "
216 "SetProgressReporter" ) );
234 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
235 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
HASH_128> oldFillHashes;
236 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> isolatedIslandsMap;
241 connectivity->ClearRatsnest();
249 :
_(
"Building zone fills..." ) );
262 zone->CacheBoundingBox();
266 for(
PAD*
pad : footprint->Pads() )
275 for(
ZONE* zone : footprint->Zones() )
276 zone->CacheBoundingBox();
279 footprint->BuildCourtyardCaches();
284 auto findHighestPriorityZone = [&](
const BOX2I& aBBox,
const PCB_LAYER_ID aItemLayer,
286 const std::function<bool(
const ZONE* )> aTestFn ) ->
ZONE*
288 unsigned highestPriority = 0;
289 ZONE* highestPriorityZone =
nullptr;
294 if( zone->GetIsRuleArea() )
297 if( zone->GetAssignedPriority() < highestPriority )
300 if( !zone->IsOnLayer( aItemLayer ) )
304 if( zone->GetNumCorners() <= 2 )
307 if( !zone->GetBoundingBox().Intersects( aBBox ) )
310 if( !aTestFn( zone ) )
314 if( zone->GetAssignedPriority() > highestPriority || zone->GetNetCode() == aNetcode )
317 highestPriorityZone = zone;
321 return highestPriorityZone;
324 auto isInPourKeepoutArea = [&](
const BOX2I& aBBox,
const PCB_LAYER_ID aItemLayer,
329 if( !zone->GetIsRuleArea() )
332 if( !zone->GetDoNotAllowCopperPour() )
335 if( !zone->IsOnLayer( aItemLayer ) )
339 if( zone->GetNumCorners() <= 2 )
342 if( !zone->GetBoundingBox().Intersects( aBBox ) )
345 if( zone->Outline()->Contains( aTestPoint ) )
359 via->ClearZoneLayerOverrides();
361 if( !
via->GetRemoveUnconnected() )
366 int testRadius =
via->GetDrillValue() / 2 + 1;
367 unsigned netcode =
via->GetNetCode();
368 LSET layers =
via->GetLayerSet() & boardCuMask;
371 auto viaTestFn = [&](
const ZONE* aZone ) ->
bool
373 return aZone->Outline()->
Contains( center, -1, testRadius );
378 if( !
via->ConditionallyFlashed( layer ) )
381 if( isInPourKeepoutArea( bbox, layer, center ) )
387 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, viaTestFn );
401 for(
PAD*
pad : footprint->Pads() )
403 pad->ClearZoneLayerOverrides();
405 if( !
pad->GetRemoveUnconnected() )
410 unsigned netcode =
pad->GetNetCode();
411 LSET layers =
pad->GetLayerSet() & boardCuMask;
413 auto padTestFn = [&](
const ZONE* aZone ) ->
bool
415 return aZone->Outline()->
Contains( center );
420 if( !
pad->ConditionallyFlashed( layer ) )
423 if( isInPourKeepoutArea( bbox, layer, center ) )
429 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, padTestFn );
440 for(
ZONE* zone : aZones )
443 if( zone->GetIsRuleArea() )
447 if( zone->GetNumCorners() <= 2 )
457 zone->BuildHashValue( layer );
458 oldFillHashes[ { zone, layer } ] = zone->GetHashValue( layer );
461 toFill.emplace_back( std::make_pair( zone, layer ) );
470 auto check_fill_dependency =
478 if( aOtherZone->GetFillFlag( aLayer ) )
483 if( aOtherZone->GetIsRuleArea() )
487 if( aOtherZone->GetNumCorners() <= 2 )
491 if( !aOtherZone->GetLayerSet().test( aLayer ) )
498 if( aOtherZone->SameNet( aZone ) )
506 if( !inflatedBBox.
Intersects( aOtherZone->GetBoundingBox() ) )
513 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
516 ZONE* zone = aFillItem.first;
521 for(
ZONE* otherZone : aZones )
523 if( otherZone == zone )
526 if( check_fill_dependency( zone, layer, otherZone ) )
541 std::unique_lock<std::mutex> zoneLock( zone->
GetLock(), std::try_to_lock );
543 if( !zoneLock.owns_lock() )
560 auto tesselate_lambda =
561 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
567 ZONE* zone = aFillItem.first;
570 std::unique_lock<std::mutex> zoneLock( zone->
GetLock(), std::try_to_lock );
572 if( !zoneLock.owns_lock() )
584 std::vector<std::pair<std::future<int>,
int>> returns;
585 returns.reserve( toFill.size() );
587 bool cancelled =
false;
591 for(
const std::pair<ZONE*, PCB_LAYER_ID>& fillItem : toFill )
592 returns.emplace_back( std::make_pair(
tp.submit( fill_lambda, fillItem ), 0 ) );
594 while( !cancelled && finished != 2 * toFill.size() )
596 for(
size_t ii = 0; ii < returns.size(); ++ii )
598 auto& ret = returns[ii];
603 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
605 if( status == std::future_status::ready )
607 if( ret.first.get() )
616 if( ret.second == 0 )
617 returns[ii].first =
tp.submit( fill_lambda, toFill[ii] );
618 else if( ret.second == 1 )
619 returns[ii].first =
tp.submit( tesselate_lambda, toFill[ii] );
624 std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
638 for(
auto& ret : returns )
640 if( ret.first.valid() )
642 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
644 while( status != std::future_status::ready )
649 status = ret.first.wait_for( std::chrono::milliseconds( 100 ) );
668 connectivity->FillIsolatedIslandsMap( isolatedIslandsMap );
669 connectivity->SetProgressReporter(
nullptr );
674 for(
ZONE* zone : aZones )
677 if( zone->GetIsRuleArea() )
680 zone->SetIsFilled(
true );
686 for(
const auto& [ zone, zoneIslands ] : isolatedIslandsMap )
689 bool allIslands =
true;
691 for(
const auto& [ layer, layerIslands ] : zoneIslands )
693 if( layerIslands.m_IsolatedOutlines.size()
694 !=
static_cast<size_t>( zone->GetFilledPolysList( layer )->OutlineCount() ) )
704 for(
const auto& [ layer, layerIslands ] : zoneIslands )
709 if( layerIslands.m_IsolatedOutlines.empty() )
712 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
716 std::sort( islands.begin(), islands.end(), std::greater<int>() );
718 std::shared_ptr<SHAPE_POLY_SET> poly = zone->GetFilledPolysList( layer );
719 long long int minArea = zone->GetMinIslandArea();
722 for(
int idx : islands )
726 if( mode == ISLAND_REMOVAL_MODE::ALWAYS )
727 poly->DeletePolygonAndTriangulationData( idx,
false );
728 else if ( mode == ISLAND_REMOVAL_MODE::AREA && outline.
Area(
true ) < minArea )
729 poly->DeletePolygonAndTriangulationData( idx,
false );
731 zone->SetIsIsland( layer, idx );
734 poly->UpdateTriangulationDataHash();
735 zone->CalculateFilledArea();
744 using island_check_return = std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
int>>;
746 std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
double>> polys_to_check;
751 for(
ZONE* zone : aZones )
761 double minArea = (double) zone->GetMinThickness() * zone->GetMinThickness() * 3;
768 polys_to_check.emplace_back( zone->GetFilledPolysList( layer ), minArea );
773 [&](
int aStart,
int aEnd ) -> island_check_return
775 island_check_return retval;
777 for(
int ii = aStart; ii < aEnd && !cancelled; ++ii )
779 auto [poly, minArea] = polys_to_check[ii];
781 for(
int jj = poly->OutlineCount() - 1; jj >= 0; jj-- )
786 double island_area = test_poly.
Area();
788 if( island_area < minArea )
801 if( intersection.
Area() < island_area / 2.0 )
802 retval.emplace_back( poly, jj );
809 auto island_returns =
tp.parallelize_loop( 0, polys_to_check.size(), island_lambda );
813 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
815 std::future<island_check_return>& ret = island_returns[ii];
819 std::future_status status = ret.wait_for( std::chrono::seconds( 0 ) );
821 while( status != std::future_status::ready )
831 status = ret.wait_for( std::chrono::milliseconds( 100 ) );
839 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
841 std::future<island_check_return>& ret = island_returns[ii];
845 for(
auto& action_item : ret.get() )
846 action_item.first->DeletePolygonAndTriangulationData( action_item.second,
true );
850 for(
ZONE* zone : aZones )
851 zone->CalculateFilledArea();
856 bool outOfDate =
false;
858 for(
ZONE* zone : aZones )
861 if( zone->GetIsRuleArea() )
866 zone->BuildHashValue( layer );
868 if( oldFillHashes[ { zone, layer } ] != zone->GetHashValue( layer ) )
875 KIDIALOG dlg( aParent,
_(
"Zone fills are out-of-date. Refill?" ),
876 _(
"Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
910 if( aPad->
GetShape() == PAD_SHAPE::CUSTOM )
918 std::vector<VECTOR2I> convex_hull;
923 for(
const VECTOR2I& pt : convex_hull )
952 switch( aItem->
Type() )
959 if(
text->IsVisible() )
961 if(
text->IsKnockout() )
1011 std::vector<PAD*>& aThermalConnectionPads,
1012 std::vector<PAD*>& aNoConnectionPads )
1018 std::shared_ptr<SHAPE> padShape;
1024 for(
PAD*
pad : footprint->Pads() )
1026 BOX2I padBBox =
pad->GetBoundingBox();
1032 bool noConnection =
pad->GetNetCode() != aZone->
GetNetCode();
1039 noConnection =
true;
1046 aNoConnectionPads.push_back(
pad );
1052 connection = ZONE_CONNECTION::FULL;
1056 constraint = bds.
m_DRCEngine->EvalZoneConnection(
pad, aZone, aLayer );
1060 if( connection == ZONE_CONNECTION::THERMAL && !
pad->CanFlashLayer( aLayer ) )
1061 connection = ZONE_CONNECTION::NONE;
1063 switch( connection )
1065 case ZONE_CONNECTION::THERMAL:
1066 padShape =
pad->GetEffectiveShape( aLayer, FLASHING::ALWAYS_FLASHED );
1068 if( aFill.
Collide( padShape.get(), 0 ) )
1074 aThermalConnectionPads.push_back(
pad );
1080 case ZONE_CONNECTION::NONE:
1089 if(
pad->FlashLayer( aLayer ) )
1093 else if(
pad->GetDrillSize().x > 0 )
1096 pad, aZone, aLayer );
1101 holeClearance = padClearance;
1124 const std::vector<PAD*>& aNoConnectionPads,
1130 auto checkForCancel =
1133 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
1146 auto evalRulesForItems =
1160 auto knockoutPadClearance =
1165 bool hasHole = aPad->GetDrillSize().x > 0;
1166 bool flashLayer = aPad->FlashLayer( aLayer );
1167 bool platedHole = hasHole && aPad->GetAttribute() == PAD_ATTRIB::PTH;
1169 if( flashLayer || platedHole )
1172 aZone, aPad, aLayer ) );
1175 if( flashLayer && gap >= 0 )
1176 addKnockout( aPad, aLayer, gap + extra_margin, aHoles );
1181 if( aPad->GetAttribute() == PAD_ATTRIB::NPTH )
1185 aZone, aPad, aLayer ) );
1188 aZone, aPad, aLayer ) );
1195 for(
PAD*
pad : aNoConnectionPads )
1200 knockoutPadClearance(
pad );
1205 auto knockoutTrackClearance =
1208 if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
1210 bool sameNet = aTrack->GetNetCode() == aZone->
GetNetCode();
1216 aZone, aTrack, aLayer );
1229 aZone, aTrack, aLayer ) );
1236 if(
via->FlashLayer( aLayer ) && gap > 0 )
1238 via->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
1243 aZone,
via, aLayer ) );
1248 aZone,
via, aLayer ) );
1253 int radius =
via->GetDrillValue() / 2;
1256 radius + gap + extra_margin,
1264 aTrack->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
1273 if( !track->IsOnLayer( aLayer ) )
1279 knockoutTrackClearance( track );
1284 auto knockoutGraphicClearance =
1292 bool sameNet = shapeNet == aZone->
GetNetCode();
1298 if( aItem->IsOnLayer( aLayer )
1300 || aItem->IsOnLayer(
Margin ) )
1302 if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
1304 bool ignoreLineWidths =
false;
1306 aZone, aItem, aLayer );
1308 if( aItem->IsOnLayer( aLayer ) && !sameNet )
1311 aZone, aItem, aLayer ) );
1313 else if( aItem->IsOnLayer(
Edge_Cuts ) )
1316 aZone, aItem, aLayer ) );
1317 ignoreLineWidths =
true;
1319 else if( aItem->IsOnLayer(
Margin ) )
1322 aZone, aItem, aLayer ) );
1327 gap += extra_margin;
1328 addKnockout( aItem, aLayer, gap, ignoreLineWidths, aHoles );
1334 auto knockoutCourtyardClearance =
1337 if( aFootprint->GetBoundingBox().Intersects( zone_boundingbox ) )
1340 aFootprint, aLayer );
1344 aHoles.
Append( aFootprint->GetCourtyard( aLayer ) );
1357 knockoutCourtyardClearance( footprint );
1358 knockoutGraphicClearance( &footprint->Reference() );
1359 knockoutGraphicClearance( &footprint->Value() );
1361 std::set<PAD*> allowedNetTiePads;
1365 if( footprint->IsNetTie() )
1367 for(
PAD*
pad : footprint->Pads() )
1376 if(
pad->IsOnLayer( aLayer ) )
1377 allowedNetTiePads.insert(
pad );
1379 for(
PAD* other : footprint->GetNetTiePads(
pad ) )
1381 if( other->IsOnLayer( aLayer ) )
1382 allowedNetTiePads.insert( other );
1388 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
1393 BOX2I itemBBox = item->GetBoundingBox();
1395 if( !zone_boundingbox.
Intersects( itemBBox ) )
1398 bool skipItem =
false;
1400 if( item->IsOnLayer( aLayer ) )
1402 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape();
1404 for(
PAD*
pad : allowedNetTiePads )
1406 if(
pad->GetBoundingBox().Intersects( itemBBox )
1407 &&
pad->GetEffectiveShape()->Collide( itemShape.get() ) )
1416 knockoutGraphicClearance( item );
1425 knockoutGraphicClearance( item );
1430 auto knockoutZoneClearance =
1431 [&](
ZONE* aKnockout )
1434 if( !aKnockout->GetLayerSet().test( aLayer ) )
1437 if( aKnockout->GetBoundingBox().Intersects( zone_boundingbox ) )
1439 if( aKnockout->GetIsRuleArea() )
1442 aKnockout->TransformSmoothedOutlineToPolygon( aHoles, 0,
m_maxError,
1448 aZone, aKnockout, aLayer ) );
1451 aZone, aKnockout, aLayer ) );
1454 aKnockout->TransformShapeToPolygon( poly, aLayer, gap + extra_margin,
1470 if( otherZone->GetIsRuleArea() )
1472 if( otherZone->GetDoNotAllowCopperPour() && !aZone->
IsTeardropArea() )
1473 knockoutZoneClearance( otherZone );
1475 else if( otherZone->HigherPriority( aZone ) )
1477 if( !otherZone->SameNet( aZone ) )
1478 knockoutZoneClearance( otherZone );
1484 for(
ZONE* otherZone : footprint->Zones() )
1489 if( otherZone->GetIsRuleArea() )
1491 if( otherZone->GetDoNotAllowCopperPour() && !aZone->
IsTeardropArea() )
1492 knockoutZoneClearance( otherZone );
1494 else if( otherZone->HigherPriority( aZone ) )
1496 if( !otherZone->SameNet( aZone ) )
1497 knockoutZoneClearance( otherZone );
1515 auto knockoutZoneOutline =
1516 [&](
ZONE* aKnockout )
1519 if( !aKnockout->GetLayerSet().test( aLayer ) )
1522 if( aKnockout->GetBoundingBox().Intersects( zoneBBox ) )
1538 if( otherZone->SameNet( aZone )
1542 if( !otherZone->IsTeardropArea() )
1543 knockoutZoneOutline( otherZone );
1549 for(
ZONE* otherZone : footprint->Zones() )
1551 if( otherZone->SameNet( aZone ) && otherZone->HigherPriority( aZone ) )
1554 if( !otherZone->IsTeardropArea() )
1555 knockoutZoneOutline( otherZone );
1573 std::map<int, std::vector<std::pair<int, VECTOR2I>>> insertion_points;
1585 insertion_points[result.m_outline1].push_back( { result.m_vertex1, pt1 } );
1586 insertion_points[result.m_outline1].push_back( { result.m_vertex1, pt2 } );
1589 for(
auto& [outline, vertices] : insertion_points )
1597 std::stable_sort( vertices.begin(), vertices.end(),
1598 [](
const std::pair<int, VECTOR2I>& a,
const std::pair<int, VECTOR2I>& b )
1599 { return a.first > b.first; } );
1601 for(
const auto& [vertex, pt] : vertices )
1602 line.
Insert( vertex + 1, pt );
1607#define DUMP_POLYS_TO_COPPER_LAYER( a, b, c ) \
1608 { if( m_debugZoneFiller && aDebugLayer == b ) \
1610 m_board->SetLayerName( b, c ); \
1611 SHAPE_POLY_SET d = a; \
1612 d.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE ); \
1652 CORNER_STRATEGY fastCornerStrategy = CORNER_STRATEGY::CHAMFER_ALL_CORNERS;
1655 std::vector<PAD*> thermalConnectionPads;
1656 std::vector<PAD*> noConnectionPads;
1657 std::deque<SHAPE_LINE_CHAIN> thermalSpokes;
1660 aFillPolys = aSmoothedOutline;
1697 static const bool USE_BBOX_CACHES =
true;
1724 const VECTOR2I& testPt = spoke.CPoint( 3 );
1727 if( testAreas.
Contains( testPt, -1, 1, USE_BBOX_CACHES ) )
1736 if( interval++ > 400 )
1749 if( &other != &spoke
1750 && other.PointInside( testPt, 1, USE_BBOX_CACHES )
1751 && spoke.PointInside( other.CPoint( 3 ), 1, USE_BBOX_CACHES ) )
1781 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
1783 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
1784 BOX2I islandExtents;
1786 for(
const VECTOR2I& pt : island.front().CPoints() )
1788 islandExtents.
Merge( pt );
1808 if( aZone->
GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
1847 for(
PAD*
pad : thermalConnectionPads )
1876 auto checkForCancel =
1879 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
1882 auto knockoutGraphicClearance =
1885 if( aItem->IsKnockout() && aItem->IsOnLayer( aLayer )
1886 && aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
1889 aZone, aItem, aLayer );
1900 knockoutGraphicClearance( &footprint->Reference() );
1901 knockoutGraphicClearance( &footprint->Value() );
1903 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
1904 knockoutGraphicClearance( item );
1912 knockoutGraphicClearance( item );
1915 aFillPolys = aSmoothedOutline;
1920 if( !keepout->GetIsRuleArea() )
1923 if( keepout->GetDoNotAllowCopperPour() && keepout->IsOnLayer( aLayer ) )
1925 if( keepout->GetBoundingBox().Intersects( zone_boundingbox ) )
1939 if( aZone->
GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
1968 debugLayer = aLayer;
1972 if( !aZone->
BuildSmoothedPoly( maxExtents, aLayer, boardOutline, &smoothedPoly ) )
1980 if(
fillCopperZone( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aFillPolys ) )
1997 const std::vector<PAD*>& aSpokedPadsList,
1998 std::deque<SHAPE_LINE_CHAIN>& aSpokesList )
2011 for(
PAD*
pad : aSpokedPadsList )
2014 if( !
pad->IsOnLayer( aLayer ) )
2018 int thermalReliefGap = constraint.
GetValue().
Min();
2026 int spoke_max_allowed_w = std::min(
pad->GetSize().x,
pad->GetSize().y );
2031 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
2034 if( spoke_w < aZone->GetMinThickness() )
2037 int spoke_half_w = spoke_w / 2;
2040 BOX2I itemBB =
pad->GetBoundingBox();
2046 bool customSpokes =
false;
2048 if(
pad->GetShape() == PAD_SHAPE::CUSTOM )
2050 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives() )
2052 if( primitive->IsProxyItem() && primitive->GetShape() == SHAPE_T::SEGMENT )
2054 customSpokes =
true;
2065 auto buildSpokesFromOrigin =
2073 double dx = direction.
x;
2074 double dy = direction.y;
2078 if( direction.x == 0 )
2082 else if( direction.y == 0 )
2089 double tx = std::min( half_size.
x /
std::abs( dx ),
2091 return VECTOR2I( dx * tx, dy * tx );
2103 for(
const EDA_ANGLE& spokeAngle : angles )
2105 VECTOR2D direction( spokeAngle.Cos(), spokeAngle.Sin() );
2108 VECTOR2I intersection = intersectLineBox( direction );
2112 spoke.
Append( center + spoke_side );
2113 spoke.
Append( center - spoke_side );
2114 spoke.
Append( center + intersection - spoke_side );
2115 spoke.
Append( center + intersection );
2116 spoke.
Append( center + intersection + spoke_side );
2118 aSpokesList.push_back( std::move( spoke ) );
2127 pad->TransformShapeToPolygon( thermalPoly, aLayer, thermalReliefGap +
epsilon,
2131 thermalOutline = thermalPoly.
Outline( 0 );
2133 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives() )
2135 if( primitive->IsProxyItem() && primitive->GetShape() == SHAPE_T::SEGMENT )
2137 SEG seg( primitive->GetStart(), primitive->GetEnd() );
2142 seg.
A +=
pad->ShapePos();
2143 seg.
B +=
pad->ShapePos();
2150 if( thermalOutline.
Intersect( seg, intersections ) )
2152 seg.
B = intersections.front().p;
2154 VECTOR2I offset = ( seg.
B - seg.
A ).Perpendicular().
Resize( spoke_half_w );
2157 spoke.
Append( seg.
A + offset );
2158 spoke.
Append( seg.
A - offset );
2159 spoke.
Append( seg.
B - offset );
2161 spoke.
Append( seg.
B + offset );
2164 aSpokesList.push_back( std::move( spoke ) );
2185 spokesBox.
Inflate( thermalReliefGap +
epsilon + zone_half_width );
2190 if(
pad->GetShape() == PAD_SHAPE::CIRCLE
2191 || (
pad->GetShape() == PAD_SHAPE::OVAL &&
pad->GetSizeX() ==
pad->GetSizeY() ) )
2193 buildSpokesFromOrigin( spokesBox,
ANGLE_0 );
2198 for(
auto it = aSpokesList.rbegin(); it != aSpokesList.rbegin() + 4; ++it )
2199 it->Rotate(
pad->GetThermalSpokeAngle() );
2204 buildSpokesFromOrigin( spokesBox,
pad->GetThermalSpokeAngle() );
2207 auto spokeIter = aSpokesList.rbegin();
2209 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
2211 spokeIter->Rotate(
pad->GetOrientation() );
2212 spokeIter->Move(
pad->ShapePos() );
2220 for(
size_t ii = 0; ii < aSpokesList.size(); ++ii )
2221 aSpokesList[ii].GenerateBBoxCache();
2257 hole_base.
Append( corner );
2258 corner.
x += hole_size;
2259 hole_base.
Append( corner );
2260 corner.
y += hole_size;
2261 hole_base.
Append( corner );
2263 hole_base.
Append( corner );
2283 #define SMOOTH_MIN_VAL_MM 0.02
2284 #define SMOOTH_SMALL_VAL_MM 0.04
2300 smooth_value = std::min( smooth_value, aZone->
GetHatchGap() / 2 );
2303 maxError = std::max( maxError * 2, smooth_value / 20 );
2305 switch( smooth_level )
2317 hole_base = smooth_hole.
Fillet( smooth_value, maxError ).
Outline( 0 );
2329 for(
int xx = 0; ; xx++ )
2331 int xpos = xx * gridsize;
2336 for(
int yy = 0; ; yy++ )
2338 int ypos = yy * gridsize;
2367 CORNER_STRATEGY::CHAMFER_ALL_CORNERS, maxError );
2372 deflatedOutline.
Deflate( outline_margin, CORNER_STRATEGY::CHAMFER_ALL_CORNERS, maxError );
2384 int min_apron_radius = ( aZone->
GetHatchGap() * 10 ) / 19;
2393 &&
via->IsOnLayer( aLayer )
2394 &&
via->GetBoundingBox().Intersects( zone_boundingbox ) )
2396 int r = std::max( min_apron_radius,
2397 via->GetDrillValue() / 2 + outline_margin );
2407 for(
PAD*
pad : footprint->Pads() )
2410 &&
pad->IsOnLayer( aLayer )
2411 &&
pad->GetBoundingBox().Intersects( zone_boundingbox ) )
2418 int pad_width = std::min(
pad->GetSize().x,
pad->GetSize().y );
2419 int slot_width = std::min(
pad->GetDrillSize().x,
pad->GetDrillSize().y );
2420 int min_annular_ring_width = ( pad_width - slot_width ) / 2;
2421 int clearance = std::max( min_apron_radius - pad_width / 2,
2422 outline_margin - min_annular_ring_width );
2424 clearance = std::max( 0, clearance - linethickness / 2 );
2425 pad->TransformShapeToPolygon( aprons, aLayer, clearance, maxError,
2441 if( area < minimal_hole_area )
constexpr int ARC_HIGH_DEF
constexpr EDA_IU_SCALE pcbIUScale
@ ZLO_FORCE_NO_ZONE_CONNECTION
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
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...
void SetParentGroup(PCB_GROUP *aGroup)
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.
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr, bool aAllowUseArcsInPolygons=false, bool aIncludeNPTHAsOutlines=false)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
const ZONES & Zones() const
int GetMaxClearanceValue() const
Returns the maximum clearance value for any object on the board.
int GetCopperLayerCount() const
const FOOTPRINTS & Footprints() const
const TRACKS & Tracks() const
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
const DRAWINGS & Drawings() const
const Vec & GetPosition() const
size_type GetHeight() const
const Vec GetCenter() const
bool Intersects(const BOX2< Vec > &aRect) const
size_type GetWidth() const
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Represent a set of changes (additions, deletions or modifications) of a data model (e....
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Create an undo entry for an item that has been already modified.
MINOPTMAX< int > & Value()
const MINOPTMAX< int > & GetValue() const
ZONE_CONNECTION m_ZoneConnection
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)
Checks the 'do not show again' setting for the dialog.
bool SetOKCancelLabels(const ButtonLabel &ok, const ButtonLabel &cancel) override
Shows the 'do not show again' checkbox.
LSET is a set of PCB_LAYER_IDs.
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
bool Contains(PCB_LAYER_ID aLayer)
See if the layer set contains a PCB layer.
static LSET InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
const BOX2I GetBoundingBox() const override
The bounding box is cached, so this will be efficient most of the time.
void SetOffset(const VECTOR2I &aOffset)
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool ignoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
void SetPosition(const VECTOR2I &aPos) override
PAD_SHAPE GetShape() const
PADSTACK::CUSTOM_SHAPE_ZONE_MODE GetCustomShapeInZoneOpt() const
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 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 TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth=false) const override
Convert the item shape to a closed polygon.
A progress reporter interface for use in multi-threaded environments.
virtual bool IsCancelled() const =0
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void Report(const wxString &aMessage)=0
Display aMessage in the progress bar dialog.
virtual void AdvancePhase()=0
Use the next available virtual zone of the dialog progress bar.
virtual void AdvanceProgress()=0
Increment the progress bar length (inside the current virtual zone).
virtual void SetMaxProgress(int aMaxProgress)=0
Fix the value that gives the 100 percent progress bar length (inside the current virtual zone).
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.
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.
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)
std::vector< INTERSECTION > INTERSECTIONS
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 BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset difference For aFastMode meaning, see function booleanOp.
void Fracture(POLYGON_MODE aFastMode)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
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 BooleanIntersection(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
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(POLYGON_MODE aFastMode)
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFastMo...
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 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 Move(const VECTOR2I &aVector) override
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
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.
extended_type SquaredEuclideanNorm() const
Compute the squared euclidean norm of the vector, which is defined as (x ** 2 + y ** 2).
VECTOR2< T > Perpendicular() const
Compute the perpendicular vector.
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
VERTEX * getPoint(VERTEX *aPt) const
std::set< RESULTS > GetResults() const
VERTEX_CONNECTOR(const BOX2I &aBBox, const SHAPE_POLY_SET &aPolys, int aDist)
std::set< RESULTS > m_results
std::deque< VERTEX > m_vertices
int32_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 ...
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)
void updateList()
After inserting or changing nodes, this function should be called to remove duplicate vertices and en...
void * GetUserData() const
bool isEar() 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)
Removes clearance from the shape for copper items which share the zone's layer but are not connected ...
void addKnockout(PAD *aPad, PCB_LAYER_ID aLayer, int aGap, SHAPE_POLY_SET &aHoles)
Add a knockout for a pad.
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...
ZONE_FILLER(BOARD *aBoard, COMMIT *aCommit)
void buildThermalSpokes(const ZONE *box, PCB_LAYER_ID aLayer, const std::vector< PAD * > &aSpokedPadsList, std::deque< SHAPE_LINE_CHAIN > &aSpokes)
Function buildThermalSpokes Constructs a list of all thermal spokes for the given zone.
void subtractHigherPriorityZones(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aRawFill)
Removes the outlines of higher-proirity zones with the same net.
SHAPE_POLY_SET m_boardOutline
bool addHatchFillTypeOnZone(const ZONE *aZone, PCB_LAYER_ID aLayer, PCB_LAYER_ID aDebugLayer, SHAPE_POLY_SET &aFillPolys)
for zones having the ZONE_FILL_MODE::ZONE_FILL_MODE::HATCH_PATTERN, create a grid pattern in filled a...
void SetProgressReporter(PROGRESS_REPORTER *aReporter)
void knockoutThermalReliefs(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aFill, std::vector< PAD * > &aThermalConnectionPads, std::vector< PAD * > &aNoConnectionPads)
Removes thermal reliefs from the shape for any pads connected to the zone.
PROGRESS_REPORTER * m_progressReporter
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 *aZone, PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aSmoothedOutline, SHAPE_POLY_SET &aFillPolys)
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 SetNeedRefill(bool aNeedRefill)
int GetHatchBorderAlgorithm() const
std::optional< int > GetLocalClearance() const override
void CacheTriangulation(PCB_LAYER_ID aLayer=UNDEFINED_LAYER)
Create a list of triangles that "fill" the solid areas used for instance to draw these solid areas on...
const BOX2I GetBoundingBox() const override
SHAPE_POLY_SET * Outline()
void SetFillFlag(PCB_LAYER_ID aLayer, bool aFlag)
void SetFilledPolysList(PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPolysList)
Set the list of filled polygons.
int GetMinThickness() const
bool HigherPriority(const ZONE *aOther) const
int GetHatchThickness() const
double GetHatchHoleMinArea() const
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
double GetHatchSmoothingValue() const
int GetHatchSmoothingLevel() const
bool IsOnCopperLayer() const override
unsigned GetAssignedPriority() const
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 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
@ 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
a few functions useful in geometry calculations.
double m_ExtraClearance
When filling zones, we add an extra amount of clearance to each zone to ensure that rounding errors d...
bool m_DebugZoneFiller
A mode that dumps the various stages of a F_Cu fill into In1_Cu through In9_Cu.
This file is part of the common library.
PCB_LAYER_ID
A quick note on layer IDs:
T clamp(T min, T value, T max)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
constexpr int mmToIU(double mm) const
A storage class for 128-bit hash value.
A struct recording the isolated and single-pad islands within a zone.
BS::thread_pool thread_pool
thread_pool & GetKiCadThreadPool()
Get a reference to the current 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_TARGET_T
class PCB_TARGET, a target (graphic item)
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
VECTOR2< int32_t > VECTOR2I
#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.