53 m_brdOutlinesValid( false ),
55 m_progressReporter( nullptr ),
72 wxASSERT_MSG(
m_commit, wxT(
"ZONE_FILLER must have a valid commit to call "
73 "SetProgressReporter" ) );
91 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
92 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
MD5_HASH> oldFillHashes;
93 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> isolatedIslandsMap;
98 connectivity->ClearRatsnest();
106 :
_(
"Building zone fills..." ) );
119 zone->CacheBoundingBox();
123 for(
PAD*
pad : footprint->Pads() )
128 pad->BuildEffectivePolygon();
132 for(
ZONE* zone : footprint->Zones() )
133 zone->CacheBoundingBox();
136 footprint->BuildCourtyardCaches();
141 auto findHighestPriorityZone = [&](
const BOX2I& aBBox,
const PCB_LAYER_ID aItemLayer,
143 const std::function<bool(
const ZONE* )> aTestFn ) ->
ZONE*
145 unsigned highestPriority = 0;
146 ZONE* highestPriorityZone =
nullptr;
151 if( zone->GetIsRuleArea() )
154 if( zone->GetAssignedPriority() < highestPriority )
157 if( !zone->IsOnLayer( aItemLayer ) )
161 if( zone->GetNumCorners() <= 2 )
164 if( !zone->GetBoundingBox().Intersects( aBBox ) )
167 if( !aTestFn( zone ) )
171 if( zone->GetAssignedPriority() > highestPriority || zone->GetNetCode() == aNetcode )
174 highestPriorityZone = zone;
178 return highestPriorityZone;
181 auto isInPourKeepoutArea = [&](
const BOX2I& aBBox,
const PCB_LAYER_ID aItemLayer,
186 if( !zone->GetIsRuleArea() )
189 if( !zone->GetDoNotAllowCopperPour() )
192 if( !zone->IsOnLayer( aItemLayer ) )
196 if( zone->GetNumCorners() <= 2 )
199 if( !zone->GetBoundingBox().Intersects( aBBox ) )
202 if( zone->Outline()->Contains( aTestPoint ) )
216 via->ClearZoneLayerOverrides();
218 if( !
via->GetRemoveUnconnected() )
223 int testRadius =
via->GetDrillValue() / 2 + 1;
224 unsigned netcode =
via->GetNetCode();
225 LSET layers =
via->GetLayerSet() & boardCuMask;
228 auto viaTestFn = [&](
const ZONE* aZone ) ->
bool
230 return aZone->Outline()->
Contains( center, -1, testRadius );
235 if( !
via->ConditionallyFlashed( layer ) )
238 if( isInPourKeepoutArea( bbox, layer, center ) )
244 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, viaTestFn );
258 for(
PAD*
pad : footprint->Pads() )
260 pad->ClearZoneLayerOverrides();
262 if( !
pad->GetRemoveUnconnected() )
267 unsigned netcode =
pad->GetNetCode();
268 LSET layers =
pad->GetLayerSet() & boardCuMask;
270 auto padTestFn = [&](
const ZONE* aZone ) ->
bool
272 return aZone->Outline()->
Contains( center );
277 if( !
pad->ConditionallyFlashed( layer ) )
280 if( isInPourKeepoutArea( bbox, layer, center ) )
286 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, padTestFn );
297 for(
ZONE* zone : aZones )
300 if( zone->GetIsRuleArea() )
304 if( zone->GetNumCorners() <= 2 )
314 zone->BuildHashValue( layer );
315 oldFillHashes[ { zone, layer } ] = zone->GetHashValue( layer );
318 toFill.emplace_back( std::make_pair( zone, layer ) );
327 auto check_fill_dependency =
335 if( aOtherZone->GetFillFlag( aLayer ) )
340 if( aOtherZone->GetIsRuleArea() )
344 if( aOtherZone->GetNumCorners() <= 2 )
348 if( !aOtherZone->GetLayerSet().test( aLayer ) )
355 if( aOtherZone->SameNet( aZone ) )
363 if( !inflatedBBox.
Intersects( aOtherZone->GetBoundingBox() ) )
370 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
373 ZONE* zone = aFillItem.first;
378 for(
ZONE* otherZone : aZones )
380 if( otherZone == zone )
383 if( check_fill_dependency( zone, layer, otherZone ) )
398 std::unique_lock<std::mutex> zoneLock( zone->
GetLock(), std::try_to_lock );
400 if( !zoneLock.owns_lock() )
417 auto tesselate_lambda =
418 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
424 ZONE* zone = aFillItem.first;
427 std::unique_lock<std::mutex> zoneLock( zone->
GetLock(), std::try_to_lock );
429 if( !zoneLock.owns_lock() )
441 std::vector<std::pair<std::future<int>,
int>> returns;
442 returns.reserve( toFill.size() );
444 bool cancelled =
false;
448 for(
const std::pair<ZONE*, PCB_LAYER_ID>& fillItem : toFill )
449 returns.emplace_back( std::make_pair(
tp.submit( fill_lambda, fillItem ), 0 ) );
451 while( !cancelled && finished != 2 * toFill.size() )
453 for(
size_t ii = 0; ii < returns.size(); ++ii )
455 auto& ret = returns[ii];
460 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
462 if( status == std::future_status::ready )
464 if( ret.first.get() )
473 if( ret.second == 0 )
474 returns[ii].first =
tp.submit( fill_lambda, toFill[ii] );
475 else if( ret.second == 1 )
476 returns[ii].first =
tp.submit( tesselate_lambda, toFill[ii] );
481 std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
495 for(
auto& ret : returns )
497 if( ret.first.valid() )
499 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
501 while( status != std::future_status::ready )
506 status = ret.first.wait_for( std::chrono::milliseconds( 100 ) );
525 connectivity->FillIsolatedIslandsMap( isolatedIslandsMap );
526 connectivity->SetProgressReporter(
nullptr );
531 for(
ZONE* zone : aZones )
534 if( zone->GetIsRuleArea() )
537 zone->SetIsFilled(
true );
543 for(
const auto& [ zone, zoneIslands ] : isolatedIslandsMap )
546 bool allIslands =
true;
548 for(
const auto& [ layer, layerIslands ] : zoneIslands )
550 if( layerIslands.m_IsolatedOutlines.size()
551 !=
static_cast<size_t>( zone->GetFilledPolysList( layer )->OutlineCount() ) )
561 for(
const auto& [ layer, layerIslands ] : zoneIslands )
566 if( layerIslands.m_IsolatedOutlines.empty() )
569 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
573 std::sort( islands.begin(), islands.end(), std::greater<int>() );
575 std::shared_ptr<SHAPE_POLY_SET> poly = zone->GetFilledPolysList( layer );
576 long long int minArea = zone->GetMinIslandArea();
579 for(
int idx : islands )
583 if( mode == ISLAND_REMOVAL_MODE::ALWAYS )
584 poly->DeletePolygonAndTriangulationData( idx,
false );
585 else if ( mode == ISLAND_REMOVAL_MODE::AREA && outline.
Area(
true ) < minArea )
586 poly->DeletePolygonAndTriangulationData( idx,
false );
588 zone->SetIsIsland( layer, idx );
591 poly->UpdateTriangulationDataHash();
592 zone->CalculateFilledArea();
601 using island_check_return = std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
int>>;
603 std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
double>> polys_to_check;
608 for(
ZONE* zone : aZones )
615 double minArea = (double) zone->GetMinThickness() * zone->GetMinThickness() * 3;
622 polys_to_check.emplace_back( zone->GetFilledPolysList( layer ), minArea );
627 [&](
int aStart,
int aEnd ) -> island_check_return
629 island_check_return retval;
631 for(
int ii = aStart; ii < aEnd && !cancelled; ++ii )
633 auto [poly, minArea] = polys_to_check[ii];
635 for(
int jj = poly->OutlineCount() - 1; jj >= 0; jj-- )
640 double island_area = test_poly.
Area();
642 if( island_area < minArea )
655 if( intersection.
Area() < island_area / 2.0 )
656 retval.emplace_back( poly, jj );
663 auto island_returns =
tp.parallelize_loop( 0, polys_to_check.size(), island_lambda );
667 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
669 std::future<island_check_return>& ret = island_returns[ii];
673 std::future_status status = ret.wait_for( std::chrono::seconds( 0 ) );
675 while( status != std::future_status::ready )
685 status = ret.wait_for( std::chrono::milliseconds( 100 ) );
693 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
695 std::future<island_check_return>& ret = island_returns[ii];
699 for(
auto& action_item : ret.get() )
700 action_item.first->DeletePolygonAndTriangulationData( action_item.second,
true );
704 for(
ZONE* zone : aZones )
705 zone->CalculateFilledArea();
710 bool outOfDate =
false;
712 for(
ZONE* zone : aZones )
715 if( zone->GetIsRuleArea() )
720 zone->BuildHashValue( layer );
722 if( oldFillHashes[ { zone, layer } ] != zone->GetHashValue( layer ) )
729 KIDIALOG dlg( aParent,
_(
"Zone fills are out-of-date. Refill?" ),
730 _(
"Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
764 if( aPad->
GetShape() == PAD_SHAPE::CUSTOM )
772 std::vector<VECTOR2I> convex_hull;
777 for(
const VECTOR2I& pt : convex_hull )
806 switch( aItem->
Type() )
813 if(
text->IsVisible() )
815 if(
text->IsKnockout() )
857 std::vector<PAD*>& aThermalConnectionPads,
858 std::vector<PAD*>& aNoConnectionPads )
869 for(
PAD*
pad : footprint->Pads() )
871 BOX2I padBBox =
pad->GetBoundingBox();
878 ||
pad->GetNetCode() <= 0
882 aNoConnectionPads.push_back(
pad );
888 connection = ZONE_CONNECTION::FULL;
892 constraint = bds.
m_DRCEngine->EvalZoneConnection(
pad, aZone, aLayer );
898 case ZONE_CONNECTION::THERMAL:
903 if(
pad->CanFlashLayer( aLayer ) )
905 aThermalConnectionPads.push_back(
pad );
908 else if(
pad->GetDrillSize().x > 0 )
915 case ZONE_CONNECTION::NONE:
924 if(
pad->FlashLayer( aLayer ) )
928 else if(
pad->GetDrillSize().x > 0 )
931 pad, aZone, aLayer );
936 holeClearance = padClearance;
959 const std::vector<PAD*> aNoConnectionPads,
965 auto checkForCancel =
968 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
981 auto evalRulesForItems =
991 auto knockoutPadClearance =
996 bool hasHole = aPad->GetDrillSize().x > 0;
997 bool flashLayer = aPad->FlashLayer( aLayer );
998 bool platedHole = hasHole && aPad->GetAttribute() == PAD_ATTRIB::PTH;
1000 if( flashLayer || platedHole )
1003 aZone, aPad, aLayer ) );
1006 if( flashLayer && gap > 0 )
1007 addKnockout( aPad, aLayer, gap + extra_margin, aHoles );
1012 if( aPad->GetAttribute() == PAD_ATTRIB::NPTH )
1016 aZone, aPad, aLayer ) );
1019 aZone, aPad, aLayer ) );
1026 for(
PAD*
pad : aNoConnectionPads )
1031 knockoutPadClearance(
pad );
1036 auto knockoutTrackClearance =
1039 if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
1041 bool sameNet = aTrack->GetNetCode() == aZone->
GetNetCode()
1045 aZone, aTrack, aLayer );
1058 aZone, aTrack, aLayer ) );
1065 if(
via->FlashLayer( aLayer ) && gap > 0 )
1067 via->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
1072 aZone,
via, aLayer ) );
1077 aZone,
via, aLayer ) );
1082 int radius =
via->GetDrillValue() / 2;
1085 radius + gap + extra_margin,
1093 aTrack->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
1102 if( !track->IsOnLayer( aLayer ) )
1108 knockoutTrackClearance( track );
1113 auto knockoutGraphicClearance =
1120 if( aItem->IsOnLayer( aLayer )
1122 || aItem->IsOnLayer(
Margin ) )
1124 if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
1126 bool ignoreLineWidths =
false;
1128 aZone, aItem, aLayer );
1130 if( aItem->IsOnLayer( aLayer ) && !sameNet )
1133 aZone, aItem, aLayer ) );
1135 else if( aItem->IsOnLayer(
Edge_Cuts ) )
1139 ignoreLineWidths =
true;
1141 else if( aItem->IsOnLayer(
Margin ) )
1144 aZone, aItem,
Margin ) );
1148 addKnockout( aItem, aLayer, gap + extra_margin, ignoreLineWidths, aHoles );
1155 knockoutGraphicClearance( &footprint->Reference() );
1156 knockoutGraphicClearance( &footprint->Value() );
1158 std::set<PAD*> allowedNetTiePads;
1162 if( footprint->IsNetTie() )
1164 for(
PAD*
pad : footprint->Pads() )
1168 if(
pad->IsOnLayer( aLayer ) )
1169 allowedNetTiePads.insert(
pad );
1171 for(
PAD* other : footprint->GetNetTiePads(
pad ) )
1173 if( other->IsOnLayer( aLayer ) )
1174 allowedNetTiePads.insert( other );
1180 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
1185 BOX2I itemBBox = item->GetBoundingBox();
1187 if( !zone_boundingbox.
Intersects( itemBBox ) )
1190 bool skipItem =
false;
1192 if( item->IsOnLayer( aLayer ) )
1194 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape();
1196 for(
PAD*
pad : allowedNetTiePads )
1198 if(
pad->GetBoundingBox().Intersects( itemBBox )
1199 &&
pad->GetEffectiveShape()->Collide( itemShape.get() ) )
1208 knockoutGraphicClearance( item );
1217 knockoutGraphicClearance( item );
1222 auto knockoutZoneClearance =
1223 [&](
ZONE* aKnockout )
1226 if( !aKnockout->GetLayerSet().test( aLayer ) )
1229 if( aKnockout->GetBoundingBox().Intersects( zone_boundingbox ) )
1231 if( aKnockout->GetIsRuleArea() )
1234 aKnockout->TransformSmoothedOutlineToPolygon( aHoles, 0,
m_maxError,
1240 aKnockout, aLayer );
1243 aKnockout, aLayer ) );
1246 aKnockout->TransformShapeToPolygon( poly, aLayer, gap + extra_margin,
1262 if( otherZone->GetIsRuleArea() )
1264 if( otherZone->GetDoNotAllowCopperPour() && !aZone->
IsTeardropArea() )
1265 knockoutZoneClearance( otherZone );
1267 else if( otherZone->HigherPriority( aZone ) )
1269 if( !otherZone->SameNet( aZone ) )
1270 knockoutZoneClearance( otherZone );
1276 for(
ZONE* otherZone : footprint->Zones() )
1281 if( otherZone->GetIsRuleArea() )
1283 if( otherZone->GetDoNotAllowCopperPour() && !aZone->
IsTeardropArea() )
1284 knockoutZoneClearance( otherZone );
1286 else if( otherZone->HigherPriority( aZone ) )
1288 if( !otherZone->SameNet( aZone ) )
1289 knockoutZoneClearance( otherZone );
1307 auto knockoutZoneOutline =
1308 [&](
ZONE* aKnockout )
1311 if( !aKnockout->GetLayerSet().test( aLayer ) )
1314 if( aKnockout->GetBoundingBox().Intersects( zoneBBox ) )
1330 if( otherZone->SameNet( aZone )
1334 if( !otherZone->IsTeardropArea() )
1335 knockoutZoneOutline( otherZone );
1341 for(
ZONE* otherZone : footprint->Zones() )
1343 if( otherZone->SameNet( aZone ) && otherZone->HigherPriority( aZone ) )
1346 if( !otherZone->IsTeardropArea() )
1347 knockoutZoneOutline( otherZone );
1354#define DUMP_POLYS_TO_COPPER_LAYER( a, b, c ) \
1355 { if( m_debugZoneFiller && aDebugLayer == b ) \
1357 m_board->SetLayerName( b, c ); \
1358 SHAPE_POLY_SET d = a; \
1359 d.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE ); \
1402 std::vector<PAD*> thermalConnectionPads;
1403 std::vector<PAD*> noConnectionPads;
1404 std::deque<SHAPE_LINE_CHAIN> thermalSpokes;
1407 aFillPolys = aSmoothedOutline;
1444 static const bool USE_BBOX_CACHES =
true;
1471 const VECTOR2I& testPt = spoke.CPoint( 3 );
1474 if( testAreas.
Contains( testPt, -1, 1, USE_BBOX_CACHES ) )
1483 if( interval++ > 400 )
1496 if( &other != &spoke
1497 && other.PointInside( testPt, 1, USE_BBOX_CACHES )
1498 && spoke.PointInside( other.CPoint( 3 ), 1, USE_BBOX_CACHES ) )
1528 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
1530 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
1531 BOX2I islandExtents;
1533 for(
const VECTOR2I& pt : island.front().CPoints() )
1535 islandExtents.
Merge( pt );
1554 if( aZone->
GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
1578 for(
PAD*
pad : thermalConnectionPads )
1607 auto checkForCancel =
1610 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
1613 auto knockoutGraphicClearance =
1616 if( aItem->IsKnockout() && aItem->IsOnLayer( aLayer )
1617 && aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
1620 aZone, aItem, aLayer );
1631 knockoutGraphicClearance( &footprint->Reference() );
1632 knockoutGraphicClearance( &footprint->Value() );
1634 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
1635 knockoutGraphicClearance( item );
1643 knockoutGraphicClearance( item );
1646 aFillPolys = aSmoothedOutline;
1651 if( !keepout->GetIsRuleArea() )
1654 if( keepout->GetDoNotAllowCopperPour() && keepout->IsOnLayer( aLayer ) )
1656 if( keepout->GetBoundingBox().Intersects( zone_boundingbox ) )
1670 if( aZone->
GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
1699 debugLayer = aLayer;
1703 if( !aZone->
BuildSmoothedPoly( maxExtents, aLayer, boardOutline, &smoothedPoly ) )
1711 if(
fillCopperZone( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aFillPolys ) )
1728 const std::vector<PAD*>& aSpokedPadsList,
1729 std::deque<SHAPE_LINE_CHAIN>& aSpokesList )
1741 for(
PAD*
pad : aSpokedPadsList )
1744 if( !
pad->IsOnLayer( aLayer ) )
1748 int thermalReliefGap = constraint.
GetValue().
Min();
1756 int spoke_max_allowed_w = std::min(
pad->GetSize().x,
pad->GetSize().y );
1758 spoke_w = std::max( spoke_w, constraint.
Value().
Min() );
1759 spoke_w = std::min( spoke_w, constraint.
Value().
Max() );
1762 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
1765 if( spoke_w < aZone->GetMinThickness() )
1768 int spoke_half_w = spoke_w / 2;
1771 BOX2I itemBB =
pad->GetBoundingBox();
1777 bool customSpokes =
false;
1779 if(
pad->GetShape() == PAD_SHAPE::CUSTOM )
1781 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives() )
1783 if( primitive->IsProxyItem() && primitive->GetShape() == SHAPE_T::SEGMENT )
1785 customSpokes =
true;
1796 auto buildSpokesFromOrigin =
1797 [&](
const BOX2I& box )
1799 for(
int i = 0; i < 4; i++ )
1806 spoke.
Append( +spoke_half_w, -spoke_half_w );
1807 spoke.
Append( -spoke_half_w, -spoke_half_w );
1808 spoke.
Append( -spoke_half_w, box.GetBottom() );
1809 spoke.
Append( 0, box.GetBottom() );
1810 spoke.
Append( +spoke_half_w, box.GetBottom() );
1814 spoke.
Append( +spoke_half_w, +spoke_half_w );
1815 spoke.
Append( -spoke_half_w, +spoke_half_w );
1816 spoke.
Append( -spoke_half_w, box.GetTop() );
1817 spoke.
Append( 0, box.GetTop() );
1818 spoke.
Append( +spoke_half_w, box.GetTop() );
1822 spoke.
Append( -spoke_half_w, +spoke_half_w );
1823 spoke.
Append( -spoke_half_w, -spoke_half_w );
1824 spoke.
Append( box.GetRight(), -spoke_half_w );
1825 spoke.
Append( box.GetRight(), 0 );
1826 spoke.
Append( box.GetRight(), +spoke_half_w );
1830 spoke.
Append( +spoke_half_w, +spoke_half_w );
1831 spoke.
Append( +spoke_half_w, -spoke_half_w );
1832 spoke.
Append( box.GetLeft(), -spoke_half_w );
1833 spoke.
Append( box.GetLeft(), 0 );
1834 spoke.
Append( box.GetLeft(), +spoke_half_w );
1839 aSpokesList.push_back( std::move( spoke ) );
1848 pad->TransformShapeToPolygon( thermalPoly, aLayer, thermalReliefGap +
epsilon,
1852 thermalOutline = thermalPoly.
Outline( 0 );
1854 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives() )
1856 if( primitive->IsProxyItem() && primitive->GetShape() == SHAPE_T::SEGMENT )
1858 SEG seg( primitive->GetStart(), primitive->GetEnd() );
1863 seg.
A +=
pad->ShapePos();
1864 seg.
B +=
pad->ShapePos();
1867 if( !
pad->GetEffectivePolygon()->Contains( seg.
A ) )
1871 if( thermalOutline.
Intersect( seg, intersections ) )
1873 seg.
B = intersections.front().p;
1875 VECTOR2I offset = ( seg.
B - seg.
A ).Perpendicular().
Resize( spoke_half_w );
1878 spoke.
Append( seg.
A + offset );
1879 spoke.
Append( seg.
A - offset );
1880 spoke.
Append( seg.
B - offset );
1882 spoke.
Append( seg.
B + offset );
1885 aSpokesList.push_back( std::move( spoke ) );
1892 else if( (
pad->GetOrientation() +
pad->GetThermalSpokeAngle() ).IsCardinal() )
1894 BOX2I spokesBox =
pad->GetBoundingBox();
1900 buildSpokesFromOrigin( spokesBox );
1902 auto spokeIter = aSpokesList.rbegin();
1904 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
1905 spokeIter->Move(
pad->ShapePos() );
1909 else if(
pad->GetSizeX() ==
pad->GetSizeY() &&
pad->GetShape() != PAD_SHAPE::CUSTOM )
1924 buildSpokesFromOrigin( spokesBox );
1926 auto spokeIter = aSpokesList.rbegin();
1928 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
1930 spokeIter->Rotate(
pad->GetOrientation() +
pad->GetThermalSpokeAngle() );
1931 spokeIter->Move(
pad->ShapePos() );
1953 buildSpokesFromOrigin( spokesBox );
1955 BOX2I realBBox =
pad->GetBoundingBox();
1958 auto spokeIter = aSpokesList.rbegin();
1960 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
1962 spokeIter->Rotate(
pad->GetOrientation() +
pad->GetThermalSpokeAngle() );
1963 spokeIter->
Move(
pad->ShapePos() );
1965 VECTOR2I origin_p = spokeIter->GetPoint( 0 );
1966 VECTOR2I origin_m = spokeIter->GetPoint( 1 );
1967 VECTOR2I origin = ( origin_p + origin_m ) / 2;
1968 VECTOR2I end_m = spokeIter->GetPoint( 2 );
1969 VECTOR2I end = spokeIter->GetPoint( 3 );
1970 VECTOR2I end_p = spokeIter->GetPoint( 4 );
1972 ClipLine( &realBBox, origin_p.
x, origin_p.
y, end_p.
x, end_p.
y );
1973 ClipLine( &realBBox, origin_m.
x, origin_m.
y, end_m.
x, end_m.
y );
1974 ClipLine( &realBBox, origin.
x, origin.
y, end.
x, end.
y );
1976 spokeIter->SetPoint( 2, end_m );
1977 spokeIter->SetPoint( 3, end );
1978 spokeIter->SetPoint( 4, end_p );
1983 for(
size_t ii = 0; ii < aSpokesList.size(); ++ii )
1984 aSpokesList[ii].GenerateBBoxCache();
2020 hole_base.
Append( corner );
2021 corner.
x += hole_size;
2022 hole_base.
Append( corner );
2023 corner.
y += hole_size;
2024 hole_base.
Append( corner );
2026 hole_base.
Append( corner );
2046 #define SMOOTH_MIN_VAL_MM 0.02
2047 #define SMOOTH_SMALL_VAL_MM 0.04
2063 smooth_value = std::min( smooth_value, aZone->
GetHatchGap() / 2 );
2066 maxError = std::max( maxError * 2, smooth_value / 20 );
2068 switch( smooth_level )
2080 hole_base = smooth_hole.
Fillet( smooth_value, maxError ).
Outline( 0 );
2092 for(
int xx = 0; ; xx++ )
2094 int xpos = xx * gridsize;
2099 for(
int yy = 0; ; yy++ )
2101 int ypos = yy * gridsize;
2147 int min_apron_radius = ( aZone->
GetHatchGap() * 10 ) / 19;
2156 &&
via->IsOnLayer( aLayer )
2157 &&
via->GetBoundingBox().Intersects( zone_boundingbox ) )
2159 int r = std::max( min_apron_radius,
2160 via->GetDrillValue() / 2 + outline_margin );
2170 for(
PAD*
pad : footprint->Pads() )
2173 &&
pad->IsOnLayer( aLayer )
2174 &&
pad->GetBoundingBox().Intersects( zone_boundingbox ) )
2181 int pad_width = std::min(
pad->GetSize().x,
pad->GetSize().y );
2182 int slot_width = std::min(
pad->GetDrillSize().x,
pad->GetDrillSize().y );
2183 int min_annular_ring_width = ( pad_width - slot_width ) / 2;
2184 int clearance = std::max( min_apron_radius - pad_width / 2,
2185 outline_margin - min_annular_ring_width );
2187 clearance = std::max( 0, clearance - linethickness / 2 );
2188 pad->TransformShapeToPolygon( aprons, aLayer, clearance, maxError,
2204 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...
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.
Information pertinent to a Pcbnew printed circuit board.
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr, bool aAllowUseArcsInPolygons=false)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
int GetMaxClearanceValue() const
Returns the maximum clearance value for any object on the board.
FOOTPRINTS & Footprints()
int GetCopperLayerCount() const
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
const Vec & GetPosition() const
void Offset(coord_type dx, coord_type dy)
bool Intersects(const BOX2< Vec > &aRect) const
coord_type GetHeight() const
coord_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 TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
bool TransformHoleToPolygon(SHAPE_POLY_SET &aBuffer, int aClearance, int aError, ERROR_LOC aErrorLoc) const
Build the corner list of the polygonal drill shape in the board coordinate system.
void SetOffset(const VECTOR2I &aOffset)
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.
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth=false) const override
Convert the shape to a closed polygon.
bool IsVisible() const override
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.
CORNER_STRATEGY
define how inflate transform build inflated polygon
@ CHAMFER_ALL_CORNERS
All angles are chamfered.
@ ROUND_ALL_CORNERS
All angles are rounded.
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)
bool Fill(std::vector< ZONE * > &aZones, bool aCheck=false, wxWindow *aParent=nullptr)
Fills the given list of zones.
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...
Handle a list of polygons defining a copper zone.
void SetNeedRefill(bool aNeedRefill)
int GetHatchBorderAlgorithm() const
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)
int GetLocalClearance(wxString *aSource) const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
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.
@ 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
Extra fill clearance for zone fills.
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)
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ 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)
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.