56 m_brdOutlinesValid( false ),
58 m_progressReporter( nullptr ),
75 wxASSERT_MSG(
m_commit, wxT(
"ZONE_FILLER must have a valid commit to call "
76 "SetProgressReporter" ) );
94 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
95 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
MD5_HASH> oldFillHashes;
96 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> isolatedIslandsMap;
101 connectivity->ClearRatsnest();
109 :
_(
"Building zone fills..." ) );
122 zone->CacheBoundingBox();
126 for(
PAD*
pad : footprint->Pads() )
135 for(
ZONE* zone : footprint->Zones() )
136 zone->CacheBoundingBox();
139 footprint->BuildCourtyardCaches();
144 auto findHighestPriorityZone = [&](
const BOX2I& aBBox,
const PCB_LAYER_ID aItemLayer,
146 const std::function<bool(
const ZONE* )> aTestFn ) ->
ZONE*
148 unsigned highestPriority = 0;
149 ZONE* highestPriorityZone =
nullptr;
154 if( zone->GetIsRuleArea() )
157 if( zone->GetAssignedPriority() < highestPriority )
160 if( !zone->IsOnLayer( aItemLayer ) )
164 if( zone->GetNumCorners() <= 2 )
167 if( !zone->GetBoundingBox().Intersects( aBBox ) )
170 if( !aTestFn( zone ) )
174 if( zone->GetAssignedPriority() > highestPriority || zone->GetNetCode() == aNetcode )
177 highestPriorityZone = zone;
181 return highestPriorityZone;
184 auto isInPourKeepoutArea = [&](
const BOX2I& aBBox,
const PCB_LAYER_ID aItemLayer,
189 if( !zone->GetIsRuleArea() )
192 if( !zone->GetDoNotAllowCopperPour() )
195 if( !zone->IsOnLayer( aItemLayer ) )
199 if( zone->GetNumCorners() <= 2 )
202 if( !zone->GetBoundingBox().Intersects( aBBox ) )
205 if( zone->Outline()->Contains( aTestPoint ) )
219 via->ClearZoneLayerOverrides();
221 if( !
via->GetRemoveUnconnected() )
226 int testRadius =
via->GetDrillValue() / 2 + 1;
227 unsigned netcode =
via->GetNetCode();
228 LSET layers =
via->GetLayerSet() & boardCuMask;
231 auto viaTestFn = [&](
const ZONE* aZone ) ->
bool
233 return aZone->Outline()->
Contains( center, -1, testRadius );
238 if( !
via->ConditionallyFlashed( layer ) )
241 if( isInPourKeepoutArea( bbox, layer, center ) )
247 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, viaTestFn );
261 for(
PAD*
pad : footprint->Pads() )
263 pad->ClearZoneLayerOverrides();
265 if( !
pad->GetRemoveUnconnected() )
270 unsigned netcode =
pad->GetNetCode();
271 LSET layers =
pad->GetLayerSet() & boardCuMask;
273 auto padTestFn = [&](
const ZONE* aZone ) ->
bool
275 return aZone->Outline()->
Contains( center );
280 if( !
pad->ConditionallyFlashed( layer ) )
283 if( isInPourKeepoutArea( bbox, layer, center ) )
289 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, padTestFn );
300 for(
ZONE* zone : aZones )
303 if( zone->GetIsRuleArea() )
307 if( zone->GetNumCorners() <= 2 )
317 zone->BuildHashValue( layer );
318 oldFillHashes[ { zone, layer } ] = zone->GetHashValue( layer );
321 toFill.emplace_back( std::make_pair( zone, layer ) );
330 auto check_fill_dependency =
338 if( aOtherZone->GetFillFlag( aLayer ) )
343 if( aOtherZone->GetIsRuleArea() )
347 if( aOtherZone->GetNumCorners() <= 2 )
351 if( !aOtherZone->GetLayerSet().test( aLayer ) )
358 if( aOtherZone->SameNet( aZone ) )
366 if( !inflatedBBox.
Intersects( aOtherZone->GetBoundingBox() ) )
373 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
376 ZONE* zone = aFillItem.first;
381 for(
ZONE* otherZone : aZones )
383 if( otherZone == zone )
386 if( check_fill_dependency( zone, layer, otherZone ) )
401 std::unique_lock<std::mutex> zoneLock( zone->
GetLock(), std::try_to_lock );
403 if( !zoneLock.owns_lock() )
420 auto tesselate_lambda =
421 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
427 ZONE* zone = aFillItem.first;
430 std::unique_lock<std::mutex> zoneLock( zone->
GetLock(), std::try_to_lock );
432 if( !zoneLock.owns_lock() )
444 std::vector<std::pair<std::future<int>,
int>> returns;
445 returns.reserve( toFill.size() );
447 bool cancelled =
false;
451 for(
const std::pair<ZONE*, PCB_LAYER_ID>& fillItem : toFill )
452 returns.emplace_back( std::make_pair(
tp.submit( fill_lambda, fillItem ), 0 ) );
454 while( !cancelled && finished != 2 * toFill.size() )
456 for(
size_t ii = 0; ii < returns.size(); ++ii )
458 auto& ret = returns[ii];
463 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
465 if( status == std::future_status::ready )
467 if( ret.first.get() )
476 if( ret.second == 0 )
477 returns[ii].first =
tp.submit( fill_lambda, toFill[ii] );
478 else if( ret.second == 1 )
479 returns[ii].first =
tp.submit( tesselate_lambda, toFill[ii] );
484 std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
498 for(
auto& ret : returns )
500 if( ret.first.valid() )
502 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
504 while( status != std::future_status::ready )
509 status = ret.first.wait_for( std::chrono::milliseconds( 100 ) );
528 connectivity->FillIsolatedIslandsMap( isolatedIslandsMap );
529 connectivity->SetProgressReporter(
nullptr );
534 for(
ZONE* zone : aZones )
537 if( zone->GetIsRuleArea() )
540 zone->SetIsFilled(
true );
546 for(
const auto& [ zone, zoneIslands ] : isolatedIslandsMap )
549 bool allIslands =
true;
551 for(
const auto& [ layer, layerIslands ] : zoneIslands )
553 if( layerIslands.m_IsolatedOutlines.size()
554 !=
static_cast<size_t>( zone->GetFilledPolysList( layer )->OutlineCount() ) )
564 for(
const auto& [ layer, layerIslands ] : zoneIslands )
569 if( layerIslands.m_IsolatedOutlines.empty() )
572 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
576 std::sort( islands.begin(), islands.end(), std::greater<int>() );
578 std::shared_ptr<SHAPE_POLY_SET> poly = zone->GetFilledPolysList( layer );
579 long long int minArea = zone->GetMinIslandArea();
582 for(
int idx : islands )
586 if( mode == ISLAND_REMOVAL_MODE::ALWAYS )
587 poly->DeletePolygonAndTriangulationData( idx,
false );
588 else if ( mode == ISLAND_REMOVAL_MODE::AREA && outline.
Area(
true ) < minArea )
589 poly->DeletePolygonAndTriangulationData( idx,
false );
591 zone->SetIsIsland( layer, idx );
594 poly->UpdateTriangulationDataHash();
595 zone->CalculateFilledArea();
604 using island_check_return = std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
int>>;
606 std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
double>> polys_to_check;
611 for(
ZONE* zone : aZones )
621 double minArea = (double) zone->GetMinThickness() * zone->GetMinThickness() * 3;
628 polys_to_check.emplace_back( zone->GetFilledPolysList( layer ), minArea );
633 [&](
int aStart,
int aEnd ) -> island_check_return
635 island_check_return retval;
637 for(
int ii = aStart; ii < aEnd && !cancelled; ++ii )
639 auto [poly, minArea] = polys_to_check[ii];
641 for(
int jj = poly->OutlineCount() - 1; jj >= 0; jj-- )
646 double island_area = test_poly.
Area();
648 if( island_area < minArea )
661 if( intersection.
Area() < island_area / 2.0 )
662 retval.emplace_back( poly, jj );
669 auto island_returns =
tp.parallelize_loop( 0, polys_to_check.size(), island_lambda );
673 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
675 std::future<island_check_return>& ret = island_returns[ii];
679 std::future_status status = ret.wait_for( std::chrono::seconds( 0 ) );
681 while( status != std::future_status::ready )
691 status = ret.wait_for( std::chrono::milliseconds( 100 ) );
699 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
701 std::future<island_check_return>& ret = island_returns[ii];
705 for(
auto& action_item : ret.get() )
706 action_item.first->DeletePolygonAndTriangulationData( action_item.second,
true );
710 for(
ZONE* zone : aZones )
711 zone->CalculateFilledArea();
716 bool outOfDate =
false;
718 for(
ZONE* zone : aZones )
721 if( zone->GetIsRuleArea() )
726 zone->BuildHashValue( layer );
728 if( oldFillHashes[ { zone, layer } ] != zone->GetHashValue( layer ) )
735 KIDIALOG dlg( aParent,
_(
"Zone fills are out-of-date. Refill?" ),
736 _(
"Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
770 if( aPad->
GetShape() == PAD_SHAPE::CUSTOM )
778 std::vector<VECTOR2I> convex_hull;
783 for(
const VECTOR2I& pt : convex_hull )
812 switch( aItem->
Type() )
819 if(
text->IsVisible() )
821 if(
text->IsKnockout() )
871 std::vector<PAD*>& aThermalConnectionPads,
872 std::vector<PAD*>& aNoConnectionPads )
883 for(
PAD*
pad : footprint->Pads() )
885 BOX2I padBBox =
pad->GetBoundingBox();
891 bool noConnection =
pad->GetNetCode() != aZone->
GetNetCode();
905 aNoConnectionPads.push_back(
pad );
911 connection = ZONE_CONNECTION::FULL;
915 constraint = bds.
m_DRCEngine->EvalZoneConnection(
pad, aZone, aLayer );
921 case ZONE_CONNECTION::THERMAL:
926 if(
pad->CanFlashLayer( aLayer ) )
928 aThermalConnectionPads.push_back(
pad );
931 else if(
pad->GetDrillSize().x > 0 )
938 case ZONE_CONNECTION::NONE:
947 if(
pad->FlashLayer( aLayer ) )
951 else if(
pad->GetDrillSize().x > 0 )
954 pad, aZone, aLayer );
959 holeClearance = padClearance;
982 const std::vector<PAD*> aNoConnectionPads,
988 auto checkForCancel =
991 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
1004 auto evalRulesForItems =
1014 auto knockoutPadClearance =
1019 bool hasHole = aPad->GetDrillSize().x > 0;
1020 bool flashLayer = aPad->FlashLayer( aLayer );
1021 bool platedHole = hasHole && aPad->GetAttribute() == PAD_ATTRIB::PTH;
1023 if( flashLayer || platedHole )
1026 aZone, aPad, aLayer ) );
1029 if( flashLayer && gap > 0 )
1030 addKnockout( aPad, aLayer, gap + extra_margin, aHoles );
1035 if( aPad->GetAttribute() == PAD_ATTRIB::NPTH )
1039 aZone, aPad, aLayer ) );
1042 aZone, aPad, aLayer ) );
1049 for(
PAD*
pad : aNoConnectionPads )
1054 knockoutPadClearance(
pad );
1059 auto knockoutTrackClearance =
1062 if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
1064 bool sameNet = aTrack->GetNetCode() == aZone->
GetNetCode();
1070 aZone, aTrack, aLayer );
1083 aZone, aTrack, aLayer ) );
1090 if(
via->FlashLayer( aLayer ) && gap > 0 )
1092 via->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
1097 aZone,
via, aLayer ) );
1102 aZone,
via, aLayer ) );
1107 int radius =
via->GetDrillValue() / 2;
1110 radius + gap + extra_margin,
1118 aTrack->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
1127 if( !track->IsOnLayer( aLayer ) )
1133 knockoutTrackClearance( track );
1138 auto knockoutGraphicClearance =
1146 bool sameNet = shapeNet == aZone->
GetNetCode();
1152 if( aItem->IsOnLayer( aLayer )
1154 || aItem->IsOnLayer(
Margin ) )
1156 if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
1158 bool ignoreLineWidths =
false;
1160 aZone, aItem, aLayer );
1162 if( aItem->IsOnLayer( aLayer ) && !sameNet )
1165 aZone, aItem, aLayer ) );
1167 else if( aItem->IsOnLayer(
Edge_Cuts ) )
1170 aZone, aItem, aLayer ) );
1171 ignoreLineWidths =
true;
1173 else if( aItem->IsOnLayer(
Margin ) )
1176 aZone, aItem, aLayer ) );
1180 addKnockout( aItem, aLayer, gap + extra_margin, ignoreLineWidths, aHoles );
1187 knockoutGraphicClearance( &footprint->Reference() );
1188 knockoutGraphicClearance( &footprint->Value() );
1190 std::set<PAD*> allowedNetTiePads;
1194 if( footprint->IsNetTie() )
1196 for(
PAD*
pad : footprint->Pads() )
1205 if(
pad->IsOnLayer( aLayer ) )
1206 allowedNetTiePads.insert(
pad );
1208 for(
PAD* other : footprint->GetNetTiePads(
pad ) )
1210 if( other->IsOnLayer( aLayer ) )
1211 allowedNetTiePads.insert( other );
1217 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
1222 BOX2I itemBBox = item->GetBoundingBox();
1224 if( !zone_boundingbox.
Intersects( itemBBox ) )
1227 bool skipItem =
false;
1229 if( item->IsOnLayer( aLayer ) )
1231 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape();
1233 for(
PAD*
pad : allowedNetTiePads )
1235 if(
pad->GetBoundingBox().Intersects( itemBBox )
1236 &&
pad->GetEffectiveShape()->Collide( itemShape.get() ) )
1245 knockoutGraphicClearance( item );
1254 knockoutGraphicClearance( item );
1259 auto knockoutZoneClearance =
1260 [&](
ZONE* aKnockout )
1263 if( !aKnockout->GetLayerSet().test( aLayer ) )
1266 if( aKnockout->GetBoundingBox().Intersects( zone_boundingbox ) )
1268 if( aKnockout->GetIsRuleArea() )
1271 aKnockout->TransformSmoothedOutlineToPolygon( aHoles, 0,
m_maxError,
1277 aKnockout, aLayer );
1280 aKnockout, aLayer ) );
1283 aKnockout->TransformShapeToPolygon( poly, aLayer, gap + extra_margin,
1299 if( otherZone->GetIsRuleArea() )
1301 if( otherZone->GetDoNotAllowCopperPour() && !aZone->
IsTeardropArea() )
1302 knockoutZoneClearance( otherZone );
1304 else if( otherZone->HigherPriority( aZone ) )
1306 if( !otherZone->SameNet( aZone ) )
1307 knockoutZoneClearance( otherZone );
1313 for(
ZONE* otherZone : footprint->Zones() )
1318 if( otherZone->GetIsRuleArea() )
1320 if( otherZone->GetDoNotAllowCopperPour() && !aZone->
IsTeardropArea() )
1321 knockoutZoneClearance( otherZone );
1323 else if( otherZone->HigherPriority( aZone ) )
1325 if( !otherZone->SameNet( aZone ) )
1326 knockoutZoneClearance( otherZone );
1344 auto knockoutZoneOutline =
1345 [&](
ZONE* aKnockout )
1348 if( !aKnockout->GetLayerSet().test( aLayer ) )
1351 if( aKnockout->GetBoundingBox().Intersects( zoneBBox ) )
1367 if( otherZone->SameNet( aZone )
1371 if( !otherZone->IsTeardropArea() )
1372 knockoutZoneOutline( otherZone );
1378 for(
ZONE* otherZone : footprint->Zones() )
1380 if( otherZone->SameNet( aZone ) && otherZone->HigherPriority( aZone ) )
1383 if( !otherZone->IsTeardropArea() )
1384 knockoutZoneOutline( otherZone );
1391#define DUMP_POLYS_TO_COPPER_LAYER( a, b, c ) \
1392 { if( m_debugZoneFiller && aDebugLayer == b ) \
1394 m_board->SetLayerName( b, c ); \
1395 SHAPE_POLY_SET d = a; \
1396 d.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE ); \
1436 CORNER_STRATEGY fastCornerStrategy = CORNER_STRATEGY::CHAMFER_ALL_CORNERS;
1439 std::vector<PAD*> thermalConnectionPads;
1440 std::vector<PAD*> noConnectionPads;
1441 std::deque<SHAPE_LINE_CHAIN> thermalSpokes;
1444 aFillPolys = aSmoothedOutline;
1481 static const bool USE_BBOX_CACHES =
true;
1508 const VECTOR2I& testPt = spoke.CPoint( 3 );
1511 if( testAreas.
Contains( testPt, -1, 1, USE_BBOX_CACHES ) )
1520 if( interval++ > 400 )
1533 if( &other != &spoke
1534 && other.PointInside( testPt, 1, USE_BBOX_CACHES )
1535 && spoke.PointInside( other.CPoint( 3 ), 1, USE_BBOX_CACHES ) )
1565 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
1567 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
1568 BOX2I islandExtents;
1570 for(
const VECTOR2I& pt : island.front().CPoints() )
1572 islandExtents.
Merge( pt );
1591 if( aZone->
GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
1615 for(
PAD*
pad : thermalConnectionPads )
1644 auto checkForCancel =
1647 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
1650 auto knockoutGraphicClearance =
1653 if( aItem->IsKnockout() && aItem->IsOnLayer( aLayer )
1654 && aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
1657 aZone, aItem, aLayer );
1668 knockoutGraphicClearance( &footprint->Reference() );
1669 knockoutGraphicClearance( &footprint->Value() );
1671 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
1672 knockoutGraphicClearance( item );
1680 knockoutGraphicClearance( item );
1683 aFillPolys = aSmoothedOutline;
1688 if( !keepout->GetIsRuleArea() )
1691 if( keepout->GetDoNotAllowCopperPour() && keepout->IsOnLayer( aLayer ) )
1693 if( keepout->GetBoundingBox().Intersects( zone_boundingbox ) )
1707 if( aZone->
GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
1736 debugLayer = aLayer;
1740 if( !aZone->
BuildSmoothedPoly( maxExtents, aLayer, boardOutline, &smoothedPoly ) )
1748 if(
fillCopperZone( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aFillPolys ) )
1765 const std::vector<PAD*>& aSpokedPadsList,
1766 std::deque<SHAPE_LINE_CHAIN>& aSpokesList )
1778 for(
PAD*
pad : aSpokedPadsList )
1781 if( !
pad->IsOnLayer( aLayer ) )
1785 int thermalReliefGap = constraint.
GetValue().
Min();
1793 int spoke_max_allowed_w = std::min(
pad->GetSize().x,
pad->GetSize().y );
1795 spoke_w = std::max( spoke_w, constraint.
Value().
Min() );
1796 spoke_w = std::min( spoke_w, constraint.
Value().
Max() );
1799 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
1802 if( spoke_w < aZone->GetMinThickness() )
1805 int spoke_half_w = spoke_w / 2;
1808 BOX2I itemBB =
pad->GetBoundingBox();
1814 bool customSpokes =
false;
1816 if(
pad->GetShape() == PAD_SHAPE::CUSTOM )
1818 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives() )
1820 if( primitive->IsProxyItem() && primitive->GetShape() == SHAPE_T::SEGMENT )
1822 customSpokes =
true;
1833 auto buildSpokesFromOrigin =
1834 [&](
const BOX2I& box )
1836 for(
int i = 0; i < 4; i++ )
1843 spoke.
Append( +spoke_half_w, -spoke_half_w );
1844 spoke.
Append( -spoke_half_w, -spoke_half_w );
1845 spoke.
Append( -spoke_half_w, box.GetBottom() );
1846 spoke.
Append( 0, box.GetBottom() );
1847 spoke.
Append( +spoke_half_w, box.GetBottom() );
1851 spoke.
Append( +spoke_half_w, +spoke_half_w );
1852 spoke.
Append( -spoke_half_w, +spoke_half_w );
1853 spoke.
Append( -spoke_half_w, box.GetTop() );
1854 spoke.
Append( 0, box.GetTop() );
1855 spoke.
Append( +spoke_half_w, box.GetTop() );
1859 spoke.
Append( -spoke_half_w, +spoke_half_w );
1860 spoke.
Append( -spoke_half_w, -spoke_half_w );
1861 spoke.
Append( box.GetRight(), -spoke_half_w );
1862 spoke.
Append( box.GetRight(), 0 );
1863 spoke.
Append( box.GetRight(), +spoke_half_w );
1867 spoke.
Append( +spoke_half_w, +spoke_half_w );
1868 spoke.
Append( +spoke_half_w, -spoke_half_w );
1869 spoke.
Append( box.GetLeft(), -spoke_half_w );
1870 spoke.
Append( box.GetLeft(), 0 );
1871 spoke.
Append( box.GetLeft(), +spoke_half_w );
1876 aSpokesList.push_back( std::move( spoke ) );
1885 pad->TransformShapeToPolygon( thermalPoly, aLayer, thermalReliefGap +
epsilon,
1889 thermalOutline = thermalPoly.
Outline( 0 );
1891 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives() )
1893 if( primitive->IsProxyItem() && primitive->GetShape() == SHAPE_T::SEGMENT )
1895 SEG seg( primitive->GetStart(), primitive->GetEnd() );
1900 seg.
A +=
pad->ShapePos();
1901 seg.
B +=
pad->ShapePos();
1908 if( thermalOutline.
Intersect( seg, intersections ) )
1910 seg.
B = intersections.front().p;
1912 VECTOR2I offset = ( seg.
B - seg.
A ).Perpendicular().
Resize( spoke_half_w );
1915 spoke.
Append( seg.
A + offset );
1916 spoke.
Append( seg.
A - offset );
1917 spoke.
Append( seg.
B - offset );
1919 spoke.
Append( seg.
B + offset );
1922 aSpokesList.push_back( std::move( spoke ) );
1929 else if( (
pad->GetOrientation() +
pad->GetThermalSpokeAngle() ).IsCardinal() )
1931 BOX2I spokesBox =
pad->GetBoundingBox();
1937 buildSpokesFromOrigin( spokesBox );
1939 auto spokeIter = aSpokesList.rbegin();
1941 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
1942 spokeIter->Move(
pad->ShapePos() );
1946 else if(
pad->GetSizeX() ==
pad->GetSizeY() &&
pad->GetShape() != PAD_SHAPE::CUSTOM )
1961 buildSpokesFromOrigin( spokesBox );
1963 auto spokeIter = aSpokesList.rbegin();
1965 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
1967 spokeIter->Rotate(
pad->GetOrientation() +
pad->GetThermalSpokeAngle() );
1968 spokeIter->Move(
pad->ShapePos() );
1993 buildSpokesFromOrigin( spokesBox );
1995 BOX2I realBBox =
pad->GetBoundingBox();
1998 auto spokeIter = aSpokesList.rbegin();
2000 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
2002 spokeIter->Rotate(
pad->GetOrientation() +
pad->GetThermalSpokeAngle() );
2003 spokeIter->
Move(
pad->ShapePos() );
2005 VECTOR2I origin_p = spokeIter->GetPoint( 0 );
2006 VECTOR2I origin_m = spokeIter->GetPoint( 1 );
2007 VECTOR2I origin = ( origin_p + origin_m ) / 2;
2008 VECTOR2I end_m = spokeIter->GetPoint( 2 );
2009 VECTOR2I end = spokeIter->GetPoint( 3 );
2010 VECTOR2I end_p = spokeIter->GetPoint( 4 );
2012 ClipLine( &realBBox, origin_p.
x, origin_p.
y, end_p.
x, end_p.
y );
2013 ClipLine( &realBBox, origin_m.
x, origin_m.
y, end_m.
x, end_m.
y );
2014 ClipLine( &realBBox, origin.
x, origin.
y, end.
x, end.
y );
2016 spokeIter->SetPoint( 2, end_m );
2017 spokeIter->SetPoint( 3, end );
2018 spokeIter->SetPoint( 4, end_p );
2026 for(
size_t ii = 0; ii < aSpokesList.size(); ++ii )
2027 aSpokesList[ii].GenerateBBoxCache();
2063 hole_base.
Append( corner );
2064 corner.
x += hole_size;
2065 hole_base.
Append( corner );
2066 corner.
y += hole_size;
2067 hole_base.
Append( corner );
2069 hole_base.
Append( corner );
2089 #define SMOOTH_MIN_VAL_MM 0.02
2090 #define SMOOTH_SMALL_VAL_MM 0.04
2106 smooth_value = std::min( smooth_value, aZone->
GetHatchGap() / 2 );
2109 maxError = std::max( maxError * 2, smooth_value / 20 );
2111 switch( smooth_level )
2123 hole_base = smooth_hole.
Fillet( smooth_value, maxError ).
Outline( 0 );
2135 for(
int xx = 0; ; xx++ )
2137 int xpos = xx * gridsize;
2142 for(
int yy = 0; ; yy++ )
2144 int ypos = yy * gridsize;
2173 CORNER_STRATEGY::CHAMFER_ALL_CORNERS, maxError );
2178 deflatedOutline.
Deflate( outline_margin, CORNER_STRATEGY::CHAMFER_ALL_CORNERS, maxError );
2190 int min_apron_radius = ( aZone->
GetHatchGap() * 10 ) / 19;
2199 &&
via->IsOnLayer( aLayer )
2200 &&
via->GetBoundingBox().Intersects( zone_boundingbox ) )
2202 int r = std::max( min_apron_radius,
2203 via->GetDrillValue() / 2 + outline_margin );
2213 for(
PAD*
pad : footprint->Pads() )
2216 &&
pad->IsOnLayer( aLayer )
2217 &&
pad->GetBoundingBox().Intersects( zone_boundingbox ) )
2224 int pad_width = std::min(
pad->GetSize().x,
pad->GetSize().y );
2225 int slot_width = std::min(
pad->GetDrillSize().x,
pad->GetDrillSize().y );
2226 int min_annular_ring_width = ( pad_width - slot_width ) / 2;
2227 int clearance = std::max( min_apron_radius - pad_width / 2,
2228 outline_margin - min_annular_ring_width );
2230 clearance = std::max( 0, clearance - linethickness / 2 );
2231 pad->TransformShapeToPolygon( aprons, aLayer, clearance, maxError,
2247 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
void Offset(coord_type dx, coord_type dy)
size_type GetHeight() const
bool Intersects(const BOX2< Vec > &aRect) const
size_type GetWidth() const
void Move(const Vec &aMoveVector)
Move the rectangle by the aMoveVector.
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.
CUST_PAD_SHAPE_IN_ZONE GetCustomShapeInZoneOpt() const
void SetPosition(const VECTOR2I &aPos) override
PAD_SHAPE GetShape() 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).
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.
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 BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
void addKnockout(PAD *aPad, PCB_LAYER_ID aLayer, int aGap, SHAPE_POLY_SET &aHoles)
Add a knockout for a pad.
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 ...
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
This file is part of the common library.
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
a few functions useful in geometry calculations.
bool ClipLine(const BOX2I *aClipBox, int &x1, int &y1, int &x2, int &y2)
Test if any part of a line falls within the bounds of a rectangle.
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.
PCB_LAYER_ID
A quick note on layer IDs:
@ CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL
constexpr int mmToIU(double mm) const
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".
#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.