39#include <wx/filename.h>
69 for(
RULE_AREA& ra : aTool->GetData()->m_areas )
71 if( ra.m_ruleName.Contains( ( aName ) ) )
80 if( aPath.EndsWith( wxT(
"/" ) ) )
88 wxString
path = ra.m_sheetPath;
90 if(
path.EndsWith( wxT(
"/" ) ) )
115 if( ra.m_zone && ra.m_zone->GetPlacementAreaSource() == aGroupName )
129 if( gen->GetGeneratorType() != wxT(
"tuning_pattern" ) )
132 if( gen->HitTest( outline,
false ) )
149 if( aRAZone->
Outline()->
Contains( zone->Outline()->COutline( 0 ).Centre() ) )
161 for(
const ZONE* zone : aBoard->
Zones() )
163 if( zone == aRuleArea.
m_zone )
166 if( zone->GetZoneName() != aZoneName )
181 for(
const ZONE* zone : aBoard->
Zones() )
183 if( zone == aRuleArea.
m_zone )
186 const wxString&
name = zone->GetZoneName();
189 if(
name != aBaseName && !
name.StartsWith( aBaseName + wxT(
"_" ) ) )
204 std::vector<wxString> tests = {
"vme-wren" };
206 for(
const wxString& relPath : tests )
213 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
222 auto ruleData = mtTool->
GetData();
225 static_cast<int>( ruleData->m_areas.size() ) ) );
232 ruleData->m_replaceExisting =
true;
237 || ra.
m_sheetName == wxT(
"pp_driver_2x.kicad_sch" ) )
251 int n_areas_io = 0, n_areas_pp = 0, n_areas_other = 0;
254 static_cast<int>(ruleData->m_areas.size() ) ) );
256 for(
const RULE_AREA& ra : ruleData->m_areas )
260 if( ra.
m_ruleName.Contains( wxT(
"io_drivers_fp" ) ) )
265 else if( ra.
m_ruleName.Contains( wxT(
"io_drivers_pp" ) ) )
277 n_areas_io, n_areas_pp, n_areas_other ) );
283 const std::vector<wxString> rulesToTest = { wxT(
"io_drivers_fp" ),
284 wxT(
"io_drivers_pp" ) };
286 for(
const wxString& ruleName : rulesToTest )
288 for(
const RULE_AREA& refArea : ruleData->m_areas )
290 if( !refArea.
m_ruleName.Contains( ruleName ) )
295 for(
const RULE_AREA& targetArea : ruleData->m_areas )
300 if( !targetArea.
m_ruleName.Contains( ruleName ) )
303 auto cgRef = CONNECTION_GRAPH::BuildFromFootprintSet( refArea.
m_components,
306 CONNECTION_GRAPH::BuildFromFootprintSet( targetArea.
m_components,
311 std::vector<TMATCH::TOPOLOGY_MISMATCH_REASON> details;
312 bool status = cgRef->FindIsomorphism( cgTarget.get(),
result, details );
315 "topo match: '%s' [%d] -> '%s' [%d] result %d", refArea.
m_ruleName.c_str().AsChar(),
317 static_cast<int>( targetArea.
m_components.size() ), status ? 1 : 0 ) );
319 for(
const auto& iter :
result )
322 iter.second->GetReference(),
323 iter.first->GetReference() ) );
326 BOOST_CHECK( status );
327 BOOST_CHECK( details.empty() );
334 BOOST_ASSERT( refArea );
336 const std::vector<wxString> targetAreaNames( { wxT(
"io_drivers_fp/bank2/io78/" ),
337 wxT(
"io_drivers_fp/bank1/io78/" ),
338 wxT(
"io_drivers_fp/bank0/io01/" ) } );
340 for(
const wxString& targetRaName : targetAreaNames )
344 BOOST_ASSERT( targetRA !=
nullptr );
348 ruleData->m_compatMap[targetRA].m_doCopy =
true;
353 BOOST_ASSERT(
result >= 0 );
369 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
376 auto ruleData = mtTool->
GetData();
379 static_cast<int>( ruleData->m_areas.size() ) ) );
381 BOOST_CHECK( ruleData->m_areas.size() >= 2 );
383 if( ruleData->m_areas.size() < 2 )
391 if( ra.
m_ruleName.Contains( wxT(
"Untitled Sheet/" ) ) )
393 else if( ra.
m_ruleName.Contains( wxT(
"Untitled Sheet1/" ) ) )
397 if( !refArea || !targetArea )
399 BOOST_TEST_MESSAGE(
"Could not find Untitled Sheet and Untitled Sheet1 rule areas, skipping test" );
427 if( !refFP || !targetFP )
429 BOOST_TEST_MESSAGE(
"Could not find matching footprints in the rule areas, skipping test" );
434 bool refValueVisible = refValueField ? refValueField->
IsVisible() :
true;
436 std::vector<FP_3DMODEL> refModels = refFP->
Models();
440 ruleData->m_compatMap[targetArea].m_doCopy =
true;
441 ruleData->m_options.m_copyPlacement =
true;
445 BOOST_CHECK(
result >= 0 );
449 if( targetValueField && refValueField )
453 refValueVisible, targetValueField->
IsVisible() ) );
458 if( !refModels.empty() )
461 static_cast<int>( refModels.size() ),
462 static_cast<int>( targetFP->
Models().size() ) ) );
481 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
488 auto ruleData = mtTool->
GetData();
491 static_cast<int>( ruleData->m_areas.size() ) ) );
495 if( ruleData->m_areas.size() < 2 )
512 int refViaCountBefore = 0;
514 for(
PCB_TRACK* track : m_board->Tracks() )
526 BOOST_TEST_MESSAGE( wxString::Format(
"Reference area vias before repeat: %d", refViaCountBefore ) );
527 BOOST_CHECK( refViaCountBefore > 0 );
531 ruleData->m_compatMap[targetArea].m_doCopy =
true;
532 ruleData->m_options.m_copyPlacement =
true;
533 ruleData->m_options.m_copyRouting =
true;
537 BOOST_CHECK(
result >= 0 );
539 int refViaCountAfter = 0;
541 for(
PCB_TRACK* track : m_board->Tracks() )
553 BOOST_TEST_MESSAGE( wxString::Format(
"Reference area vias after repeat: %d", refViaCountAfter ) );
570 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
635 auto cgRef = std::make_unique<CONNECTION_GRAPH>();
636 auto cgTarget = std::make_unique<CONNECTION_GRAPH>();
639 LIB_ID fpid( wxT(
"Package_SO" ), wxT(
"SOIC-8_3.9x4.9mm_P1.27mm" ) );
651 PAD padRef1( &fpRef );
654 fpRef.
Add( &padRef1 );
656 PAD padRef2( &fpRef );
659 fpRef.
Add( &padRef2 );
661 PAD padTarget1( &fpTarget );
664 fpTarget.
Add( &padTarget1 );
666 PAD padTarget2( &fpTarget );
669 fpTarget.
Add( &padTarget2 );
672 cgRef->AddFootprint( &fpRef,
VECTOR2I( 0, 0 ) );
673 cgTarget->AddFootprint( &fpTarget,
VECTOR2I( 0, 0 ) );
675 cgRef->BuildConnectivity();
676 cgTarget->BuildConnectivity();
682 COMPONENT* cmpRef = cgRef->Components()[0];
683 COMPONENT* cmpTarget = cgTarget->Components()[0];
685 bool sameKind = cmpRef->IsSameKind( *cmpTarget );
687 BOOST_TEST_MESSAGE( wxString::Format(
"TRIM_1.1 and TRIM_2.1 IsSameKind: %d", sameKind ? 1 : 0 ) );
688 BOOST_CHECK( sameKind );
692 std::vector<TMATCH::TOPOLOGY_MISMATCH_REASON> details;
693 bool status = cgRef->FindIsomorphism( cgTarget.get(),
result, details );
695 BOOST_TEST_MESSAGE( wxString::Format(
"Topology match result: %d", status ? 1 : 0 ) );
697 if( !status && !details.empty() )
699 for(
const auto& reason : details )
702 reason.m_reference, reason.m_candidate, reason.m_reason ) );
706 BOOST_CHECK( status );
707 BOOST_CHECK( details.empty() );
710 fpRef.
Pads().clear();
711 fpTarget.
Pads().clear();
726 auto cgRef = std::make_unique<CONNECTION_GRAPH>();
727 auto cgTarget = std::make_unique<CONNECTION_GRAPH>();
729 LIB_ID fpid( wxT(
"_BugFpLib" ), wxT(
"SW_Hotswap" ) );
742 PAD padRef1( &fpRef );
745 fpRef.
Add( &padRef1 );
747 PAD padRef2( &fpRef );
750 fpRef.
Add( &padRef2 );
752 PAD padTarget1( &fpTarget );
755 fpTarget.
Add( &padTarget1 );
757 PAD padTarget2( &fpTarget );
760 fpTarget.
Add( &padTarget2 );
762 cgRef->AddFootprint( &fpRef,
VECTOR2I( 0, 0 ) );
763 cgTarget->AddFootprint( &fpTarget,
VECTOR2I( 0, 0 ) );
765 cgRef->BuildConnectivity();
766 cgTarget->BuildConnectivity();
771 COMPONENT* cmpRef = cgRef->Components()[0];
772 COMPONENT* cmpTarget = cgTarget->Components()[0];
774 BOOST_CHECK_MESSAGE( cmpRef->IsSameKind( *cmpTarget ),
775 "REF** placeholder must be the same kind as an annotated footprint "
776 "with matching FPID (issue 24585)" );
779 std::vector<TMATCH::TOPOLOGY_MISMATCH_REASON> details;
780 bool status = cgRef->FindIsomorphism( cgTarget.get(),
result, details );
784 for(
const auto& reason : details )
787 reason.m_reference, reason.m_candidate, reason.m_reason ) );
791 BOOST_CHECK_MESSAGE( status,
792 "Design block layout with an un-annotated REF** footprint must match "
793 "an annotated destination (issue 24585)" );
794 BOOST_CHECK( details.empty() );
796 fpRef.
Pads().clear();
797 fpTarget.
Pads().clear();
810 LIB_ID fpid( wxT(
"_BugFpLib" ), wxT(
"SW_Hotswap" ) );
811 LIB_ID otherFpid( wxT(
"_BugFpLib" ), wxT(
"R_0402" ) );
824 BOOST_CHECK_MESSAGE( !cmpUnrelated.IsSameKind( cmpTarget ),
825 "Two annotated footprints with unrelated prefixes must not match even "
826 "with the same FPID (issue 24585)" );
830 fpPlaceholder.
SetFPID( otherFpid );
834 BOOST_CHECK_MESSAGE( !cmpPlaceholder.IsSameKind( cmpTarget ),
835 "A REF** placeholder must not match a target with a different FPID "
855 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
862 auto ruleData = mtTool->
GetData();
870 if( ra.
m_sheetPath == wxT(
"/io_drivers_fp/bank0/io01/" ) )
872 else if( ra.
m_sheetPath == wxT(
"/io_drivers_fp/bank0/" ) )
874 else if( ra.
m_sheetPath == wxT(
"/io_drivers_fp/" ) )
882 BOOST_TEST_MESSAGE( wxString::Format(
"Leaf /io_drivers_fp/bank0/io01/ components: %d",
921 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
928 auto ruleData = mtTool->
GetData();
934 if( ra.
m_sheetName == wxT(
"io_driver.kicad_sch" ) )
948 auto cgRef = CONNECTION_GRAPH::BuildFromFootprintSet( refArea->
m_components,
950 auto cgTarget = CONNECTION_GRAPH::BuildFromFootprintSet( targetArea->
m_components,
955 std::atomic<bool> cancelled(
true );
956 std::atomic<int> matched( 0 );
957 std::atomic<int> total( 0 );
965 std::vector<TMATCH::TOPOLOGY_MISMATCH_REASON> details;
967 bool status = cgRef->FindIsomorphism( cgTarget.get(),
result, details, params );
969 BOOST_CHECK( !status );
970 BOOST_CHECK(
result.empty() );
977 std::atomic<bool> cancelled(
false );
978 std::atomic<int> matched( 0 );
979 std::atomic<int> total( 0 );
987 std::vector<TMATCH::TOPOLOGY_MISMATCH_REASON> details;
989 bool status = cgRef->FindIsomorphism( cgTarget.get(),
result, details, params );
991 BOOST_CHECK( status );
993 int finalMatched = matched.load();
994 int finalTotal = total.load();
996 BOOST_TEST_MESSAGE( wxString::Format(
"Progress: matched=%d, total=%d", finalMatched, finalTotal ) );
998 BOOST_CHECK( finalTotal > 0 );
1005 std::vector<TMATCH::TOPOLOGY_MISMATCH_REASON> details;
1007 bool status = cgRef->FindIsomorphism( cgTarget.get(),
result, details );
1009 BOOST_CHECK( status );
1010 BOOST_CHECK( !
result.empty() );
1036 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
1043 auto ruleData = mtTool->
GetData();
1046 static_cast<int>( ruleData->m_areas.size() ) ) );
1053 for(
RULE_AREA& ra : ruleData->m_areas )
1060 if(
source == wxT(
"/i2c_thingy_ch0/" ) )
1062 else if(
source == wxT(
"/i2c_thingy_ch1/" ) )
1066 BOOST_REQUIRE_MESSAGE( ch0Area !=
nullptr,
"Could not find i2c_thingy_ch0 rule area" );
1067 BOOST_REQUIRE_MESSAGE( ch1Area !=
nullptr,
"Could not find i2c_thingy_ch1 rule area" );
1075 auto cgRef = CONNECTION_GRAPH::BuildFromFootprintSet( ch0Area->
m_components,
1077 auto cgTarget = CONNECTION_GRAPH::BuildFromFootprintSet( ch1Area->
m_components,
1081 std::vector<TMATCH::TOPOLOGY_MISMATCH_REASON> details;
1082 bool status = cgRef->FindIsomorphism( cgTarget.get(),
result, details );
1086 for(
const auto& reason : details )
1089 reason.m_reference, reason.m_candidate,
1090 reason.m_reason ) );
1094 BOOST_CHECK_MESSAGE( status,
1095 "Topology match failed for channels with hierarchical pins "
1096 "tied to global nets (issue 21739)" );
1110 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
1113 auto addNet = [&](
const wxString& aName ) ->
int
1120 const int netGnd = addNet( wxT(
"GND" ) );
1121 const int netVcc = addNet( wxT(
"+5VP" ) );
1122 const int netChainInRef = addNet( wxT(
"Net-(D-RefChainIn)" ) );
1123 const int netBridge = addNet( wxT(
"Net-(D38-DOUT)" ) );
1124 const int netChainOutTgt = addNet( wxT(
"Net-(D43-DOUT)" ) );
1125 const int netD2Dout = addNet( wxT(
"unconnected-(D2-DOUT)" ) );
1126 const int netD3Dout = addNet( wxT(
"unconnected-(D3-DOUT)" ) );
1127 const int netD5Dout = addNet( wxT(
"unconnected-(D5-DOUT)" ) );
1128 const int netD6Dout = addNet( wxT(
"unconnected-(D6-DOUT)" ) );
1130 LIB_ID ledId( wxT(
"TestLib" ), wxT(
"WS2812" ) );
1134 [&](
const wxString& aRef,
int aDout,
int aDin ) ->
FOOTPRINT*
1142 [&](
const wxString& aNumber,
int aNetCode )
1146 pad->SetNumber( aNumber );
1151 pad->SetNetCode( aNetCode );
1155 addPad( wxT(
"1" ), aDout );
1156 addPad( wxT(
"2" ), netGnd );
1157 addPad( wxT(
"3" ), aDin );
1158 addPad( wxT(
"4" ), netVcc );
1165 std::set<FOOTPRINT*> refFps;
1166 refFps.insert( makeLed( wxT(
"D1" ), netBridge, netChainInRef ) );
1167 refFps.insert( makeLed( wxT(
"D2" ), netD2Dout, netChainInRef ) );
1168 refFps.insert( makeLed( wxT(
"D3" ), netD3Dout, netChainInRef ) );
1172 std::set<FOOTPRINT*> tgtFps;
1173 tgtFps.insert( makeLed( wxT(
"D4" ), netChainOutTgt, netBridge ) );
1174 tgtFps.insert( makeLed( wxT(
"D5" ), netD5Dout, netBridge ) );
1175 tgtFps.insert( makeLed( wxT(
"D6" ), netD6Dout, netBridge ) );
1177 auto cgRef = CONNECTION_GRAPH::BuildFromFootprintSet( refFps, tgtFps );
1178 auto cgTarget = CONNECTION_GRAPH::BuildFromFootprintSet( tgtFps, refFps );
1181 std::vector<TMATCH::TOPOLOGY_MISMATCH_REASON> details;
1182 bool status = cgRef->FindIsomorphism( cgTarget.get(),
result, details );
1186 for(
const auto& reason : details )
1189 reason.m_reference, reason.m_candidate,
1190 reason.m_reason ) );
1194 BOOST_CHECK_MESSAGE( status,
1195 "Topology match failed because the design-block boundary signal net "
1196 "was misclassified as a global rail and excluded asymmetrically" );
1210 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
1212 auto addNet = [&](
const wxString& aName ) ->
int
1219 const int netGnd = addNet( wxT(
"GND" ) );
1220 const int netVcc = addNet( wxT(
"+3V3" ) );
1222 const LIB_ID cap0201( wxT(
"Capacitor_SMD" ), wxT(
"C_0201_0603Metric" ) );
1223 const LIB_ID cap0402( wxT(
"Capacitor_SMD" ), wxT(
"C_0402_1005Metric" ) );
1225 auto makeCap = [&](
const wxString& aRef,
const LIB_ID& aFpId ) ->
FOOTPRINT*
1232 for(
const wxString& padNumber : { wxString( wxT(
"1" ) ), wxString( wxT(
"2" ) ) } )
1235 pad->SetNumber( padNumber );
1239 pad->SetNetCode( padNumber == wxT(
"1" ) ? netVcc : netGnd );
1248 std::set<FOOTPRINT*> blockFps;
1249 std::set<FOOTPRINT*> groupFps;
1251 for(
int i = 0; i < 8; i++ )
1253 blockFps.insert( makeCap( wxString::Format( wxT(
"C%d" ), 600 + i ), cap0201 ) );
1254 groupFps.insert( makeCap( wxString::Format( wxT(
"C%d" ), 600 + i ), cap0201 ) );
1257 blockFps.insert( makeCap( wxT(
"C619" ), cap0201 ) );
1258 groupFps.insert( makeCap( wxT(
"C619" ), cap0402 ) );
1260 auto cgRef = CONNECTION_GRAPH::BuildFromFootprintSet( blockFps, groupFps );
1261 auto cgTarget = CONNECTION_GRAPH::BuildFromFootprintSet( groupFps, blockFps );
1264 std::vector<TMATCH::TOPOLOGY_MISMATCH_REASON> details;
1266 BOOST_CHECK( !cgRef->FindIsomorphism( cgTarget.get(),
result, details ) );
1269 for(
const auto& reason : details )
1271 BOOST_TEST_MESSAGE( wxString::Format(
"Mismatch: %s <-> %s: %s", reason.m_reference, reason.m_candidate,
1272 reason.m_reason ) );
1291 m_board = std::make_unique<BOARD>();
1296 m_board->Add( net );
1298 auto makeFootprint =
1307 pad->SetNumber( wxT(
"1" ) );
1309 pad->SetPosition( aPos );
1321 FOOTPRINT* refFp1 = makeFootprint( wxT(
"R1" ),
1323 FOOTPRINT* refFp2 = makeFootprint( wxT(
"R2" ),
1331 m_board->Add( silkRect );
1334 FOOTPRINT* destFp1 = makeFootprint( wxT(
"R3" ),
1336 FOOTPRINT* destFp2 = makeFootprint( wxT(
"R4" ),
1340 destGroup->
SetName( wxT(
"design-block-dest" ) );
1341 destGroup->
AddItem( destFp1 );
1342 destGroup->
AddItem( destFp2 );
1343 m_board->Add( destGroup );
1352 m_board->Add( unrelatedSilk );
1356 for(
BOARD_ITEM* item : m_board->Drawings() )
1362 BOOST_REQUIRE_EQUAL( silkBefore, 2 );
1395 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
1401 .m_connectedRoutingOnly =
false,
1402 .m_copyPlacement =
true,
1403 .m_copyOtherItems =
true,
1404 .m_groupItems =
false,
1405 .m_includeLockedItems =
true };
1408 BOOST_CHECK_MESSAGE(
result >= 0,
"RepeatLayout failed" );
1417 int silkInGroup = 0;
1418 bool unrelatedSurvived =
false;
1421 for(
BOARD_ITEM* item : m_board->Drawings() )
1428 if( item == unrelatedSilk )
1429 unrelatedSurvived =
true;
1431 if( item->GetParentGroup() == destGroup )
1442 BOOST_CHECK_MESSAGE( silkAfter == 3,
1443 wxString::Format(
"Expected 3 silkscreen shapes after Apply Design Block "
1444 "Layout (2 original + 1 copy), found %d (issue 24372)",
1446 BOOST_CHECK_MESSAGE( silkInGroup == 1,
1447 wxString::Format(
"Expected 1 silkscreen shape in destination group, "
1448 "found %d (issue 24372)",
1450 BOOST_CHECK_MESSAGE( unrelatedSurvived,
1451 "Unrelated silkscreen drawing outside the design block group was "
1452 "deleted by Apply Design Block Layout (issue 24372)" );
1468 m_board = std::make_unique<BOARD>();
1472 m_board->Add( net );
1474 auto makeFootprint = [&](
const wxString& aRef,
const VECTOR2I& aPos ) ->
FOOTPRINT*
1482 pad->SetNumber( wxT(
"1" ) );
1484 pad->SetPosition( aPos );
1500 for(
FOOTPRINT* fp : { refFp1, refFp2 } )
1501 fp->GetField(
FIELD_T::VALUE )->SetTextAngle( sourceFieldAngle );
1507 for(
FOOTPRINT* fp : { destFp1, destFp2 } )
1508 fp->SetOrientation( blockRotation );
1511 destGroup->
SetName( wxT(
"design-block-dest" ) );
1512 destGroup->
AddItem( destFp1 );
1513 destGroup->
AddItem( destFp2 );
1514 m_board->Add( destGroup );
1544 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
1550 .m_connectedRoutingOnly =
false,
1551 .m_copyPlacement =
true,
1552 .m_copyOtherItems =
true,
1553 .m_groupItems =
false,
1554 .m_includeLockedItems =
true };
1557 BOOST_REQUIRE_MESSAGE(
result >= 0,
"RepeatLayout failed" );
1564 const double expected = ( sourceFieldAngle + blockRotation ).AsDegrees();
1566 for(
FOOTPRINT* fp : { destFp1, destFp2 } )
1574 wxString::Format(
"Field on %s rotated to %.3f deg, expected %.3f deg "
1575 "(field double-rotation regression)",
1591 for(
bool nested : {
false,
true } )
1595 m_board = std::make_unique<BOARD>();
1599 m_board->Add( shared );
1601 auto makeFootprint =
1606 fp->
SetFPID(
LIB_ID( wxT(
"TestLib" ), wxT(
"Receptacle" ) ) );
1615 pad->SetNumber( wxT(
"1" ) );
1617 pad->SetPosition( aPos );
1623 pad->SetNet( aNet );
1630 const KIID refSheet, destSheet, innerA, innerB, symA;
1631 const KIID symB = nested ? symA :
KIID();
1634 [&](
const KIID& aSheet,
const KIID& aInner,
const KIID& aSymbol )
1639 aInner.AsString(), aSymbol.AsString() ) );
1642 return KIID_PATH( wxT(
"/" ) + aSymbol.AsString() );
1647 makeFootprint( wxT(
"J5" ),
VECTOR2I( 0, 0 ), pathOf( refSheet, innerA, symA ),
nullptr );
1649 pathOf( refSheet, innerB, symB ),
nullptr );
1654 pathOf( destSheet, innerA, symA ), shared );
1657 pathOf( destSheet, innerB, symB ), shared );
1661 std::set<FOOTPRINT*> refSet{ refFpA, refFpB };
1662 std::set<FOOTPRINT*> destSet{ destFpA, destFpB };
1663 auto cgRef = CONNECTION_GRAPH::BuildFromFootprintSet( refSet, destSet );
1664 auto cgTarget = CONNECTION_GRAPH::BuildFromFootprintSet( destSet, refSet );
1666 std::vector<TMATCH::TOPOLOGY_MISMATCH_REASON> details;
1667 BOOST_REQUIRE_MESSAGE( !cgRef->FindIsomorphism( cgTarget.get(), topoOnly, details ),
1668 "Test precondition broken: areas are net isomorphic" );
1672 destGroup->
SetName( wxT(
"design-block-dest" ) );
1673 destGroup->
AddItem( destFpA );
1674 destGroup->
AddItem( destFpB );
1675 m_board->Add( destGroup );
1705 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
1710 .m_connectedRoutingOnly =
false,
1711 .m_copyPlacement =
true,
1712 .m_copyOtherItems =
true,
1713 .m_groupItems =
false,
1714 .m_includeLockedItems =
true };
1721 BOOST_CHECK_MESSAGE(
result >= 0,
"Apply Design Block Layout aborted even though the symbol instance paths "
1722 "give an unambiguous mapping (No compatible component regression)" );
1727 wxString::Format(
"Destination relative placement wrong, expected "
1728 "(10mm,0) got (%d,%d) IU",
1745 m_board = std::make_unique<BOARD>();
1749 m_board->Add( net );
1751 auto makeFootprint = [&](
const wxString& aRef,
const VECTOR2I& aPos ) ->
FOOTPRINT*
1762 txt->
SetText( wxT(
"${REFERENCE}" ) );
1769 pad->SetNumber( wxT(
"1" ) );
1771 pad->SetPosition( aPos );
1786 if( item->Type() ==
PCB_TEXT_T && item->GetLayer() == layer )
1800 destGroup->
SetName( wxT(
"design-block-dest" ) );
1801 destGroup->
AddItem( destFp1 );
1802 destGroup->
AddItem( destFp2 );
1803 m_board->Add( destGroup );
1805 BOOST_REQUIRE_EQUAL( countSilkText( destFp1,
F_SilkS ), 1 );
1806 BOOST_REQUIRE_EQUAL( countSilkText( destFp1,
B_SilkS ), 1 );
1836 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
1842 .m_connectedRoutingOnly =
false,
1843 .m_copyPlacement =
true,
1844 .m_copyOtherItems =
true,
1845 .m_groupItems =
false,
1846 .m_includeLockedItems =
true };
1850 BOOST_CHECK_MESSAGE(
result >= 0, wxString::Format(
"RepeatLayout failed: %s", err ) );
1855 for(
FOOTPRINT* destFp : { destFp1, destFp2 } )
1857 BOOST_CHECK_MESSAGE( countSilkText( destFp,
F_SilkS ) == 1,
1858 wxString::Format(
"%s lost its F.Silkscreen reference text "
1859 "(issue 24583): F=%d B=%d",
1860 destFp->GetReference(), countSilkText( destFp,
F_SilkS ),
1861 countSilkText( destFp,
B_SilkS ) ) );
1873 m_board = std::make_unique<BOARD>();
1897 m_board->Add( destPlaceholder );
1900 destGroup->
SetName( wxT(
"design-block-dest" ) );
1901 destGroup->
AddItem( destPlaceholder );
1902 m_board->Add( destGroup );
1906 for(
BOARD_ITEM* item : m_board->Drawings() )
1912 BOOST_REQUIRE_EQUAL( silkBefore, 2 );
1940 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
1946 .m_connectedRoutingOnly =
false,
1947 .m_copyPlacement =
true,
1948 .m_copyOtherItems =
true,
1949 .m_groupItems =
false,
1950 .m_includeLockedItems =
true };
1958 BOOST_REQUIRE_MESSAGE(
result >= 0, wxString::Format(
"RepeatLayout failed for a footprint-free "
1959 "(graphics-only) design block (issue 24592): %s",
1967 for(
BOARD_ITEM* item : m_board->Drawings() )
1980 BOOST_CHECK_MESSAGE( silkAfter == 2, wxString::Format(
"Expected 2 silkscreen shapes after Apply Design Block "
1981 "Layout (source + 1 copy, placeholder replaced), found "
1984 BOOST_REQUIRE_MESSAGE( copiedRect !=
nullptr,
"Footprint-free block graphic was not copied (issue 24592)" );
1986 "Copied block graphic was not added to the destination group (issue 24592)" );
1997 m_board = std::make_unique<BOARD>();
2001 m_board->Add( net );
2010 m_board->Add( srcTrack );
2012 BOOST_REQUIRE_EQUAL( srcTrack->
GetNetCode(), 1 );
2020 m_board->Add( destPlaceholder );
2023 destGroup->
SetName( wxT(
"design-block-dest" ) );
2024 destGroup->
AddItem( destPlaceholder );
2025 m_board->Add( destGroup );
2053 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
2059 .m_connectedRoutingOnly =
false,
2060 .m_copyPlacement =
true,
2061 .m_copyOtherItems =
true,
2062 .m_groupItems =
false,
2063 .m_includeLockedItems =
true };
2071 BOOST_REQUIRE_MESSAGE(
result >= 0, wxString::Format(
"RepeatLayout failed for a footprint-free copper "
2072 "block (issue 24592): %s",
2078 for(
PCB_TRACK* track : m_board->Tracks() )
2080 if( track != srcTrack )
2081 copiedTrack = track;
2084 BOOST_REQUIRE_MESSAGE( copiedTrack !=
nullptr,
"Footprint-free block track was not copied (issue 24592)" );
2085 BOOST_CHECK_MESSAGE( copiedTrack->
GetNetCode() == 0,
2086 wxString::Format(
"Copied copper should be no-net, got net code %d "
2090 "Copied copper was not added to the destination group (issue 24592)" );
2105 m_board = std::make_unique<BOARD>();
2114 m_board->Add( srcRect );
2122 m_board->Add( destPlaceholder );
2125 destGroup->
SetName( wxT(
"design-block-dest" ) );
2126 destGroup->
AddItem( destPlaceholder );
2127 m_board->Add( destGroup );
2131 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
2136 auto applyOnce = [&]() ->
int
2163 .m_connectedRoutingOnly =
false,
2164 .m_copyPlacement =
true,
2165 .m_copyOtherItems =
true,
2166 .m_groupItems =
false,
2167 .m_includeLockedItems =
true };
2176 BOOST_REQUIRE_MESSAGE( applyOnce() >= 0,
"First apply failed (issue 24592)" );
2177 BOOST_REQUIRE_MESSAGE( applyOnce() >= 0,
"Second apply failed (issue 24592)" );
2183 for(
BOARD_ITEM* item : m_board->Drawings() )
2192 BOOST_CHECK_MESSAGE( rects == 2, wxString::Format(
"Re-apply stacked copies: expected 2 rectangles "
2193 "(source + 1 copy), found %d (issue 24592)",
2207 m_board = std::make_unique<BOARD>();
2211 m_board->Add( net );
2220 m_board->Add( srcTrack );
2228 m_board->Add( destPlaceholder );
2231 destGroup->
SetName( wxT(
"design-block-dest" ) );
2232 destGroup->
AddItem( destPlaceholder );
2233 m_board->Add( destGroup );
2241 m_board->Add( siblingTrack );
2244 siblingGroup->
SetName( wxT(
"design-block-sibling" ) );
2245 siblingGroup->
AddItem( siblingTrack );
2246 m_board->Add( siblingGroup );
2254 m_board->Add( looseTrack );
2282 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
2288 .m_connectedRoutingOnly =
false,
2289 .m_copyPlacement =
true,
2290 .m_copyOtherItems =
true,
2291 .m_groupItems =
false,
2292 .m_includeLockedItems =
true };
2300 BOOST_REQUIRE_MESSAGE(
result >= 0, wxString::Format(
"RepeatLayout failed: %s", err ) );
2303 int siblingTracks = 0;
2304 int looseTracks = 0;
2306 for(
PCB_TRACK* track : m_board->Tracks() )
2308 int y = track->GetStart().y;
2316 BOOST_CHECK_MESSAGE( siblingTracks == 1,
2317 wxString::Format(
"Sibling group routing was deleted (issue 24767): found %d, expected 1",
2319 BOOST_CHECK_MESSAGE( looseTracks == 1,
2320 wxString::Format(
"Loose no-net routing in the target area was deleted (issue 24944): "
2321 "found %d, expected 1",
2333 m_board = std::make_unique<BOARD>();
2338 m_board->Add( net1 );
2339 m_board->Add( net2 );
2341 auto addTrack = [&](
double aStartX,
double aStartY,
double aEndX,
double aEndY,
NETINFO_ITEM* aNet )
2349 m_board->Add( track );
2362 m_board->Add( destPlaceholder );
2367 destGroup->
SetName( wxT(
"design-block-dest" ) );
2368 destGroup->
AddItem( destPlaceholder );
2369 destGroup->
AddItem( prevTrack );
2370 m_board->Add( destGroup );
2408 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
2414 .m_connectedRoutingOnly =
false,
2415 .m_copyPlacement =
true,
2416 .m_copyOtherItems =
true,
2417 .m_groupItems =
false,
2418 .m_includeLockedItems =
true };
2426 BOOST_REQUIRE_MESSAGE(
result >= 0, wxString::Format(
"RepeatLayout failed: %s", err ) );
2429 int unrelatedTracks = 0;
2431 int copiedTracks = 0;
2432 int lockedTracks = 0;
2433 int staleTweakTracks = 0;
2435 for(
PCB_TRACK* track : m_board->Tracks() )
2437 int y = track->GetStart().y;
2451 BOOST_CHECK_MESSAGE( unrelatedTracks == 1,
2452 wxString::Format(
"Unrelated net routing in the target area was deleted (issue 24944): "
2453 "found %d, expected 1",
2454 unrelatedTracks ) );
2455 BOOST_CHECK_MESSAGE( lockedTracks == 1,
2456 wxString::Format(
"Locked bystander routing in the target area was deleted (issue 24944): "
2457 "found %d, expected 1",
2459 BOOST_CHECK_MESSAGE(
2461 wxString::Format(
"The group's own routing should be replaced: found %d, expected 0", prevTracks ) );
2462 BOOST_CHECK_MESSAGE( staleTweakTracks == 0,
2463 wxString::Format(
"Loose routing on the group's nets should be replaced: found %d, "
2465 staleTweakTracks ) );
2466 BOOST_CHECK_MESSAGE( copiedTracks == 1,
2467 wxString::Format(
"Block routing was not copied into the target area: found %d, expected 1",
2485 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
2492 auto ruleData = mtTool->
GetData();
2495 static_cast<int>( ruleData->m_areas.size() ) ) );
2497 BOOST_REQUIRE_EQUAL( ruleData->m_areas.size(), 4 );
2500 const size_t sharedCount = ruleData->m_areas.front().m_components.size();
2504 for(
const RULE_AREA& ra : ruleData->m_areas )
2507 RULE_AREA* refArea = &ruleData->m_areas.front();
2511 BOOST_REQUIRE_EQUAL( ruleData->m_compatMap.size(), ruleData->m_areas.size() - 1 );
2513 for(
const auto& [targetArea, compatData] : ruleData->m_compatMap )
2515 BOOST_CHECK_MESSAGE( !compatData.m_isOk,
2516 "Duplicate placement area was wrongly reported as a valid copy target "
2518 BOOST_CHECK( !compatData.m_mismatchReasons.empty() );
2522 RULE_AREA* targetArea = &ruleData->m_areas[1];
2529 BOOST_CHECK_MESSAGE(
result < 0,
2530 "RepeatLayout copied a Rule Area onto an identical-component area "
2532 BOOST_CHECK( !err.IsEmpty() );
2554 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
2561 auto ruleData = mtTool->
GetData();
2564 static_cast<int>( ruleData->m_areas.size() ) ) );
2566 BOOST_REQUIRE_EQUAL( ruleData->m_areas.size(), 4 );
2570 for(
RULE_AREA& ra : ruleData->m_areas )
2578 std::set<KIID> groupUuidsBefore;
2579 std::set<wxString> userGroupNamesBefore;
2583 groupUuidsBefore.insert(
group->m_Uuid );
2585 if( !
group->GetName().IsEmpty() )
2586 userGroupNamesBefore.insert(
group->GetName() );
2591 for(
auto& [targetArea, compatData] : ruleData->m_compatMap )
2592 compatData.m_doCopy =
true;
2594 ruleData->m_options.m_copyPlacement =
true;
2595 ruleData->m_options.m_copyRouting =
true;
2596 ruleData->m_options.m_copyOtherItems =
true;
2597 ruleData->m_options.m_groupItems =
true;
2598 ruleData->m_options.m_includeLockedItems =
true;
2604 int clonedUserGroups = 0;
2608 bool isNew = !groupUuidsBefore.contains(
group->m_Uuid );
2610 if( isNew && userGroupNamesBefore.contains(
group->GetName() ) )
2614 BOOST_CHECK_MESSAGE( clonedUserGroups == 0,
2615 wxString::Format(
"Repeat layout cloned %d unrelated user groups "
2617 clonedUserGroups ) );
2636 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
2643 auto ruleData = mtTool->
GetData();
2645 BOOST_REQUIRE_EQUAL( ruleData->m_areas.size(), 2 );
2650 for(
RULE_AREA& ra : ruleData->m_areas )
2652 if( ra.
m_ruleName.Contains( wxT(
"Untitled Sheet/" ) ) )
2654 else if( ra.
m_ruleName.Contains( wxT(
"Untitled Sheet1/" ) ) )
2664 auto cgRef = CONNECTION_GRAPH::BuildFromFootprintSet( refArea->
m_components,
2666 auto cgTarget = CONNECTION_GRAPH::BuildFromFootprintSet( targetArea->
m_components,
2670 std::vector<TMATCH::TOPOLOGY_MISMATCH_REASON> details;
2671 bool status = cgRef->FindIsomorphism( cgTarget.get(),
result, details );
2674 BOOST_CHECK( !status );
2679 std::set<wxString> refRefDes;
2680 std::set<wxString> targetRefDes;
2688 bool sawConnectivityReason =
false;
2690 for(
const auto& reason : details )
2693 reason.m_candidate, reason.m_reason ) );
2697 BOOST_CHECK( !reason.m_reason.Contains( wxT(
"No compatible component found" ) ) );
2699 if( reason.m_reason.Contains( wxT(
"connects to" ) )
2700 || reason.m_reason.Contains( wxT(
"connectivity" ) ) )
2702 sawConnectivityReason =
true;
2706 BOOST_CHECK_MESSAGE( refRefDes.count( reason.m_reference ) > 0,
2707 wxString::Format(
"Reason reference '%s' should be a reference-area "
2708 "component", reason.m_reference ) );
2709 BOOST_CHECK_MESSAGE( targetRefDes.count( reason.m_candidate ) > 0,
2710 wxString::Format(
"Reason candidate '%s' should be a target-area "
2711 "component", reason.m_candidate ) );
2715 BOOST_CHECK_MESSAGE( sawConnectivityReason,
2716 "Topology mismatch message should explain the connectivity difference "
2717 "rather than report a generic missing-component error (issue 24192)" );
2731 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
2734 [&](
const wxString& aName ) ->
int
2741 const int netGnd = addNet( wxT(
"GND" ) );
2742 const int netP3V3 = addNet( wxT(
"+3V3" ) );
2743 const int netCollide = addNet( wxT(
"Net-(D3-A)" ) );
2744 const int netRefY = addNet( wxT(
"Net-(D4-A)" ) );
2745 const int netTgtX = addNet( wxT(
"Net-(D2-A)" ) );
2747 LIB_ID ledAId( wxT(
"TestLib" ), wxT(
"LED_A" ) );
2748 LIB_ID ledBId( wxT(
"TestLib" ), wxT(
"LED_B" ) );
2749 LIB_ID resId( wxT(
"TestLib" ), wxT(
"R" ) );
2752 [&](
FOOTPRINT* fp,
const wxString& aNum,
int aNet )
2756 pad->SetNumber( aNum );
2760 pad->SetNetCode( aNet );
2776 [&](
const LIB_ID& aLedId,
const wxString& aLedRef,
const wxString& aResRef,
int aAnodeNet,
2777 std::set<FOOTPRINT*>& aSet )
2779 FOOTPRINT* led = addFp( aLedId, aLedRef );
2780 addPad( led, wxT(
"1" ), netGnd );
2781 addPad( led, wxT(
"2" ), aAnodeNet );
2785 addPad(
res, wxT(
"1" ), aAnodeNet );
2786 addPad(
res, wxT(
"2" ), netP3V3 );
2791 std::set<FOOTPRINT*> refFps;
2792 addLedAndRes( ledAId, wxT(
"D3" ), wxT(
"R27" ), netCollide, refFps );
2793 addLedAndRes( ledBId, wxT(
"D4" ), wxT(
"R30" ), netRefY, refFps );
2796 std::set<FOOTPRINT*> tgtFps;
2797 addLedAndRes( ledAId, wxT(
"D2" ), wxT(
"R1" ), netTgtX, tgtFps );
2798 addLedAndRes( ledBId, wxT(
"D3" ), wxT(
"R2" ), netCollide, tgtFps );
2801 std::unordered_set<EDA_ITEM*> refItems( refFps.begin(), refFps.end() );
2804 auto cgRef = CONNECTION_GRAPH::BuildFromFootprintSet( refFps, tgtFps );
2805 auto cgTarget = CONNECTION_GRAPH::BuildFromFootprintSet( tgtFps, refFps );
2808 std::vector<TMATCH::TOPOLOGY_MISMATCH_REASON> details;
2809 bool status = cgRef->FindIsomorphism( cgTarget.get(),
result, details );
2813 for(
const auto& reason : details )
2815 BOOST_TEST_MESSAGE( wxString::Format(
"Mismatch: %s to %s: %s", reason.m_reference, reason.m_candidate,
2816 reason.m_reason ) );
2820 BOOST_CHECK_MESSAGE( status,
"Topology match failed even after isolating the block's auto nets (issue 24767)" );
2834 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
2836 const LIB_ID receptacleId( wxT(
"Don-Con" ), wxT(
"Mill-Max-Pin_Receptacle" ) );
2839 auto makeReceptacle =
2840 [&](
const wxString& aRef,
const wxString& aValue,
bool aWithSymbolPath ) ->
FOOTPRINT*
2847 if( aWithSymbolPath )
2859 pad->SetNumber( wxT(
"1" ) );
2871 FOOTPRINT* refNC0 = makeReceptacle( wxT(
"J3" ), wxT(
"NC_0" ),
false );
2872 FOOTPRINT* refNC1 = makeReceptacle( wxT(
"J5" ), wxT(
"NC_1" ),
false );
2873 FOOTPRINT* refNO0 = makeReceptacle( wxT(
"J6" ), wxT(
"NO_0" ),
false );
2874 FOOTPRINT* refNO1 = makeReceptacle( wxT(
"J7" ), wxT(
"NO_1" ),
false );
2877 FOOTPRINT* tgtNO1 = makeReceptacle( wxT(
"J20" ), wxT(
"NO_1" ),
true );
2878 FOOTPRINT* tgtNO0 = makeReceptacle( wxT(
"J21" ), wxT(
"NO_0" ),
true );
2879 FOOTPRINT* tgtNC1 = makeReceptacle( wxT(
"J22" ), wxT(
"NC_1" ),
true );
2880 FOOTPRINT* tgtNC0 = makeReceptacle( wxT(
"J23" ), wxT(
"NC_0" ),
true );
2882 auto cgRef = std::make_unique<CONNECTION_GRAPH>();
2883 cgRef->AddFootprint( refNC0,
VECTOR2I( 0, 0 ) );
2884 cgRef->AddFootprint( refNC1,
VECTOR2I( 0, 0 ) );
2885 cgRef->AddFootprint( refNO0,
VECTOR2I( 0, 0 ) );
2886 cgRef->AddFootprint( refNO1,
VECTOR2I( 0, 0 ) );
2887 cgRef->BuildConnectivity();
2889 auto cgTarget = std::make_unique<CONNECTION_GRAPH>();
2890 cgTarget->AddFootprint( tgtNO1,
VECTOR2I( 0, 0 ) );
2891 cgTarget->AddFootprint( tgtNO0,
VECTOR2I( 0, 0 ) );
2892 cgTarget->AddFootprint( tgtNC1,
VECTOR2I( 0, 0 ) );
2893 cgTarget->AddFootprint( tgtNC0,
VECTOR2I( 0, 0 ) );
2894 cgTarget->BuildConnectivity();
2897 std::vector<TMATCH::TOPOLOGY_MISMATCH_REASON> details;
2898 bool status = cgRef->FindIsomorphism( cgTarget.get(),
result, details );
2900 BOOST_CHECK( status );
2904 for(
const auto& [refFp, targetFp] :
result )
2906 BOOST_TEST_MESSAGE( wxString::Format(
"%s (%s) -> %s (%s)", refFp->GetReference(), refFp->GetValue(),
2907 targetFp->GetReference(), targetFp->GetValue() ) );
2920 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
2922 const KIID outerRef, outerTarget, inner1, inner2, symbol;
2926 [&](
const wxString& aRef,
const KIID& aOuter,
const KIID& aInner ) ->
FOOTPRINT*
2932 fp->
SetPath(
KIID_PATH( wxString::Format(
"/%s/%s/%s", aOuter.AsString(), aInner.AsString(),
2940 pad->SetNumber( wxT(
"1" ) );
2951 FOOTPRINT* ref1 = makePart( wxT(
"R101" ), outerRef, inner1 );
2952 FOOTPRINT* ref2 = makePart( wxT(
"R201" ), outerRef, inner2 );
2955 FOOTPRINT* target2 = makePart( wxT(
"R301" ), outerTarget, inner2 );
2956 FOOTPRINT* target1 = makePart( wxT(
"R401" ), outerTarget, inner1 );
2958 auto cgRef = std::make_unique<CONNECTION_GRAPH>();
2959 cgRef->AddFootprint( ref1,
VECTOR2I( 0, 0 ) );
2960 cgRef->AddFootprint( ref2,
VECTOR2I( 0, 0 ) );
2961 cgRef->BuildConnectivity();
2963 auto cgTarget = std::make_unique<CONNECTION_GRAPH>();
2964 cgTarget->AddFootprint( target2,
VECTOR2I( 0, 0 ) );
2965 cgTarget->AddFootprint( target1,
VECTOR2I( 0, 0 ) );
2966 cgTarget->BuildConnectivity();
2969 std::vector<TMATCH::TOPOLOGY_MISMATCH_REASON> details;
2972 BOOST_CHECK(
result[ref1] == target1 );
2973 BOOST_CHECK(
result[ref2] == target2 );
2983 m_board = std::make_unique<BOARD>();
2986 auto makeReceptacle =
2987 [&](
const wxString& aRef,
const wxString& aValue,
const VECTOR2I& aPos,
2991 fp->
SetFPID(
LIB_ID( wxT(
"Don-Con" ), wxT(
"Mill-Max-Pin_Receptacle" ) ) );
2996 if( aWithSymbolPath )
3004 m_board->Add( net );
3008 pad->SetNumber( wxT(
"1" ) );
3013 pad->SetPosition( aPos );
3021 [](
double a,
double b )
3030 return (
double) ( aNC1.x - aNC0.
x ) * ( aNO0.y - aNC0.
y ) - (double) ( aNC1.y - aNC0.
y ) * ( aNO0.x - aNC0.
x );
3034 FOOTPRINT* srcNC0 = makeReceptacle( wxT(
"J3" ), wxT(
"NC_0" ), mm( 0, 0 ),
false );
3035 FOOTPRINT* srcNC1 = makeReceptacle( wxT(
"J5" ), wxT(
"NC_1" ), mm( 0, 7.9 ),
false );
3036 FOOTPRINT* srcNO0 = makeReceptacle( wxT(
"J6" ), wxT(
"NO_0" ), mm( -3.58, 2.28 ),
false );
3037 FOOTPRINT* srcNO1 = makeReceptacle( wxT(
"J7" ), wxT(
"NO_1" ), mm( 3.58, 5.62 ),
false );
3042 FOOTPRINT* dstNC0 = makeReceptacle( wxT(
"J8" ), wxT(
"NC_0" ), mm( 40, 40 ),
true );
3043 FOOTPRINT* dstNC1 = makeReceptacle( wxT(
"J9" ), wxT(
"NC_1" ), mm( 40, 47.9 ),
true );
3044 FOOTPRINT* dstNO0 = makeReceptacle( wxT(
"J10" ), wxT(
"NO_0" ), mm( 43.58, 42.28 ),
true );
3045 FOOTPRINT* dstNO1 = makeReceptacle( wxT(
"J11" ), wxT(
"NO_1" ), mm( 36.42, 45.62 ),
true );
3050 destGroup->
SetName( wxT(
"Pin receptacles for safety switch" ) );
3052 for(
FOOTPRINT* fp : { dstNC0, dstNC1, dstNO0, dstNO1 } )
3055 m_board->Add( destGroup );
3060 for(
FOOTPRINT* fp : { srcNC0, srcNC1, srcNO0, srcNO1 } )
3074 for(
FOOTPRINT* fp : { dstNC0, dstNC1, dstNO0, dstNO1 } )
3084 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
3090 .m_connectedRoutingOnly =
false,
3091 .m_copyPlacement =
true,
3092 .m_copyOtherItems =
false,
3093 .m_groupItems =
false,
3094 .m_includeLockedItems =
true };
3097 BOOST_REQUIRE_MESSAGE(
result >= 0,
"RepeatLayout failed" );
3104 BOOST_TEST_MESSAGE( wxString::Format( wxT(
"block chirality %.0f, destination chirality after apply %.0f" ),
3105 srcChir, dstChir ) );
3107 BOOST_CHECK_MESSAGE( srcChir * dstChir > 0.0,
"Applied layout left the receptacles mirrored (NC/NO swapped)" );
3119 m_board = std::make_unique<BOARD>();
3123 [&](
const wxString& aName ) ->
int
3126 m_board->Add( net );
3130 const int netGnd = addNet( wxT(
"GND" ) );
3131 const int netVcc = addNet( wxT(
"+3V3" ) );
3133 const LIB_ID icId( wxT(
"TestLib" ), wxT(
"SOT-23-6" ) );
3134 const LIB_ID rId( wxT(
"TestLib" ), wxT(
"R_0402" ) );
3139 [&](
int aIdx,
int aStrapNet ) ->
ZONE*
3141 const int netOut = addNet( wxString::Format( wxT(
"Net-(U%d-OUT)" ), aIdx ) );
3142 const int netCfg = addNet( wxString::Format( wxT(
"Net-(U%d-CFG)" ), aIdx ) );
3145 [&](
FOOTPRINT* aFp,
const wxString& aNumber,
int aNetCode )
3149 pad->SetNumber( aNumber );
3154 pad->SetNetCode( aNetCode );
3160 ic->
SetReference( wxString::Format( wxT(
"U%d" ), aIdx ) );
3162 addPad( ic, wxT(
"1" ), netOut );
3163 addPad( ic, wxT(
"2" ), netGnd );
3167 r->
SetReference( wxString::Format( wxT(
"R%d" ), aIdx ) );
3169 addPad( r, wxT(
"1" ), netCfg );
3170 addPad( r, wxT(
"2" ), aStrapNet );
3172 ZONE* zone =
new ZONE( m_board.get() );
3173 m_board->Add( zone );
3178 std::vector<std::pair<int, int>> channelStraps = { { 1, netGnd }, { 2, netGnd }, { 3, netVcc } };
3179 std::vector<ZONE*> zones;
3183 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
3189 ruleData->
m_areas.reserve( channelStraps.size() );
3191 for(
const auto& [idx, strap] : channelStraps )
3193 ZONE* zone = makeChannel( idx, strap );
3194 zones.push_back( zone );
3198 ra.
m_ruleName = wxString::Format( wxT(
"Channel %d" ), idx );
3200 for(
FOOTPRINT* fp : m_board->Footprints() )
3202 if( fp->GetReference() == wxString::Format( wxT(
"U%d" ), idx )
3203 || fp->GetReference() == wxString::Format( wxT(
"R%d" ), idx ) )
3209 ruleData->
m_areas.push_back( ra );
3214 BOOST_REQUIRE_EQUAL( status, 0 );
3218 if( ra.
m_zone == zones[1] )
3224 for(
const wxString& reason : it->second.m_mismatchReasons )
3227 BOOST_CHECK_MESSAGE( it->second.m_isOk,
3228 wxString::Format(
"Channel 2 must match %s", ra.
m_ruleName ) );
3240 m_board = std::make_unique<BOARD>();
3244 [&](
const wxString& aName ) ->
int
3247 m_board->Add( net );
3251 const int netGnd = addNet( wxT(
"GND" ) );
3253 const LIB_ID icId( wxT(
"TestLib" ), wxT(
"SOT-23-6" ) );
3254 const LIB_ID rId( wxT(
"TestLib" ), wxT(
"R_0402" ) );
3257 [&](
FOOTPRINT* aFp,
const wxString& aNumber,
int aNetCode )
3261 pad->SetNumber( aNumber );
3265 pad->SetNetCode( aNetCode );
3280 const int netLocal1 = addNet( wxT(
"Net-(U1-SIG)" ) );
3281 FOOTPRINT* u1 = makeFp( icId, wxT(
"U1" ) );
3282 addPad( u1, wxT(
"1" ), netLocal1 );
3283 addPad( u1, wxT(
"2" ), netGnd );
3284 FOOTPRINT* r1 = makeFp( rId, wxT(
"R1" ) );
3285 addPad( r1, wxT(
"1" ), netLocal1 );
3286 addPad( r1, wxT(
"2" ), netGnd );
3290 const int netLocal2a = addNet( wxT(
"Net-(U2-SIG)" ) );
3291 const int netLocal2b = addNet( wxT(
"Net-(R2-SIG)" ) );
3292 FOOTPRINT* u2 = makeFp( icId, wxT(
"U2" ) );
3293 addPad( u2, wxT(
"1" ), netLocal2a );
3294 addPad( u2, wxT(
"2" ), netGnd );
3295 FOOTPRINT* r2 = makeFp( rId, wxT(
"R2" ) );
3296 addPad( r2, wxT(
"1" ), netLocal2b );
3297 addPad( r2, wxT(
"2" ), netGnd );
3299 ZONE* zone1 =
new ZONE( m_board.get() );
3300 m_board->Add( zone1 );
3301 ZONE* zone2 =
new ZONE( m_board.get() );
3302 m_board->Add( zone2 );
3303 ZONE* zoneDup =
new ZONE( m_board.get() );
3304 m_board->Add( zoneDup );
3308 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
3314 ruleData->
m_areas.reserve( 3 );
3320 ruleData->
m_areas.push_back( ra1 );
3326 ruleData->
m_areas.push_back( ra2 );
3332 raDup.
m_ruleName = wxT(
"Channel 1 duplicate" );
3334 ruleData->
m_areas.push_back( raDup );
3337 BOOST_REQUIRE_EQUAL( status, 0 );
3352 BOOST_CHECK_MESSAGE( !it->second.m_isOk,
3353 "Channel 1 and channel 2 differ on a local net and must not match; an "
3354 "overlapping rule area must not hide that net by marking it global" );
3366 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
3401 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
3433 if(
group->GetName() == wxT(
"FirstChannel" ) )
3435 else if(
group->GetName() == wxT(
"SecondChannel" ) )
3441 first->
SetName( wxT(
"Channel'*" ) );
3442 second->
SetName( wxT(
"Channel'Other" ) );
3446 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
3455 BOOST_REQUIRE_EQUAL( candidate->
m_components.size(), 64 );
3470 BOOST_CHECK( outlineBounds.
Contains( fp->GetPosition() ) );
3482 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
3489 auto ruleData = mtTool->
GetData();
3492 for(
RULE_AREA& ra : ruleData->m_areas )
3512 std::vector<PCB_GENERATOR*> strip;
3516 if( gen->GetGeneratorType() != wxT(
"tuning_pattern" ) )
3519 if( !gen->HitTest(
source->m_zone->Outline()->COutline( 0 ),
false ) )
3520 strip.push_back( gen );
3525 for(
EDA_ITEM* member : gen->GetItems() )
3527 if( member->IsBOARD_ITEM() )
3528 static_cast<BOARD_ITEM*
>( member )->SetParentGroup(
nullptr );
3531 m_board->Remove( gen );
3538 ruleData->m_options.m_groupItems =
true;
3541 ruleData->m_compatMap[target].m_doCopy =
true;
3558 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
3565 auto ruleData = mtTool->
GetData();
3568 for(
RULE_AREA& ra : ruleData->m_areas )
3584 std::set<EDA_GROUP*> groups;
3596 for(
EDA_ITEM* member : g->GetItems() )
3604 BOOST_CHECK(
source->m_zone->Outline()->Contains( bb.
GetEnd() ) );
3620 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
3627 auto ruleData = mtTool->
GetData();
3630 for(
RULE_AREA& ra : ruleData->m_areas )
3654 std::vector<ZONE*> stripZones;
3656 for(
ZONE* zone : m_board->Zones() )
3658 if( zone->GetIsRuleArea() )
3662 stripZones.push_back( zone );
3665 for(
ZONE* zone : stripZones )
3668 group->RemoveItem( zone );
3670 m_board->Remove( zone );
3676 ruleData->m_compatMap[target].m_doCopy =
true;
3694 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
3711 std::vector<TMATCH::TOPOLOGY_MISMATCH_REASON> details;
3712 bool status = cgRef->FindIsomorphism( cgTarget.get(),
result, details );
3714 BOOST_CHECK( status );
3715 BOOST_CHECK( details.empty() );
3727 m_board = std::make_unique<BOARD>();
3728 BOARD* board = m_board.get();
3733 [&](
const wxString& aRef,
const VECTOR2I& aPos )
3743 pad->SetNumber( wxT(
"1" ) );
3752 pad->SetNetCode( 1 );
3764 board->
Add( track );
3769 toolMgr.
SetEnvironment( board,
nullptr,
nullptr,
nullptr, toolsHolder );
3776 auto ruleData = mtTool->
GetData();
3786 ZONE* raZone =
nullptr;
3790 if( zone->GetIsRuleArea() && zone->GetZoneName() == wxT(
"auto-placement-area-/ChannelA/" ) )
3803 "Sheet rule area outline must enclose loose inter-block routing (issue 24983)" );
3819 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
3826 auto ruleData = mtTool->
GetData();
3831 for(
RULE_AREA& ra : ruleData->m_areas )
3833 if( ra.
m_ruleName.Contains( wxT(
"Untitled Sheet/" ) ) )
3835 else if( ra.
m_ruleName.Contains( wxT(
"Untitled Sheet1/" ) ) )
3871 ruleData->m_compatMap[targetArea].m_doCopy =
true;
3872 ruleData->m_options.m_copyPlacement =
true;
3887 std::vector<PCB_GROUP*> found;
3891 if(
group->GetName() == aName )
3892 found.push_back(
group );
3901 std::set<FOOTPRINT*> footprints;
3907 footprints.insert(
static_cast<FOOTPRINT*
>( child ) );
3920 const wxString sourceChannel = wxT(
"ChanA" );
3921 const wxString targetChannel = wxT(
"ChanB" );
3924 const std::pair<wxString, wxString> channels[] = { { wxT(
"FirstChannel" ), sourceChannel },
3925 { wxT(
"SecondChannel" ), targetChannel } };
3927 for(
const auto& [nested, flat] : channels )
3931 BOOST_REQUIRE_EQUAL( found.size(), 1 );
3938 channelGroup->
SetName( flat );
3943 aBoard->Add( channelGroup );
3949 toolMgr.
SetEnvironment( aBoard.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
3956 for(
const wxString&
name : { sourceChannel, targetChannel } )
3977 std::vector<PCB_GROUP*> targetGroups =
findGroupsByName( aBoard.get(), targetChannel );
3979 BOOST_REQUIRE_EQUAL( targetGroups.size(), 1 );
3981 const std::set<FOOTPRINT*> targetFootprints =
collectFootprints( targetGroups[0] );
3986 compatData.m_doCopy =
true;
4009 BOOST_REQUIRE_EQUAL( targetGroups.size(), 1 );
4035 toolMgr.
SetEnvironment( m_board.get(),
nullptr,
nullptr,
nullptr, toolsHolder );
4042 for(
const wxString&
name : { wxString( wxT(
"FirstChannel" ) ), wxString( wxT(
"SecondChannel" ) ) } )
4056 std::vector<PCB_GROUP*> refGroups =
findGroupsByName( m_board.get(), wxT(
"FirstChannel" ) );
4057 std::vector<PCB_GROUP*> targetGroups =
findGroupsByName( m_board.get(), wxT(
"SecondChannel" ) );
4058 BOOST_REQUIRE_EQUAL( refGroups.size(), 1 );
4059 BOOST_REQUIRE_EQUAL( targetGroups.size(), 1 );
4061 auto countTracks = [&](
PCB_GROUP* aGroup )
4063 return std::count_if( m_board->Tracks().begin(), m_board->Tracks().end(),
4066 return aGroup->ContainsItem( aTrack );
4070 long refTracks = countTracks( refGroups[0] );
4075 .m_connectedRoutingOnly =
false,
4076 .m_copyPlacement =
true,
4077 .m_copyOtherItems =
true,
4078 .m_groupItems =
false,
4079 .m_includeLockedItems =
true };
4083 BOOST_REQUIRE_MESSAGE(
result >= 0, wxString::Format(
"RepeatLayout failed: %s", err ) );
4085 for(
EDA_ITEM* member : targetGroups[0]->GetItems() )
4086 BOOST_CHECK_MESSAGE( member->Type() !=
PCB_FOOTPRINT_T,
"footprint pulled out of its nested block group" );
4108 BOOST_REQUIRE_EQUAL( refArea->
m_components.size(), 1 );
4116 compat.m_doCopy =
true;
4121 std::vector<ZONE*> peers;
4124 peers.push_back( area->m_zone );
4126 BOOST_REQUIRE_EQUAL( peers.size(), 3 );
4128 for(
ZONE* peer : peers )
4129 BOOST_CHECK( peer->GetLinkSet() == refZone->
GetLinkSet() );
4133 ZONE* cleanZone =
nullptr;
4143 if( area->m_zone == peers[0] )
4144 sharedFp = *area->m_components.begin();
4145 else if( area->m_zone == peers[2] )
4146 cleanFp = *area->m_components.begin();
4149 cleanZone = peers[2];
4159 commit.
Push( wxT(
"Move reference" ) );
4171 peerCommit.
Modify( cleanFp );
4172 cleanFp->
Move( -half );
4173 peerCommit.
Push( wxT(
"Move target" ) );
4186 ZONE* other =
source == refZone ? peers[0] : refZone;
4192 compat.m_doCopy = area->m_zone == other;
4197 BOOST_CHECK( refZone->
GetLinkSet() == peers[0]->GetLinkSet() );
4198 BOOST_CHECK( refZone->
GetLinkSet() != oldSet );
4199 BOOST_CHECK( peers[1]->GetLinkSet() == oldSet );
4200 BOOST_CHECK( peers[2]->GetLinkSet() == oldSet );
4205 wxString
path = wxFileName::CreateTempFileName( wxT(
"linked_rule_areas" ) );
4215 wxRemoveFile(
path );
4218 for(
ZONE* zone : { refZone, peers[0], peers[1], peers[2] } )
4220 ZONE* loaded =
dynamic_cast<ZONE*
>( reloaded->ResolveItem( zone->m_Uuid,
true ) );
4223 BOOST_CHECK( loaded->
GetLinkSet() == zone->GetLinkSet() );
4227 std::set<KIID> appendedSets;
4229 for(
const ZONE* zone : m_board->Zones() )
4231 if( zone->GetLinkSet() !=
niluuid && zone->GetLinkSet() != pairSet && zone->GetLinkSet() != oldSet )
4232 appendedSets.insert( zone->GetLinkSet() );
4244 BOOST_CHECK( peers[1]->GetLinkSet() ==
niluuid );
4245 BOOST_CHECK( peers[2]->GetLinkSet() ==
niluuid );
4247 BOOST_CHECK( refZone->
GetLinkSet() == pairSet );
4253 std::vector<EDA_ITEM*> items;
4257 if( fp->GetSheetname() == aSheet )
4258 items.push_back( fp );
4268 std::set<int> outsideNets;
4272 if( fp->GetSheetname() != aSheet )
4274 for(
PAD*
pad : fp->Pads() )
4275 outsideNets.insert(
pad->GetNetCode() );
4281 auto outside = [&](
PAD* aPad ) {
return outsideNets.contains( aPad->GetNetCode() ); };
4283 if( fp->GetSheetname() == aSheet && std::ranges::all_of( fp->Pads(), outside ) )
4305 return std::ranges::count_if(
m_tool->GetData()->m_compatMap,
4306 [](
const auto& aEntry ) { return aEntry.second.m_isOk; } );
4316 const wxString ref = wxT(
"/io_drivers_pp/bank0/out01/" );
4317 std::vector<EDA_ITEM*> selected =
sheetFootprints( m_board.get(), ref );
4319 BOOST_REQUIRE_EQUAL( selected.size(), 11 );
4322 m_tool->StartRepeatFromSelection( selected );
4325 for(
const auto& [area, compat] : m_tool->GetData()->m_compatMap )
4328 BOOST_CHECK( compat.m_unmatched.empty() );
4331 std::vector<EDA_ITEM*> few( selected.begin(), selected.begin() + 4 );
4333 m_tool->StartRepeatFromSelection( few );
4337 std::set<FOOTPRINT*> sheet;
4340 sheet.insert(
static_cast<FOOTPRINT*
>( item ) );
4342 BOOST_CHECK( m_tool->ExpandToMatchingTopology( { *sheet.begin() },
true ) == sheet );
4345 const size_t areasBefore = std::ranges::count_if(
4346 m_board->Zones(), [](
ZONE* aZone ) { return aZone->GetPlacementAreaEnabled(); } );
4347 const size_t tracksBefore = m_board->Tracks().size();
4349 m_tool->StartRepeatFromSelection( selected );
4351 m_tool->GetData()->m_linkAreas =
true;
4355 for(
FOOTPRINT* fp : m_tool->GetData()->m_refRA->m_components )
4357 if( fp->m_Uuid == m_tool->GetData()->m_options.m_anchor )
4363 std::vector<std::pair<FOOTPRINT*, VECTOR2I>>
expected;
4367 for(
const auto& [area, compat] : m_tool->GetData()->m_compatMap )
4374 for(
const auto& [refFp, targetFp] : compat.m_matchingComponents )
4379 if( !probeRef && refFp !=
anchor )
4382 probeTarget = targetFp;
4389 BOOST_CHECK_GT( m_board->Tracks().size(), tracksBefore );
4391 for(
const auto& [fp, pos] :
expected )
4394 std::vector<ZONE*> created;
4395 std::set<KIID> linkSets;
4396 std::set<KIID> anchors;
4398 for(
ZONE* zone : m_board->Zones() )
4400 if( !zone->GetPlacementAreaEnabled() )
4403 created.push_back( zone );
4405 if( zone->GetLinkSet() !=
niluuid )
4407 linkSets.insert( zone->GetLinkSet() );
4408 anchors.insert( zone->GetRepeatOptions().m_anchor );
4418 ZONE* refZone = *std::ranges::find_if( created, [&](
ZONE* aZone )
4426 BOOST_CHECK( m_tool->UpdateLinkedLayouts( refZone ) );
4431 m_tool->UnlinkAreas( std::set<ZONE*>( created.begin(), created.end() ) );
4436 m_tool->FindExistingRuleAreas();
4437 m_tool->CheckRACompatibility( refZone );
4439 for(
auto& [area, compat] : m_tool->GetData()->m_compatMap )
4440 compat.m_doCopy =
true;
4442 m_tool->GetData()->m_options.m_connectedRoutingOnly =
false;
4443 m_tool->GetData()->m_options.m_groupItems =
false;
4450 const size_t tracksAfterSettling = m_board->Tracks().size();
4459 m_board->Remove( leaf );
4462 m_tool->StartRepeatFromSelection(
sheetFootprints( m_board.get(), ref ) );
4465 m_tool->DiscoverRepeatCandidates(
true );
4471 for(
FOOTPRINT* fp : m_board->Footprints() )
4474 m_tool->StartRepeatFromSelection(
sheetFootprints( m_board.get(), ref ) );
4477 m_tool->DiscoverRepeatCandidates(
true );
4485 if(
static_cast<FOOTPRINT*
>( item )->GetReference().StartsWith( wxT(
"IC" ) ) )
4491 std::set<FOOTPRINT*> step = m_tool->ExpandToMatchingTopology( { seed }, false );
4492 std::set<int> seedNets;
4495 seedNets.insert(
pad->GetNetCode() );
4497 BOOST_CHECK_GT( step.size(), 1 );
4501 BOOST_CHECK( fp == seed || std::ranges::any_of( fp->Pads(), [&](
PAD* aPad )
4502 { return aPad->GetNetCode() > 0
4503 && seedNets.contains( aPad->GetNetCode() ); } ) );
constexpr EDA_IU_SCALE pcbIUScale
void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
virtual bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
virtual void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
void SetLocked(bool aLocked) override
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Information pertinent to a Pcbnew printed circuit board.
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
const GENERATORS & Generators() const
const ZONES & Zones() const
const GROUPS & Groups() const
The groups must maintain the following invariants.
const FOOTPRINTS & Footprints() const
static constexpr BOX2< VECTOR2I > ByCorners(const VECTOR2I &aCorner1, const VECTOR2I &aCorner2)
constexpr const Vec GetEnd() const
constexpr bool Contains(const Vec &aPoint) const
constexpr const Vec & GetOrigin() const
constexpr coord_type GetRight() const
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Store all of the related component information found in a netlist.
A set of EDA_ITEMs (i.e., without duplicates).
void AddItem(EDA_ITEM *aItem)
Add item to group.
virtual EDA_ITEM * AsEdaItem()=0
void SetName(const wxString &aName)
A base class for most all the KiCad significant classes used in schematics and boards.
virtual EDA_GROUP * GetParentGroup() const
KICAD_T Type() const
Returns the type of object.
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
virtual bool IsVisible() const
virtual void SetText(const wxString &aText)
wxString AsString() const
A logical library item identifier and consists of various portions much like a URI.
LSET is a set of PCB_LAYER_IDs.
static const LSET & AllTechMask()
Return a mask holding all technical layers (no CU layer) on both side.
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Handle the data for a net.
@ NORMAL
Shape is the same on all layers.
static constexpr PCB_LAYER_ID ALL_LAYERS
! The layer identifier to use for the single defintion on normal padstacks
void SetNumber(const wxString &aNumber)
Set the pad number (note that it can be alphanumeric, such as the array reference "AA12").
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
void SetLocalZoneConnection(ZONE_CONNECTION aType)
std::optional< int > GetLocalSolderMaskMargin() const
ZONE_CONNECTION GetLocalZoneConnection() const
A set of BOARD_ITEMs (i.e., without duplicates).
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction, RECURSE_MODE aMode) const override
Invoke a function on all children.
A PCB_IO derivation for saving and loading Pcbnew s-expression formatted files.
void SaveBoard(const wxString &aFileName, BOARD &aBoard, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Write aBoard to a storage file in a format that this PCB_IO implementation knows about or it can be u...
void LoadAndAppendBoard(const wxString &aFileName, BOARD &aAppendToMe, const std::map< std::string, UTF8 > *aProperties=nullptr, PROJECT *aProject=nullptr)
Same as LoadBoard(), but appends the loaded board to an existing board, which must already exist.
std::unique_ptr< BOARD > LoadBoard(const wxString &aFileName, const std::map< std::string, UTF8 > *aProperties=nullptr, PROJECT *aProject=nullptr)
Load information from some input file format that this PCB_IO implementation knows about into new BOA...
void SetEnd(const VECTOR2I &aEnd) override
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetStart(const VECTOR2I &aStart) override
void SetStroke(const STROKE_PARAMS &aStroke) override
EDA_ANGLE GetTextAngle() const override
void SetPosition(const VECTOR2I &aPos) override
void SetEnd(const VECTOR2I &aEnd)
void SetStart(const VECTOR2I &aStart)
const VECTOR2I & GetStart() const
virtual void SetWidth(int aWidth)
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
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.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
virtual VECTOR2I Centre() const
Compute a center-of-mass of the shape.
Simple container to manage line stroke parameters.
Handle a list of polygons defining a copper zone.
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
const REPEAT_LAYOUT_OPTIONS & GetRepeatOptions() const
void AddPolygon(std::vector< VECTOR2I > &aPolygon)
Add a polygon to the zone outline.
wxString GetPlacementAreaSource() const
PLACEMENT_SOURCE_T GetPlacementAreaSourceType() const
SHAPE_POLY_SET * Outline()
void SetIsRuleArea(bool aEnable)
void SetLayerSet(const LSET &aLayerSet) override
const KIID & GetLinkSet() const
The set of placement rule areas that share one layout, or niluuid when this one is not linked.
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
PCB_LAYER_ID
A quick note on layer IDs:
SHAPE_LINE_CHAIN BoxToLineChain(const BOX2I &aBox)
Get a SHAPE_LINE_CHAIN representing the outline of a box.
void LoadBoard(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< BOARD > &aBoard)
std::map< FOOTPRINT *, FOOTPRINT * > COMPONENT_MATCHES
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ SMD
Smd pad, appears on the solder paste layer (default)
Class to handle a set of BOARD_ITEMs.
Utility functions for working with shapes.
std::vector< FAB_LAYER_COLOR > dummy
MULTICHANNEL_TEST_FIXTURE()
SETTINGS_MANAGER m_settingsManager
std::unique_ptr< BOARD > m_board
Options for copying a placement rule area onto the others linked to it.
KIID m_anchor
This area's own anchor footprint, or niluuid for the area center.
bool m_includeLockedItems
std::unordered_map< RULE_AREA *, RULE_AREA_COMPAT_DATA > m_compatMap
REPEAT_LAYOUT_OPTIONS m_options
bool m_linkAreas
Link the ticked targets to the reference.
std::vector< RULE_AREA > m_areas
TMATCH::COMPONENT_MATCHES m_matchingComponents
std::unordered_set< EDA_ITEM * > m_designBlockItems
PLACEMENT_SOURCE_T m_sourceType
std::set< FOOTPRINT * > m_components
std::atomic< bool > * m_cancelled
std::atomic< int > * m_matchedComponents
std::atomic< int > * m_totalComponents
@ VALUE
Field Value of part, i.e. "3.3K".
static void addTrack(BOARD &aBoard, int aNetCode, PCB_LAYER_ID aLayer, const VECTOR2I &aStart, const VECTOR2I &aEnd)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
static FOOTPRINT * addFootprint(BOARD &aBoard, const wxString &aReference)
VECTOR3I expected(15, 30, 45)
int countCopperZonesInArea(BOARD *aBoard, ZONE *aRAZone)
static FOOTPRINT * railOnlyPart(BOARD *aBoard, const wxString &aSheet)
static std::set< FOOTPRINT * > collectFootprints(const PCB_GROUP *aGroup)
RULE_AREA * findGroupRuleAreaByName(MULTICHANNEL_TOOL *aTool, const wxString &aGroupName)
static void checkGroupChannelRepeatLayout(SETTINGS_MANAGER &aSettingsManager, std::unique_ptr< BOARD > &aBoard, bool aGroupItems)
static std::vector< EDA_ITEM * > sheetFootprints(BOARD *aBoard, const wxString &aSheet)
RULE_AREA * findRuleAreaByPartialName(MULTICHANNEL_TOOL *aTool, const wxString &aName)
int countZonesByNamePrefixInRuleArea(BOARD *aBoard, const wxString &aBaseName, const RULE_AREA &aRuleArea)
RULE_AREA * findSheetRuleAreaByPath(MULTICHANNEL_TOOL *aTool, wxString aPath)
BOOST_FIXTURE_TEST_CASE(MultichannelToolRegressions, MULTICHANNEL_TEST_FIXTURE)
int countZonesByNameInRuleArea(BOARD *aBoard, const wxString &aZoneName, const RULE_AREA &aRuleArea)
int countTuningGensInArea(BOARD *aBoard, ZONE *aZone)
RULE_AREA * findRuleAreaByPlacementGroup(MULTICHANNEL_TOOL *aTool, const wxString &aGroupName)
static std::vector< PCB_GROUP * > findGroupsByName(BOARD *aBoard, const wxString &aName)
static std::vector< int > candidates(const SEGMENT_INDEX &aIndex, const SEG &aQuery, int aPadding)
BOOST_TEST_CONTEXT("Test Clearance")
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
VECTOR2< int32_t > VECTOR2I
@ NONE
Pads are not covered.