58 RESULTS(
int aOutline1,
int aOutline2,
int aVertex1,
int aVertex2 ) :
104 SEG::ecoord min_dist = std::numeric_limits<SEG::ecoord>::max();
107 auto check_pt = [&](
VERTEX* p )
109 VECTOR2D diff( p->x - aPt->
x, p->y - aPt->
y );
112 if( dist2 < limit2 && dist2 < min_dist
122 while( p && p->
z <= maxZ )
130 while( p && p->
z >= minZ )
142 std::set<VERTEX*> visited;
155 if( ( visited.empty() || !visited.contains( p ) ) && ( q =
getPoint( p ) ) )
159 if( !visited.contains( q ) &&
161 p->
i, q->
i ).second )
165 visited.insert( p->
prev );
167 visited.insert( p->
next );
170 visited.insert( q->
prev );
172 visited.insert( q->
next );
196 m_brdOutlinesValid( false ),
198 m_progressReporter( nullptr ),
200 m_worstClearance( 0 )
215 wxASSERT_MSG(
m_commit, wxT(
"ZONE_FILLER must have a valid commit to call "
216 "SetProgressReporter" ) );
234 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
235 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
HASH_128> oldFillHashes;
236 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> isolatedIslandsMap;
241 connectivity->ClearRatsnest();
249 :
_(
"Building zone fills..." ) );
262 zone->CacheBoundingBox();
266 for(
PAD*
pad : footprint->Pads() )
270 pad->BuildEffectiveShapes();
275 for(
ZONE* zone : footprint->Zones() )
276 zone->CacheBoundingBox();
279 footprint->BuildCourtyardCaches();
284 auto findHighestPriorityZone = [&](
const BOX2I& aBBox,
const PCB_LAYER_ID aItemLayer,
286 const std::function<bool(
const ZONE* )> aTestFn ) ->
ZONE*
288 unsigned highestPriority = 0;
289 ZONE* highestPriorityZone =
nullptr;
294 if( zone->GetIsRuleArea() )
297 if( zone->GetAssignedPriority() < highestPriority )
300 if( !zone->IsOnLayer( aItemLayer ) )
304 if( zone->GetNumCorners() <= 2 )
307 if( !zone->GetBoundingBox().Intersects( aBBox ) )
310 if( !aTestFn( zone ) )
314 if( zone->GetAssignedPriority() > highestPriority || zone->GetNetCode() == aNetcode )
317 highestPriorityZone = zone;
321 return highestPriorityZone;
324 auto isInPourKeepoutArea = [&](
const BOX2I& aBBox,
const PCB_LAYER_ID aItemLayer,
329 if( !zone->GetIsRuleArea() )
332 if( !zone->HasKeepoutParametersSet() )
335 if( !zone->GetDoNotAllowCopperPour() )
338 if( !zone->IsOnLayer( aItemLayer ) )
342 if( zone->GetNumCorners() <= 2 )
345 if( !zone->GetBoundingBox().Intersects( aBBox ) )
348 if( zone->Outline()->Contains( aTestPoint ) )
362 via->ClearZoneLayerOverrides();
364 if( !
via->GetRemoveUnconnected() )
369 int testRadius =
via->GetDrillValue() / 2 + 1;
370 unsigned netcode =
via->GetNetCode();
371 LSET layers =
via->GetLayerSet() & boardCuMask;
374 auto viaTestFn = [&](
const ZONE* aZone ) ->
bool
376 return aZone->Outline()->
Contains( center, -1, testRadius );
381 if( !
via->ConditionallyFlashed( layer ) )
384 if( isInPourKeepoutArea( bbox, layer, center ) )
390 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, viaTestFn );
404 for(
PAD*
pad : footprint->Pads() )
406 pad->ClearZoneLayerOverrides();
408 if( !
pad->GetRemoveUnconnected() )
413 unsigned netcode =
pad->GetNetCode();
414 LSET layers =
pad->GetLayerSet() & boardCuMask;
416 auto padTestFn = [&](
const ZONE* aZone ) ->
bool
418 return aZone->Outline()->
Contains( center );
423 if( !
pad->ConditionallyFlashed( layer ) )
426 if( isInPourKeepoutArea( bbox, layer, center ) )
432 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, padTestFn );
443 for(
ZONE* zone : aZones )
446 if( zone->GetIsRuleArea() )
450 if( zone->GetNumCorners() <= 2 )
460 zone->BuildHashValue( layer );
461 oldFillHashes[ { zone, layer } ] = zone->GetHashValue( layer );
464 toFill.emplace_back( std::make_pair( zone, layer ) );
473 auto check_fill_dependency =
481 if( aOtherZone->GetFillFlag( aLayer ) )
486 if( aOtherZone->GetIsRuleArea() )
490 if( aOtherZone->GetNumCorners() <= 2 )
494 if( !aOtherZone->GetLayerSet().test( aLayer ) )
501 if( aOtherZone->SameNet( aZone ) )
509 if( !inflatedBBox.
Intersects( aOtherZone->GetBoundingBox() ) )
516 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
519 ZONE* zone = aFillItem.first;
524 for(
ZONE* otherZone : aZones )
526 if( otherZone == zone )
529 if( check_fill_dependency( zone, layer, otherZone ) )
544 std::unique_lock<std::mutex> zoneLock( zone->
GetLock(), std::try_to_lock );
546 if( !zoneLock.owns_lock() )
563 auto tesselate_lambda =
564 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
570 ZONE* zone = aFillItem.first;
573 std::unique_lock<std::mutex> zoneLock( zone->
GetLock(), std::try_to_lock );
575 if( !zoneLock.owns_lock() )
587 std::vector<std::pair<std::future<int>,
int>> returns;
588 returns.reserve( toFill.size() );
590 bool cancelled =
false;
594 for(
const std::pair<ZONE*, PCB_LAYER_ID>& fillItem : toFill )
595 returns.emplace_back( std::make_pair(
tp.submit( fill_lambda, fillItem ), 0 ) );
597 while( !cancelled && finished != 2 * toFill.size() )
599 for(
size_t ii = 0; ii < returns.size(); ++ii )
601 auto& ret = returns[ii];
606 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
608 if( status == std::future_status::ready )
610 if( ret.first.get() )
619 if( ret.second == 0 )
620 returns[ii].first =
tp.submit( fill_lambda, toFill[ii] );
621 else if( ret.second == 1 )
622 returns[ii].first =
tp.submit( tesselate_lambda, toFill[ii] );
627 std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
641 for(
auto& ret : returns )
643 if( ret.first.valid() )
645 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
647 while( status != std::future_status::ready )
652 status = ret.first.wait_for( std::chrono::milliseconds( 100 ) );
671 connectivity->FillIsolatedIslandsMap( isolatedIslandsMap );
672 connectivity->SetProgressReporter(
nullptr );
677 for(
ZONE* zone : aZones )
680 if( zone->GetIsRuleArea() )
683 zone->SetIsFilled(
true );
689 for(
const auto& [ zone, zoneIslands ] : isolatedIslandsMap )
692 bool allIslands =
true;
694 for(
const auto& [ layer, layerIslands ] : zoneIslands )
696 if( layerIslands.m_IsolatedOutlines.size()
697 !=
static_cast<size_t>( zone->GetFilledPolysList( layer )->OutlineCount() ) )
707 for(
const auto& [ layer, layerIslands ] : zoneIslands )
712 if( layerIslands.m_IsolatedOutlines.empty() )
715 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
719 std::sort( islands.begin(), islands.end(), std::greater<int>() );
721 std::shared_ptr<SHAPE_POLY_SET> poly = zone->GetFilledPolysList( layer );
722 long long int minArea = zone->GetMinIslandArea();
725 for(
int idx : islands )
729 if( mode == ISLAND_REMOVAL_MODE::ALWAYS )
730 poly->DeletePolygonAndTriangulationData( idx,
false );
731 else if ( mode == ISLAND_REMOVAL_MODE::AREA && outline.
Area(
true ) < minArea )
732 poly->DeletePolygonAndTriangulationData( idx,
false );
734 zone->SetIsIsland( layer, idx );
737 poly->UpdateTriangulationDataHash();
738 zone->CalculateFilledArea();
747 using island_check_return = std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
int>>;
749 std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
double>> polys_to_check;
754 for(
ZONE* zone : aZones )
764 double minArea = (double) zone->GetMinThickness() * zone->GetMinThickness() * 3;
771 polys_to_check.emplace_back( zone->GetFilledPolysList( layer ), minArea );
776 [&](
int aStart,
int aEnd ) -> island_check_return
778 island_check_return retval;
780 for(
int ii = aStart; ii < aEnd && !cancelled; ++ii )
782 auto [poly, minArea] = polys_to_check[ii];
784 for(
int jj = poly->OutlineCount() - 1; jj >= 0; jj-- )
789 double island_area = test_poly.
Area();
791 if( island_area < minArea )
804 if( intersection.
Area() < island_area / 2.0 )
805 retval.emplace_back( poly, jj );
812 auto island_returns =
tp.parallelize_loop( 0, polys_to_check.size(), island_lambda );
816 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
818 std::future<island_check_return>& ret = island_returns[ii];
822 std::future_status status = ret.wait_for( std::chrono::seconds( 0 ) );
824 while( status != std::future_status::ready )
834 status = ret.wait_for( std::chrono::milliseconds( 100 ) );
842 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
844 std::future<island_check_return>& ret = island_returns[ii];
848 for(
auto& action_item : ret.get() )
849 action_item.first->DeletePolygonAndTriangulationData( action_item.second,
true );
853 for(
ZONE* zone : aZones )
854 zone->CalculateFilledArea();
859 bool outOfDate =
false;
861 for(
ZONE* zone : aZones )
864 if( zone->GetIsRuleArea() )
869 zone->BuildHashValue( layer );
871 if( oldFillHashes[ { zone, layer } ] != zone->GetHashValue( layer ) )
878 KIDIALOG dlg( aParent,
_(
"Zone fills are out-of-date. Refill?" ),
879 _(
"Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
913 if( aPad->
GetShape( aLayer ) == PAD_SHAPE::CUSTOM )
921 std::vector<VECTOR2I> convex_hull;
926 for(
const VECTOR2I& pt : convex_hull )
955 switch( aItem->
Type() )
962 if(
text->IsVisible() )
964 if(
text->IsKnockout() )
1014 std::vector<PAD*>& aThermalConnectionPads,
1015 std::vector<PAD*>& aNoConnectionPads )
1021 std::shared_ptr<SHAPE> padShape;
1027 for(
PAD*
pad : footprint->Pads() )
1029 BOX2I padBBox =
pad->GetBoundingBox();
1035 bool noConnection =
pad->GetNetCode() != aZone->
GetNetCode();
1042 noConnection =
true;
1049 aNoConnectionPads.push_back(
pad );
1055 connection = ZONE_CONNECTION::FULL;
1059 constraint = bds.
m_DRCEngine->EvalZoneConnection(
pad, aZone, aLayer );
1063 if( connection == ZONE_CONNECTION::THERMAL && !
pad->CanFlashLayer( aLayer ) )
1064 connection = ZONE_CONNECTION::NONE;
1066 switch( connection )
1068 case ZONE_CONNECTION::THERMAL:
1069 padShape =
pad->GetEffectiveShape( aLayer, FLASHING::ALWAYS_FLASHED );
1071 if( aFill.
Collide( padShape.get(), 0 ) )
1077 aThermalConnectionPads.push_back(
pad );
1083 case ZONE_CONNECTION::NONE:
1092 if(
pad->FlashLayer( aLayer ) )
1096 else if(
pad->GetDrillSize().x > 0 )
1099 pad, aZone, aLayer );
1104 holeClearance = padClearance;
1127 const std::vector<PAD*>& aNoConnectionPads,
1133 auto checkForCancel =
1136 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
1149 auto evalRulesForItems =
1163 auto knockoutPadClearance =
1168 bool hasHole = aPad->GetDrillSize().x > 0;
1169 bool flashLayer = aPad->FlashLayer( aLayer );
1170 bool platedHole = hasHole && aPad->GetAttribute() == PAD_ATTRIB::PTH;
1172 if( flashLayer || platedHole )
1175 aZone, aPad, aLayer ) );
1178 if( flashLayer && gap >= 0 )
1179 addKnockout( aPad, aLayer, gap + extra_margin, aHoles );
1184 if( aPad->GetAttribute() == PAD_ATTRIB::NPTH )
1188 aZone, aPad, aLayer ) );
1191 aZone, aPad, aLayer ) );
1198 for(
PAD*
pad : aNoConnectionPads )
1203 knockoutPadClearance(
pad );
1208 auto knockoutTrackClearance =
1211 if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
1213 bool sameNet = aTrack->GetNetCode() == aZone->
GetNetCode();
1219 aZone, aTrack, aLayer );
1232 aZone, aTrack, aLayer ) );
1239 if(
via->FlashLayer( aLayer ) && gap > 0 )
1241 via->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
1246 aZone,
via, aLayer ) );
1251 aZone,
via, aLayer ) );
1256 int radius =
via->GetDrillValue() / 2;
1259 radius + gap + extra_margin,
1267 aTrack->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
1276 if( !track->IsOnLayer( aLayer ) )
1282 knockoutTrackClearance( track );
1287 auto knockoutGraphicClearance =
1295 bool sameNet = shapeNet == aZone->
GetNetCode();
1301 if( aItem->IsOnLayer( aLayer )
1303 || aItem->IsOnLayer(
Margin ) )
1305 if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
1307 bool ignoreLineWidths =
false;
1309 aZone, aItem, aLayer );
1311 if( aItem->IsOnLayer( aLayer ) && !sameNet )
1314 aZone, aItem, aLayer ) );
1316 else if( aItem->IsOnLayer(
Edge_Cuts ) )
1319 aZone, aItem, aLayer ) );
1320 ignoreLineWidths =
true;
1322 else if( aItem->IsOnLayer(
Margin ) )
1325 aZone, aItem, aLayer ) );
1330 gap += extra_margin;
1331 addKnockout( aItem, aLayer, gap, ignoreLineWidths, aHoles );
1337 auto knockoutCourtyardClearance =
1340 if( aFootprint->GetBoundingBox().Intersects( zone_boundingbox ) )
1343 aFootprint, aLayer );
1347 aHoles.
Append( aFootprint->GetCourtyard( aLayer ) );
1360 knockoutCourtyardClearance( footprint );
1361 knockoutGraphicClearance( &footprint->Reference() );
1362 knockoutGraphicClearance( &footprint->Value() );
1364 std::set<PAD*> allowedNetTiePads;
1368 if( footprint->IsNetTie() )
1370 for(
PAD*
pad : footprint->Pads() )
1379 if(
pad->IsOnLayer( aLayer ) )
1380 allowedNetTiePads.insert(
pad );
1382 for(
PAD* other : footprint->GetNetTiePads(
pad ) )
1384 if( other->IsOnLayer( aLayer ) )
1385 allowedNetTiePads.insert( other );
1391 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
1396 BOX2I itemBBox = item->GetBoundingBox();
1398 if( !zone_boundingbox.
Intersects( itemBBox ) )
1401 bool skipItem =
false;
1403 if( item->IsOnLayer( aLayer ) )
1405 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape();
1407 for(
PAD*
pad : allowedNetTiePads )
1409 if(
pad->GetBoundingBox().Intersects( itemBBox )
1410 &&
pad->GetEffectiveShape( aLayer )->Collide( itemShape.get() ) )
1419 knockoutGraphicClearance( item );
1428 knockoutGraphicClearance( item );
1433 auto knockoutZoneClearance =
1434 [&](
ZONE* aKnockout )
1437 if( !aKnockout->GetLayerSet().test( aLayer ) )
1440 if( aKnockout->GetBoundingBox().Intersects( zone_boundingbox ) )
1442 if( aKnockout->GetIsRuleArea() )
1445 aKnockout->TransformSmoothedOutlineToPolygon( aHoles, 0,
m_maxError,
1451 aZone, aKnockout, aLayer ) );
1454 aZone, aKnockout, aLayer ) );
1457 aKnockout->TransformShapeToPolygon( poly, aLayer, gap + extra_margin,
1473 if( otherZone->GetIsRuleArea() )
1475 if( otherZone->GetDoNotAllowCopperPour() && !aZone->
IsTeardropArea() )
1476 knockoutZoneClearance( otherZone );
1478 else if( otherZone->HigherPriority( aZone ) )
1480 if( !otherZone->SameNet( aZone ) )
1481 knockoutZoneClearance( otherZone );
1487 for(
ZONE* otherZone : footprint->Zones() )
1492 if( otherZone->GetIsRuleArea() )
1494 if( otherZone->GetDoNotAllowCopperPour() && !aZone->
IsTeardropArea() )
1495 knockoutZoneClearance( otherZone );
1497 else if( otherZone->HigherPriority( aZone ) )
1499 if( !otherZone->SameNet( aZone ) )
1500 knockoutZoneClearance( otherZone );
1518 auto knockoutZoneOutline =
1519 [&](
ZONE* aKnockout )
1522 if( !aKnockout->GetLayerSet().test( aLayer ) )
1525 if( aKnockout->GetBoundingBox().Intersects( zoneBBox ) )
1541 if( otherZone->SameNet( aZone )
1545 if( !otherZone->IsTeardropArea() )
1546 knockoutZoneOutline( otherZone );
1552 for(
ZONE* otherZone : footprint->Zones() )
1554 if( otherZone->SameNet( aZone ) && otherZone->HigherPriority( aZone ) )
1557 if( !otherZone->IsTeardropArea() )
1558 knockoutZoneOutline( otherZone );
1576 std::map<int, std::vector<std::pair<int, VECTOR2I>>> insertion_points;
1588 insertion_points[result.m_outline1].push_back( { result.m_vertex1, pt1 } );
1589 insertion_points[result.m_outline1].push_back( { result.m_vertex1, pt2 } );
1592 for(
auto& [outline, vertices] : insertion_points )
1600 std::stable_sort( vertices.begin(), vertices.end(),
1601 [](
const std::pair<int, VECTOR2I>& a,
const std::pair<int, VECTOR2I>& b )
1602 { return a.first > b.first; } );
1604 for(
const auto& [vertex, pt] : vertices )
1605 line.
Insert( vertex + 1, pt );
1610#define DUMP_POLYS_TO_COPPER_LAYER( a, b, c ) \
1611 { if( m_debugZoneFiller && aDebugLayer == b ) \
1613 m_board->SetLayerName( b, c ); \
1614 SHAPE_POLY_SET d = a; \
1615 d.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE ); \
1655 CORNER_STRATEGY fastCornerStrategy = CORNER_STRATEGY::CHAMFER_ALL_CORNERS;
1658 std::vector<PAD*> thermalConnectionPads;
1659 std::vector<PAD*> noConnectionPads;
1660 std::deque<SHAPE_LINE_CHAIN> thermalSpokes;
1663 aFillPolys = aSmoothedOutline;
1700 static const bool USE_BBOX_CACHES =
true;
1727 const VECTOR2I& testPt = spoke.CPoint( 3 );
1730 if( testAreas.
Contains( testPt, -1, 1, USE_BBOX_CACHES ) )
1739 if( interval++ > 400 )
1752 if( &other != &spoke
1753 && other.PointInside( testPt, 1, USE_BBOX_CACHES )
1754 && spoke.PointInside( other.CPoint( 3 ), 1, USE_BBOX_CACHES ) )
1784 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
1786 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
1787 BOX2I islandExtents;
1789 for(
const VECTOR2I& pt : island.front().CPoints() )
1791 islandExtents.
Merge( pt );
1811 if( aZone->
GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
1846 for(
PAD*
pad : thermalConnectionPads )
1875 auto checkForCancel =
1878 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
1881 auto knockoutGraphicClearance =
1884 if( aItem->IsKnockout() && aItem->IsOnLayer( aLayer )
1885 && aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
1888 aZone, aItem, aLayer );
1899 knockoutGraphicClearance( &footprint->Reference() );
1900 knockoutGraphicClearance( &footprint->Value() );
1902 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
1903 knockoutGraphicClearance( item );
1911 knockoutGraphicClearance( item );
1914 aFillPolys = aSmoothedOutline;
1919 if( !keepout->GetIsRuleArea() )
1922 if( !keepout->HasKeepoutParametersSet() )
1925 if( keepout->GetDoNotAllowCopperPour() && keepout->IsOnLayer( aLayer ) )
1927 if( keepout->GetBoundingBox().Intersects( zone_boundingbox ) )
1941 if( aZone->
GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
1970 debugLayer = aLayer;
1974 if( !aZone->
BuildSmoothedPoly( maxExtents, aLayer, boardOutline, &smoothedPoly ) )
1982 if(
fillCopperZone( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aFillPolys ) )
1999 const std::vector<PAD*>& aSpokedPadsList,
2000 std::deque<SHAPE_LINE_CHAIN>& aSpokesList )
2013 for(
PAD*
pad : aSpokedPadsList )
2016 if( !
pad->IsOnLayer( aLayer ) )
2020 int thermalReliefGap = constraint.
GetValue().
Min();
2028 int spoke_max_allowed_w = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
2030 spoke_w = std::clamp( spoke_w, constraint.
Value().
Min(), constraint.
Value().
Max() );
2033 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
2036 if( spoke_w < aZone->GetMinThickness() )
2039 int spoke_half_w = spoke_w / 2;
2042 BOX2I itemBB =
pad->GetBoundingBox();
2048 bool customSpokes =
false;
2050 if(
pad->GetShape( aLayer ) == PAD_SHAPE::CUSTOM )
2052 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
2054 if( primitive->IsProxyItem() && primitive->GetShape() == SHAPE_T::SEGMENT )
2056 customSpokes =
true;
2067 auto buildSpokesFromOrigin =
2075 double dx = direction.
x;
2076 double dy = direction.y;
2080 if( direction.x == 0 )
2084 else if( direction.y == 0 )
2091 double tx = std::min( half_size.
x /
std::abs( dx ),
2093 return VECTOR2I( dx * tx, dy * tx );
2105 for(
const EDA_ANGLE& spokeAngle : angles )
2107 VECTOR2D direction( spokeAngle.Cos(), spokeAngle.Sin() );
2110 VECTOR2I intersection = intersectLineBox( direction );
2114 spoke.
Append( center + spoke_side );
2115 spoke.
Append( center - spoke_side );
2116 spoke.
Append( center + intersection - spoke_side );
2117 spoke.
Append( center + intersection );
2118 spoke.
Append( center + intersection + spoke_side );
2120 aSpokesList.push_back( std::move( spoke ) );
2129 pad->TransformShapeToPolygon( thermalPoly, aLayer, thermalReliefGap +
epsilon,
2133 thermalOutline = thermalPoly.
Outline( 0 );
2135 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
2137 if( primitive->IsProxyItem() && primitive->GetShape() == SHAPE_T::SEGMENT )
2139 SEG seg( primitive->GetStart(), primitive->GetEnd() );
2144 seg.
A +=
pad->ShapePos( aLayer );
2145 seg.
B +=
pad->ShapePos( aLayer );
2152 if( thermalOutline.
Intersect( seg, intersections ) )
2154 seg.
B = intersections.front().p;
2156 VECTOR2I offset = ( seg.
B - seg.
A ).Perpendicular().
Resize( spoke_half_w );
2159 spoke.
Append( seg.
A + offset );
2160 spoke.
Append( seg.
A - offset );
2161 spoke.
Append( seg.
B - offset );
2163 spoke.
Append( seg.
B + offset );
2166 aSpokesList.push_back( std::move( spoke ) );
2187 spokesBox.
Inflate( thermalReliefGap +
epsilon + zone_half_width );
2192 if(
pad->GetShape( aLayer ) == PAD_SHAPE::CIRCLE
2193 || (
pad->GetShape( aLayer ) == PAD_SHAPE::OVAL
2194 &&
pad->GetSizeX() ==
pad->GetSizeY() ) )
2196 buildSpokesFromOrigin( spokesBox,
ANGLE_0 );
2201 for(
auto it = aSpokesList.rbegin(); it != aSpokesList.rbegin() + 4; ++it )
2202 it->Rotate(
pad->GetThermalSpokeAngle() );
2207 buildSpokesFromOrigin( spokesBox,
pad->GetThermalSpokeAngle() );
2210 auto spokeIter = aSpokesList.rbegin();
2212 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
2214 spokeIter->Rotate(
pad->GetOrientation() );
2215 spokeIter->Move(
pad->ShapePos( aLayer ) );
2223 for(
size_t ii = 0; ii < aSpokesList.size(); ++ii )
2224 aSpokesList[ii].GenerateBBoxCache();
2260 hole_base.
Append( corner );
2261 corner.
x += hole_size;
2262 hole_base.
Append( corner );
2263 corner.
y += hole_size;
2264 hole_base.
Append( corner );
2266 hole_base.
Append( corner );
2286 #define SMOOTH_MIN_VAL_MM 0.02
2287 #define SMOOTH_SMALL_VAL_MM 0.04
2303 smooth_value = std::min( smooth_value, aZone->
GetHatchGap() / 2 );
2306 maxError = std::max( maxError * 2, smooth_value / 20 );
2308 switch( smooth_level )
2320 hole_base = smooth_hole.
Fillet( smooth_value, maxError ).
Outline( 0 );
2332 for(
int xx = 0; ; xx++ )
2334 int xpos = xx * gridsize;
2339 for(
int yy = 0; ; yy++ )
2341 int ypos = yy * gridsize;
2370 CORNER_STRATEGY::CHAMFER_ALL_CORNERS, maxError );
2375 deflatedOutline.
Deflate( outline_margin, CORNER_STRATEGY::CHAMFER_ALL_CORNERS, maxError );
2387 int min_apron_radius = ( aZone->
GetHatchGap() * 10 ) / 19;
2396 &&
via->IsOnLayer( aLayer )
2397 &&
via->GetBoundingBox().Intersects( zone_boundingbox ) )
2399 int r = std::max( min_apron_radius,
2400 via->GetDrillValue() / 2 + outline_margin );
2410 for(
PAD*
pad : footprint->Pads() )
2413 &&
pad->IsOnLayer( aLayer )
2414 &&
pad->GetBoundingBox().Intersects( zone_boundingbox ) )
2421 int pad_width = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
2422 int slot_width = std::min(
pad->GetDrillSize().x,
pad->GetDrillSize().y );
2423 int min_annular_ring_width = ( pad_width - slot_width ) / 2;
2424 int clearance = std::max( min_apron_radius - pad_width / 2,
2425 outline_margin - min_annular_ring_width );
2427 clearance = std::max( 0, clearance - linethickness / 2 );
2428 pad->TransformShapeToPolygon( aprons, aLayer, clearance, maxError,
2444 if( area < minimal_hole_area )
constexpr int ARC_HIGH_DEF
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...
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
constexpr const Vec & GetPosition() 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 size_type GetWidth() 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 bool Intersects(const BOX2< Vec > &aRect) const
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.
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.
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
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 TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool ignoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
void SetOffset(PCB_LAYER_ID aLayer, const VECTOR2I &aOffset)
void SetPosition(const VECTOR2I &aPos) override
PADSTACK::CUSTOM_SHAPE_ZONE_MODE GetCustomShapeInZoneOpt() const
void SetOrientation(const EDA_ANGLE &aAngle)
Set the rotation angle of the pad.
bool TransformHoleToPolygon(SHAPE_POLY_SET &aBuffer, int aClearance, int aError, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Build the corner list of the polygonal drill shape in the board coordinate system.
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth=false) const override
Convert the item shape to a closed polygon.
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth=false) const override
Convert the item shape to a closed polygon.
A progress reporter interface for use in multi-threaded environments.
virtual bool IsCancelled() const =0
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void Report(const wxString &aMessage)=0
Display aMessage in the progress bar dialog.
virtual void AdvancePhase()=0
Use the next available virtual zone of the dialog progress bar.
virtual void AdvanceProgress()=0
Increment the progress bar length (inside the current virtual zone).
virtual void SetMaxProgress(int aMaxProgress)=0
Fix the value that gives the 100 percent progress bar length (inside the current virtual zone).
RESULTS(int aOutline1, int aOutline2, int aVertex1, int aVertex2)
bool operator<(const RESULTS &aOther) const
VECTOR2I::extended_type ecoord
static SEG::ecoord Square(int a)
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void Move(const VECTOR2I &aVector) override
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int Intersect(const SEG &aSeg, INTERSECTIONS &aIp) const
Find all intersection points between our line chain and the segment aSeg.
double Area(bool aAbsolute=true) const
Return the area of this chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
void Insert(size_t aVertex, const VECTOR2I &aP)
std::vector< INTERSECTION > INTERSECTIONS
Represent a set of closed polygons.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
void RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
SHAPE_POLY_SET Chamfer(int aDistance)
Return a chamfered version of the polygon set.
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset difference For aFastMode meaning, see function booleanOp.
void Fracture(POLYGON_MODE aFastMode)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
void DeletePolygon(int aIdx)
Delete aIdx-th polygon from the set.
double Area()
Return the area of this poly set.
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
POLYGON & Polygon(int aIndex)
Return the aIndex-th subpolygon in the set.
void BooleanIntersection(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify(POLYGON_MODE aFastMode)
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFastMo...
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
void Deflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError)
void BuildBBoxCaches() const
Construct BBoxCaches for Contains(), below.
int OutlineCount() const
Return the number of outlines in the set.
SHAPE_POLY_SET Fillet(int aRadius, int aErrorMax)
Return a filleted version of the polygon set.
void Move(const VECTOR2I &aVector) override
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
SHAPE_POLY_SET CloneDropTriangulation() const
const BOX2I BBoxFromCaches() const
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
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
int32_t zOrder(const double aX, const double aY) const
Note that while the inputs are doubles, these are scaled by the size of the bounding box to fit into ...
VERTEX * createList(const SHAPE_LINE_CHAIN &points, VERTEX *aTail=nullptr, void *aUserData=nullptr)
Create a list of vertices from a line chain.
void SetBoundingBox(const BOX2I &aBBox)
void updateList()
After inserting or changing nodes, this function should be called to remove duplicate vertices and en...
void * GetUserData() const
bool isEar() const
Check whether the given vertex is in the middle of an ear.
void buildCopperItemClearances(const ZONE *aZone, PCB_LAYER_ID aLayer, const std::vector< PAD * > &aNoConnectionPads, SHAPE_POLY_SET &aHoles)
Removes clearance from the shape for copper items which share the zone's layer but are not connected ...
void addKnockout(PAD *aPad, PCB_LAYER_ID aLayer, int aGap, SHAPE_POLY_SET &aHoles)
Add a knockout for a pad.
void connect_nearby_polys(SHAPE_POLY_SET &aPolys, double aDistance)
Create strands of zero-width between elements of SHAPE_POLY_SET that are within aDistance of each oth...
ZONE_FILLER(BOARD *aBoard, COMMIT *aCommit)
void buildThermalSpokes(const ZONE *box, PCB_LAYER_ID aLayer, const std::vector< PAD * > &aSpokedPadsList, std::deque< SHAPE_LINE_CHAIN > &aSpokes)
Function buildThermalSpokes Constructs a list of all thermal spokes for the given zone.
void subtractHigherPriorityZones(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aRawFill)
Removes the outlines of higher-proirity zones with the same net.
SHAPE_POLY_SET m_boardOutline
bool addHatchFillTypeOnZone(const ZONE *aZone, PCB_LAYER_ID aLayer, PCB_LAYER_ID aDebugLayer, SHAPE_POLY_SET &aFillPolys)
for zones having the ZONE_FILL_MODE::ZONE_FILL_MODE::HATCH_PATTERN, create a grid pattern in filled a...
void SetProgressReporter(PROGRESS_REPORTER *aReporter)
void knockoutThermalReliefs(const ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aFill, std::vector< PAD * > &aThermalConnectionPads, std::vector< PAD * > &aNoConnectionPads)
Removes thermal reliefs from the shape for any pads connected to the zone.
PROGRESS_REPORTER * m_progressReporter
bool fillCopperZone(const ZONE *aZone, PCB_LAYER_ID aLayer, PCB_LAYER_ID aDebugLayer, const SHAPE_POLY_SET &aSmoothedOutline, const SHAPE_POLY_SET &aMaxExtents, SHAPE_POLY_SET &aFillPolys)
Function fillCopperZone Add non copper areas polygons (pads and tracks with clearance) to a filled co...
void addHoleKnockout(PAD *aPad, int aGap, SHAPE_POLY_SET &aHoles)
Add a knockout for a pad's hole.
bool fillNonCopperZone(const ZONE *aZone, PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aSmoothedOutline, SHAPE_POLY_SET &aFillPolys)
bool fillSingleZone(ZONE *aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aFillPolys)
Build the filled solid areas polygons from zone outlines (stored in m_Poly) The solid areas can be mo...
bool Fill(const std::vector< ZONE * > &aZones, bool aCheck=false, wxWindow *aParent=nullptr)
Fills the given list of zones.
Handle a list of polygons defining a copper zone.
void SetNeedRefill(bool aNeedRefill)
int GetHatchBorderAlgorithm() const
std::optional< int > GetLocalClearance() const override
void CacheTriangulation(PCB_LAYER_ID aLayer=UNDEFINED_LAYER)
Create a list of triangles that "fill" the solid areas used for instance to draw these solid areas on...
const BOX2I GetBoundingBox() const override
SHAPE_POLY_SET * Outline()
void SetFillFlag(PCB_LAYER_ID aLayer, bool aFlag)
void SetFilledPolysList(PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPolysList)
Set the list of filled polygons.
int GetMinThickness() const
bool HigherPriority(const ZONE *aOther) const
int GetHatchThickness() const
double GetHatchHoleMinArea() const
bool IsTeardropArea() const
EDA_ANGLE GetHatchOrientation() const
bool BuildSmoothedPoly(SHAPE_POLY_SET &aSmoothedPoly, PCB_LAYER_ID aLayer, SHAPE_POLY_SET *aBoardOutline, SHAPE_POLY_SET *aSmoothedPolyWithApron=nullptr) const
ZONE_FILL_MODE GetFillMode() const
double GetHatchSmoothingValue() const
int GetHatchSmoothingLevel() const
bool IsOnCopperLayer() const override
unsigned GetAssignedPriority() const
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void BuildConvexHull(std::vector< VECTOR2I > &aResult, const std::vector< VECTOR2I > &aPoly)
Calculate the convex hull of a list of points in counter-clockwise order.
CORNER_STRATEGY
define how inflate transform build inflated polygon
@ EDGE_CLEARANCE_CONSTRAINT
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
@ THERMAL_SPOKE_WIDTH_CONSTRAINT
@ THERMAL_RELIEF_GAP_CONSTRAINT
@ HOLE_CLEARANCE_CONSTRAINT
@ PHYSICAL_CLEARANCE_CONSTRAINT
static constexpr EDA_ANGLE ANGLE_0
a few functions useful in geometry calculations.
double m_ExtraClearance
When filling zones, we add an extra amount of clearance to each zone to ensure that rounding errors d...
bool m_DebugZoneFiller
A mode that dumps the various stages of a F_Cu fill into In1_Cu through In9_Cu.
This file is part of the common library.
PCB_LAYER_ID
A quick note on layer IDs:
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
constexpr int mmToIU(double mm) const
A storage class for 128-bit hash value.
A struct recording the isolated and single-pad islands within a zone.
BS::thread_pool thread_pool
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
VECTOR2< int32_t > VECTOR2I
#define SMOOTH_MIN_VAL_MM
#define DUMP_POLYS_TO_COPPER_LAYER(a, b, c)
#define SMOOTH_SMALL_VAL_MM
ISLAND_REMOVAL_MODE
Whether or not to remove isolated islands from a zone.
ZONE_CONNECTION
How pads are covered by copper in zone.