52 {
"ClaySight_MK1",
"ClaySight_MK1.asc" },
53 {
"TMS1mmX19",
"TMS1mmX19.asc" },
54 {
"MC4_PLUS_CSHAPE",
"MC4_PLUS_CSHAPE.asc" },
55 {
"MC2_PLUS_REV1",
"MC2_PLUS_REV1.asc" },
56 {
"Ems4_Rev2",
"Ems4_Rev2.asc" },
57 {
"LCORE_4",
"LCORE_4.asc" },
58 {
"LCORE_2",
"LCORE_2.asc" },
59 {
"Dexter_MotorCtrl",
"Dexter_MotorCtrl.asc" },
60 {
"MAIS_FC",
"MAIS_FC.asc" },
61 {
"ClaySight_MK2",
"ClaySight_MK2.asc" },
81 aBoard.
dir <<
" should be a readable PADS file" );
83 std::unique_ptr<BOARD> board;
87 board.reset( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
89 catch(
const std::exception& e )
91 BOOST_WARN_MESSAGE(
false,
92 aBoard.
dir <<
" threw exception during load: " << e.what() );
96 BOOST_REQUIRE_MESSAGE( board !=
nullptr, aBoard.
dir <<
" failed to load" );
98 aBoard.
dir <<
" should have footprints" );
118 BOOST_WARN_MESSAGE( board->Tracks().size() > 0,
119 aBoard.
dir <<
" has no tracks (parser may not support this format version)" );
121 if( board->Tracks().size() > 0 && board->Footprints().size() > 0 )
126 for(
FOOTPRINT* fp : board->Footprints() )
127 fpBbox.
Merge( fp->GetBoundingBox() );
133 trackBbox.
Merge( trk->GetBoundingBox() );
136 aBoard.
dir <<
" footprint and track bounding boxes should overlap" );
140 std::set<std::pair<int, int>> viaPositions;
141 bool hasDuplicate =
false;
150 auto key = std::make_pair(
via->GetPosition().x,
via->GetPosition().y );
152 if( viaPositions.count( key ) )
158 viaPositions.insert( key );
162 aBoard.
dir <<
" should have no duplicate through-hole vias" );
170 aBoard.
dir <<
" track on non-copper layer " << trk->GetLayer() );
175 for(
FOOTPRINT* fp : board->Footprints() )
177 for(
PAD*
pad : fp->Pads() )
181 aBoard.
dir <<
" " << fp->GetReference() <<
" pad has zero size" );
186 for(
ZONE* zone : board->Zones() )
189 BOOST_REQUIRE_MESSAGE( outline !=
nullptr,
190 aBoard.
dir <<
" zone has null outline" );
195 aBoard.
dir <<
" zone outline " << ii <<
" has "
230 for(
FOOTPRINT* fp : board->Footprints() )
231 totalPads += fp->Pads().size();
256 int edgeCutsCount = 0;
274 if(
dynamic_cast<PCB_TEXT*
>( item ) )
281 std::set<wxString> trackNets;
300 "trace on unexpected layer " << layer );
361 std::unique_ptr<BOARD> board( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
367 for(
PCB_TRACK* track : board->Tracks() )
376 BOOST_CHECK( track_count > 0 );
387 std::unique_ptr<BOARD> board( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
391 int silkscreen_count = 0;
392 int comments_count = 0;
393 int copper_count = 0;
407 else if( layer ==
F_Cu )
443 for(
FOOTPRINT* fp : board->Footprints() )
444 totalPads += fp->Pads().size();
464 std::set<wxString> trackNets;
482 "trace on non-copper layer " << trk->GetLayer() );
496 if( shape->GetLayer() ==
F_SilkS )
512 BOOST_CHECK( defaultNc->GetViaDiameter() > 0 );
513 BOOST_CHECK( defaultNc->GetViaDrill() > 0 );
514 BOOST_CHECK( defaultNc->GetViaDiameter() > defaultNc->GetViaDrill() );
521 int edgeCutsCount = 0;
536 wxString textContent;
543 textContent =
text->GetText();
552 BOOST_CHECK( textContent.Contains( wxT(
"\n" ) ) );
553 BOOST_CHECK( !textContent.Contains( wxT(
"_" ) ) );
554 BOOST_CHECK( textContent.Contains( wxT(
"CLAYSIGHT MCU V.2" ) ) );
555 BOOST_CHECK( textContent.Contains( wxT(
"The Ohio State University" ) ) );
576 bool foundCopperThickness =
false;
577 bool foundDielectric =
false;
583 if( item->GetThickness() > 0 )
584 foundCopperThickness =
true;
588 if( item->GetEpsilonR() > 3.0 )
589 foundDielectric =
true;
593 BOOST_CHECK_MESSAGE( foundCopperThickness,
"stackup should have non-zero copper thickness" );
612 +
"plugins/pads/synthetic_degenerate_pour.asc";
614 std::unique_ptr<BOARD> board( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
624 if( board->Zones().size() == 1 )
626 ZONE* zone = board->Zones()[0];
646 +
"plugins/pads/synthetic_filled_copper.asc";
648 std::unique_ptr<BOARD> board( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
651 BOOST_REQUIRE_EQUAL( board->Zones().size(), 1 );
653 ZONE* zone = board->Zones()[0];
674 std::unique_ptr<BOARD> board( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
682 int dwgsUserCount = 0;
694 "graphics on PADS layer 18 (drill drawing) should map to Dwgs_User" );
701 for(
FOOTPRINT* fp : board->Footprints() )
703 if( fp->GetReference() == wxT(
"U1" ) )
710 BOOST_REQUIRE_MESSAGE( u1 !=
nullptr,
"U1 footprint should exist" );
712 bool foundOvalPad =
false;
725 BOOST_CHECK_MESSAGE( foundOvalPad,
"U1 should have oval pads (OF shape, not RT thermal)" );
730 int pourZoneCount = 0;
731 int filledZoneCount = 0;
733 for(
ZONE* zone : board->Zones() )
735 if( !zone->GetIsRuleArea() )
739 if( zone->IsFilled() )
745 "should not have duplicate zones from HATOUT; got " << pourZoneCount );
764 "horizontal dimension endpoints should have equal Y coordinates; "
765 "start.y=" << start.
y <<
" end.y=" <<
end.y );
791 std::unique_ptr<BOARD> board( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
796 std::map<std::pair<int, int>,
int> viaPositionCount;
798 int throughCount = 0;
804 const int maxExpectedViaWidth = 1200000;
806 int oversizedViaCount = 0;
808 for(
PCB_TRACK* track : board->Tracks() )
816 auto key = std::make_pair( pos.
x, pos.
y );
817 viaPositionCount[key]++;
824 if(
via->GetWidth(
F_Cu ) > maxExpectedViaWidth )
830 "no vias should be blind; STANDARDVIA spans all copper layers; got "
831 << blindCount <<
" blind vias" );
837 "via size should use copper pad, not soldermask opening; got "
838 << oversizedViaCount <<
" oversized vias" );
841 int duplicateCount = 0;
843 for(
const auto& [pos, count] : viaPositionCount )
850 "should not have duplicate vias at the same position; got "
851 << duplicateCount <<
" positions with duplicates" );
856 int backTentedCount = 0;
859 for(
PCB_TRACK* track : board->Tracks() )
873 "vias without soldermask opening should be tented; "
874 << backTentedCount <<
" of " << totalVias <<
" back-tented" );
892 std::unique_ptr<BOARD> board( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
898 for(
FOOTPRINT* fp : board->Footprints() )
900 if( fp->GetReference() ==
"U1" )
907 BOOST_REQUIRE_MESSAGE( u1,
"U1 not found on board" );
912 const int expectedMajor = 6000000;
913 const int expectedMinor = 1500000;
914 const int tolerance = 10000;
920 wxString padNum =
pad->GetNumber();
922 if( padNum ==
"1" || padNum ==
"2" || padNum ==
"3"
923 || padNum ==
"4" || padNum ==
"5" )
926 "pad " << padNum <<
" should have oblong drill" );
929 int major = std::max( drillSize.
x, drillSize.
y );
930 int minor = std::min( drillSize.
x, drillSize.
y );
933 "pad " << padNum <<
" drill major axis " << major
934 <<
" should be ~" << expectedMajor );
937 "pad " << padNum <<
" drill minor axis " << minor
938 <<
" should be ~" << expectedMinor );
946 "expected 5 pads with oblong drill, got " << oblongCount );
964 std::unique_ptr<BOARD> board( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
970 for(
FOOTPRINT* fp : board->Footprints() )
972 if( fp->GetReference() ==
"M4" )
979 BOOST_REQUIRE_MESSAGE( m4,
"M4 not found on board" );
983 const int expectedPadSize = 6350000;
984 const int expectedDrill = 3175000;
985 const int tolerance = 10000;
987 BOOST_REQUIRE_MESSAGE( m4->
Pads().size() == 1,
988 "MTHOLEAAAB has 1 terminal; got " << m4->
Pads().size() );
993 "M4 pad 1 drill should be circular" );
996 int padDim = std::max( padSize.
x, padSize.
y );
999 "M4 pad size " << padDim <<
" should be ~" << expectedPadSize
1003 int drillDim = std::max( drillSize.
x, drillSize.
y );
1006 "M4 drill size " << drillDim <<
" should be ~" << expectedDrill
1025 std::unique_ptr<BOARD> board( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
1033 auto hasTrueCrossing = [](
const SHAPE_POLY_SET& aPoly,
int aIdx ) ->
bool
1035 std::vector<SEG> segs;
1038 segs.emplace_back( *it );
1040 for(
size_t i = 0; i < segs.size(); i++ )
1042 for(
size_t j = i + 1; j < segs.size(); j++ )
1046 if( segs[i].
A == segs[j].
A || segs[i].
A == segs[j].
B
1047 || segs[i].
B == segs[j].
A || segs[i].
B == segs[j].
B )
1052 if( segs[i].Intersects( segs[j] ) )
1060 int zonesChecked = 0;
1062 for(
ZONE* zone : board->Zones() )
1064 if( !zone->IsFilled() )
1069 if( !zone->HasFilledPolysForLayer( layer ) )
1072 std::shared_ptr<SHAPE_POLY_SET> fill = zone->GetFilledPolysList( layer );
1074 if( !fill || fill->OutlineCount() == 0 )
1079 for(
int pi = 0; pi < fill->OutlineCount(); pi++ )
1081 if( fill->Outline( pi ).PointCount() < 3 )
1085 !hasTrueCrossing( *fill, pi ),
1086 "zone \"" << zone->GetNetname() <<
"\" on "
1087 << board->GetLayerName( layer )
1088 <<
" outline " << pi
1089 <<
" has self-intersecting fill polygon" );
1119 std::unique_ptr<BOARD> board( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
1122 BOOST_REQUIRE_EQUAL( board->Footprints().size(), 5 );
1124 auto findFP = [&](
const wxString& aRef ) ->
FOOTPRINT*
1126 for(
FOOTPRINT* fp : board->Footprints() )
1127 if( fp->GetReference() == aRef )
1135 BOOST_REQUIRE_MESSAGE( u1,
"U1 should exist" );
1136 BOOST_REQUIRE_EQUAL( u1->
Pads().size(), 1 );
1148 BOOST_REQUIRE_MESSAGE( u2,
"U2 should exist" );
1149 BOOST_REQUIRE_EQUAL( u2->
Pads().size(), 1 );
1161 BOOST_REQUIRE_MESSAGE( u3,
"U3 should exist" );
1162 BOOST_REQUIRE_EQUAL( u3->
Pads().size(), 1 );
1175 BOOST_REQUIRE_MESSAGE( u4,
"U4 should exist" );
1176 BOOST_REQUIRE_EQUAL( u4->
Pads().size(), 1 );
1191 BOOST_REQUIRE_MESSAGE( u5,
"U5 should exist" );
1192 BOOST_REQUIRE_EQUAL( u5->
Pads().size(), 1 );
1214 std::unique_ptr<BOARD> board( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
1218 bool foundSmdWithMask =
false;
1220 for(
FOOTPRINT* fp : board->Footprints() )
1222 for(
PAD*
pad : fp->Pads() )
1227 foundSmdWithMask =
true;
1232 if( foundSmdWithMask )
1237 "At least one SMD pad in issue23254.asc should have F.Mask and F.Paste" );
1250 std::unique_ptr<BOARD> board;
1251 board.reset( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
1256 bool foundSquarePad =
false;
1258 for(
FOOTPRINT* fp : board->Footprints() )
1260 for(
PAD*
pad : fp->Pads() )
1264 foundSquarePad =
true;
1269 if( foundSquarePad )
1274 "At least one pad should have RECTANGLE shape (square pad import)" );
1278 bool foundZoneWithFull =
false;
1279 bool foundPadWithThermal =
false;
1280 bool foundPadWithoutThermal =
false;
1282 for(
ZONE* zone : board->Zones() )
1286 foundZoneWithFull =
true;
1292 "Zones should default to FULL (solid) connection" );
1294 for(
FOOTPRINT* fp : board->Footprints() )
1296 for(
PAD*
pad : fp->Pads() )
1299 foundPadWithThermal =
true;
1301 foundPadWithoutThermal =
true;
1306 "Pads with RT/ST entries should have per-pad THERMAL connection" );
1308 "Pads without RT/ST entries should not have per-pad THERMAL override" );
1314 auto nc1It = netclasses.find( wxT(
"NETTCLASS1" ) );
1315 auto nc2It = netclasses.find( wxT(
"NETTCLASS2" ) );
1320 if( nc1It != netclasses.end() )
1323 "NETTCLASS1 should have a track width rule" );
1326 if( nc2It != netclasses.end() )
1329 "NETTCLASS2 should have a track width rule" );
1331 "NETTCLASS2 should have a clearance rule" );
1336 std::map<wxString, wxString> netAssignments;
1338 for(
const auto& [matcher, ncName] : patterns )
1339 netAssignments[matcher->GetPattern()] = ncName;
1342 "+24V0 should be assigned to a net class" );
1344 "+24V0_FILTER should be assigned to a net class" );
1346 "+24V0_FILTER_RTN should be assigned to a net class" );
1348 if( netAssignments.count( wxT(
"+24V0" ) ) )
1353 if( netAssignments.count( wxT(
"+24V0_FILTER_RTN" ) ) )
1355 BOOST_CHECK_EQUAL( netAssignments[wxT(
"+24V0_FILTER_RTN" )], wxT(
"NETTCLASS2" ) );
1373 std::unique_ptr<BOARD> board( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
1380 "NETTCLASS1 should be imported" );
1382 "NETTCLASS2 should be imported" );
1386 std::map<wxString, wxString> netAssignments;
1388 for(
const auto& [matcher, ncName] : patterns )
1389 netAssignments[matcher->GetPattern()] = ncName;
1393 BOOST_CHECK_EQUAL( netAssignments[wxT(
"+24V0_FILTER" )], wxT(
"NETTCLASS1" ) );
1396 BOOST_CHECK_EQUAL( netAssignments[wxT(
"+24V0_FILTER_RTN" )], wxT(
"NETTCLASS2" ) );
1401 auto nc2It = netclasses.find( wxT(
"NETTCLASS2" ) );
1403 if( nc2It != netclasses.end() )
1406 "NETTCLASS2 should have clearance from RULE_SET" );
1408 "NETTCLASS2 should have track width from RULE_SET" );
1428 +
"plugins/pads/issue23540/test_import.asc";
1430 std::unique_ptr<BOARD> board( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
1450 "route arc angle " << absDeg <<
" should be ~180 degrees (semicircle)" );
1458 int chordY = ( start.
y +
end.y ) / 2;
1461 "arc midpoint Y=" << mid.
y <<
" should be above (less than) "
1462 "chord center Y=" << chordY );
1465 BOOST_REQUIRE_MESSAGE( arcCount == 1,
1466 "expected exactly 1 PCB_ARC from route CW/CCW arc, got " << arcCount );
1470 int straightOnArcNet = 0;
1479 "route arc net should contain no straight track remnant, got "
1480 << straightOnArcNet );
1504 +
"plugins/pads/issue23425/controlCARDDockingStation.asc";
1506 std::unique_ptr<BOARD> board( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
1512 for(
FOOTPRINT* fp : board->Footprints() )
1514 if( fp->GetReference() == wxT(
"J3" ) )
1521 BOOST_REQUIRE_MESSAGE( j3,
"J3 (HSEC8 edge connector) not found on board" );
1524 const int expectedOffset = 762000;
1525 const int tolerance = 1000;
1527 int offsetPadCount = 0;
1540 "J3 pad " <<
pad->GetNumber()
1541 <<
" offset Y should be 0 (unrotated pad-local), got " << offset.
y );
1544 "J3 pad " <<
pad->GetNumber()
1545 <<
" offset X magnitude " <<
std::abs( offset.
x )
1546 <<
" should be ~" << expectedOffset );
1553 "expected the HSEC8 finger pads to carry a finger offset; got "
1554 << offsetPadCount );
1575 std::unique_ptr<BOARD> board( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
1581 PAD* mtg_top_pad =
nullptr;
1582 PAD* mtg_bot_pad =
nullptr;
1583 PAD* conn_top_pin1 =
nullptr;
1584 PAD* conn_bot_pin1 =
nullptr;
1586 for(
FOOTPRINT* fp : board->Footprints() )
1588 wxString ref = fp->GetReference();
1590 for(
PAD*
pad : fp->Pads() )
1594 else if( ref ==
"E3" )
1596 else if( ref ==
"X1" &&
pad->GetNumber() ==
"1" )
1597 conn_top_pin1 =
pad;
1598 else if( ref ==
"X2" &&
pad->GetNumber() ==
"1" )
1599 conn_bot_pin1 =
pad;
1603 BOOST_REQUIRE_MESSAGE( mtg_top_pad,
"E1 (top mounting hole) not found" );
1604 BOOST_REQUIRE_MESSAGE( mtg_bot_pad,
"E3 (bottom mounting hole) not found" );
1605 BOOST_REQUIRE_MESSAGE( conn_top_pin1,
"X1 pin 1 (top connector square pad) not found" );
1606 BOOST_REQUIRE_MESSAGE( conn_bot_pin1,
"X2 pin 1 (bottom connector square pad) not found" );
1611 "Mounting hole with same shape but different sizes should use NORMAL padstack mode" );
1615 "Bottom-placed mounting hole should also use NORMAL padstack mode" );
1622 top_size == bot_size,
1623 "Top and bottom mounting holes should have equal pad size on F_Cu; "
1624 "top=" << top_size.
x <<
" bot=" << bot_size.
x );
1631 "Mounting hole pad size must be non-zero" );
1636 "Connector pin-1 with square-on-top / round-on-bottom must use FRONT_INNER_BACK" );
1641 "Top connector pin-1 must have RECTANGLE shape on F_Cu" );
1645 "Top connector pin-1 must have CIRCLE shape on B_Cu" );
1650 "Bottom connector pin-1 must have CIRCLE shape on F_Cu after flip" );
1654 "Bottom connector pin-1 must have RECTANGLE shape on B_Cu after flip" );
1681 std::unique_ptr<BOARD> board( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
1691 for(
FOOTPRINT* fp : board->Footprints() )
1693 if( fp->GetValue() == wxT(
"TP_BOTTOM_SMD" ) )
1695 else if( fp->GetValue() == wxT(
"TP_TOP_SMD" ) )
1700 BOOST_REQUIRE_MESSAGE( tpBottom,
"TP_BOTTOM_SMD test point footprint should exist" );
1703 if( tpBottom->
Pads().size() == 1 )
1707 "TP_BOTTOM_SMD pad should be on B.Cu" );
1709 "TP_BOTTOM_SMD pad should not be on F.Cu" );
1714 "TP_BOTTOM_SMD pad size " << padSize <<
" should be ~800000 nm" );
1718 BOOST_REQUIRE_MESSAGE( tpTop,
"TP_TOP_SMD test point footprint should exist" );
1721 if( tpTop->
Pads().size() == 1 )
1725 "TP_TOP_SMD pad should be on F.Cu" );
1727 "TP_TOP_SMD pad should not be on B.Cu" );
1731 "TP_TOP_SMD pad size " << padSize <<
" should be ~800000 nm" );
1756 "TP_BOTTOM_SMD position should not have a bare PCB_VIA" );
1758 "TP_TOP_SMD position should not have a bare PCB_VIA" );
1778 std::unique_ptr<BOARD> board;
1779 board.reset( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
1784 int copyrightCount = 0;
1785 bool frontCopyrightNotMirrored =
false;
1786 bool backCopyrightMirrored =
false;
1797 "imported free text should not be empty" );
1799 if( t->
GetText().Contains( wxT(
"TEXMATE" ) ) )
1805 "copyright text should retain the (c) character" );
1810 "front silkscreen text should not be mirrored" );
1811 frontCopyrightNotMirrored =
true;
1816 "back-side text should be mirrored" );
1817 backCopyrightMirrored =
true;
1823 "expected the copyright text on both front and back, got " << copyrightCount );
1824 BOOST_CHECK( frontCopyrightNotMirrored );
1825 BOOST_CHECK( backCopyrightMirrored );
1829 bool foundCN1 =
false;
1831 for(
FOOTPRINT* fp : board->Footprints() )
1833 if( fp->GetReference() != wxT(
"CN1" ) )
1839 "CN1 should have at least 10 pads, got " << fp->Pads().size() );
1841 for(
PAD*
pad : fp->Pads() )
1849 "CN1 finger pad " <<
pad->GetNumber().ToStdString()
1850 <<
" should be oriented 90 degrees, got "
1851 <<
pad->GetOrientation().AsDegrees() );
1872 std::unique_ptr<BOARD> board( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
1875 auto findFP = [&](
const wxString& aRef ) ->
FOOTPRINT*
1877 for(
FOOTPRINT* fp : board->Footprints() )
1879 if( fp->GetReference() == aRef )
1886 const int tolerance = 5000;
1893 BOOST_REQUIRE_MESSAGE( l1,
"L1 footprint should be imported" );
1899 "L1 pad " <<
pad->GetNumber().ToStdString()
1900 <<
" should have THERMAL zone connection" );
1902 std::optional<int> spoke =
pad->GetLocalThermalSpokeWidthOverride();
1903 BOOST_REQUIRE_MESSAGE( spoke.has_value(),
1904 "L1 pad " <<
pad->GetNumber().ToStdString()
1905 <<
" should have a spoke-width override" );
1907 "L1 pad " <<
pad->GetNumber().ToStdString() <<
" spoke width "
1908 << spoke.value() <<
" should be ~1000000 nm" );
1910 std::optional<int> gap =
pad->GetLocalThermalGapOverride();
1911 BOOST_REQUIRE_MESSAGE( gap.has_value(),
1912 "L1 pad " <<
pad->GetNumber().ToStdString()
1913 <<
" should have a thermal gap override" );
1915 "L1 pad " <<
pad->GetNumber().ToStdString() <<
" thermal gap "
1916 << gap.value() <<
" should be ~120000 nm" );
1924 BOOST_REQUIRE_MESSAGE( e1,
"E1 footprint should be imported" );
1929 "E1 pad should have THERMAL zone connection" );
1931 "E1 pad should NOT have a thermal gap override (outer == pad size)" );
1950 std::unique_ptr<BOARD> board( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
1956 std::set<wxString> refDes;
1958 for(
FOOTPRINT* fp : board->Footprints() )
1959 refDes.insert( fp->GetReference() );
1986 parser.
Parse( filename );
1990 auto it = decals.find(
"104130-6" );
1991 BOOST_REQUIRE_MESSAGE( it != decals.end(),
"104130-6 decal should exist" );
1992 BOOST_REQUIRE_EQUAL( it->second.terminals.size(), 34u );
1994 auto sop_it = decals.find(
"SOP16" );
1995 BOOST_REQUIRE_MESSAGE( sop_it != decals.end(),
"SOP16 decal should exist" );
1996 BOOST_REQUIRE_EQUAL( sop_it->second.terminals.size(), 16u );
2024 std::unique_ptr<BOARD> board( plugin.
LoadBoard( filename,
nullptr,
nullptr,
nullptr ) );
2028 const double tolerance = 0.005;
2036 const std::map<wxString, EXPECTED>
expected = {
2037 { wxT(
"R1" ), { 2, 105000.0 / 900000.0 } },
2038 { wxT(
"D1" ), { 6, 225000.0 / 825000.0 } },
2041 int checkedRefs = 0;
2043 for(
FOOTPRINT* fp : board->Footprints() )
2045 auto it =
expected.find( fp->GetReference() );
2052 int roundRectCount = 0;
2054 for(
PAD*
pad : fp->Pads() )
2057 fp->GetReference() <<
" pad " <<
pad->GetNumber()
2058 <<
" should import as roundrect" );
2064 std::abs(
pad->GetRoundRectRadiusRatio(
F_Cu ) - it->second.ratio ) < tolerance,
2065 fp->GetReference() <<
" pad " <<
pad->GetNumber() <<
" ratio "
2066 <<
pad->GetRoundRectRadiusRatio(
F_Cu ) <<
" should be ~" << it->second.ratio );
2072 fp->GetReference() <<
" should have " << it->second.padCount
2073 <<
" roundrect pads, got " << roundRectCount );
2077 "expected R1 and D1 footprints to be imported, found " << checkedRefs );
General utilities for PCB file IO for QA programs.
@ BS_ITEM_TYPE_DIELECTRIC
Container for design settings for a BOARD object.
std::shared_ptr< NET_SETTINGS > m_NetSettings
int m_CopperEdgeClearance
int GetBoardThickness() const
The full thickness of the board including copper and masks.
BOARD_STACKUP & GetStackupDescriptor()
std::vector< VIA_DIMENSION > m_ViasDimensionsList
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Manage one layer needed to make a physical board.
Manage layers needed to make a physical board.
const std::vector< BOARD_STACKUP_ITEM * > & GetList() const
constexpr void SetMaximum()
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
constexpr bool Intersects(const BOX2< Vec > &aRect) const
virtual const wxString & GetText() const
Return the string associated with the text object.
Handle the data for a net.
const wxString & GetNetname() const
const std::map< wxString, std::shared_ptr< NETCLASS > > & GetNetclasses() const
Gets all netclasses.
std::shared_ptr< NETCLASS > GetDefaultNetclass() const
Gets the default netclass for the project.
std::vector< std::pair< std::unique_ptr< EDA_COMBINED_MATCHER >, wxString > > & GetNetclassPatternAssignments()
Gets the netclass pattern assignments.
@ NORMAL
Shape is the same on all layers.
@ FRONT_INNER_BACK
Up to three shapes can be defined (F_Cu, inner copper layers, B_Cu)
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
const std::map< std::string, PART_DECAL > & GetPartDecals() const
void Parse(const wxString &aFileName)
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
VECTOR2I GetSize(PCB_LAYER_ID aLayer) const
const PADSTACK & Padstack() const
EDA_ANGLE GetAngle() const
const VECTOR2I & GetMid() const
For better understanding of the points that make a dimension:
BOARD * LoadBoard(const wxString &aFileName, BOARD *aAppendToMe, const std::map< std::string, UTF8 > *aProperties, PROJECT *aProject) override
Load information from some input file format that this PCB_IO implementation knows about into either ...
bool CanReadBoard(const wxString &aFileName) const override
Checks if this PCB_IO can read the specified board file.
const VECTOR2I & GetStart() const
const VECTOR2I & GetEnd() const
int PointCount() const
Return the number of points (vertices) in this line chain.
Represent a set of closed polygons.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
CONST_SEGMENT_ITERATOR CIterateSegmentsWithHoles() const
Return an iterator object, for the aOutline-th outline in the set (with holes).
int OutlineCount() const
Return the number of outlines in the set.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
Handle a list of polygons defining a copper zone.
SHAPE_POLY_SET * Outline()
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ SMD
Smd pad, appears on the solder paste layer (default)
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
VECTOR3I expected(15, 30, 45)
static void RunStructuralChecks(const PADS_BOARD_INFO &aBoard)
Run structural integrity checks on a successfully loaded board.
static wxString GetBoardPath(const PADS_BOARD_INFO &aBoard)
static const PADS_BOARD_INFO PADS_BOARDS[]
static std::unique_ptr< BOARD > LoadAndVerify(const PADS_BOARD_INFO &aBoard)
Verify that the PADS file is recognized and loads without crashing.
BOOST_AUTO_TEST_CASE(ImportClaySight_MK1)
BOOST_CHECK_MESSAGE(totalMismatches==0, std::to_string(totalMismatches)+" board(s) with strategy disagreements")
BOOST_CHECK_EQUAL(result, "25.4")
@ 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_ARC_T
class PCB_ARC, an arc track segment on a copper layer
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
VECTOR2< int32_t > VECTOR2I
@ THERMAL
Use thermal relief for pads.
@ FULL
pads are covered by copper