58 RESULTS(
int aOutline1,
int aOutline2,
int aVertex1,
int aVertex2 ) :
105 SEG::ecoord min_dist = std::numeric_limits<SEG::ecoord>::max();
108 auto check_pt = [&](
VERTEX* p )
110 VECTOR2D diff( p->x - aPt->
x, p->y - aPt->
y );
113 if( dist2 > 0 && dist2 < limit2 && dist2 < min_dist && p->isEar(
true ) )
122 while( p && p->
z <= maxZ )
130 while( p && p->
z >= minZ )
145 std::set<VERTEX*> visited;
158 if( ( visited.empty() || !visited.contains( p ) ) && ( q =
getPoint( p ) ) )
162 if( !visited.contains( q ) &&
164 p->
i, q->
i ).second )
168 visited.insert( p->
prev );
170 visited.insert( p->
next );
173 visited.insert( q->
prev );
175 visited.insert( q->
next );
199 m_brdOutlinesValid( false ),
201 m_progressReporter( nullptr ),
203 m_worstClearance( 0 )
218 wxASSERT_MSG(
m_commit, wxT(
"ZONE_FILLER must have a valid commit to call "
219 "SetProgressReporter" ) );
237 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
238 std::map<std::pair<ZONE*, PCB_LAYER_ID>,
HASH_128> oldFillHashes;
239 std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> isolatedIslandsMap;
244 connectivity->ClearRatsnest();
252 :
_(
"Building zone fills..." ) );
265 zone->CacheBoundingBox();
269 for(
PAD*
pad : footprint->Pads() )
273 pad->BuildEffectiveShapes();
278 for(
ZONE* zone : footprint->Zones() )
279 zone->CacheBoundingBox();
282 footprint->BuildCourtyardCaches();
287 auto findHighestPriorityZone = [&](
const BOX2I& aBBox,
const PCB_LAYER_ID aItemLayer,
289 const std::function<bool(
const ZONE* )> aTestFn ) ->
ZONE*
291 unsigned highestPriority = 0;
292 ZONE* highestPriorityZone =
nullptr;
297 if( zone->GetIsRuleArea() )
300 if( zone->GetAssignedPriority() < highestPriority )
303 if( !zone->IsOnLayer( aItemLayer ) )
307 if( zone->GetNumCorners() <= 2 )
310 if( !zone->GetBoundingBox().Intersects( aBBox ) )
313 if( !aTestFn( zone ) )
317 if( zone->GetAssignedPriority() > highestPriority || zone->GetNetCode() == aNetcode )
320 highestPriorityZone = zone;
324 return highestPriorityZone;
327 auto isInPourKeepoutArea = [&](
const BOX2I& aBBox,
const PCB_LAYER_ID aItemLayer,
332 if( !zone->GetIsRuleArea() )
335 if( !zone->HasKeepoutParametersSet() )
338 if( !zone->GetDoNotAllowCopperPour() )
341 if( !zone->IsOnLayer( aItemLayer ) )
345 if( zone->GetNumCorners() <= 2 )
348 if( !zone->GetBoundingBox().Intersects( aBBox ) )
351 if( zone->Outline()->Contains( aTestPoint ) )
365 via->ClearZoneLayerOverrides();
367 if( !
via->GetRemoveUnconnected() )
372 int testRadius =
via->GetDrillValue() / 2 + 1;
373 unsigned netcode =
via->GetNetCode();
374 LSET layers =
via->GetLayerSet() & boardCuMask;
377 auto viaTestFn = [&](
const ZONE* aZone ) ->
bool
379 return aZone->Outline()->
Contains( center, -1, testRadius );
384 if( !
via->ConditionallyFlashed( layer ) )
387 if( isInPourKeepoutArea( bbox, layer, center ) )
393 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, viaTestFn );
407 for(
PAD*
pad : footprint->Pads() )
409 pad->ClearZoneLayerOverrides();
411 if( !
pad->GetRemoveUnconnected() )
416 unsigned netcode =
pad->GetNetCode();
417 LSET layers =
pad->GetLayerSet() & boardCuMask;
419 auto padTestFn = [&](
const ZONE* aZone ) ->
bool
421 return aZone->Outline()->
Contains( center );
426 if( !
pad->ConditionallyFlashed( layer ) )
429 if( isInPourKeepoutArea( bbox, layer, center ) )
435 ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, padTestFn );
446 for(
ZONE* zone : aZones )
449 if( zone->GetIsRuleArea() )
453 if( zone->GetNumCorners() <= 2 )
463 zone->BuildHashValue( layer );
464 oldFillHashes[ { zone, layer } ] = zone->GetHashValue( layer );
467 toFill.emplace_back( std::make_pair( zone, layer ) );
476 auto check_fill_dependency =
484 if( aOtherZone->GetFillFlag( aLayer ) )
489 if( aOtherZone->GetIsRuleArea() )
493 if( aOtherZone->GetNumCorners() <= 2 )
497 if( !aOtherZone->GetLayerSet().test( aLayer ) )
504 if( aOtherZone->SameNet( aZone ) )
512 if( !inflatedBBox.
Intersects( aOtherZone->GetBoundingBox() ) )
519 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
522 ZONE* zone = aFillItem.first;
527 for(
ZONE* otherZone : aZones )
529 if( otherZone == zone )
532 if( check_fill_dependency( zone, layer, otherZone ) )
547 std::unique_lock<std::mutex> zoneLock( zone->
GetLock(), std::try_to_lock );
549 if( !zoneLock.owns_lock() )
566 auto tesselate_lambda =
567 [&]( std::pair<ZONE*, PCB_LAYER_ID> aFillItem ) ->
int
573 ZONE* zone = aFillItem.first;
576 std::unique_lock<std::mutex> zoneLock( zone->
GetLock(), std::try_to_lock );
578 if( !zoneLock.owns_lock() )
590 std::vector<std::pair<std::future<int>,
int>> returns;
591 returns.reserve( toFill.size() );
593 bool cancelled =
false;
597 for(
const std::pair<ZONE*, PCB_LAYER_ID>& fillItem : toFill )
598 returns.emplace_back( std::make_pair(
tp.submit( fill_lambda, fillItem ), 0 ) );
600 while( !cancelled && finished != 2 * toFill.size() )
602 for(
size_t ii = 0; ii < returns.size(); ++ii )
604 auto& ret = returns[ii];
609 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
611 if( status == std::future_status::ready )
613 if( ret.first.get() )
622 if( ret.second == 0 )
623 returns[ii].first =
tp.submit( fill_lambda, toFill[ii] );
624 else if( ret.second == 1 )
625 returns[ii].first =
tp.submit( tesselate_lambda, toFill[ii] );
630 std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
644 for(
auto& ret : returns )
646 if( ret.first.valid() )
648 std::future_status status = ret.first.wait_for( std::chrono::seconds( 0 ) );
650 while( status != std::future_status::ready )
655 status = ret.first.wait_for( std::chrono::milliseconds( 100 ) );
674 connectivity->FillIsolatedIslandsMap( isolatedIslandsMap );
675 connectivity->SetProgressReporter(
nullptr );
680 for(
ZONE* zone : aZones )
683 if( zone->GetIsRuleArea() )
686 zone->SetIsFilled(
true );
692 for(
const auto& [ zone, zoneIslands ] : isolatedIslandsMap )
695 bool allIslands =
true;
697 for(
const auto& [ layer, layerIslands ] : zoneIslands )
699 if( layerIslands.m_IsolatedOutlines.size()
700 !=
static_cast<size_t>( zone->GetFilledPolysList( layer )->OutlineCount() ) )
710 for(
const auto& [ layer, layerIslands ] : zoneIslands )
715 if( layerIslands.m_IsolatedOutlines.empty() )
718 std::vector<int> islands = layerIslands.m_IsolatedOutlines;
722 std::sort( islands.begin(), islands.end(), std::greater<int>() );
724 std::shared_ptr<SHAPE_POLY_SET> poly = zone->GetFilledPolysList( layer );
725 long long int minArea = zone->GetMinIslandArea();
728 for(
int idx : islands )
732 if( mode == ISLAND_REMOVAL_MODE::ALWAYS )
733 poly->DeletePolygonAndTriangulationData( idx,
false );
734 else if ( mode == ISLAND_REMOVAL_MODE::AREA && outline.
Area(
true ) < minArea )
735 poly->DeletePolygonAndTriangulationData( idx,
false );
737 zone->SetIsIsland( layer, idx );
740 poly->UpdateTriangulationDataHash();
741 zone->CalculateFilledArea();
750 using island_check_return = std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
int>>;
752 std::vector<std::pair<std::shared_ptr<SHAPE_POLY_SET>,
double>> polys_to_check;
757 for(
ZONE* zone : aZones )
767 double minArea = (double) zone->GetMinThickness() * zone->GetMinThickness() * 3;
774 polys_to_check.emplace_back( zone->GetFilledPolysList( layer ), minArea );
779 [&](
int aStart,
int aEnd ) -> island_check_return
781 island_check_return retval;
783 for(
int ii = aStart; ii < aEnd && !cancelled; ++ii )
785 auto [poly, minArea] = polys_to_check[ii];
787 for(
int jj = poly->OutlineCount() - 1; jj >= 0; jj-- )
792 double island_area = test_poly.
Area();
794 if( island_area < minArea )
806 if( intersection.
Area() < island_area / 2.0 )
807 retval.emplace_back( poly, jj );
814 auto island_returns =
tp.parallelize_loop( 0, polys_to_check.size(), island_lambda );
818 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
820 std::future<island_check_return>& ret = island_returns[ii];
824 std::future_status status = ret.wait_for( std::chrono::seconds( 0 ) );
826 while( status != std::future_status::ready )
836 status = ret.wait_for( std::chrono::milliseconds( 100 ) );
844 for(
size_t ii = 0; ii < island_returns.size(); ++ii )
846 std::future<island_check_return>& ret = island_returns[ii];
850 for(
auto& action_item : ret.get() )
851 action_item.first->DeletePolygonAndTriangulationData( action_item.second,
true );
855 for(
ZONE* zone : aZones )
856 zone->CalculateFilledArea();
861 bool outOfDate =
false;
863 for(
ZONE* zone : aZones )
866 if( zone->GetIsRuleArea() )
871 zone->BuildHashValue( layer );
873 if( oldFillHashes[ { zone, layer } ] != zone->GetHashValue( layer ) )
880 KIDIALOG dlg( aParent,
_(
"Zone fills are out-of-date. Refill?" ),
881 _(
"Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
915 if( aPad->
GetShape( aLayer ) == PAD_SHAPE::CUSTOM )
923 std::vector<VECTOR2I> convex_hull;
928 for(
const VECTOR2I& pt : convex_hull )
957 switch( aItem->
Type() )
964 if(
text->IsVisible() )
966 if(
text->IsKnockout() )
1016 std::vector<PAD*>& aThermalConnectionPads,
1017 std::vector<PAD*>& aNoConnectionPads )
1023 std::shared_ptr<SHAPE> padShape;
1029 for(
PAD*
pad : footprint->Pads() )
1031 BOX2I padBBox =
pad->GetBoundingBox();
1037 bool noConnection =
pad->GetNetCode() != aZone->
GetNetCode();
1044 noConnection =
true;
1051 aNoConnectionPads.push_back(
pad );
1057 connection = ZONE_CONNECTION::FULL;
1061 constraint = bds.
m_DRCEngine->EvalZoneConnection(
pad, aZone, aLayer );
1065 if( connection == ZONE_CONNECTION::THERMAL && !
pad->CanFlashLayer( aLayer ) )
1066 connection = ZONE_CONNECTION::NONE;
1068 switch( connection )
1070 case ZONE_CONNECTION::THERMAL:
1071 padShape =
pad->GetEffectiveShape( aLayer, FLASHING::ALWAYS_FLASHED );
1073 if( aFill.
Collide( padShape.get(), 0 ) )
1079 aThermalConnectionPads.push_back(
pad );
1085 case ZONE_CONNECTION::NONE:
1094 if(
pad->FlashLayer( aLayer ) )
1098 else if(
pad->GetDrillSize().x > 0 )
1101 pad, aZone, aLayer );
1106 holeClearance = padClearance;
1129 const std::vector<PAD*>& aNoConnectionPads,
1135 auto checkForCancel =
1138 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
1151 auto evalRulesForItems =
1165 auto knockoutPadClearance =
1170 bool hasHole = aPad->GetDrillSize().x > 0;
1171 bool flashLayer = aPad->FlashLayer( aLayer );
1172 bool platedHole = hasHole && aPad->GetAttribute() == PAD_ATTRIB::PTH;
1174 if( flashLayer || platedHole )
1177 aZone, aPad, aLayer ) );
1180 if( flashLayer && gap >= 0 )
1181 addKnockout( aPad, aLayer, gap + extra_margin, aHoles );
1186 if( aPad->GetAttribute() == PAD_ATTRIB::NPTH )
1190 aZone, aPad, aLayer ) );
1193 aZone, aPad, aLayer ) );
1200 for(
PAD*
pad : aNoConnectionPads )
1205 knockoutPadClearance(
pad );
1210 auto knockoutTrackClearance =
1213 if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
1215 bool sameNet = aTrack->GetNetCode() == aZone->
GetNetCode();
1221 aZone, aTrack, aLayer );
1234 aZone, aTrack, aLayer ) );
1241 if(
via->FlashLayer( aLayer ) && gap > 0 )
1243 via->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
1248 aZone,
via, aLayer ) );
1253 aZone,
via, aLayer ) );
1258 int radius =
via->GetDrillValue() / 2;
1261 radius + gap + extra_margin,
1269 aTrack->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
1278 if( !track->IsOnLayer( aLayer ) )
1284 knockoutTrackClearance( track );
1289 auto knockoutGraphicClearance =
1297 bool sameNet = shapeNet == aZone->
GetNetCode();
1303 if( aItem->IsOnLayer( aLayer )
1305 || aItem->IsOnLayer(
Margin ) )
1307 if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
1309 bool ignoreLineWidths =
false;
1311 aZone, aItem, aLayer );
1313 if( aItem->IsOnLayer( aLayer ) && !sameNet )
1316 aZone, aItem, aLayer ) );
1318 else if( aItem->IsOnLayer(
Edge_Cuts ) )
1321 aZone, aItem, aLayer ) );
1322 ignoreLineWidths =
true;
1324 else if( aItem->IsOnLayer(
Margin ) )
1327 aZone, aItem, aLayer ) );
1332 gap += extra_margin;
1333 addKnockout( aItem, aLayer, gap, ignoreLineWidths, aHoles );
1339 auto knockoutCourtyardClearance =
1342 if( aFootprint->GetBoundingBox().Intersects( zone_boundingbox ) )
1345 aFootprint, aLayer );
1349 aHoles.
Append( aFootprint->GetCourtyard( aLayer ) );
1362 knockoutCourtyardClearance( footprint );
1363 knockoutGraphicClearance( &footprint->Reference() );
1364 knockoutGraphicClearance( &footprint->Value() );
1366 std::set<PAD*> allowedNetTiePads;
1370 if( footprint->IsNetTie() )
1372 for(
PAD*
pad : footprint->Pads() )
1381 if(
pad->IsOnLayer( aLayer ) )
1382 allowedNetTiePads.insert(
pad );
1384 for(
PAD* other : footprint->GetNetTiePads(
pad ) )
1386 if( other->IsOnLayer( aLayer ) )
1387 allowedNetTiePads.insert( other );
1393 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
1398 BOX2I itemBBox = item->GetBoundingBox();
1400 if( !zone_boundingbox.
Intersects( itemBBox ) )
1403 bool skipItem =
false;
1405 if( item->IsOnLayer( aLayer ) )
1407 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape();
1409 for(
PAD*
pad : allowedNetTiePads )
1411 if(
pad->GetBoundingBox().Intersects( itemBBox )
1412 &&
pad->GetEffectiveShape( aLayer )->Collide( itemShape.get() ) )
1421 knockoutGraphicClearance( item );
1430 knockoutGraphicClearance( item );
1435 auto knockoutZoneClearance =
1436 [&](
ZONE* aKnockout )
1439 if( !aKnockout->GetLayerSet().test( aLayer ) )
1442 if( aKnockout->GetBoundingBox().Intersects( zone_boundingbox ) )
1444 if( aKnockout->GetIsRuleArea() )
1447 aKnockout->TransformSmoothedOutlineToPolygon( aHoles, 0,
m_maxError,
1453 aZone, aKnockout, aLayer ) );
1456 aZone, aKnockout, aLayer ) );
1459 aKnockout->TransformShapeToPolygon( poly, aLayer, gap + extra_margin,
1475 if( otherZone->GetIsRuleArea() )
1477 if( otherZone->GetDoNotAllowCopperPour() && !aZone->
IsTeardropArea() )
1478 knockoutZoneClearance( otherZone );
1480 else if( otherZone->HigherPriority( aZone ) )
1482 if( !otherZone->SameNet( aZone ) )
1483 knockoutZoneClearance( otherZone );
1489 for(
ZONE* otherZone : footprint->Zones() )
1494 if( otherZone->GetIsRuleArea() )
1496 if( otherZone->GetDoNotAllowCopperPour() && !aZone->
IsTeardropArea() )
1497 knockoutZoneClearance( otherZone );
1499 else if( otherZone->HigherPriority( aZone ) )
1501 if( !otherZone->SameNet( aZone ) )
1502 knockoutZoneClearance( otherZone );
1520 auto knockoutZoneOutline =
1521 [&](
ZONE* aKnockout )
1524 if( !aKnockout->GetLayerSet().test( aLayer ) )
1527 if( aKnockout->GetBoundingBox().Intersects( zoneBBox ) )
1543 if( otherZone->SameNet( aZone )
1547 if( !otherZone->IsTeardropArea() )
1548 knockoutZoneOutline( otherZone );
1554 for(
ZONE* otherZone : footprint->Zones() )
1556 if( otherZone->SameNet( aZone ) && otherZone->HigherPriority( aZone ) )
1559 if( !otherZone->IsTeardropArea() )
1560 knockoutZoneOutline( otherZone );
1578 std::map<int, std::vector<std::pair<int, VECTOR2I>>> insertion_points;
1590 insertion_points[result.m_outline1].push_back( { result.m_vertex1, pt1 } );
1591 insertion_points[result.m_outline1].push_back( { result.m_vertex1, pt2 } );
1594 for(
auto& [outline, vertices] : insertion_points )
1602 std::stable_sort( vertices.begin(), vertices.end(),
1603 [](
const std::pair<int, VECTOR2I>& a,
const std::pair<int, VECTOR2I>& b )
1605 return a.first > b.first;
1608 for(
const auto& [vertex, pt] : vertices )
1609 line.
Insert( vertex + 1, pt );
1614#define DUMP_POLYS_TO_COPPER_LAYER( a, b, c ) \
1615 { if( m_debugZoneFiller && aDebugLayer == b ) \
1617 m_board->SetLayerName( b, c ); \
1618 SHAPE_POLY_SET d = a; \
1654 CORNER_STRATEGY fastCornerStrategy = CORNER_STRATEGY::CHAMFER_ALL_CORNERS;
1657 std::vector<PAD*> thermalConnectionPads;
1658 std::vector<PAD*> noConnectionPads;
1659 std::deque<SHAPE_LINE_CHAIN> thermalSpokes;
1662 aFillPolys = aSmoothedOutline;
1699 static const bool USE_BBOX_CACHES =
true;
1726 const VECTOR2I& testPt = spoke.CPoint( 3 );
1729 if( testAreas.
Contains( testPt, -1, 1, USE_BBOX_CACHES ) )
1738 if( interval++ > 400 )
1751 if( &other != &spoke
1752 && other.PointInside( testPt, 1, USE_BBOX_CACHES )
1753 && spoke.PointInside( other.CPoint( 3 ), 1, USE_BBOX_CACHES ) )
1783 for(
int ii = aFillPolys.
OutlineCount() - 1; ii >= 0; ii-- )
1785 std::vector<SHAPE_LINE_CHAIN>& island = aFillPolys.
Polygon( ii );
1786 BOX2I islandExtents;
1788 for(
const VECTOR2I& pt : island.front().CPoints() )
1790 islandExtents.
Merge( pt );
1809 if( aZone->
GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
1844 for(
PAD*
pad : thermalConnectionPads )
1873 auto checkForCancel =
1876 return aReporter && ( ticker++ % 50 ) == 0 && aReporter->IsCancelled();
1879 auto knockoutGraphicClearance =
1882 if( aItem->IsKnockout() && aItem->IsOnLayer( aLayer )
1883 && aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
1886 aZone, aItem, aLayer );
1897 knockoutGraphicClearance( &footprint->Reference() );
1898 knockoutGraphicClearance( &footprint->Value() );
1900 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
1901 knockoutGraphicClearance( item );
1909 knockoutGraphicClearance( item );
1912 aFillPolys = aSmoothedOutline;
1917 if( !keepout->GetIsRuleArea() )
1920 if( !keepout->HasKeepoutParametersSet() )
1923 if( keepout->GetDoNotAllowCopperPour() && keepout->IsOnLayer( aLayer ) )
1925 if( keepout->GetBoundingBox().Intersects( zone_boundingbox ) )
1927 if( keepout->Outline()->ArcCount() == 0 )
1950 if( aZone->
GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
1979 debugLayer = aLayer;
1983 if( !aZone->
BuildSmoothedPoly( maxExtents, aLayer, boardOutline, &smoothedPoly ) )
1991 if(
fillCopperZone( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aFillPolys ) )
2008 const std::vector<PAD*>& aSpokedPadsList,
2009 std::deque<SHAPE_LINE_CHAIN>& aSpokesList )
2022 for(
PAD*
pad : aSpokedPadsList )
2025 if( !
pad->IsOnLayer( aLayer ) )
2029 int thermalReliefGap = constraint.
GetValue().
Min();
2037 int spoke_max_allowed_w = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
2039 spoke_w = std::clamp( spoke_w, constraint.
Value().
Min(), constraint.
Value().
Max() );
2042 spoke_w = std::min( spoke_w, spoke_max_allowed_w );
2045 if( spoke_w < aZone->GetMinThickness() )
2048 int spoke_half_w = spoke_w / 2;
2051 BOX2I itemBB =
pad->GetBoundingBox();
2057 bool customSpokes =
false;
2059 if(
pad->GetShape( aLayer ) == PAD_SHAPE::CUSTOM )
2061 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
2063 if( primitive->IsProxyItem() && primitive->GetShape() == SHAPE_T::SEGMENT )
2065 customSpokes =
true;
2076 auto buildSpokesFromOrigin =
2084 double dx = direction.
x;
2085 double dy = direction.y;
2089 if( direction.x == 0 )
2091 else if( direction.y == 0 )
2096 double tx = std::min( half_size.
x /
std::abs( dx ),
2098 return VECTOR2I( dx * tx, dy * tx );
2110 for(
const EDA_ANGLE& spokeAngle : angles )
2112 VECTOR2D direction( spokeAngle.Cos(), spokeAngle.Sin() );
2115 VECTOR2I intersection = intersectLineBox( direction );
2119 spoke.
Append( center + spoke_side );
2120 spoke.
Append( center - spoke_side );
2121 spoke.
Append( center + intersection - spoke_side );
2122 spoke.
Append( center + intersection );
2123 spoke.
Append( center + intersection + spoke_side );
2125 aSpokesList.push_back( std::move( spoke ) );
2134 pad->TransformShapeToPolygon( thermalPoly, aLayer, thermalReliefGap +
epsilon,
2138 thermalOutline = thermalPoly.
Outline( 0 );
2142 auto trimToOutline = [&](
SEG& aSegment )
2146 if( padOutline.
Intersect( aSegment, intersections ) )
2148 intersections.clear();
2151 if( thermalOutline.
Intersect( aSegment, intersections ) )
2153 aSegment.B = intersections.front().p;
2160 for(
const std::shared_ptr<PCB_SHAPE>& primitive :
pad->GetPrimitives( aLayer ) )
2162 if( primitive->IsProxyItem() && primitive->GetShape() == SHAPE_T::SEGMENT )
2164 SEG seg( primitive->GetStart(), primitive->GetEnd() );
2169 seg.
A +=
pad->ShapePos( aLayer );
2170 seg.
B +=
pad->ShapePos( aLayer );
2185 if( trimToOutline( seg ) )
2187 VECTOR2I direction = ( seg.
B - seg.
A ).Resize( spoke_half_w );
2190 SEG segL( seg.
A - direction - offset, seg.
B + direction - offset );
2191 SEG segR( seg.
A - direction + offset, seg.
B + direction + offset );
2193 if( trimToOutline( segL ) && trimToOutline( segR ) )
2200 spoke.
Append( seg.
A + offset );
2201 spoke.
Append( seg.
A - offset );
2203 spoke.
Append( segL.
B + direction );
2204 spoke.
Append( seg.
B + direction );
2205 spoke.
Append( segR.
B + direction );
2208 aSpokesList.push_back( std::move( spoke ) );
2231 spokesBox.
Inflate( thermalReliefGap +
epsilon + zone_half_width );
2236 if(
pad->GetShape( aLayer ) == PAD_SHAPE::CIRCLE
2237 || (
pad->GetShape( aLayer ) == PAD_SHAPE::OVAL
2238 &&
pad->GetSizeX() ==
pad->GetSizeY() ) )
2240 buildSpokesFromOrigin( spokesBox,
ANGLE_0 );
2245 for(
auto it = aSpokesList.rbegin(); it != aSpokesList.rbegin() + 4; ++it )
2246 it->Rotate(
pad->GetThermalSpokeAngle() );
2251 buildSpokesFromOrigin( spokesBox,
pad->GetThermalSpokeAngle() );
2254 auto spokeIter = aSpokesList.rbegin();
2256 for(
int ii = 0; ii < 4; ++ii, ++spokeIter )
2258 spokeIter->Rotate(
pad->GetOrientation() );
2259 spokeIter->Move(
pad->ShapePos( aLayer ) );
2267 for(
size_t ii = 0; ii < aSpokesList.size(); ++ii )
2268 aSpokesList[ii].GenerateBBoxCache();
2304 hole_base.
Append( corner );
2305 corner.
x += hole_size;
2306 hole_base.
Append( corner );
2307 corner.
y += hole_size;
2308 hole_base.
Append( corner );
2310 hole_base.
Append( corner );
2330 #define SMOOTH_MIN_VAL_MM 0.02
2331 #define SMOOTH_SMALL_VAL_MM 0.04
2347 smooth_value = std::min( smooth_value, aZone->
GetHatchGap() / 2 );
2350 maxError = std::max( maxError * 2, smooth_value / 20 );
2352 switch( smooth_level )
2364 hole_base = smooth_hole.
Fillet( smooth_value, maxError ).
Outline( 0 );
2376 for(
int xx = 0; ; xx++ )
2378 int xpos = xx * gridsize;
2383 for(
int yy = 0; ; yy++ )
2385 int ypos = yy * gridsize;
2414 CORNER_STRATEGY::CHAMFER_ALL_CORNERS, maxError );
2419 deflatedOutline.
Deflate( outline_margin, CORNER_STRATEGY::CHAMFER_ALL_CORNERS, maxError );
2431 int min_apron_radius = ( aZone->
GetHatchGap() * 10 ) / 19;
2440 &&
via->IsOnLayer( aLayer )
2441 &&
via->GetBoundingBox().Intersects( zone_boundingbox ) )
2443 int r = std::max( min_apron_radius,
2444 via->GetDrillValue() / 2 + outline_margin );
2454 for(
PAD*
pad : footprint->Pads() )
2457 &&
pad->IsOnLayer( aLayer )
2458 &&
pad->GetBoundingBox().Intersects( zone_boundingbox ) )
2465 int pad_width = std::min(
pad->GetSize( aLayer ).x,
pad->GetSize( aLayer ).y );
2466 int slot_width = std::min(
pad->GetDrillSize().x,
pad->GetDrillSize().y );
2467 int min_annular_ring_width = ( pad_width - slot_width ) / 2;
2468 int clearance = std::max( min_apron_radius - pad_width / 2,
2469 outline_margin - min_annular_ring_width );
2471 clearance = std::max( 0, clearance - linethickness / 2 );
2472 pad->TransformShapeToPolygon( aprons, aLayer, clearance, maxError,
2488 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)
Modify a given item in the model.
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)
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 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 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.
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
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)
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 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.
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::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_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.