25#include <boost/test/data/test_case.hpp>
70 for(
PAD*
pad : m_board->Footprints()[0]->Pads() )
72 if(
pad->GetNumber() ==
"2" ||
pad->GetNumber() ==
"4" ||
pad->GetNumber() ==
"6" )
83 for(
PCB_TRACK* track : m_board->Tracks() )
92 track->SetWidth( track->GetWidth() +
delta +
delta );
96 arc12 = track->m_Uuid;
102 bool foundPad2Error =
false;
103 bool foundPad4Error =
false;
104 bool foundPad6Error =
false;
105 bool foundArc8Error =
false;
106 bool foundArc12Error =
false;
107 bool foundOtherError =
false;
112 [&](
const std::shared_ptr<DRC_ITEM>& aItem,
const VECTOR2I& aPos,
int aLayer,
113 const std::function<
void(
PCB_MARKER* )>& aPathGenerator )
117 BOARD_ITEM* item_a = m_board->ResolveItem( aItem->GetMainItemID() );
118 PAD* pad_a =
dynamic_cast<PAD*
>( item_a );
121 BOARD_ITEM* item_b = m_board->ResolveItem( aItem->GetAuxItemID() );
122 PAD* pad_b =
dynamic_cast<PAD*
>( item_b );
125 if( pad_a && pad_a->
GetNumber() ==
"2" ) foundPad2Error =
true;
126 else if( pad_a && pad_a->
GetNumber() ==
"4" ) foundPad4Error =
true;
127 else if( pad_a && pad_a->
GetNumber() ==
"6" ) foundPad6Error =
true;
128 else if( pad_b && pad_b->
GetNumber() ==
"2" ) foundPad2Error =
true;
129 else if( pad_b && pad_b->
GetNumber() ==
"4" ) foundPad4Error =
true;
130 else if( pad_b && pad_b->
GetNumber() ==
"6" ) foundPad6Error =
true;
131 else if( trk_a && trk_a->
m_Uuid == arc8 ) foundArc8Error =
true;
132 else if( trk_a && trk_a->
m_Uuid == arc12 ) foundArc12Error =
true;
133 else if( trk_b && trk_b->
m_Uuid == arc8 ) foundArc8Error =
true;
134 else if( trk_b && trk_b->
m_Uuid == arc12 ) foundArc12Error =
true;
135 else foundOtherError =
true;
165 for(
ZONE* zone : m_board->Zones() )
167 if( zone->GetLayerSet().Contains(
F_Cu ) )
204 std::vector<DRC_ITEM> violations;
207 [&](
const std::shared_ptr<DRC_ITEM>& aItem,
const VECTOR2I& aPos,
int aLayer,
208 const std::function<
void(
PCB_MARKER* )>& aPathGenerator )
211 violations.push_back( *aItem );
216 if( violations.empty() )
225 std::map<KIID, EDA_ITEM*> itemMap;
226 m_board->FillItemMap( itemMap );
228 for(
const DRC_ITEM& item : violations )
231 BOOST_ERROR( wxString::Format(
"Zone fill regression: %s failed", relPath ) );
250 struct ScopeGuard {
bool& ref;
bool orig; ~ScopeGuard() { ref = orig; } }
253 auto runDrcClearanceCheck =
254 [
this](
bool aIterative ) ->
int
265 std::vector<DRC_ITEM> violations;
267 std::map<KIID, EDA_ITEM*> itemMap;
268 m_board->FillItemMap( itemMap );
272 [&](
const std::shared_ptr<DRC_ITEM>& aItem,
const VECTOR2I& aPos,
274 const std::function<
void(
PCB_MARKER* )>& aPathGenerator )
278 BOARD_ITEM* itemA = m_board->ResolveItem( aItem->GetMainItemID() );
279 BOARD_ITEM* itemB = m_board->ResolveItem( aItem->GetAuxItemID() );
281 if(
dynamic_cast<ZONE*
>( itemA ) &&
dynamic_cast<ZONE*
>( itemB ) )
283 violations.push_back( *aItem );
286 aItem->ShowReport( &unitsProvider,
294 return static_cast<int>( violations.size() );
297 int iterativeViolations = runDrcClearanceCheck(
true );
299 BOOST_CHECK_MESSAGE( iterativeViolations == 0,
300 wxString::Format(
"Iterative refill produced %d zone-to-zone clearance "
301 "violations (expected 0)", iterativeViolations ) );
303 int nonIterativeViolations = runDrcClearanceCheck(
false );
305 BOOST_CHECK_MESSAGE( nonIterativeViolations == 0,
306 wxString::Format(
"Non-iterative refill produced %d zone-to-zone clearance "
307 "violations (expected 0)", nonIterativeViolations ) );
326 std::vector<DRC_ITEM> violations;
329 [&](
const std::shared_ptr<DRC_ITEM>& aItem,
const VECTOR2I& aPos,
int aLayer,
330 const std::function<
void(
PCB_MARKER* )>& aPathGenerator )
333 violations.push_back( *aItem );
338 if( violations.empty() )
341 BOOST_TEST_MESSAGE( wxString::Format(
"Zone fill copper sliver regression: %s passed", relPath ) );
347 std::map<KIID, EDA_ITEM*> itemMap;
348 m_board->FillItemMap( itemMap );
350 for(
const DRC_ITEM& item : violations )
353 BOOST_ERROR( wxString::Format(
"Zone fill copper sliver regression: %s failed", relPath ) );
359 {
"teardrop_issue_JPC2", 5 },
366 const wxString& relPath =
test.first;
367 const int count =
test.second;
377 for(
ZONE* zone : m_board->Zones() )
379 if( zone->IsTeardropArea() )
383 BOOST_CHECK_MESSAGE( zoneCount == count,
"Expected " << count <<
" teardrop zones in "
384 << relPath <<
", found "
392 std::vector<wxString> tests = { {
"issue19956/issue19956" }
395 for(
const wxString& relPath : tests )
401 for(
ZONE* zone : m_board->Zones() )
405 std::shared_ptr<SHAPE> a_shape( zone->GetEffectiveShape( layer ) );
407 for(
PAD*
pad : m_board->GetPads() )
409 std::shared_ptr<SHAPE> pad_shape(
pad->GetEffectiveShape( layer ) );
410 int clearance = pad_shape->GetClearance( a_shape.get() );
411 BOOST_CHECK_MESSAGE(
pad->GetNetCode() == zone->GetNetCode() ||
clearance != 0,
412 wxString::Format(
"Pad %s from Footprint %s has net code %s and "
413 "is connected to zone with net code %s",
415 pad->GetParentFootprint()->GetReferenceAsString(),
417 zone->GetNetname() ) );
447 struct ScopeGuard {
bool& ref;
bool orig; ~ScopeGuard() { ref = orig; } } guard{ cfg.
m_ZoneFillIterativeRefill, originalIterativeRefill };
454 ZONE* gndZone =
nullptr;
456 for(
ZONE* zone : m_board->Zones() )
458 if( zone->GetNetname() ==
"GND" )
465 BOOST_REQUIRE_MESSAGE( gndZone !=
nullptr,
"GND zone not found in test board" );
469 bool hasOutline = m_board->GetBoardPolygonOutlines( boardOutline,
true );
470 BOOST_REQUIRE_MESSAGE( hasOutline,
"Board outline not found" );
472 double boardArea = 0.0;
483 double fillRatio = gndFilledArea / boardArea;
485 BOOST_TEST_MESSAGE( wxString::Format(
"Board area: %.2f sq mm, GND filled area: %.2f sq mm, "
486 "Fill ratio: %.1f%%",
487 boardArea / 1e6, gndFilledArea / 1e6,
488 fillRatio * 100.0 ) );
490 BOOST_CHECK_MESSAGE( fillRatio >= 0.25,
491 wxString::Format(
"GND zone fill ratio %.1f%% is less than expected 25%%. "
492 "This indicates issue 21746 - lower priority zones not "
493 "filling areas where higher priority isolated islands "
495 fillRatio * 100.0 ) );
520 int viasWithUnreachableFlashing = 0;
521 int totalConditionalVias = 0;
523 PCB_LAYER_ID in1Cu = m_board->GetLayerID( wxT(
"In1.Cu" ) );
524 PCB_LAYER_ID in2Cu = m_board->GetLayerID( wxT(
"In2.Cu" ) );
526 for(
PCB_TRACK* track : m_board->Tracks() )
533 if( !
via->GetRemoveUnconnected() )
536 totalConditionalVias++;
539 bool flashedOnIn1 =
via->FlashLayer( in1Cu );
540 bool flashedOnIn2 =
via->FlashLayer( in2Cu );
542 if( !flashedOnIn1 && !flashedOnIn2 )
546 int holeRadius =
via->GetDrillValue() / 2;
549 bool zoneReachesVia =
false;
551 for(
ZONE* zone : m_board->Zones() )
553 if( zone->GetIsRuleArea() )
556 if( zone->GetNetCode() !=
via->GetNetCode() )
561 if( !zone->IsOnLayer( layer ) )
564 if( !zone->HasFilledPolysForLayer( layer ) )
567 const std::shared_ptr<SHAPE_POLY_SET>& fill = zone->GetFilledPolysList( layer );
569 if( fill->Contains( viaCenter, -1, holeRadius ) )
571 zoneReachesVia =
true;
581 if( !zoneReachesVia && ( flashedOnIn1 || flashedOnIn2 ) )
582 viasWithUnreachableFlashing++;
585 BOOST_TEST_MESSAGE( wxString::Format(
"Total conditional vias: %d, Vias with unreachable "
586 "flashing: %d", totalConditionalVias,
587 viasWithUnreachableFlashing ) );
589 BOOST_CHECK_MESSAGE( viasWithUnreachableFlashing == 0,
590 wxString::Format(
"Found %d vias flashed on zone layers where the zone "
591 "fill doesn't actually reach them. This indicates "
592 "issue 22010 is not fixed.",
593 viasWithUnreachableFlashing ) );
615 int viasShortingZones = 0;
616 int totalConditionalVias = 0;
618 for(
PCB_TRACK* track : m_board->Tracks() )
625 if( !
via->GetRemoveUnconnected() )
628 totalConditionalVias++;
632 for(
ZONE* zone : m_board->Zones() )
634 if( zone->GetIsRuleArea() )
637 if( zone->GetNetCode() ==
via->GetNetCode() )
642 if( !
via->FlashLayer( layer ) )
645 if( !zone->HasFilledPolysForLayer( layer ) )
648 const std::shared_ptr<SHAPE_POLY_SET>& fill = zone->GetFilledPolysList( layer );
649 int viaRadius =
via->GetWidth( layer ) / 2;
651 if( fill->Contains( viaCenter, -1, viaRadius ) )
654 "Via at (%d, %d) on net %s is flashing on layer %s where zone "
655 "net %s is filled - this creates a short!",
656 viaCenter.
x, viaCenter.
y,
via->GetNetname(),
657 m_board->GetLayerName( layer ), zone->GetNetname() ) );
664 BOOST_TEST_MESSAGE( wxString::Format(
"Total conditional vias: %d, Vias shorting zones: %d",
665 totalConditionalVias, viasShortingZones ) );
667 BOOST_CHECK_MESSAGE( viasShortingZones == 0,
668 wxString::Format(
"Found %d vias flashed on layers where they short to "
669 "zones with different nets. This indicates issue 12964 "
671 viasShortingZones ) );
689 KI_TEST::LoadBoard( m_settingsManager,
"hatch_thermal_connectivity/hatch_thermal_connectivity",
694 m_board->BuildConnectivity();
696 int unconnectedCount = m_board->GetConnectivity()->GetUnconnectedCount(
false );
698 BOOST_CHECK_MESSAGE( unconnectedCount == 0,
699 wxString::Format(
"Found %d unconnected items after zone fill. "
700 "Hatch zone thermal reliefs should maintain connectivity "
701 "even with large hatch gaps.",
702 unconnectedCount ) );
726 PCB_LAYER_ID in1Cu = m_board->GetLayerID( wxT(
"In1.Cu" ) );
728 ZONE* gndZone =
nullptr;
730 for(
ZONE* zone : m_board->Zones() )
732 if( zone->GetNetname() ==
"GND" && zone->IsOnLayer( in1Cu ) )
739 BOOST_REQUIRE_MESSAGE( gndZone !=
nullptr,
"GND zone on In1.Cu not found in test board" );
747 "GND zone has no fill on In1.Cu" );
755 double zoneOutlineArea = gndZone->
Outline()->
Area();
757 BOOST_REQUIRE_MESSAGE( zoneOutlineArea > 0.0,
"Zone outline area must be positive" );
759 double fillArea = 0.0;
761 for(
int i = 0; i < fill->OutlineCount(); i++ )
762 fillArea +=
std::abs( fill->Outline( i ).Area() );
764 double fillRatio = fillArea / zoneOutlineArea;
768 BOOST_CHECK_GE( fillRatio, 0.90 );
791 struct ScopeGuard {
bool& ref;
bool orig; ~ScopeGuard() { ref = orig; } }
799 std::vector<ZONE*> keepouts;
801 for(
ZONE* zone : m_board->Zones() )
803 if( zone->GetIsRuleArea() && zone->GetDoNotAllowZoneFills() )
804 keepouts.push_back( zone );
807 BOOST_REQUIRE_MESSAGE( !keepouts.empty(),
"No zone keepouts found in test board" );
810 int violationCount = 0;
812 for(
ZONE* keepout : keepouts )
814 for(
PCB_LAYER_ID layer : keepout->GetLayerSet().Seq() )
819 for(
ZONE* zone : m_board->Zones() )
821 if( zone->GetIsRuleArea() )
824 if( !zone->IsOnLayer( layer ) )
827 if( !zone->HasFilledPolysForLayer( layer ) )
830 const std::shared_ptr<SHAPE_POLY_SET>& fill = zone->GetFilledPolysList( layer );
838 double intersectionArea = 0;
844 if( intersectionArea > 1e6 )
847 "Zone %s fill on layer %s overlaps keepout by %.2f sq mm",
849 m_board->GetLayerName( layer ),
850 intersectionArea / 1e6 ) );
858 BOOST_CHECK_MESSAGE( violationCount == 0,
859 wxString::Format(
"Found %d zone fills overlapping keepout areas. "
860 "This indicates issue 22809 - iterative refiller "
861 "ignores zone keepouts.", violationCount ) );
884 PCB_LAYER_ID in2Cu = m_board->GetLayerID( wxT(
"In2.Cu" ) );
885 int padsWithMissingFlashing = 0;
886 int totalConditionalPads = 0;
888 for(
FOOTPRINT* footprint : m_board->Footprints() )
890 for(
PAD*
pad : footprint->Pads() )
892 if( !
pad->GetRemoveUnconnected() )
895 if( !
pad->HasHole() )
898 if(
pad->GetNetname() !=
"VBUS_DUT" &&
pad->GetNetname() !=
"VBUS_DBG" )
901 totalConditionalPads++;
904 bool shouldFlash =
false;
906 for(
ZONE* zone : m_board->Zones() )
908 if( zone->GetIsRuleArea() )
911 if( zone->GetNetCode() !=
pad->GetNetCode() )
914 if( !zone->IsOnLayer( in2Cu ) )
917 if( zone->Outline()->Contains(
pad->GetPosition() ) )
924 if( shouldFlash && !
pad->FlashLayer( in2Cu ) )
927 "Pad %s at (%d, %d) on net %s is inside zone but not flashing on In2.Cu",
928 pad->GetNumber(),
pad->GetPosition().x,
pad->GetPosition().y,
929 pad->GetNetname() ) );
930 padsWithMissingFlashing++;
935 BOOST_TEST_MESSAGE( wxString::Format(
"Total conditional pads: %d, Pads with missing "
936 "flashing: %d", totalConditionalPads,
937 padsWithMissingFlashing ) );
939 BOOST_CHECK_MESSAGE( padsWithMissingFlashing == 0,
940 wxString::Format(
"Found %d TH pads that should flash on inner layers "
941 "but don't. This indicates issue 22826 is not fixed.",
942 padsWithMissingFlashing ) );
960 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr,
nullptr );
970 if( !commit.
Empty() )
974 int teardropCount = 0;
975 bool foundBadTeardrop =
false;
977 for(
ZONE* zone : m_board->Zones() )
979 if( !zone->IsTeardropArea() )
996 int concaveCount = 0;
998 for(
int i = 0; i <
chain.PointCount(); i++ )
1000 int prev = ( i == 0 ) ?
chain.PointCount() - 1 : i - 1;
1001 int next = ( i + 1 ) %
chain.PointCount();
1007 int64_t cross = (int64_t)
v1.x *
v2.y - (int64_t)
v1.y *
v2.x;
1017 if( concaveCount > 5 )
1020 "indicating possible corner intersection",
1022 foundBadTeardrop =
true;
1026 BOOST_CHECK_MESSAGE( teardropCount > 0,
"Expected at least one teardrop zone" );
1028 BOOST_CHECK_MESSAGE( !foundBadTeardrop,
1029 "Found teardrop with excessive concave vertices, indicating "
1030 "issue 19405 - teardrop curve intersecting rounded rectangle corner" );
1047 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr,
nullptr );
1057 if( !commit.
Empty() )
1061 int teardropCount = 0;
1062 bool foundBadTeardrop =
false;
1064 for(
ZONE* zone : m_board->Zones() )
1066 if( !zone->IsTeardropArea() )
1080 int concaveCount = 0;
1082 for(
int i = 0; i <
chain.PointCount(); i++ )
1084 int prev = ( i == 0 ) ?
chain.PointCount() - 1 : i - 1;
1085 int next = ( i + 1 ) %
chain.PointCount();
1090 int64_t cross = (int64_t)
v1.x *
v2.y - (int64_t)
v1.y *
v2.x;
1096 if( concaveCount > 5 )
1100 foundBadTeardrop =
true;
1104 BOOST_CHECK_MESSAGE( teardropCount > 0,
"Expected at least one teardrop zone" );
1106 BOOST_CHECK_MESSAGE( !foundBadTeardrop,
1107 "Found teardrop with excessive concave vertices on oval pad, "
1108 "indicating curve is not tangent to semicircular end" );
1125 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr,
nullptr );
1135 if( !commit.
Empty() )
1139 PAD* largePad =
nullptr;
1141 for(
FOOTPRINT* fp : m_board->Footprints() )
1143 for(
PAD*
pad : fp->Pads() )
1153 BOOST_REQUIRE_MESSAGE( largePad !=
nullptr,
"Expected a circular pad in test board" );
1159 int teardropCount = 0;
1160 bool foundBadTeardrop =
false;
1162 for(
ZONE* zone : m_board->Zones() )
1164 if( !zone->IsTeardropArea() )
1177 int concaveCount = 0;
1179 for(
int i = 0; i <
chain.PointCount(); i++ )
1181 int prev = ( i == 0 ) ?
chain.PointCount() - 1 : i - 1;
1182 int next = ( i + 1 ) %
chain.PointCount();
1187 int64_t cross = (int64_t)
v1.x *
v2.y - (int64_t)
v1.y *
v2.x;
1193 if( concaveCount > 5 )
1195 BOOST_TEST_MESSAGE( wxString::Format(
"Large circle teardrop has %d concave vertices",
1197 foundBadTeardrop =
true;
1202 int maxError = m_board->GetDesignSettings().m_MaxError;
1204 for(
int i = 0; i <
chain.PointCount(); i++ )
1207 double dist = ( pt - padCenter ).EuclideanNorm();
1210 if( dist > padRadius * 0.5 && dist < padRadius * 1.5 )
1212 double deviation =
std::abs( dist - padRadius );
1215 if( deviation > maxError * 5 && deviation < padRadius * 0.2 )
1218 "Teardrop point at distance %.2f from pad center (radius %.2f), "
1219 "deviation %.2f exceeds tolerance",
1220 dist / 1000.0, padRadius / 1000.0, deviation / 1000.0 ) );
1226 BOOST_CHECK_MESSAGE( teardropCount > 0,
"Expected at least one teardrop zone" );
1228 BOOST_CHECK_MESSAGE( !foundBadTeardrop,
1229 "Found teardrop with excessive concave vertices on large circle, "
1230 "indicating anchor points may not be on circle edge" );
1254 for(
ZONE* zone : m_board->Zones() )
1256 if( zone->GetIsRuleArea() )
1261 if( !zone->HasFilledPolysForLayer( layer ) )
1264 const std::shared_ptr<SHAPE_POLY_SET>& fill = zone->GetFilledPolysList( layer );
1266 for(
PAD*
pad : m_board->GetPads() )
1268 if( !
pad->IsOnLayer( layer ) )
1271 if(
pad->GetNetCode() == zone->GetNetCode() )
1274 std::shared_ptr<SHAPE> padShape =
pad->GetEffectiveShape( layer );
1275 int clearance = padShape->GetClearance( fill.get() );
1280 "Pad %s (net %s) at (%d, %d) has zero clearance to zone %s "
1282 pad->GetNumber(),
pad->GetNetname(),
1283 pad->GetPosition().x,
pad->GetPosition().y,
1284 zone->GetNetname(), m_board->GetLayerName( layer ) ) );
1291 BOOST_CHECK_MESSAGE( violations == 0,
1292 wxString::Format(
"Found %d pads with missing zone clearance. "
1293 "Coincident pads with different nets must not be "
1294 "deduplicated in zone fill knockout.",
1316 std::vector<DRC_ITEM> violations;
1321 [&](
const std::shared_ptr<DRC_ITEM>& aItem,
const VECTOR2I& aPos,
int aLayer,
1322 const std::function<
void(
PCB_MARKER* )>& aPathGenerator )
1326 BOARD_ITEM* item_a = m_board->ResolveItem( aItem->GetMainItemID() );
1327 BOARD_ITEM* item_b = m_board->ResolveItem( aItem->GetAuxItemID() );
1329 ZONE* zone_a =
dynamic_cast<ZONE*
>( item_a );
1330 ZONE* zone_b =
dynamic_cast<ZONE*
>( item_b );
1332 if( zone_a || zone_b )
1333 violations.push_back( *aItem );
1360 ZONE* hvZone =
nullptr;
1361 ZONE* lvZone =
nullptr;
1363 for(
ZONE* zone : m_board->Zones() )
1365 if( zone->GetNetname() ==
"HV_NET" )
1367 else if( zone->GetNetname() ==
"LV_NET" )
1376 hvZone, lvZone,
F_Cu );
1379 <<
" (expected " <<
pcbIUScale.mmToIU( 4.6 ) <<
")" );
1384 hvZone, lvZone,
In1_Cu );
1387 <<
" (expected " <<
pcbIUScale.mmToIU( 2.3 ) <<
")" );
1394 std::vector<DRC_ITEM> violations;
1399 [&](
const std::shared_ptr<DRC_ITEM>& aItem,
const VECTOR2I& aPos,
int aLayer,
1400 const std::function<
void(
PCB_MARKER* )>& aPathGenerator )
1404 BOARD_ITEM* item_a = m_board->ResolveItem( aItem->GetMainItemID() );
1405 BOARD_ITEM* item_b = m_board->ResolveItem( aItem->GetAuxItemID() );
1407 ZONE* zone_a =
dynamic_cast<ZONE*
>( item_a );
1408 ZONE* zone_b =
dynamic_cast<ZONE*
>( item_b );
1410 if( zone_a && zone_b )
1413 << aLayer <<
": " << aItem->GetErrorMessage(
true ) );
1414 violations.push_back( *aItem );
1427 KI_TEST::LoadBoard( m_settingsManager,
"issue23332_min_width/issue23332_min_width", m_board );
1433 for(
ZONE* zone : m_board->Zones() )
1435 int half_min_width = zone->GetMinThickness() / 2;
1442 if( !zone->HasFilledPolysForLayer( layer ) )
1445 std::shared_ptr<SHAPE_POLY_SET> fill = zone->GetFilledPolysList( layer );
1447 if( !fill || fill->OutlineCount() == 0 )
1452 for(
int ii = 0; ii < fill->OutlineCount(); ii++ )
1457 for(
int jj = 0; jj < fill->HoleCount( ii ); jj++ )
1458 island.
AddHole( fill->Hole( ii, jj ) );
1460 double originalArea = island.
Area();
1462 if( originalArea <= 0 )
1473 double prunedArea =
test.Area();
1474 double areaLoss = ( originalArea - prunedArea ) / originalArea;
1477 "Zone %s layer %d island %d: area=%.0f, loss=%.4f%%",
1478 zone->GetNetname(),
static_cast<int>( layer ), ii,
1479 originalArea, areaLoss * 100.0 ) );
1481 BOOST_CHECK_MESSAGE( areaLoss < 0.01,
1483 "Zone %s layer %d island %d lost %.2f%% area from "
1484 "min-width pruning (min_width=%.3fmm)",
1485 zone->GetNetname(),
static_cast<int>( layer ), ii,
1487 zone->GetMinThickness()
1488 /
static_cast<double>(
pcbIUScale.IU_PER_MM ) ) );
1503 for(
ZONE* zone : m_board->Zones() )
1505 int half_min_width = zone->GetMinThickness() / 2;
1512 if( !zone->HasFilledPolysForLayer( layer ) )
1515 std::shared_ptr<SHAPE_POLY_SET> fill = zone->GetFilledPolysList( layer );
1517 if( !fill || fill->OutlineCount() == 0 )
1520 for(
int ii = 0; ii < fill->OutlineCount(); ii++ )
1525 for(
int jj = 0; jj < fill->HoleCount( ii ); jj++ )
1526 island.
AddHole( fill->Hole( ii, jj ) );
1528 double originalArea = island.
Area();
1530 if( originalArea <= 0 )
1541 double prunedArea =
test.Area();
1542 double areaLoss = ( originalArea - prunedArea ) / originalArea;
1544 BOOST_CHECK_MESSAGE( areaLoss < 0.01,
1546 "Zone %s (priority %d) layer %d island %d lost "
1547 "%.2f%% area from min-width pruning, suggesting "
1548 "degenerate geometry from overlapping same-net zones",
1550 zone->GetAssignedPriority(),
1551 static_cast<int>( layer ), ii,
1552 areaLoss * 100.0 ) );
constexpr int ARC_HIGH_DEF
constexpr EDA_IU_SCALE pcbIUScale
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
Container for design settings for a BOARD object.
std::shared_ptr< DRC_ENGINE > m_DRCEngine
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
const MINOPTMAX< int > & GetValue() const
void RunTests(EDA_UNITS aUnits, bool aReportAllTrackErrors, bool aTestFootprints, BOARD_COMMIT *aCommit=nullptr)
Run the DRC tests.
void SetViolationHandler(DRC_VIOLATION_HANDLER aHandler)
Set an optional DRC violation handler (receives DRC_ITEMs and positions).
DRC_CONSTRAINT EvalRules(DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
void InitEngine(const wxFileName &aRulePath)
Initialize the DRC engine.
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
const wxString & GetNumber() const
VECTOR2I GetPosition() const override
const VECTOR2I & GetSize(PCB_LAYER_ID aLayer) const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
double Area(bool aAbsolute=true) const
Return the area of this chain.
Represent a set of closed polygons.
void BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
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.
double Area()
Return the area of this poly set.
int AddHole(const SHAPE_LINE_CHAIN &aHole, int aOutline=-1)
Adds a new hole to the given outline (default: last) and returns its index.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
void BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
int OutlineCount() const
Return the number of outlines in the set.
SHAPE_POLY_SET CloneDropTriangulation() const
TEARDROP_MANAGER manage and build teardrop areas A teardrop area is a polygonal area (a copper ZONE) ...
void UpdateTeardrops(BOARD_COMMIT &aCommit, const std::vector< BOARD_ITEM * > *dirtyPadsAndVias, const std::set< PCB_TRACK * > *dirtyTracks, bool aForceFullUpdate=false)
Update teardrops on a list of items.
Handle a list of polygons defining a copper zone.
std::shared_ptr< SHAPE_POLY_SET > GetFilledPolysList(PCB_LAYER_ID aLayer) const
double GetFilledArea()
This area is cached from the most recent call to CalculateFilledArea().
SHAPE_POLY_SET * Outline()
bool HasFilledPolysForLayer(PCB_LAYER_ID aLayer) const
double CalculateFilledArea()
Compute the area currently occupied by the zone fill.
@ CHAMFER_ALL_CORNERS
All angles are chamfered.
@ ROUND_ALL_CORNERS
All angles are rounded.
bool m_ZoneFillIterativeRefill
Enable iterative zone filling to handle isolated islands in higher priority zones.
PCB_LAYER_ID
A quick note on layer IDs:
void LoadBoard(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< BOARD > &aBoard)
void FillZones(BOARD *m_board)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
std::unique_ptr< BOARD > m_board
SETTINGS_MANAGER m_settingsManager
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
const SHAPE_LINE_CHAIN chain
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
BOOST_CHECK_EQUAL(result, "25.4")
static const std::vector< wxString > RegressionZoneFillTests_tests
static const std::vector< std::pair< wxString, int > > RegressionTeardropFill_tests
BOOST_DATA_TEST_CASE_F(ZONE_FILL_TEST_FIXTURE, RegressionZoneFillTests, boost::unit_test::data::make(RegressionZoneFillTests_tests), relPath)
static const std::vector< wxString > RegressionSliverZoneFillTests_tests
BOOST_FIXTURE_TEST_CASE(BasicZoneFills, ZONE_FILL_TEST_FIXTURE)
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
VECTOR2< int32_t > VECTOR2I