65 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
83 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
87 int emptyRefDesCount = 0;
88 int validRefDesCount = 0;
90 for(
FOOTPRINT* fp : board->Footprints() )
92 wxString refdes = fp->GetReference();
94 if( refdes.IsEmpty() )
100 BOOST_TEST_MESSAGE(
"Valid RefDes: " << validRefDesCount <<
", Empty: " << emptyRefDesCount );
103 BOOST_CHECK_GT( validRefDesCount, emptyRefDesCount );
112 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
116 int validPadCount = 0;
117 int zeroPadCount = 0;
118 int hugePadCount = 0;
120 for(
FOOTPRINT* fp : board->Footprints() )
122 for(
PAD*
pad : fp->Pads() )
126 if( size.
x == 0 || size.
y == 0 )
130 <<
pad->GetNumber() );
132 else if( size.
x > 50000000 || size.
y > 50000000 )
136 <<
": " << size.
x / 1000000.0 <<
"mm x "
137 << size.
y / 1000000.0 <<
"mm" );
147 <<
", Huge: " << hugePadCount );
159 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
163 int validViaCount = 0;
164 int suspiciousViaCount = 0;
167 const int HARDCODED_SIZE = 1000000;
169 for(
PCB_TRACK* track : board->Tracks() )
174 int width =
via->GetWidth(
F_Cu );
176 if( width == HARDCODED_SIZE )
178 suspiciousViaCount++;
180 else if( width > 0 && width < 10000000 )
187 BOOST_TEST_MESSAGE(
"Valid vias: " << validViaCount <<
", Hardcoded-size vias: " << suspiciousViaCount );
190 if( suspiciousViaCount > 0 )
192 BOOST_WARN_MESSAGE(
false,
"Found " << suspiciousViaCount <<
" vias with hardcoded 1mm size" );
202 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
206 int validTrackCount = 0;
207 int zeroTrackCount = 0;
209 for(
PCB_TRACK* track : board->Tracks() )
213 int width = track->GetWidth();
217 else if( width > 0 && width < 10000000 )
222 BOOST_TEST_MESSAGE(
"Valid tracks: " << validTrackCount <<
", Zero-width: " << zeroTrackCount );
233 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
237 int numberedPads = 0;
238 int unnumberedPads = 0;
240 for(
FOOTPRINT* fp : board->Footprints() )
242 for(
PAD*
pad : fp->Pads() )
244 if(
pad->GetNumber().IsEmpty() )
251 BOOST_TEST_MESSAGE(
"Numbered pads: " << numberedPads <<
", Unnumbered: " << unnumberedPads );
255 if( unnumberedPads > 0 )
257 BOOST_WARN_MESSAGE(
false,
"Found " << unnumberedPads <<
" pads without numbers" );
267 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
272 int outlineSegmentCount = 0;
278 outlineSegmentCount++;
285 BOOST_CHECK_GE( outlineSegmentCount, 4 );
288 std::vector<PCB_SHAPE*> outlineShapes;
294 outlineShapes.push_back(
static_cast<PCB_SHAPE*
>( item ) );
298 if( !outlineShapes.empty() )
302 int connectedCount = 0;
314 VECTOR2I otherStart = other->GetStart();
315 VECTOR2I otherEnd = other->GetEnd();
318 if( start == otherStart || start == otherEnd )
322 if(
end == otherStart ||
end == otherEnd )
330 BOOST_CHECK_GE( connectedCount, outlineShapes.size() * 2 );
340 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
346 bool hasBbox =
false;
354 boardBbox = item->GetBoundingBox();
359 boardBbox.
Merge( item->GetBoundingBox() );
364 BOOST_REQUIRE_MESSAGE( hasBbox,
"Board should have an outline" );
370 BOX2I testBbox = boardBbox;
373 for(
FOOTPRINT* fp : board->Footprints() )
375 for(
PAD*
pad : fp->Pads() )
379 if( testBbox.
Contains( padCenter ) )
387 <<
pad->GetNumber() <<
" at ("
388 << padCenter.
x / 1000000.0 <<
", "
389 << padCenter.
y / 1000000.0 <<
") mm" );
394 BOOST_TEST_MESSAGE(
"Pads inside outline: " << padsInside <<
", outside: " << padsOutside );
398 if( padsOutside > 0 )
400 BOOST_WARN_MESSAGE(
false,
"Found " << padsOutside <<
" pads outside board outline" );
404 BOOST_CHECK_GT( padsInside, padsOutside );
414 BOOST_CHECK_EXCEPTION(
415 LoadAllegroBoard(
"v13_header/v13_header.brd" ),
IO_ERROR,
418 wxString msg = e.
What();
420 return msg.Contains( wxS(
"predates Allegro 16.0" ) )
421 && msg.Contains( wxS(
"Allegro PCB Design" ) );
433 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"rects/rects.brd" );
439 ZONE* zone = board->Zones().front();
445 int copperPolyCount = 0;
446 int copperPolyWithNet = 0;
474 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"copper_text/copper_text.brd" );
477 int copperTextCount = 0;
478 bool foundTestingText =
false;
490 if(
text->GetText() == wxS(
"TESTING" ) )
492 foundTestingText =
true;
499 BOOST_CHECK_MESSAGE( foundTestingText,
"Board should contain 'TESTING' text on F.Cu" );
539 std::vector<std::string> boards;
545 for(
const auto& boardDir : std::filesystem::directory_iterator( dataPath ) )
547 if( !boardDir.is_directory() )
550 for(
const auto& entry : std::filesystem::directory_iterator( boardDir ) )
552 if( entry.is_regular_file() && entry.path().extension() ==
".brd" && entry.file_size() > 0 )
554 std::string
name = entry.path().filename().string();
557 if(
name !=
"v13_header.brd" )
559 boards.push_back( boardDir.path().string() +
"/" +
name );
565 catch(
const std::filesystem::filesystem_error& e )
570 std::sort( boards.begin(), boards.end() );
589 BOARD* board = GetCachedBoard( dataPath );
592 const std::vector<wxString> expectedLayers = { wxS(
"TOP" ), wxS(
"LYR2_GND" ),
593 wxS(
"LYR5_PWR" ), wxS(
"BOTTOM" ) };
595 for(
const wxString& layerName : expectedLayers )
602 "Layer " << layerName <<
" should exist" );
604 const ZONE* largest =
nullptr;
605 double largestArea = 0;
609 if( zone->GetIsRuleArea() )
612 if( zone->GetNetCode() == 0 )
615 if( !zone->GetLayerSet().Contains( layerId ) )
618 BOX2I bbox = zone->GetBoundingBox();
619 double area =
static_cast<double>( bbox.
GetWidth() )
620 *
static_cast<double>( bbox.
GetHeight() );
622 if( area > largestArea )
629 BOOST_REQUIRE_MESSAGE( largest !=
nullptr,
630 "Should find a netted copper zone on " << layerName );
642 std::vector<std::string> boards = GetAllBoardFiles();
644 for(
const std::string& boardPath : boards )
646 std::string boardName = std::filesystem::path( boardPath ).filename().string();
647 BOARD* board = GetCachedBoard( boardPath );
654 int negativePadCount = 0;
658 for(
PAD*
pad : fp->Pads() )
662 if( size.
x < 0 || size.
y < 0 )
666 <<
" pad " <<
pad->GetNumber() <<
": " << size.
x <<
" x "
684 std::vector<std::string> boards = GetAllBoardFiles();
686 for(
const std::string& boardPath : boards )
688 std::string boardName = std::filesystem::path( boardPath ).filename().string();
689 BOARD* board = GetCachedBoard( boardPath );
696 int invalidViaCount = 0;
703 int drill =
via->GetDrill();
704 int width =
via->GetWidth(
F_Cu );
710 <<
via->GetPosition().x / 1000000.0 <<
", "
711 <<
via->GetPosition().y / 1000000.0
712 <<
") has drill " << drill / 1000000.0
713 <<
"mm > width " << width / 1000000.0 <<
"mm" );
730 std::vector<std::string> boards = GetAllBoardFiles();
732 for(
const std::string& boardPath : boards )
734 std::string boardName = std::filesystem::path( boardPath ).filename().string();
735 BOARD* board = GetCachedBoard( boardPath );
742 int misclassifiedSmdCount = 0;
743 int correctSmdCount = 0;
744 int correctThCount = 0;
748 for(
PAD*
pad : fp->Pads() )
750 bool hasDrill =
pad->GetDrillSizeX() > 0 &&
pad->GetDrillSizeY() > 0;
755 misclassifiedSmdCount++;
757 <<
"." <<
pad->GetNumber()
758 <<
" has no drill but is marked as PTH (should be SMD)" );
772 <<
", Correct TH=" << correctThCount
773 <<
", Misclassified=" << misclassifiedSmdCount );
787 std::vector<std::string> boards = GetAllBoardFiles();
789 for(
const std::string& boardPath : boards )
791 std::string boardName = std::filesystem::path( boardPath ).filename().string();
792 BOARD* board = GetCachedBoard( boardPath );
799 int quadPackageCount = 0;
800 int packagesWithRotatedPads = 0;
801 int packagesWithUnrotatedPads = 0;
805 wxString refdes = fp->GetReference().Upper();
808 if( !refdes.StartsWith(
"U" ) )
812 if( fp->Pads().size() < 16 )
819 for(
PAD*
pad : fp->Pads() )
830 padBounds.
Merge( pos );
838 if( width == 0 || height == 0 )
841 double aspectRatio =
static_cast<double>( std::max( width, height ) ) /
842 static_cast<double>( std::min( width, height ) );
844 if( aspectRatio > 2.0 )
850 std::set<int> uniqueAngles;
852 for(
PAD*
pad : fp->Pads() )
856 int degrees =
static_cast<int>( angle.
AsDegrees() + 0.5 ) % 360;
857 uniqueAngles.insert( degrees );
862 if( uniqueAngles.size() >= 2 )
864 packagesWithRotatedPads++;
866 <<
" has " << uniqueAngles.size() <<
" unique pad orientations" );
870 packagesWithUnrotatedPads++;
872 <<
" has only " << uniqueAngles.size()
873 <<
" unique pad orientation (may be missing rotation)" );
877 if( quadPackageCount > 0 )
880 <<
" potential quad packages, "
881 << packagesWithRotatedPads <<
" with rotated pads, "
882 << packagesWithUnrotatedPads <<
" without" );
886 if( packagesWithRotatedPads == 0 && quadPackageCount > 0 )
888 BOOST_WARN_MESSAGE(
false, boardName <<
" has no packages with rotated pads" );
905 BOARD* board = GetCachedBoard( dataPath );
906 BOOST_REQUIRE_MESSAGE( board !=
nullptr,
"BeagleBone_Black_RevC.brd should load successfully" );
913 if( fp->GetReference() ==
"C78" )
920 BOOST_REQUIRE_MESSAGE( c78 !=
nullptr,
"Footprint C78 should exist in BeagleBone Black" );
927 BOOST_CHECK_MESSAGE( fpLayer ==
B_Cu,
"C78 should be on the bottom copper layer (B_Cu), got "
929 BOOST_CHECK_MESSAGE( c78->
IsFlipped(),
"C78 should be flipped (IsFlipped() == true)" );
937 if( fp->GetLayer() ==
F_Cu )
939 else if( fp->GetLayer() ==
B_Cu )
943 BOOST_TEST_MESSAGE(
"Footprints on top: " << topCount <<
", on bottom: " << bottomCount );
946 BOOST_CHECK_GT( topCount, 0 );
947 BOOST_CHECK_GT( bottomCount, 0 );
957 std::vector<std::string> boards = GetAllBoardFiles();
959 for(
const std::string& boardPath : boards )
961 std::string boardName = std::filesystem::path( boardPath ).filename().string();
962 BOARD* board = GetCachedBoard( boardPath );
970 int disconnectedArcs = 0;
973 std::map<int, std::vector<VECTOR2I>> netEndpoints;
977 int netCode = track->GetNetCode();
981 netEndpoints[netCode].push_back( track->GetStart() );
982 netEndpoints[netCode].push_back( track->GetEnd() );
986 netEndpoints[netCode].push_back( track->GetPosition() );
993 for(
PAD*
pad : fp->Pads() )
995 int netCode =
pad->GetNetCode();
998 netEndpoints[netCode].push_back(
pad->GetPosition() );
1016 bool startConnected =
false;
1017 bool endConnected =
false;
1018 const int tolerance = 1000;
1020 for(
const VECTOR2I& pt : netEndpoints[netCode] )
1022 if( ( pt - arcStart ).EuclideanNorm() < tolerance )
1023 startConnected =
true;
1025 if( ( pt - arcEnd ).EuclideanNorm() < tolerance )
1026 endConnected =
true;
1031 if( !startConnected && !endConnected && netEndpoints[netCode].size() > 2 )
1035 << arcStart.
x / 1000000.0 <<
", "
1036 << arcStart.
y / 1000000.0 <<
") to ("
1037 << arcEnd.
x / 1000000.0 <<
", "
1038 << arcEnd.
y / 1000000.0
1039 <<
") appears disconnected from net " << netCode );
1046 << disconnectedArcs <<
" disconnected" );
1053 BOOST_CHECK_LE( disconnectedArcs, arcCount / 5 );
1105 std::vector<wxString> fields;
1108 for(
size_t i = 0; i < aLine.size(); ++i )
1110 if( aLine[i] ==
'!' )
1112 fields.push_back( current );
1117 current += aLine[i];
1121 if( !current.empty() )
1122 fields.push_back( current );
1134 wxString tag = aTag.BeforeFirst(
' ' );
1136 return static_cast<int>( val );
1142 std::ifstream file( aPath );
1144 if( !file.is_open() )
1155 SECTION currentSection = SECTION::UNKNOWN;
1161 while( std::getline( file, line ) )
1163 if( line.empty() || line[0] ==
'J' )
1166 if( line[0] ==
'A' )
1168 if( line.find(
"NET_NAME_SORT!NODE_SORT!NET_NAME!REFDES!" ) != std::string::npos )
1169 currentSection = SECTION::NET_NODES;
1170 else if( line.find(
"SYM_TYPE!SYM_NAME!REFDES!SYM_MIRROR!" ) != std::string::npos )
1171 currentSection = SECTION::SYM_PLACEMENT;
1172 else if( line.find(
"CLASS!SUBCLASS!RECORD_TAG!GRAPHIC_DATA_NAME!" ) != std::string::npos )
1173 currentSection = SECTION::GRAPHICS;
1175 currentSection = SECTION::UNKNOWN;
1180 if( line[0] !=
'S' )
1183 auto fields =
SplitAlgLine( wxString::FromUTF8( line ) );
1185 switch( currentSection )
1187 case SECTION::NET_NODES:
1190 if( fields.size() >= 5 )
1192 wxString netName = fields[3];
1193 wxString refdes = fields[4];
1195 if( !netName.empty() )
1199 if( !refdes.empty() )
1206 case SECTION::SYM_PLACEMENT:
1209 if( fields.size() >= 4 )
1211 wxString symType = fields[1];
1212 wxString symName = fields[2];
1213 wxString refdes = fields[3];
1215 if( symType == wxT(
"PACKAGE" ) && !refdes.empty() )
1217 data.
refDes.insert( refdes );
1224 case SECTION::GRAPHICS:
1230 if( fields.size() < 16 || fields[1] != wxT(
"BOUNDARY" ) )
1233 wxString closureType = fields[15];
1235 if( closureType != wxT(
"SHAPE" ) )
1238 wxString layer = fields[2];
1246 if( fields.size() > 23 )
1247 netName = fields[23];
1249 auto key = std::make_pair( layer, recordId );
1250 auto& zone = zoneMap[key];
1252 zone.recordId = recordId;
1254 if( !netName.empty() )
1255 zone.netName = netName;
1257 double x1 = 0, y1 = 0, x2 = 0, y2 = 0;
1259 if( fields.size() > 9 )
1261 fields[6].ToDouble( &x1 );
1262 fields[7].ToDouble( &y1 );
1263 fields[8].ToDouble( &x2 );
1264 fields[9].ToDouble( &y2 );
1265 zone.AddPoint( x1, y1 );
1266 zone.AddPoint( x2, y2 );
1276 for(
auto& [key, zone] : zoneMap )
1298 std::vector<BRD_ALG_PAIR> boardsWithAlg;
1300 for(
const auto& boardDir : std::filesystem::directory_iterator( dataPath ) )
1302 if( !boardDir.is_directory() )
1305 std::filesystem::path boardPath;
1306 std::filesystem::path algPath;
1308 for(
const auto& entry : std::filesystem::directory_iterator( boardDir ) )
1310 if( !entry.is_regular_file() )
1313 if( entry.path().extension() ==
".brd" )
1314 boardPath = entry.path();
1315 else if( entry.path().extension() ==
".alg" )
1316 algPath = entry.path();
1318 if( !boardPath.empty() && !algPath.empty() )
1320 boardsWithAlg.push_back( { boardPath.string(), algPath.string() } );
1326 return boardsWithAlg;
1337 BOOST_REQUIRE_GT( boardsWithAlg.size(), 0u );
1339 for(
const auto& [brdFile, algFile] : boardsWithAlg )
1344 BOOST_REQUIRE_GT( algData.
netNames.size(), 0u );
1346 BOARD* board = GetCachedBoard( brdFile );
1349 std::set<wxString> boardNets;
1353 if( net->GetNetCode() > 0 )
1354 boardNets.insert( net->GetNetname() );
1357 int missingNets = 0;
1359 for(
const wxString& algNet : algData.
netNames )
1361 if( boardNets.find( algNet ) == boardNets.end() )
1365 if( missingNets <= 10 )
1371 << boardNets.size() <<
", missing " << missingNets );
1385 BOOST_REQUIRE_GT( boardsWithAlg.size(), 0u );
1387 for(
const auto& [brdFile, algFile] : boardsWithAlg )
1392 BOOST_REQUIRE_GT( algData.
refDes.size(), 0u );
1394 BOARD* board = GetCachedBoard( brdFile );
1397 std::set<wxString> boardRefDes;
1400 boardRefDes.insert( fp->GetReference() );
1402 int missingRefDes = 0;
1403 int extraRefDes = 0;
1405 for(
const wxString& algRef : algData.
refDes )
1407 if( boardRefDes.find( algRef ) == boardRefDes.end() )
1411 if( missingRefDes <= 10 )
1416 for(
const wxString& boardRef : boardRefDes )
1418 if( algData.
refDes.find( boardRef ) == algData.
refDes.end() )
1422 if( extraRefDes <= 10 )
1428 <<
" components, board has " << boardRefDes.size()
1429 <<
", missing " << missingRefDes
1430 <<
", extra " << extraRefDes );
1442 std::vector<std::string> boards = GetAllBoardFiles();
1444 for(
const std::string& boardPath : boards )
1446 std::string boardName = std::filesystem::path( boardPath ).filename().string();
1447 BOARD* board = GetCachedBoard( boardPath );
1454 int zeroWidthCount = 0;
1463 if( track->GetWidth() <= 0 )
1467 if( zeroWidthCount <= 5 )
1470 << track->GetStart().x / 1000000.0 <<
", "
1471 << track->GetStart().y / 1000000.0 <<
")" );
1511 double minX = std::numeric_limits<double>::max();
1512 double minY = std::numeric_limits<double>::max();
1513 double maxX = std::numeric_limits<double>::lowest();
1514 double maxY = std::numeric_limits<double>::lowest();
1527 std::ifstream file( aPath );
1529 if( !file.is_open() )
1534 while( std::getline( file, line ) )
1536 if( line.empty() || line[0] !=
'S' )
1541 if( fields.size() < 10 )
1544 bool isDesignOutline = ( fields[1] == wxT(
"BOARD GEOMETRY" )
1545 && fields[2] == wxT(
"DESIGN_OUTLINE" ) );
1547 bool isOutline = ( fields[1] == wxT(
"BOARD GEOMETRY" )
1548 && fields[2] == wxT(
"OUTLINE" ) );
1550 if( !isDesignOutline && !isOutline )
1553 wxString shapeType = fields[4];
1556 if( shapeType == wxT(
"LINE" ) && fields.size() >= 10 )
1559 fields[6].ToCDouble( &seg.
x1 );
1560 fields[7].ToCDouble( &seg.
y1 );
1561 fields[8].ToCDouble( &seg.
x2 );
1562 fields[9].ToCDouble( &seg.
y2 );
1567 else if( shapeType == wxT(
"ARC" ) && fields.size() >= 15 )
1570 fields[6].ToCDouble( &seg.
x1 );
1571 fields[7].ToCDouble( &seg.
y1 );
1572 fields[8].ToCDouble( &seg.
x2 );
1573 fields[9].ToCDouble( &seg.
y2 );
1574 fields[10].ToCDouble( &seg.
centerX );
1575 fields[11].ToCDouble( &seg.
centerY );
1576 fields[12].ToCDouble( &seg.
radius );
1577 seg.
clockwise = ( fields[14] == wxT(
"CLOCKWISE" ) );
1582 else if( shapeType == wxT(
"RECTANGLE" ) && fields.size() >= 10 )
1585 fields[6].ToCDouble( &seg.
x1 );
1586 fields[7].ToCDouble( &seg.
y1 );
1587 fields[8].ToCDouble( &seg.
x2 );
1588 fields[9].ToCDouble( &seg.
y2 );
1598 if( isDesignOutline )
1642 BOOST_REQUIRE_GT( testBoards.size(), 0u );
1644 for(
const auto& [brdFile, algFile] : testBoards )
1656 BOARD* board = GetCachedBoard( brdFile );
1659 int edgeCutsCount = 0;
1670 <<
" -> expected Edge_Cuts segments: " << expectedCount );
1688 BOOST_REQUIRE_GT( testBoards.size(), 0u );
1691 const double milToNm = 25400.0;
1694 const int toleranceNm =
static_cast<int>( 2.0 * milToNm );
1696 for(
const auto& [brdFile, algFile] : testBoards )
1708 BOARD* board = GetCachedBoard( brdFile );
1712 bool hasBbox =
false;
1720 boardBbox = item->GetBoundingBox();
1725 boardBbox.
Merge( item->GetBoundingBox() );
1730 BOOST_REQUIRE_MESSAGE( hasBbox,
"Board should have Edge_Cuts outline" );
1733 int algMinXnm =
static_cast<int>( algOutlines.
minX * milToNm );
1734 int algMinYnm =
static_cast<int>( algOutlines.
minY * milToNm );
1735 int algMaxXnm =
static_cast<int>( algOutlines.
maxX * milToNm );
1736 int algMaxYnm =
static_cast<int>( algOutlines.
maxY * milToNm );
1737 int algWidthNm = algMaxXnm - algMinXnm;
1738 int algHeightNm = algMaxYnm - algMinYnm;
1740 int boardWidth = boardBbox.
GetWidth();
1741 int boardHeight = boardBbox.
GetHeight();
1744 << algOutlines.
minX <<
"," << algOutlines.
minY <<
" to "
1745 << algOutlines.
maxX <<
"," << algOutlines.
maxY
1746 <<
" = " << ( algOutlines.
maxX - algOutlines.
minX ) <<
" x "
1747 << ( algOutlines.
maxY - algOutlines.
minY ) );
1749 << boardBbox.
GetLeft() <<
"," << boardBbox.
GetTop() <<
" to "
1751 <<
" = " << boardWidth <<
" x " << boardHeight );
1755 BOOST_CHECK_CLOSE(
static_cast<double>( boardWidth ),
1756 static_cast<double>( algWidthNm ), 3.0 );
1757 BOOST_CHECK_CLOSE(
static_cast<double>( boardHeight ),
1758 static_cast<double>( algHeightNm ), 3.0 );
1775 BOOST_REQUIRE_GT( testBoards.size(), 0u );
1777 const double milToNm = 25400.0;
1778 const int toleranceNm =
static_cast<int>( 2.0 * milToNm );
1780 for(
const auto& [brdFile, algFile] : testBoards )
1790 bool allLines =
true;
1808 BOARD* board = GetCachedBoard( brdFile );
1812 struct ENDPOINT_PAIR
1818 std::vector<ENDPOINT_PAIR> boardSegments;
1828 boardSegments.push_back( { shape->
GetStart(), shape->
GetEnd() } );
1832 std::vector<ENDPOINT_PAIR> algSegments;
1838 VECTOR2I start(
static_cast<int>( seg.x1 * milToNm ),
1839 static_cast<int>( seg.y1 * milToNm ) );
1840 VECTOR2I end(
static_cast<int>( seg.x2 * milToNm ),
1841 static_cast<int>( seg.y2 * milToNm ) );
1842 algSegments.push_back( { start,
end } );
1846 int x1 =
static_cast<int>( seg.x1 * milToNm );
1847 int y1 =
static_cast<int>( seg.y1 * milToNm );
1848 int x2 =
static_cast<int>( seg.x2 * milToNm );
1849 int y2 =
static_cast<int>( seg.y2 * milToNm );
1851 algSegments.push_back( { { x1, y1 }, { x2, y1 } } );
1852 algSegments.push_back( { { x2, y1 }, { x2, y2 } } );
1853 algSegments.push_back( { { x2, y2 }, { x1, y2 } } );
1854 algSegments.push_back( { { x1, y2 }, { x1, y1 } } );
1860 if( boardSegments.size() != algSegments.size() )
1866 int matchedCount = 0;
1868 std::vector<bool> used( boardSegments.size(),
false );
1870 for(
size_t ai = 0; ai < algSegments.size(); ++ai )
1872 const auto& algSeg = algSegments[ai];
1874 int64_t bestDist = std::numeric_limits<int64_t>::max();
1876 for(
size_t bi = 0; bi < boardSegments.size(); ++bi )
1881 const auto& bSeg = boardSegments[bi];
1884 auto dist = [&](
const VECTOR2I& aAlgPt,
const VECTOR2I& aBoardPt ) -> int64_t
1886 int64_t dx =
std::abs(
static_cast<int64_t
>( aAlgPt.
x )
1887 -
static_cast<int64_t
>( aBoardPt.x ) );
1888 int64_t dy =
std::abs(
static_cast<int64_t
>( aAlgPt.
y )
1889 -
static_cast<int64_t
>( aBoardPt.y ) );
1893 int64_t d1 = dist( algSeg.start, bSeg.start ) + dist( algSeg.end, bSeg.end );
1894 int64_t d2 = dist( algSeg.start, bSeg.end ) + dist( algSeg.end, bSeg.start );
1895 int64_t d = std::min( d1, d2 );
1900 bestIdx =
static_cast<int>( bi );
1904 if( bestIdx >= 0 && bestDist < 2LL * toleranceNm )
1906 used[bestIdx] =
true;
1912 << algSeg.start.x / 1000000.0 <<
", "
1913 << algSeg.start.y / 1000000.0 <<
") -> ("
1914 << algSeg.end.x / 1000000.0 <<
", "
1915 << algSeg.end.y / 1000000.0 <<
") mm"
1916 <<
" bestDist=" << bestDist );
1921 <<
" outline segments" );
1935 std::vector<std::string> boards = GetAllBoardFiles();
1937 for(
const std::string& boardPath : boards )
1939 std::string boardName = std::filesystem::path( boardPath ).filename().string();
1940 BOARD* board = GetCachedBoard( boardPath );
1948 int smdWithDrill = 0;
1952 for(
PAD*
pad : fp->Pads() )
1955 bool hasDrill =
pad->GetDrillSizeX() > 0;
1961 if( pthNoDrill <= 5 )
1964 << fp->GetReference() <<
"."
1965 <<
pad->GetNumber() );
1973 if( smdWithDrill <= 5 )
1976 << fp->GetReference() <<
"."
1977 <<
pad->GetNumber() );
1997 BOOST_REQUIRE_GT( boardsWithAlg.size(), 0u );
1999 for(
const auto& [brdFile, algFile] : boardsWithAlg )
2005 BOARD* board = GetCachedBoard( brdFile );
2008 size_t boardCopperZoneLayers = 0;
2010 for(
const ZONE* zone : board->
Zones() )
2012 if( !zone->GetIsRuleArea() )
2013 boardCopperZoneLayers += ( zone->GetLayerSet() &
LSET::AllCuMask() ).count();
2019 <<
" zone polygons, board has " << boardCopperZoneLayers
2020 <<
" copper zone-layers" );
2022 BOOST_CHECK_EQUAL(
static_cast<size_t>( boardCopperZoneLayers ), algZoneCount );
2035 BOOST_REQUIRE_GT( boardsWithAlg.size(), 0u );
2037 for(
const auto& [brdFile, algFile] : boardsWithAlg )
2043 BOARD* board = GetCachedBoard( brdFile );
2046 std::map<wxString, int> algLayerCounts;
2049 algLayerCounts[zone.
layer]++;
2051 std::map<wxString, int> boardLayerCounts;
2053 for(
const ZONE* zone : board->
Zones() )
2055 if( zone->GetIsRuleArea() )
2067 for(
const auto& [layer, count] : algLayerCounts )
2069 auto it = boardLayerCounts.find( layer );
2070 int boardCount = ( it != boardLayerCounts.end() ) ? it->second : 0;
2088 BOOST_REQUIRE_GT( boardsWithAlg.size(), 0u );
2090 for(
const auto& [brdFile, algFile] : boardsWithAlg )
2096 BOARD* board = GetCachedBoard( brdFile );
2100 const double milsToNm = 25400.0;
2102 std::map<wxString, std::vector<double>> algAreas;
2106 double w = ( zone.
maxX - zone.
minX ) * milsToNm;
2107 double h = ( zone.
maxY - zone.
minY ) * milsToNm;
2108 algAreas[zone.
layer].push_back( w * h );
2111 std::map<wxString, std::vector<double>> boardAreas;
2113 for(
const ZONE* zone : board->
Zones() )
2115 if( zone->GetIsRuleArea() )
2118 BOX2I bbox = zone->GetBoundingBox();
2119 double area =
static_cast<double>( bbox.
GetWidth() )
2120 *
static_cast<double>( bbox.
GetHeight() );
2125 boardAreas[board->
GetLayerName( layer )].push_back( area );
2132 for(
auto& [layer, algList] : algAreas )
2134 std::sort( algList.begin(), algList.end() );
2135 auto it = boardAreas.find( layer );
2137 if( it == boardAreas.end() || it->second.size() != algList.size() )
2140 std::sort( it->second.begin(), it->second.end() );
2142 for(
size_t i = 0; i < algList.size(); ++i )
2144 double ref = std::max( algList[i], 1.0 );
2145 double err =
std::abs( it->second[i] - algList[i] ) / ref;
2155 if( mismatched <= 5 )
2158 <<
": alg area " << algList[i] / ( milsToNm * milsToNm )
2159 <<
" sq mils vs board area "
2160 << it->second[i] / ( milsToNm * milsToNm )
2168 << mismatched <<
" mismatched" );
2170 int total = matched + mismatched;
2174 BOOST_CHECK_GT( matched, total * 8 / 10 );
2191 BOARD* board = GetCachedBoard( dataPath );
2197 const std::set<wxString> targetRefs = { wxS(
"J1" ), wxS(
"P5" ), wxS(
"U5" ),
2198 wxS(
"U13" ), wxS(
"C78" ) };
2200 int testedCount = 0;
2201 int failedCount = 0;
2205 if( targetRefs.find( fp->GetReference() ) == targetRefs.end() )
2211 bool hasFab =
false;
2213 for(
BOARD_ITEM* item : fp->GraphicalItems() )
2215 if( item->GetLayer() == fabLayer )
2219 fabBbox = item->GetBoundingBox();
2224 fabBbox.
Merge( item->GetBoundingBox() );
2229 if( !hasFab || fp->Pads().empty() )
2234 BOX2I testBbox = fabBbox;
2241 for(
PAD*
pad : fp->Pads() )
2245 if( !testBbox.
Contains( padCenter ) )
2249 <<
" at (" << padCenter.
x / 1e6 <<
", "
2250 << padCenter.
y / 1e6 <<
") mm is outside F.Fab bbox" );
2257 BOOST_CHECK_GE( testedCount, 4 );
2271 BOARD* board = GetCachedBoard( dataPath );
2276 wxString ref = fp->GetReference();
2278 if( ref != wxS(
"P6" ) && ref != wxS(
"P10" ) )
2283 for(
PAD*
pad : fp->Pads() )
2287 if( !
pad->GetNumber().ToLong( &padNum ) )
2291 if( padNum < 1 || padNum > 19 )
2295 BOX2I bbox =
pad->GetBoundingBox();
2300 if( bboxW == bboxH )
2305 BOOST_CHECK_MESSAGE( bboxW > bboxH,
2306 ref <<
" pad " <<
pad->GetNumber()
2307 <<
" should be visually wider than tall: "
2308 << bboxW / 1e6 <<
" x " << bboxH / 1e6 <<
" mm" );
2327 BOARD* board = GetCachedBoard( dataPath );
2330 int oblongCount = 0;
2334 for(
PAD*
pad : fp->Pads() )
2338 if( drillSize.
x <= 0 || drillSize.
y <= 0 )
2341 if( drillSize.
x == drillSize.
y )
2351 <<
" slot: " << drillSize.
x / 1e6 <<
" x "
2352 << drillSize.
y / 1e6 <<
" mm"
2353 <<
" attr=" <<
static_cast<int>(
pad->GetAttribute() ) );
2372 BOARD* board = GetCachedBoard( dataPath );
2380 if( fp->GetReference() == wxT(
"J1" ) )
2387 BOOST_REQUIRE_MESSAGE( j1 !=
nullptr,
"Footprint J1 must exist in BeagleBone_Black_RevC" );
2391 BOOST_CHECK_CLOSE( orientation.
AsDegrees(), 90.0, 0.1 );
2403 BOARD* board = GetCachedBoard( dataPath );
2408 BOOST_CHECK( netSettings->HasNetclass( wxS(
"W20mil" ) ) );
2409 BOOST_CHECK( netSettings->HasNetclass( wxS(
"W24mil" ) ) );
2411 auto nc20 = netSettings->GetNetClassByName( wxS(
"W20mil" ) );
2412 auto nc24 = netSettings->GetNetClassByName( wxS(
"W24mil" ) );
2427 if( net->GetNetCode() <= 0 )
2435 if( nc->
GetName() == wxS(
"W20mil" ) )
2437 else if( nc->
GetName() == wxS(
"W24mil" ) )
2454 BOARD* board = GetCachedBoard( dataPath );
2460 BOOST_CHECK( netSettings->HasNetclass( wxS(
"DP_HDMI_TXC" ) ) );
2461 BOOST_CHECK( netSettings->HasNetclass( wxS(
"DP_USB0" ) ) );
2464 int hdmiTxcCount = 0;
2468 if( net->GetNetCode() <= 0 )
2473 if( nc && nc->
GetName() == wxS(
"DP_HDMI_TXC" ) )
2489 BOARD* board = GetCachedBoard( dataPath );
2495 BOOST_CHECK( netSettings->HasNetclass( wxS(
"MG_DDR_DQ0" ) ) );
2496 BOOST_CHECK( netSettings->HasNetclass( wxS(
"MG_DDR_ADD" ) ) );
2504 if( net->GetNetCode() <= 0 )
2512 if( nc->
GetName() == wxS(
"MG_DDR_DQ0" ) )
2514 else if( nc->
GetName() == wxS(
"MG_DDR_ADD" ) )
2531 BOARD* board = GetCachedBoard( dataPath );
2539 for(
const auto& [
name, nc] : netSettings->GetNetclasses() )
2541 if(
name.StartsWith( wxS(
"DP_" ) ) )
2543 else if(
name.StartsWith( wxS(
"MG_" ) ) )
2560 BOARD* board = GetCachedBoard( dataPath );
2565 for(
const auto& [
name, nc] : netSettings->GetNetclasses() )
2567 BOOST_CHECK_MESSAGE( !
name.StartsWith( wxS(
"DP_" ) ) && !
name.StartsWith( wxS(
"MG_" ) ),
2568 "Simple board should not have match group netclass: " +
name );
2581 BOARD* board = GetCachedBoard( dataPath );
2587 BOOST_CHECK( netSettings->HasNetclass( wxS(
"Allegro_Default" ) ) );
2588 BOOST_CHECK( netSettings->HasNetclass( wxS(
"PWR" ) ) );
2589 BOOST_CHECK( netSettings->HasNetclass( wxS(
"BGA" ) ) );
2590 BOOST_CHECK( netSettings->HasNetclass( wxS(
"90_OHM_DIFF" ) ) );
2591 BOOST_CHECK( netSettings->HasNetclass( wxS(
"100OHM_DIFF" ) ) );
2593 auto ncDefault = netSettings->GetNetClassByName( wxS(
"Allegro_Default" ) );
2594 auto ncPwr = netSettings->GetNetClassByName( wxS(
"PWR" ) );
2608 int defaultCount = 0;
2612 if( net->GetNetCode() <= 0 )
2620 if( nc->
GetName() == wxS(
"Allegro_Default" ) )
2624 BOOST_CHECK_MESSAGE( defaultCount > 0,
"DEFAULT constraint set should have assigned nets (implicit)" );
2636 BOARD* board = GetCachedBoard( dataPath );
2641 BOOST_CHECK( netSettings->HasNetclass( wxS(
"CS_0" ) ) );
2643 auto nc = netSettings->GetNetClassByName( wxS(
"CS_0" ) );
2661 BOARD* board = GetCachedBoard( dataPath );
2667 BOOST_CHECK( netSettings->HasNetclass( wxS(
"CS_0" ) ) );
2670 BOOST_CHECK( netSettings->HasNetclass( wxS(
"W20mil" ) ) );
2671 BOOST_CHECK( netSettings->HasNetclass( wxS(
"W24mil" ) ) );
2674 auto ncCS = netSettings->GetNetClassByName( wxS(
"CS_0" ) );
2681 auto nc20 = netSettings->GetNetClassByName( wxS(
"W20mil" ) );
2682 auto nc24 = netSettings->GetNetClassByName( wxS(
"W24mil" ) );
2699 BOARD* board = GetCachedBoard( dataPath );
2705 auto nc90 = netSettings->GetNetClassByName( wxS(
"90_OHM_DIFF" ) );
2713 auto nc100 = netSettings->GetNetClassByName( wxS(
"100OHM_DIFF" ) );
2721 auto ncBga = netSettings->GetNetClassByName( wxS(
"BGA" ) );
2736 BOARD* board = GetCachedBoard( dataPath );
2742 auto nc = netSettings->GetNetClassByName( wxS(
"DP_90_OHM" ) );
2762 BOARD* rawBoard =
nullptr;
2766 rawBoard = plugin.
LoadBoard( dataPath,
nullptr,
nullptr,
nullptr );
2772 catch(
const std::exception& e )
2779 BOOST_REQUIRE_MESSAGE( rawBoard !=
nullptr,
"LoadBoard with nullptr aAppendToMe must return a valid board" );
2781 std::unique_ptr<BOARD> board( rawBoard );
2783 BOOST_CHECK_GT( board->GetNetCount(), 0 );
2784 BOOST_CHECK_GT( board->Footprints().size(), 0 );
2785 BOOST_CHECK_GT( board->Tracks().size(), 0 );
2802 std::vector<std::string> boards = GetAllBoardFiles();
2804 for(
const std::string& boardPath : boards )
2806 std::string boardName = std::filesystem::path( boardPath ).filename().string();
2807 BOARD* board = GetCachedBoard( boardPath );
2814 int inconsistentCount = 0;
2818 const bool onBottom = fp->IsFlipped();
2820 for(
PAD*
pad : fp->Pads() )
2825 LSET layers =
pad->GetLayerSet();
2829 if( onBottom && hasTopCopper && !hasBotCopper )
2831 inconsistentCount++;
2833 <<
pad->GetNumber() <<
" is on bottom footprint but SMD "
2834 <<
"pad has F.Cu without B.Cu" );
2836 else if( !onBottom && hasBotCopper && !hasTopCopper )
2838 inconsistentCount++;
2840 <<
pad->GetNumber() <<
" is on top footprint but SMD "
2841 <<
"pad has B.Cu without F.Cu" );
2862 std::vector<std::string> boards = GetAllBoardFiles();
2864 for(
const std::string& boardPath : boards )
2866 std::string boardName = std::filesystem::path( boardPath ).filename().string();
2867 BOARD* board = GetCachedBoard( boardPath );
2874 int inconsistentCount = 0;
2879 bool hasSmd =
false;
2882 for(
PAD*
pad : fp->Pads() )
2890 if( !hasSmd || hasTH )
2893 const bool onBottom = fp->IsFlipped();
2895 for(
BOARD_ITEM* item : fp->GraphicalItems() )
2902 bool wrongSide =
false;
2911 inconsistentCount++;
2913 boardName <<
": " << fp->GetReference() <<
" is "
2914 << ( onBottom ?
"bottom" :
"top" ) <<
"-side SMD but has "
2915 << item->GetClass() <<
" on "
2937 BOARD* board = GetCachedBoard( dataPath );
2947 std::vector<SLOT_CHECK> checks = {
2948 { wxS(
"P6" ), wxS(
"20" ) },
2949 { wxS(
"P6" ), wxS(
"21" ) },
2950 { wxS(
"P3" ), wxS(
"6" ) },
2951 { wxS(
"P1" ), wxS(
"1" ) },
2952 { wxS(
"P1" ), wxS(
"2" ) },
2953 { wxS(
"P1" ), wxS(
"3" ) },
2956 for(
const auto& check : checks )
2964 if( candidate->GetReference() == check.fpRef )
2971 BOOST_REQUIRE_MESSAGE( fp !=
nullptr,
"Footprint " << check.fpRef <<
" should exist" );
2975 for(
PAD* candidate : fp->
Pads() )
2977 if( candidate->GetNumber() == check.padNum )
2984 BOOST_REQUIRE_MESSAGE(
pad !=
nullptr,
2985 "Pad " << check.padNum <<
" should exist on " << check.fpRef );
2991 <<
": pad=" << padSize.
x <<
"x" << padSize.
y
2992 <<
" drill=" << drillSize.
x <<
"x" << drillSize.
y );
2995 if( drillSize.
x != drillSize.
y )
2997 bool padIsTaller = ( padSize.
y > padSize.
x );
2998 bool drillIsTaller = ( drillSize.
y > drillSize.
x );
3000 BOOST_CHECK_MESSAGE( padIsTaller == drillIsTaller,
3001 "Drill slot should match pad orientation" );
3016 BOARD* board = GetCachedBoard( dataPath );
3019 int filledZoneCount = 0;
3020 int totalCopperZones = 0;
3022 for(
const ZONE* zone : board->
Zones() )
3024 if( zone->GetIsRuleArea() || zone->GetNetCode() == 0 )
3029 if( zone->IsFilled() )
3034 <<
" layers=" << zone->GetLayerSet().count() );
3039 <<
", filled: " << filledZoneCount );
3041 BOOST_CHECK_GT( totalCopperZones, 0 );
3042 BOOST_CHECK_GT( filledZoneCount, 0 );
3054 BOARD* board = GetCachedBoard( dataPath );
3057 int teardropZones = 0;
3059 for(
const ZONE* zone : board->
Zones() )
3061 if( zone->IsTeardropArea() )
3065 BOOST_CHECK_GT( teardropZones, 1000 );
3069 int padsWithTeardrops = 0;
3074 for(
const PAD*
pad : fp->Pads() )
3078 if(
pad->GetTeardropsEnabled() )
3079 padsWithTeardrops++;
3083 BOOST_CHECK_GT( padsWithTeardrops, 0 );
3084 BOOST_TEST_MESSAGE(
"Pads with teardrops enabled: " << padsWithTeardrops <<
" / " << totalPads );
3086 int viasWithTeardrops = 0;
3096 if(
static_cast<const PCB_VIA*
>( track )->GetTeardropsEnabled() )
3097 viasWithTeardrops++;
3100 BOOST_CHECK_GT( viasWithTeardrops, 0 );
3101 BOOST_TEST_MESSAGE(
"Vias with teardrops enabled: " << viasWithTeardrops <<
" / " << totalVias );
3113 BOARD* board = GetCachedBoard( dataPath );
3116 int teardropZones = 0;
3118 for(
const ZONE* zone : board->
Zones() )
3120 if( zone->IsTeardropArea() )
3126 int padsWithTeardrops = 0;
3130 for(
const PAD*
pad : fp->Pads() )
3132 if(
pad->GetTeardropsEnabled() )
3133 padsWithTeardrops++;
3154 BOARD* rawBoard = plugin.
LoadBoard( dataPath,
nullptr,
nullptr,
nullptr );
3158 std::unique_ptr<BOARD> board( rawBoard );
3160 BOOST_CHECK_MESSAGE( board->m_LegacyNetclassesLoaded,
3161 "m_LegacyNetclassesLoaded must be true after Allegro import" );
3162 BOOST_CHECK_MESSAGE( board->m_LegacyDesignSettingsLoaded,
3163 "m_LegacyDesignSettingsLoaded must be true after Allegro import" );
3173 std::vector<std::string> boards = GetAllBoardFiles();
3175 for(
const std::string& boardPath : boards )
3177 std::string boardName = std::filesystem::path( boardPath ).filename().string();
3178 BOARD* board = GetCachedBoard( boardPath );
3186 const auto& netclasses = netSettings->GetNetclasses();
3190 for(
const auto& [
name, nc] : netclasses )
3193 << nc->GetTrackWidth() <<
" clearance="
3194 << nc->GetClearance() );
3198 if( !
name.StartsWith( wxS(
"DP_" ) )
3199 && !
name.StartsWith( wxS(
"MG_" ) )
3200 && !
name.StartsWith( wxS(
"W" ) ) )
3202 BOOST_CHECK_MESSAGE( nc->HasTrackWidth(),
3203 name <<
" should have a track width" );
3204 BOOST_CHECK_MESSAGE( nc->GetTrackWidth() > 0,
3205 name <<
" track width should be positive" );
3221 BOARD* board = GetCachedBoard( dataPath );
3233 ExpectedNC expectedSets[] = {
3234 {
"Allegro_Default", 120650, 101600 },
3235 {
"PWR", 381000, 101600 },
3236 {
"BGA", 76200, 101600 },
3237 {
"90_OHM_DIFF", 114300, 101600 },
3238 {
"100OHM_DIFF", 95250, 101600 },
3241 for(
const auto&
expected : expectedSets )
3245 BOOST_CHECK_MESSAGE( netSettings->HasNetclass( ncName ),
3246 "Missing netclass: " <<
expected.name );
3248 auto nc = netSettings->GetNetClassByName( ncName );
3250 BOOST_REQUIRE_MESSAGE( nc,
"Cannot retrieve netclass: " <<
expected.name );
3256 BOOST_CHECK( netSettings->HasNetclass( wxS(
"DP_USB0" ) ) );
3257 BOOST_CHECK( netSettings->HasNetclass( wxS(
"DP_USB1" ) ) );
3258 BOOST_CHECK( netSettings->HasNetclass( wxS(
"DP_HDMI_TX0" ) ) );
3261 BOOST_CHECK( netSettings->HasNetclass( wxS(
"MG_DDR_ADD" ) ) );
3262 BOOST_CHECK( netSettings->HasNetclass( wxS(
"MG_DDR_DQ0" ) ) );
3263 BOOST_CHECK( netSettings->HasNetclass( wxS(
"MG_DDR_DQ1" ) ) );
3266 BOOST_CHECK( netSettings->HasNetclass( wxS(
"W8mil" ) ) );
3268 auto ncW8 = netSettings->GetNetClassByName( wxS(
"W8mil" ) );
3274 int assignedCount = 0;
3278 if( net->GetNetCode() <= 0 )
3287 BOOST_CHECK_MESSAGE( assignedCount > 0,
3288 "At least some nets should have non-default netclass assignments" );
General utilities for PCB file IO for QA programs.
wxString GetNetname() const
std::shared_ptr< NET_SETTINGS > m_NetSettings
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Information pertinent to a Pcbnew printed circuit board.
const NETINFO_LIST & GetNetInfo() const
const ZONES & Zones() const
PCB_LAYER_ID GetLayerID(const wxString &aLayerName) const
Return the ID of a layer.
const FOOTPRINTS & Footprints() const
const TRACKS & Tracks() const
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
const DRAWINGS & Drawings() const
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
constexpr size_type GetWidth() const
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
constexpr size_type GetHeight() const
constexpr coord_type GetLeft() const
constexpr bool Contains(const Vec &aPoint) const
constexpr coord_type GetRight() const
constexpr coord_type GetTop() const
constexpr coord_type GetBottom() const
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
virtual void SetReporter(REPORTER *aReporter)
Set an optional reporter for warnings/errors.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
virtual const char * what() const override
std::exception interface, returned as UTF-8
static ALLEGRO_CACHED_LOADER & GetInstance()
Get the singleton instance of the Allegro board cache loader.
BOARD * GetCachedBoard(const std::string &aFilePath)
Get a cached board for the given file path, or load it if not already cached, without forcing a reloa...
Custom REPORTER that captures all messages for later analysis in the unit test framework.
int GetErrorCount() const
void PrintAllMessages(const std::string &aContext) const
LSET is a set of PCB_LAYER_IDs.
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
A collection of nets and the parameters used to route or test these nets.
static const char Default[]
the name of the default NETCLASS
const wxString GetName() const
Gets the name of this (maybe aggregate) netclass in a format for internal usage or for export to exte...
Handle the data for a net.
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 ...
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
const VECTOR2I & GetStart() const
const VECTOR2I & GetEnd() const
Handle a list of polygons defining a copper zone.
PCB_LAYER_ID GetFirstLayer() const
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
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 AllegroBoardDataDir(const std::string &aBoardName)
void PrintBoardStats(const BOARD *aBoard, const std::string &aBoardName)
Print detailed board statistics for debugging using test-framework logging.
std::string AllegroBoardFile(const std::string &aFileName)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
PAD_ATTRIB
The set of pad shapes, used with PAD::{Set,Get}Attribute().
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
@ SMD
Smd pad, appears on the solder paste layer (default)
@ PTH
Plated through hole pad.
Parse board outline geometry from a .alg ASCII reference file.
void updateBounds(double aX, double aY)
static ALG_OUTLINE_DATA ParseAlgOutlines(const std::string &aPath)
std::vector< OUTLINE_SEGMENT > designOutlineSegments
std::vector< OUTLINE_SEGMENT > outlineSegments
int expectedEdgeCutsSegments() const
Expected number of Edge_Cuts segments when translating to KiCad.
std::set< wxString > netNames
static ALG_REFERENCE_DATA ParseAlgFile(const std::string &aPath)
std::map< wxString, wxString > refDesToSymName
std::set< wxString > refDes
static std::vector< wxString > SplitAlgLine(const wxString &aLine)
std::vector< ALG_ZONE_POLYGON > zonePolygons
static int ParseRecordId(const wxString &aTag)
Extract the integer record ID from a RECORD_TAG field like "36 1 0".
std::map< wxString, std::set< wxString > > netToRefDes
Parse a FabMaster .alg file and extract reference data for cross-validation.
void AddPoint(double aX, double aY)
Data for parameterized all-boards test.
Fixture for comprehensive board import tests with error capturing.
PCB_IO_ALLEGRO m_allegroPlugin
BOARD * GetCachedBoard(const std::string &aFilePath)
Get a cached board, loading it on first access.
static std::vector< std::string > GetAllBoardFiles()
Get list of all .brd files in the Allegro test data directory.
ALLEGRO_COMPREHENSIVE_FIXTURE()
std::unique_ptr< BOARD > LoadAllegroBoard(const std::string &aFileName)
PCB_IO_ALLEGRO m_allegroPlugin
BOOST_AUTO_TEST_CASE(FootprintRefDes)
Test that footprints have valid reference designators.
static std::vector< BRD_ALG_PAIR > getBoardsWithAlg()
Get a list of all board files in the test data that have a corresponding .alg reference file.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
VECTOR3I expected(15, 30, 45)
BOOST_TEST_CONTEXT("Test Clearance")
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
BOOST_CHECK_EQUAL(result, "25.4")
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ 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