61 RESULTS(
int aOutline1,
int aOutline2,
int aVertex1,
int aVertex2 ) :
108 SEG::ecoord min_dist = std::numeric_limits<SEG::ecoord>::max();
111 auto check_pt = [&](
VERTEX* p )
113 VECTOR2D diff( p->x - aPt->
x, p->y - aPt->
y );
116 if( dist2 > 0 && dist2 < limit2 && dist2 < min_dist && p->isEar(
true ) )
125 while( p && p->
z <= maxZ )
133 while( p && p->
z >= minZ )
148 std::set<VERTEX*> visited;
161 if( ( visited.empty() || !visited.contains( p ) ) && ( q =
getPoint( p ) ) )
165 if( !visited.contains( q ) &&
167 p->
i, q->
i ).second )
171 visited.insert( p->
prev );
173 visited.insert( p->
next );
176 visited.insert( q->
prev );
178 visited.insert( q->
next );
222 wxASSERT_MSG(
m_commit, wxT(
"ZONE_FILLER must have a valid commit to call SetProgressReporter" ) );
238 std::lock_guard<KISPINLOCK> lock(
m_board->GetConnectivity()->GetLock() );
240 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
241 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
HASH_128> oldFillHashes;
242 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> isolatedIslandsMap;
244 std::shared_ptr<CONNECTIVITY_DATA> connectivity =
m_board->GetConnectivity();
251 connectivity->ClearRatsnest();
259 :
_(
"Building zone fills..." ) );
272 zone->CacheBoundingBox();
276 for(
PAD*
pad : footprint->Pads() )
280 pad->BuildEffectiveShapes();
285 for(
ZONE* zone : footprint->Zones() )
286 zone->CacheBoundingBox();
289 footprint->BuildCourtyardCaches();
290 footprint->BuildNetTieCache();
295 auto findHighestPriorityZone =
297 const std::function<bool(
const ZONE* )>& testFn ) ->
ZONE*
299 unsigned highestPriority = 0;
300 ZONE* highestPriorityZone =
nullptr;
305 if( zone->GetIsRuleArea() )
308 if( zone->GetAssignedPriority() < highestPriority )
311 if( !zone->IsOnLayer( itemLayer ) )
315 if( zone->GetNumCorners() <= 2 )
318 if( !zone->GetBoundingBox().Intersects( bbox ) )
321 if( !testFn( zone ) )
325 if( zone->GetAssignedPriority() > highestPriority
326 || zone->GetNetCode() == netcode )
328 highestPriority = zone->GetAssignedPriority();
329 highestPriorityZone = zone;
333 return highestPriorityZone;
336 auto isInPourKeepoutArea =
341 if( !zone->GetIsRuleArea() )
344 if( !zone->HasKeepoutParametersSet() )
347 if( !zone->GetDoNotAllowZoneFills() )
350 if( !zone->IsOnLayer( itemLayer ) )
354 if( zone->GetNumCorners() <= 2 )
357 if( !zone->GetBoundingBox().Intersects( bbox ) )
360 if( zone->Outline()->Contains( testPoint ) )
377 via->ClearZoneLayerOverrides();
379 if( !
via->GetRemoveUnconnected() )
384 int holeRadius =
via->GetDrillValue() / 2 + 1;
385 int netcode =
via->GetNetCode();
386 LSET layers =
via->GetLayerSet() & boardCuMask;
390 [&](
const ZONE* aZone ) ->
bool
392 return aZone->Outline()->Contains(
center, -1, holeRadius );
397 if( !
via->ConditionallyFlashed( layer ) )
400 if( isInPourKeepoutArea( bbox, layer,
center ) )
406 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, viaTestFn );
411 || layer == padstack.
Drill().
end ) )
427 for(
PAD*
pad : footprint->Pads() )
429 pad->ClearZoneLayerOverrides();
431 if( !
pad->GetRemoveUnconnected() )
436 int netcode =
pad->GetNetCode();
437 LSET layers =
pad->GetLayerSet() & boardCuMask;
440 [&](
const ZONE* aZone ) ->
bool
442 return aZone->Outline()->Contains(
center );
447 if( !
pad->ConditionallyFlashed( layer ) )
450 if( isInPourKeepoutArea( bbox, layer,
center ) )
456 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, padTestFn );
467 for(
ZONE* zone : aZones )
470 if( zone->GetIsRuleArea() )
474 if( zone->GetNumCorners() <= 2 )
484 zone->BuildHashValue( layer );
485 oldFillHashes[ { zone, layer } ] = zone->GetHashValue( layer );
488 toFill.emplace_back( std::make_pair( zone, layer ) );
497 auto check_fill_dependency =
505 if( aOtherZone->GetFillFlag( aLayer ) )
510 if( aOtherZone->GetIsRuleArea() )
514 if( aOtherZone->GetNumCorners() <= 2 )
518 if( !aOtherZone->GetLayerSet().test( aLayer ) )
525 if( aOtherZone->SameNet( aZone ) )
533 if( !inflatedBBox.
Intersects( aOtherZone->GetBoundingBox() ) )
540 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
543 ZONE* zone = aFillItem.first;
548 for(
ZONE* otherZone : aZones )
550 if( otherZone == zone )
553 if( check_fill_dependency( zone, layer, otherZone ) )
568 std::unique_lock<std::mutex> zoneLock( zone->
GetLock(), std::try_to_lock );
570 if( !zoneLock.owns_lock() )
587 auto tesselate_lambda =
588 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
594 ZONE* zone = aFillItem.first;
597 std::unique_lock<std::mutex> zoneLock( zone->
GetLock(), std::try_to_lock );
599 if( !zoneLock.owns_lock() )
611 std::vector<std::pair<std::future<int>,
int>> returns;
612 returns.reserve( toFill.size() );
614 bool cancelled =
false;
618 for(
const std::pair<ZONE*, PCB_LAYER_ID>& fillItem : toFill )
620 returns.emplace_back( std::make_pair(
tp.submit_task(
623 return fill_lambda( fillItem );
627 while( !cancelled && finished != 2 * toFill.size() )
629 for(
size_t ii = 0; ii < returns.size(); ++ii )
631 auto& ret = returns[ii];
636 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
638 if( status == std::future_status::ready )
640 if( ret.first.get() )
649 if( ret.second == 0 )
651 returns[ii].first =
tp.submit_task(
654 return fill_lambda( toFill[idx] );
657 else if( ret.second == 1 )
659 returns[ii].first =
tp.submit_task(
662 return tesselate_lambda( toFill[idx] );
669 std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
683 for(
auto& ret : returns )
685 if( ret.first.valid() )
687 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
689 while( status != std::future_status::ready )
694 status = ret.first.wait_for( std::chrono::milliseconds( 100 ) );
713 connectivity->FillIsolatedIslandsMap( isolatedIslandsMap );
714 connectivity->SetProgressReporter(
nullptr );
719 for(
ZONE* zone : aZones )
722 if( zone->GetIsRuleArea() )
725 zone->SetIsFilled(
true );
731 for(
const auto& [ zone, zoneIslands ] : isolatedIslandsMap )
734 bool allIslands =
true;
736 for(
const auto& [ layer, layerIslands ] : zoneIslands )
738 if( layerIslands.m_IsolatedOutlines.size()
739 !=
static_cast<size_t>( zone->GetFilledPolysList( layer )->OutlineCount() ) )
749 for(
const auto& [ layer, layerIslands ] : zoneIslands )
754 if( layerIslands.m_IsolatedOutlines.empty() )
757 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
761 std::sort( islands.begin(), islands.end(), std::greater<int>() );
763 std::shared_ptr<SHAPE_POLY_SET> poly = zone->GetFilledPolysList( layer );
764 long long int minArea = zone->GetMinIslandArea();
767 for(
int idx : islands )
772 poly->DeletePolygonAndTriangulationData( idx,
false );
774 poly->DeletePolygonAndTriangulationData( idx,
false );
776 zone->SetIsIsland( layer, idx );
779 poly->UpdateTriangulationDataHash();
780 zone->CalculateFilledArea();
789 using island_check_return = std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
int>>;
791 std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
double>> polys_to_check;
794 polys_to_check.reserve(
m_board->GetCopperLayerCount() * aZones.size() );
796 for(
ZONE* zone : aZones )
806 double minArea = (double) zone->GetMinThickness() * zone->GetMinThickness() * 3;
813 polys_to_check.emplace_back( zone->GetFilledPolysList( layer ), minArea );
818 [&](
int aStart,
int aEnd ) -> island_check_return
820 island_check_return retval;
822 for(
int ii = aStart; ii < aEnd && !cancelled; ++ii )
824 auto [poly, minArea] = polys_to_check[ii];
826 for(
int jj = poly->OutlineCount() - 1; jj >= 0; jj-- )
831 double island_area = test_poly.
Area();
833 if( island_area < minArea )
845 if( intersection.
Area() < island_area / 2.0 )
846 retval.emplace_back( poly, jj );
853 auto island_returns =
tp.submit_blocks( 0, polys_to_check.size(), island_lambda );
857 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
859 std::future<island_check_return>& ret = island_returns[ii];
863 std::future_status status = ret.wait_for( std::chrono::seconds( 0 ) );
865 while( status != std::future_status::ready )
875 status = ret.wait_for( std::chrono::milliseconds( 100 ) );
883 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
885 std::future<island_check_return>& ret = island_returns[ii];
889 for(
auto& action_item : ret.get() )
890 action_item.first->DeletePolygonAndTriangulationData( action_item.second,
true );
894 for(
ZONE* zone : aZones )
895 zone->CalculateFilledArea();
900 bool outOfDate =
false;
902 for(
ZONE* zone : aZones )
905 if( zone->GetIsRuleArea() )
910 zone->BuildHashValue( layer );
912 if( oldFillHashes[ { zone, layer } ] != zone->GetHashValue( layer ) )
918 &&
m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill ) )
920 KIDIALOG dlg( aParent,
_(
"Prototype zone fill enabled. Disable setting and refill?" ),
_(
"Confirmation" ),
921 wxOK | wxCANCEL | wxICON_WARNING );
927 m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill =
false;
929 else if( !outOfDate )
937 KIDIALOG dlg( aParent,
_(
"Zone fills are out-of-date. Refill?" ),
_(
"Confirmation" ),
938 wxOK | wxCANCEL | wxICON_WARNING );
981 std::vector<VECTOR2I> convex_hull;
986 for(
const VECTOR2I& pt : convex_hull )
1019 minorAxis = std::min( padSize.
x, padSize.
y );
1025 minorAxis =
via->GetWidth( aLayer );
1039 switch( aItem->
Type() )
1046 if(
text->IsVisible() )
1048 if(
text->IsKnockout() )
1104 std::vector<BOARD_ITEM*>& aThermalConnectionPads,
1105 std::vector<PAD*>& aNoConnectionPads )
1111 std::shared_ptr<SHAPE> padShape;
1117 for(
PAD*
pad : footprint->Pads() )
1119 if( !
pad->IsOnLayer( aLayer ) )
1122 BOX2I padBBox =
pad->GetBoundingBox();
1128 bool noConnection =
pad->GetNetCode() != aZone->
GetNetCode();
1135 noConnection =
true;
1140 if(
pad->IsBackdrilledOrPostMachined( aLayer ) )
1141 noConnection =
true;
1146 aNoConnectionPads.push_back(
pad );
1156 aThermalConnectionPads.push_back(
pad );
1174 switch( connection )
1179 if( aFill.
Collide( padShape.get(), 0 ) )
1184 aThermalConnectionPads.push_back(
pad );
1198 if(
pad->FlashLayer( aLayer ) )
1202 else if(
pad->GetDrillSize().x > 0 )
1209 holeClearance = padClearance;
1234 if( !
via->IsOnLayer( aLayer ) )
1237 BOX2I viaBBox =
via->GetBoundingBox();
1243 bool noConnection =
via->GetNetCode() != aZone->
GetNetCode()
1245 && aLayer !=
via->Padstack().Drill().start
1246 && aLayer !=
via->Padstack().Drill().end );
1249 if(
via->IsBackdrilledOrPostMachined( aLayer ) )
1251 noConnection =
true;
1263 pmSize = std::max( pmSize, frontPM.
size );
1269 pmSize = std::max( pmSize, backPM.
size );
1275 bdSize = secDrill.
size.
x;
1277 int knockoutSize = std::max( pmSize, bdSize );
1279 if( knockoutSize > 0 )
1291 aThermalConnectionPads.push_back(
via );
1306 const std::vector<PAD*>& aNoConnectionPads,
1312 auto checkForCancel =
1315 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
1328 auto evalRulesForItems =
1342 auto knockoutPadClearance =
1347 bool hasHole = aPad->GetDrillSize().x > 0;
1348 bool flashLayer = aPad->FlashLayer( aLayer );
1351 if( flashLayer || platedHole )
1356 if( flashLayer && gap >= 0 )
1357 addKnockout( aPad, aLayer, gap + extra_margin, aHoles );
1374 if( aPad->IsBackdrilledOrPostMachined( aLayer ) )
1385 pmSize = std::max( pmSize, frontPM.
size );
1391 pmSize = std::max( pmSize, backPM.
size );
1397 bdSize = secDrill.
size.
x;
1399 int knockoutSize = std::max( pmSize, bdSize );
1401 if( knockoutSize > 0 )
1403 int clearance = std::max( gap, 0 ) + extra_margin;
1411 for(
PAD*
pad : aNoConnectionPads )
1416 knockoutPadClearance(
pad );
1421 auto knockoutTrackClearance =
1424 if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
1426 bool sameNet = aTrack->GetNetCode() == aZone->
GetNetCode();
1448 if(
via->FlashLayer( aLayer ) && gap > 0 )
1450 via->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
m_maxError,
1469 if(
via->IsBackdrilledOrPostMachined( aLayer ) )
1480 pmSize = std::max( pmSize, frontPM.
size );
1486 pmSize = std::max( pmSize, backPM.
size );
1492 bdSize = secDrill.
size.
x;
1494 int knockoutSize = std::max( pmSize, bdSize );
1496 if( knockoutSize > 0 )
1498 int clearance = std::max( gap, 0 ) + extra_margin;
1509 aTrack->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
m_maxError,
1518 if( !track->IsOnLayer( aLayer ) )
1524 knockoutTrackClearance( track );
1529 auto knockoutGraphicClearance =
1535 shapeNet =
static_cast<PCB_SHAPE*
>( aItem )->GetNetCode();
1537 bool sameNet = shapeNet == aZone->
GetNetCode();
1543 if( aItem->IsOnLayer( aLayer )
1545 || aItem->IsOnLayer(
Margin ) )
1547 if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
1549 bool ignoreLineWidths =
false;
1552 if( aItem->IsOnLayer( aLayer ) && !sameNet )
1556 else if( aItem->IsOnLayer(
Edge_Cuts ) )
1559 ignoreLineWidths =
true;
1561 else if( aItem->IsOnLayer(
Margin ) )
1568 gap += extra_margin;
1569 addKnockout( aItem, aLayer, gap, ignoreLineWidths, aHoles );
1575 auto knockoutCourtyardClearance =
1578 if( aFootprint->GetBoundingBox().Intersects( zone_boundingbox ) )
1584 aHoles.
Append( aFootprint->GetCourtyard( aLayer ) );
1597 knockoutCourtyardClearance( footprint );
1598 knockoutGraphicClearance( &footprint->Reference() );
1599 knockoutGraphicClearance( &footprint->Value() );
1601 std::set<PAD*> allowedNetTiePads;
1605 if( footprint->IsNetTie() )
1607 for(
PAD*
pad : footprint->Pads() )
1616 if(
pad->IsOnLayer( aLayer ) )
1617 allowedNetTiePads.insert(
pad );
1619 for(
PAD* other : footprint->GetNetTiePads(
pad ) )
1621 if( other->IsOnLayer( aLayer ) )
1622 allowedNetTiePads.insert( other );
1628 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
1633 BOX2I itemBBox = item->GetBoundingBox();
1635 if( !zone_boundingbox.
Intersects( itemBBox ) )
1638 bool skipItem =
false;
1640 if( item->IsOnLayer( aLayer ) )
1642 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape();
1644 for(
PAD*
pad : allowedNetTiePads )
1646 if(
pad->GetBoundingBox().Intersects( itemBBox )
1647 &&
pad->GetEffectiveShape( aLayer )->Collide( itemShape.get() ) )
1656 knockoutGraphicClearance( item );
1665 knockoutGraphicClearance( item );
1670 auto knockoutZoneClearance =
1671 [&](
ZONE* aKnockout )
1674 if( !aKnockout->GetLayerSet().test( aLayer ) )
1677 if( aKnockout->GetBoundingBox().Intersects( zone_boundingbox ) )
1679 if( aKnockout->GetIsRuleArea() )
1692 aKnockout->TransformShapeToPolygon( poly, aLayer, gap + extra_margin,
m_maxError,
1705 if( !otherZone->GetBoundingBox().Intersects( zone_boundingbox ) )
1712 if( otherZone->GetIsRuleArea() )
1714 if( otherZone->GetDoNotAllowZoneFills() && !aZone->
IsTeardropArea() )
1715 knockoutZoneClearance( otherZone );
1717 else if( otherZone->HigherPriority( aZone ) )
1719 if( !otherZone->SameNet( aZone ) )
1720 knockoutZoneClearance( otherZone );
1726 for(
ZONE* otherZone : footprint->Zones() )
1732 if( !otherZone->GetBoundingBox().Intersects( zone_boundingbox ) )
1735 if( otherZone->GetIsRuleArea() )
1737 if( otherZone->GetDoNotAllowZoneFills() && !aZone->
IsTeardropArea() )
1738 knockoutZoneClearance( otherZone );
1740 else if( otherZone->HigherPriority( aZone ) )
1742 if( !otherZone->SameNet( aZone ) )
1743 knockoutZoneClearance( otherZone );
1761 auto knockoutZoneOutline =
1762 [&](
ZONE* aKnockout )
1765 if( !aKnockout->GetLayerSet().test( aLayer ) )
1768 if( aKnockout->GetBoundingBox().Intersects( zoneBBox ) )
1784 if( otherZone->SameNet( aZone )
1788 if( !otherZone->IsTeardropArea() )
1789 knockoutZoneOutline( otherZone );
1795 for(
ZONE* otherZone : footprint->Zones() )
1797 if( otherZone->SameNet( aZone ) && otherZone->HigherPriority( aZone ) )
1800 if( !otherZone->IsTeardropArea() )
1801 knockoutZoneOutline( otherZone );
1819 std::map<int, std::vector<std::pair<int, VECTOR2I>>> insertion_points;
1831 insertion_points[
result.m_outline1].push_back( {
result.m_vertex1, pt1 } );
1832 insertion_points[
result.m_outline1].push_back( {
result.m_vertex1, pt2 } );
1835 for(
auto& [outline, vertices] : insertion_points )
1839 if( vertices.empty() )
1844 std::stable_sort( vertices.begin(), vertices.end(),
1845 [](
const std::pair<int, VECTOR2I>& a,
const std::pair<int, VECTOR2I>& b )
1847 return a.first < b.first;
1850 std::vector<VECTOR2I> new_points;
1851 new_points.reserve( line.
PointCount() + vertices.size() );
1853 size_t vertex_idx = 0;
1857 new_points.push_back( line.
CPoint( i ) );
1860 while( vertex_idx < vertices.size() && vertices[vertex_idx].first == i )
1862 new_points.push_back( vertices[vertex_idx].second );
1869 for(
const auto& pt : new_points )
1875#define DUMP_POLYS_TO_COPPER_LAYER( a, b, c ) \
1876 { if( m_debugZoneFiller && aDebugLayer == b ) \
1878 m_board->SetLayerName( b, c ); \
1879 SHAPE_POLY_SET d = a; \
1918 std::vector<BOARD_ITEM*> thermalConnectionPads;
1919 std::vector<PAD*> noConnectionPads;
1920 std::deque<SHAPE_LINE_CHAIN> thermalSpokes;
1923 aFillPolys = aSmoothedOutline;
1960 static const bool USE_BBOX_CACHES =
true;
1987 const VECTOR2I& testPt = spoke.CPoint( 3 );
1990 if( testAreas.
Contains( testPt, -1, 1, USE_BBOX_CACHES ) )
1999 if( interval++ > 400 )
2012 if( &other != &spoke
2013 && other.PointInside( testPt, 1, USE_BBOX_CACHES )
2014 && spoke.PointInside( other.CPoint( 3 ), 1, USE_BBOX_CACHES ) )
2044 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
2046 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
2047 BOX2I islandExtents;
2049 for(
const VECTOR2I& pt : island.front().CPoints() )
2051 islandExtents.
Merge( pt );
2072 || !
m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill ) )
2107 for(
BOARD_ITEM* item : thermalConnectionPads )
2138 auto checkForCancel =
2141 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
2144 auto knockoutGraphicItem =
2147 if( aItem->IsKnockout() && aItem->IsOnLayer( aLayer )
2148 && aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
2150 addKnockout( aItem, aLayer, 0,
true, clearanceHoles );
2159 knockoutGraphicItem( &footprint->Reference() );
2160 knockoutGraphicItem( &footprint->Value() );
2162 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
2163 knockoutGraphicItem( item );
2171 knockoutGraphicItem( item );
2174 aFillPolys = aSmoothedOutline;
2177 auto subtractKeepout =
2178 [&](
ZONE* candidate )
2180 if( !candidate->GetIsRuleArea() )
2183 if( !candidate->HasKeepoutParametersSet() )
2186 if( candidate->GetDoNotAllowZoneFills() && candidate->IsOnLayer( aLayer ) )
2188 if( candidate->GetBoundingBox().Intersects( zone_boundingbox ) )
2190 if( candidate->Outline()->ArcCount() == 0 )
2209 subtractKeepout( keepout );
2217 for(
ZONE* keepout : footprint->Zones() )
2218 subtractKeepout( keepout );
2259 debugLayer = aLayer;
2263 if( !aZone->
BuildSmoothedPoly( maxExtents, aLayer, boardOutline, &smoothedPoly ) )
2271 if(
fillCopperZone( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aFillPolys ) )
2288 const std::vector<BOARD_ITEM*>& aSpokedPadsList,
2289 std::deque<SHAPE_LINE_CHAIN>& aSpokesList )
2308 if( !item->IsOnLayer( aLayer ) )
2311 int thermalReliefGap = 0;
2315 bool circular =
false;
2319 pad =
static_cast<PAD*
>( item );
2343 if( thermalReliefGap < 0 )
2357 int spoke_max_allowed_w = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
2359 spoke_w = std::clamp( spoke_w, constraint.
Value().
Min(), constraint.
Value().
Max() );
2362 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
2365 if( spoke_w < aZone->GetMinThickness() )
2374 int spoke_half_w = spoke_w / 2;
2377 BOX2I itemBB = item->GetBoundingBox();
2383 bool customSpokes =
false;
2387 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
2389 if( primitive->IsProxyItem() && primitive->GetShape() ==
SHAPE_T::SEGMENT )
2391 customSpokes =
true;
2402 auto buildSpokesFromOrigin =
2409 auto intersectBBox =
2412 double dx = spokeAngle.
Cos();
2413 double dy = spokeAngle.
Sin();
2419 *spoke_side =
VECTOR2I( spoke_half_w, 0 );
2420 return KiROUND( 0.0, dy * half_size.
y );
2424 *spoke_side =
VECTOR2I( 0, spoke_half_w );
2425 return KiROUND( dx * half_size.
x, 0.0 );
2430 double dist_x = half_size.
x /
std::abs( dx );
2431 double dist_y = half_size.
y /
std::abs( dy );
2433 if( dist_x < dist_y )
2435 *spoke_side =
KiROUND( 0.0, spoke_half_w / (
ANGLE_90 - spokeAngle ).Sin() );
2436 return KiROUND( dx * dist_x, dy * dist_x );
2440 *spoke_side =
KiROUND( spoke_half_w / spokeAngle.
Sin(), 0.0 );
2441 return KiROUND( dx * dist_y, dy * dist_y );
2454 for(
const EDA_ANGLE& spokeAngle : angles )
2457 VECTOR2I intersection = intersectBBox( spokeAngle, &spoke_side );
2466 aSpokesList.push_back( std::move( spoke ) );
2478 thermalOutline = thermalPoly.
Outline( 0 );
2482 auto trimToOutline = [&](
SEG& aSegment )
2486 if( padOutline.
Intersect( aSegment, intersections ) )
2488 intersections.clear();
2491 if( thermalOutline.
Intersect( aSegment, intersections ) )
2493 aSegment.B = intersections.front().p;
2500 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
2502 if( primitive->IsProxyItem() && primitive->GetShape() ==
SHAPE_T::SEGMENT )
2504 SEG seg( primitive->GetStart(), primitive->GetEnd() );
2509 seg.
A +=
pad->ShapePos( aLayer );
2510 seg.
B +=
pad->ShapePos( aLayer );
2524 if( trimToOutline( seg ) )
2526 VECTOR2I direction = ( seg.
B - seg.
A ).Resize( spoke_half_w );
2530 SEG segL( seg.
A - direction - offset, seg.
B + direction - offset );
2531 SEG segR( seg.
A - direction + offset, seg.
B + direction + offset );
2534 if( trimToOutline( segL ) && trimToOutline( segR ) )
2542 spoke.
Append( seg.
A + offset );
2543 spoke.
Append( seg.
A - offset );
2545 spoke.
Append( segL.
B + direction );
2546 spoke.
Append( seg.
B + direction );
2547 spoke.
Append( segR.
B + direction );
2550 aSpokesList.push_back( std::move( spoke ) );
2563 thermalSpokeAngle =
pad->GetThermalSpokeAngle();
2582 position =
pad->ShapePos( aLayer );
2583 orientation =
pad->GetOrientation();
2591 position =
via->GetPosition();
2596 spokesBox.
Inflate( thermalReliefGap +
epsilon + zone_half_width );
2603 buildSpokesFromOrigin( spokesBox,
ANGLE_0 );
2605 if( thermalSpokeAngle !=
ANGLE_0 )
2608 for(
auto it = aSpokesList.rbegin(); it != aSpokesList.rbegin() + 4; ++it )
2609 it->Rotate( thermalSpokeAngle );
2614 buildSpokesFromOrigin( spokesBox, thermalSpokeAngle );
2617 auto spokeIter = aSpokesList.rbegin();
2619 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
2621 spokeIter->Rotate( orientation );
2622 spokeIter->Move( position );
2627 for(
size_t ii = 0; ii < aSpokesList.size(); ++ii )
2628 aSpokesList[ii].GenerateBBoxCache();
2647 int maxError =
m_board->GetDesignSettings().m_MaxError;
2663 hole_base.
Append( corner );
2664 corner.
x += hole_size;
2665 hole_base.
Append( corner );
2666 corner.
y += hole_size;
2667 hole_base.
Append( corner );
2669 hole_base.
Append( corner );
2689 #define SMOOTH_MIN_VAL_MM 0.02
2690 #define SMOOTH_SMALL_VAL_MM 0.04
2706 smooth_value = std::min( smooth_value, aZone->
GetHatchGap() / 2 );
2709 maxError = std::max( maxError * 2, smooth_value / 20 );
2711 switch( smooth_level )
2723 hole_base = smooth_hole.
Fillet( smooth_value, maxError ).
Outline( 0 );
2735 auto& defaultOffsets =
m_board->GetDesignSettings().m_ZoneLayerProperties;
2738 VECTOR2I offset = defaultOffsets[aLayer].hatching_offset.value_or(
VECTOR2I() );
2740 if( localOffsets.contains( aLayer ) && localOffsets.at( aLayer ).hatching_offset.has_value() )
2741 offset = localOffsets.at( aLayer ).hatching_offset.value();
2743 int x_offset = bbox.
GetX() - ( bbox.
GetX() ) % gridsize - gridsize;
2744 int y_offset = bbox.
GetY() - ( bbox.
GetY() ) % gridsize - gridsize;
2747 for(
int xx = x_offset; xx <= bbox.
GetRight(); xx += gridsize )
2749 for(
int yy = y_offset; yy <= bbox.
GetBottom(); yy += gridsize )
2760 hole.
Move(
VECTOR2I( offset.
x % gridsize, offset.
y % gridsize ) );
2773 deflated_thickness = std::max( deflated_thickness, maxError * 2 );
2795 if( area < minimal_hole_area )
constexpr EDA_IU_SCALE pcbIUScale
@ ZLO_FORCE_NO_ZONE_CONNECTION
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
Container for design settings for a BOARD object.
std::shared_ptr< DRC_ENGINE > m_DRCEngine
int GetBiggestClearanceValue() const
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const
Convert the item shape to a closed polygon.
virtual void SetIsKnockout(bool aKnockout)
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Information pertinent to a Pcbnew printed circuit board.
int GetCopperLayerCount() const
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
constexpr int GetSizeMax() const
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
constexpr coord_type GetY() const
constexpr size_type GetWidth() const
constexpr coord_type GetX() const
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
constexpr const Vec GetCenter() const
constexpr size_type GetHeight() const
constexpr coord_type GetRight() const
constexpr bool Intersects(const BOX2< Vec > &aRect) const
constexpr coord_type GetBottom() const
Represent a set of changes (additions, deletions or modifications) of a data model (e....
MINOPTMAX< int > & Value()
const MINOPTMAX< int > & GetValue() const
ZONE_CONNECTION m_ZoneConnection
DRC_CONSTRAINT EvalRules(DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
DRC_CONSTRAINT EvalZoneConnection(const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
KICAD_T Type() const
Returns the type of object.
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
bool SetOKCancelLabels(const ButtonLabel &ok, const ButtonLabel &cancel) override
LSET is a set of PCB_LAYER_IDs.
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
static const LSET & InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
UNCONNECTED_LAYER_MODE UnconnectedLayerMode() const
const BOX2I GetBoundingBox() const override
The bounding box is cached, so this will be efficient most of the time.
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
void SetOffset(PCB_LAYER_ID aLayer, const VECTOR2I &aOffset)
void SetPosition(const VECTOR2I &aPos) override
void SetOrientation(const EDA_ANGLE &aAngle)
Set the rotation angle of the pad.
bool TransformHoleToPolygon(SHAPE_POLY_SET &aBuffer, int aClearance, int aError, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Build the corner list of the polygonal drill shape in the board coordinate system.
void GetBoundingHull(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth=false) const override
Convert the item shape to a closed polygon.
void TransformTextToPolySet(SHAPE_POLY_SET &aBuffer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc) const
Function TransformTextToPolySet Convert the text to a polygonSet describing the actual character stro...
void SetPosition(const VECTOR2I &aPoint) override
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
A progress reporter interface for use in multi-threaded environments.
RESULTS(int aOutline1, int aOutline2, int aVertex1, int aVertex2)
bool operator<(const RESULTS &aOther) const
VECTOR2I::extended_type ecoord
static SEG::ecoord Square(int a)
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void Move(const VECTOR2I &aVector) override
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int Intersect(const SEG &aSeg, INTERSECTIONS &aIp) const
Find all intersection points between our line chain and the segment aSeg.
int PointCount() const
Return the number of points (vertices) in this line chain.
void Clear()
Remove all points from the line chain.
double Area(bool aAbsolute=true) const
Return the area of this chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
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.
SHAPE_POLY_SET Chamfer(int aDistance)
Return a chamfered version of the polygon set.
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.
void Fracture()
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
POLYGON & Polygon(int aIndex)
Return the aIndex-th subpolygon in the set.
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
void Deflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError)
void BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
void BuildBBoxCaches() const
Construct BBoxCaches for Contains(), below.
int OutlineCount() const
Return the number of outlines in the set.
SHAPE_POLY_SET Fillet(int aRadius, int aErrorMax)
Return a filleted version of the polygon set.
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
SHAPE_POLY_SET CloneDropTriangulation() const
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
const BOX2I BBoxFromCaches() const
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
constexpr extended_type SquaredEuclideanNorm() const
Compute the squared euclidean norm of the vector, which is defined as (x ** 2 + y ** 2).
constexpr VECTOR2< T > Perpendicular() const
Compute the perpendicular vector.
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
VERTEX * getPoint(VERTEX *aPt) const
std::set< RESULTS > GetResults() const
VERTEX_CONNECTOR(const BOX2I &aBBox, const SHAPE_POLY_SET &aPolys, int aDist)
std::set< RESULTS > m_results
std::deque< VERTEX > m_vertices
VERTEX * createList(const SHAPE_LINE_CHAIN &points, VERTEX *aTail=nullptr, void *aUserData=nullptr)
Create a list of vertices from a line chain.
void SetBoundingBox(const BOX2I &aBBox)
VERTEX_SET(int aSimplificationLevel)
uint32_t zOrder(const double aX, const double aY) const
Note that while the inputs are doubles, these are scaled by the size of the bounding box to fit into ...
void updateList()
After inserting or changing nodes, this function should be called to remove duplicate vertices and en...
void * GetUserData() const
bool isEar(bool aMatchUserData=false) const
Check whether the given vertex is in the middle of an ear.
void buildCopperItemClearances(const ZONE *aZone, PCB_LAYER_ID aLayer, const std::vector< PAD * > &aNoConnectionPads, SHAPE_POLY_SET &aHoles)
Removes clearance from the shape for copper items which share the zone's layer but are not connected ...
void connect_nearby_polys(SHAPE_POLY_SET &aPolys, double aDistance)
Create strands of zero-width between elements of SHAPE_POLY_SET that are within aDistance of each oth...
void buildThermalSpokes(const ZONE *box, PCB_LAYER_ID aLayer, const std::vector< BOARD_ITEM * > &aSpokedPadsList, std::deque< SHAPE_LINE_CHAIN > &aSpokes)
Function buildThermalSpokes Constructs a list of all thermal spokes for the given zone.
ZONE_FILLER(BOARD *aBoard, COMMIT *aCommit)
void subtractHigherPriorityZones(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aRawFill)
Removes the outlines of higher-proirity zones with the same net.
void knockoutThermalReliefs(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aFill, std::vector< BOARD_ITEM * > &aThermalConnectionPads, std::vector< PAD * > &aNoConnectionPads)
Removes thermal reliefs from the shape for any pads connected to the zone.
void addKnockout(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer, int aGap, SHAPE_POLY_SET &aHoles)
Add a knockout for a pad or via.
SHAPE_POLY_SET m_boardOutline
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)
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 *candidate, 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)
std::optional< int > GetLocalClearance() const override
ZONE_LAYER_PROPERTIES & LayerProperties(PCB_LAYER_ID aLayer)
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
@ CHAMFER_ALL_CORNERS
All angles are chamfered.
@ ROUND_ALL_CORNERS
All angles are rounded.
@ EDGE_CLEARANCE_CONSTRAINT
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
@ THERMAL_SPOKE_WIDTH_CONSTRAINT
@ THERMAL_RELIEF_GAP_CONSTRAINT
@ HOLE_CLEARANCE_CONSTRAINT
@ PHYSICAL_CLEARANCE_CONSTRAINT
static constexpr EDA_ANGLE ANGLE_0
static constexpr EDA_ANGLE ANGLE_90
a few functions useful in geometry calculations.
bool m_DebugZoneFiller
A mode that dumps the various stages of a F_Cu fill into In1_Cu through In9_Cu.
@ ALWAYS_FLASHED
Always flashed for connectivity.
PCB_LAYER_ID
A quick note on layer IDs:
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
@ PTH
Plated through hole pad.
BARCODE class definition.
A storage class for 128-bit hash value.
A struct recording the isolated and single-pad islands within a zone.
! The properties of a padstack drill. Drill position is always the pad position (origin).
VECTOR2I size
Drill diameter (x == y) or slot dimensions (x != y)
std::optional< PAD_DRILL_POST_MACHINING_MODE > mode
wxString result
Test unit parsing edge cases and error handling.
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::priority_thread_pool thread_pool
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
@ PCB_PAD_T
class PAD, a pad in a footprint
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D
#define SMOOTH_MIN_VAL_MM
int getHatchFillThermalClearance(const ZONE *aZone, BOARD_ITEM *aItem, PCB_LAYER_ID aLayer)
#define DUMP_POLYS_TO_COPPER_LAYER(a, b, c)
#define SMOOTH_SMALL_VAL_MM
ISLAND_REMOVAL_MODE
Whether or not to remove isolated islands from a zone.
ZONE_CONNECTION
How pads are covered by copper in zone.
@ THERMAL
Use thermal relief for pads.
@ NONE
Pads are not covered.
@ FULL
pads are covered by copper