66 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
84 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
88 int emptyRefDesCount = 0;
89 int validRefDesCount = 0;
91 for(
FOOTPRINT* fp : board->Footprints() )
93 wxString refdes = fp->GetReference();
95 if( refdes.IsEmpty() )
101 BOOST_TEST_MESSAGE(
"Valid RefDes: " << validRefDesCount <<
", Empty: " << emptyRefDesCount );
104 BOOST_CHECK_GT( validRefDesCount, emptyRefDesCount );
113 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
117 int validPadCount = 0;
118 int zeroPadCount = 0;
119 int hugePadCount = 0;
121 for(
FOOTPRINT* fp : board->Footprints() )
123 for(
PAD*
pad : fp->Pads() )
127 if( size.
x == 0 || size.
y == 0 )
131 <<
pad->GetNumber() );
133 else if( size.
x > 50000000 || size.
y > 50000000 )
137 <<
": " << size.
x / 1000000.0 <<
"mm x "
138 << size.
y / 1000000.0 <<
"mm" );
148 <<
", Huge: " << hugePadCount );
160 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
164 int validViaCount = 0;
165 int suspiciousViaCount = 0;
168 const int HARDCODED_SIZE = 1000000;
170 for(
PCB_TRACK* track : board->Tracks() )
175 int width =
via->GetWidth(
F_Cu );
177 if( width == HARDCODED_SIZE )
179 suspiciousViaCount++;
181 else if( width > 0 && width < 10000000 )
188 BOOST_TEST_MESSAGE(
"Valid vias: " << validViaCount <<
", Hardcoded-size vias: " << suspiciousViaCount );
191 if( suspiciousViaCount > 0 )
193 BOOST_WARN_MESSAGE(
false,
"Found " << suspiciousViaCount <<
" vias with hardcoded 1mm size" );
203 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
207 int validTrackCount = 0;
208 int zeroTrackCount = 0;
210 for(
PCB_TRACK* track : board->Tracks() )
214 int width = track->GetWidth();
218 else if( width > 0 && width < 10000000 )
223 BOOST_TEST_MESSAGE(
"Valid tracks: " << validTrackCount <<
", Zero-width: " << zeroTrackCount );
234 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
238 int numberedPads = 0;
239 int unnumberedPads = 0;
241 for(
FOOTPRINT* fp : board->Footprints() )
243 for(
PAD*
pad : fp->Pads() )
245 if(
pad->GetNumber().IsEmpty() )
252 BOOST_TEST_MESSAGE(
"Numbered pads: " << numberedPads <<
", Unnumbered: " << unnumberedPads );
256 if( unnumberedPads > 0 )
258 BOOST_WARN_MESSAGE(
false,
"Found " << unnumberedPads <<
" pads without numbers" );
280 std::vector<SEG> outlineSegs;
304 outlineSegs.push_back( seg );
312 for(
size_t i = 0; i < polyPoints.size() - 1; i++ )
315 VECTOR2I end = polyPoints[( i + 1 ) % polyPoints.size()];
316 outlineSegs.emplace_back( start,
end );
326 false,
"Unexpected shape type in board outline: " <<
static_cast<int>( shape->
GetShape() ) );
331 if( !outlineSegs.empty() )
335 int connectedCount = 0;
337 for(
const SEG& seg : outlineSegs )
339 for(
const SEG& other : outlineSegs )
345 if( seg.A == other.A || seg.A == other.B )
349 if( seg.B == other.A || seg.B == other.B )
357 BOOST_CHECK_GE( connectedCount, outlineSegs.size() * 2 );
367 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
377 BOOST_CHECK_GE( outlineSegmentCount, 1 );
388 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
394 bool hasBbox =
false;
402 boardBbox = item->GetBoundingBox();
407 boardBbox.
Merge( item->GetBoundingBox() );
412 BOOST_REQUIRE_MESSAGE( hasBbox,
"Board should have an outline" );
418 BOX2I testBbox = boardBbox;
421 for(
FOOTPRINT* fp : board->Footprints() )
423 for(
PAD*
pad : fp->Pads() )
427 if( testBbox.
Contains( padCenter ) )
435 <<
pad->GetNumber() <<
" at ("
436 << padCenter.
x / 1000000.0 <<
", "
437 << padCenter.
y / 1000000.0 <<
") mm" );
442 BOOST_TEST_MESSAGE(
"Pads inside outline: " << padsInside <<
", outside: " << padsOutside );
446 if( padsOutside > 0 )
448 BOOST_WARN_MESSAGE(
false,
"Found " << padsOutside <<
" pads outside board outline" );
452 BOOST_CHECK_GT( padsInside, padsOutside );
462 BOOST_CHECK_EXCEPTION(
463 LoadAllegroBoard(
"v13_header/v13_header.brd" ),
IO_ERROR,
466 wxString msg = e.
What();
468 return msg.Contains( wxS(
"predates Allegro 16.0" ) )
469 && msg.Contains( wxS(
"Allegro PCB Design" ) );
481 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"rects/rects.brd" );
487 ZONE* zone = board->Zones().front();
493 int copperPolyCount = 0;
494 int copperPolyWithNet = 0;
522 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"copper_text/copper_text.brd" );
525 int copperTextCount = 0;
526 bool foundTestingText =
false;
538 if(
text->GetText() == wxS(
"TESTING" ) )
540 foundTestingText =
true;
547 BOOST_CHECK_MESSAGE( foundTestingText,
"Board should contain 'TESTING' text on F.Cu" );
587 std::vector<std::string> boards;
593 for(
const auto& boardDir : std::filesystem::directory_iterator( dataPath ) )
595 if( !boardDir.is_directory() )
598 for(
const auto& entry : std::filesystem::directory_iterator( boardDir ) )
600 if( entry.is_regular_file() && entry.path().extension() ==
".brd" && entry.file_size() > 0 )
602 std::string
name = entry.path().filename().string();
605 if(
name !=
"v13_header.brd" )
607 boards.push_back( boardDir.path().string() +
"/" +
name );
613 catch(
const std::filesystem::filesystem_error& e )
618 std::sort( boards.begin(), boards.end() );
637 BOARD* board = GetCachedBoard( dataPath );
640 const std::vector<wxString> expectedLayers = { wxS(
"TOP" ), wxS(
"LYR2_GND" ),
641 wxS(
"LYR5_PWR" ), wxS(
"BOTTOM" ) };
643 for(
const wxString& layerName : expectedLayers )
650 "Layer " << layerName <<
" should exist" );
652 const ZONE* largest =
nullptr;
653 double largestArea = 0;
657 if( zone->GetIsRuleArea() )
660 if( zone->GetNetCode() == 0 )
663 if( !zone->GetLayerSet().Contains( layerId ) )
666 BOX2I bbox = zone->GetBoundingBox();
667 double area =
static_cast<double>( bbox.
GetWidth() )
668 *
static_cast<double>( bbox.
GetHeight() );
670 if( area > largestArea )
677 BOOST_REQUIRE_MESSAGE( largest !=
nullptr,
678 "Should find a netted copper zone on " << layerName );
690 std::vector<std::string> boards = GetAllBoardFiles();
692 for(
const std::string& boardPath : boards )
694 std::string boardName = std::filesystem::path( boardPath ).filename().string();
695 BOARD* board = GetCachedBoard( boardPath );
702 int negativePadCount = 0;
706 for(
PAD*
pad : fp->Pads() )
710 if( size.
x < 0 || size.
y < 0 )
714 <<
" pad " <<
pad->GetNumber() <<
": " << size.
x <<
" x "
732 std::vector<std::string> boards = GetAllBoardFiles();
734 for(
const std::string& boardPath : boards )
736 std::string boardName = std::filesystem::path( boardPath ).filename().string();
737 BOARD* board = GetCachedBoard( boardPath );
744 int invalidViaCount = 0;
751 int drill =
via->GetDrill();
752 int width =
via->GetWidth(
F_Cu );
758 <<
via->GetPosition().x / 1000000.0 <<
", "
759 <<
via->GetPosition().y / 1000000.0
760 <<
") has drill " << drill / 1000000.0
761 <<
"mm > width " << width / 1000000.0 <<
"mm" );
778 std::vector<std::string> boards = GetAllBoardFiles();
780 for(
const std::string& boardPath : boards )
782 std::string boardName = std::filesystem::path( boardPath ).filename().string();
783 BOARD* board = GetCachedBoard( boardPath );
790 int misclassifiedSmdCount = 0;
791 int correctSmdCount = 0;
792 int correctThCount = 0;
796 for(
PAD*
pad : fp->Pads() )
798 bool hasDrill =
pad->GetDrillSizeX() > 0 &&
pad->GetDrillSizeY() > 0;
803 misclassifiedSmdCount++;
805 <<
"." <<
pad->GetNumber()
806 <<
" has no drill but is marked as PTH (should be SMD)" );
820 <<
", Correct TH=" << correctThCount
821 <<
", Misclassified=" << misclassifiedSmdCount );
835 std::vector<std::string> boards = GetAllBoardFiles();
837 for(
const std::string& boardPath : boards )
839 std::string boardName = std::filesystem::path( boardPath ).filename().string();
840 BOARD* board = GetCachedBoard( boardPath );
847 int quadPackageCount = 0;
848 int packagesWithRotatedPads = 0;
849 int packagesWithUnrotatedPads = 0;
853 wxString refdes = fp->GetReference().Upper();
856 if( !refdes.StartsWith(
"U" ) )
860 if( fp->Pads().size() < 16 )
867 for(
PAD*
pad : fp->Pads() )
878 padBounds.
Merge( pos );
886 if( width == 0 || height == 0 )
889 double aspectRatio =
static_cast<double>( std::max( width, height ) ) /
890 static_cast<double>( std::min( width, height ) );
892 if( aspectRatio > 2.0 )
898 std::set<int> uniqueAngles;
900 for(
PAD*
pad : fp->Pads() )
904 int degrees =
static_cast<int>( angle.
AsDegrees() + 0.5 ) % 360;
905 uniqueAngles.insert( degrees );
910 if( uniqueAngles.size() >= 2 )
912 packagesWithRotatedPads++;
914 <<
" has " << uniqueAngles.size() <<
" unique pad orientations" );
918 packagesWithUnrotatedPads++;
920 <<
" has only " << uniqueAngles.size()
921 <<
" unique pad orientation (may be missing rotation)" );
925 if( quadPackageCount > 0 )
928 <<
" potential quad packages, "
929 << packagesWithRotatedPads <<
" with rotated pads, "
930 << packagesWithUnrotatedPads <<
" without" );
934 if( packagesWithRotatedPads == 0 && quadPackageCount > 0 )
936 BOOST_WARN_MESSAGE(
false, boardName <<
" has no packages with rotated pads" );
953 BOARD* board = GetCachedBoard( dataPath );
954 BOOST_REQUIRE_MESSAGE( board !=
nullptr,
"BeagleBone_Black_RevC.brd should load successfully" );
961 if( fp->GetReference() ==
"C78" )
968 BOOST_REQUIRE_MESSAGE( c78 !=
nullptr,
"Footprint C78 should exist in BeagleBone Black" );
975 BOOST_CHECK_MESSAGE( fpLayer ==
B_Cu,
"C78 should be on the bottom copper layer (B_Cu), got "
977 BOOST_CHECK_MESSAGE( c78->
IsFlipped(),
"C78 should be flipped (IsFlipped() == true)" );
985 if( fp->GetLayer() ==
F_Cu )
987 else if( fp->GetLayer() ==
B_Cu )
991 BOOST_TEST_MESSAGE(
"Footprints on top: " << topCount <<
", on bottom: " << bottomCount );
994 BOOST_CHECK_GT( topCount, 0 );
995 BOOST_CHECK_GT( bottomCount, 0 );
1005 std::vector<std::string> boards = GetAllBoardFiles();
1007 for(
const std::string& boardPath : boards )
1009 std::string boardName = std::filesystem::path( boardPath ).filename().string();
1010 BOARD* board = GetCachedBoard( boardPath );
1018 int disconnectedArcs = 0;
1021 std::map<int, std::vector<VECTOR2I>> netEndpoints;
1025 int netCode = track->GetNetCode();
1029 netEndpoints[netCode].push_back( track->GetStart() );
1030 netEndpoints[netCode].push_back( track->GetEnd() );
1034 netEndpoints[netCode].push_back( track->GetPosition() );
1041 for(
PAD*
pad : fp->Pads() )
1043 int netCode =
pad->GetNetCode();
1046 netEndpoints[netCode].push_back(
pad->GetPosition() );
1064 bool startConnected =
false;
1065 bool endConnected =
false;
1066 const int tolerance = 1000;
1068 for(
const VECTOR2I& pt : netEndpoints[netCode] )
1070 if( ( pt - arcStart ).EuclideanNorm() < tolerance )
1071 startConnected =
true;
1073 if( ( pt - arcEnd ).EuclideanNorm() < tolerance )
1074 endConnected =
true;
1079 if( !startConnected && !endConnected && netEndpoints[netCode].size() > 2 )
1083 << arcStart.
x / 1000000.0 <<
", "
1084 << arcStart.
y / 1000000.0 <<
") to ("
1085 << arcEnd.
x / 1000000.0 <<
", "
1086 << arcEnd.
y / 1000000.0
1087 <<
") appears disconnected from net " << netCode );
1094 << disconnectedArcs <<
" disconnected" );
1101 BOOST_CHECK_LE( disconnectedArcs, arcCount / 5 );
1153 std::vector<wxString> fields;
1156 for(
size_t i = 0; i < aLine.size(); ++i )
1158 if( aLine[i] ==
'!' )
1160 fields.push_back( current );
1165 current += aLine[i];
1169 if( !current.empty() )
1170 fields.push_back( current );
1182 wxString tag = aTag.BeforeFirst(
' ' );
1184 return static_cast<int>( val );
1190 std::ifstream file( aPath );
1192 if( !file.is_open() )
1203 SECTION currentSection = SECTION::UNKNOWN;
1209 while( std::getline( file, line ) )
1211 if( line.empty() || line[0] ==
'J' )
1214 if( line[0] ==
'A' )
1216 if( line.find(
"NET_NAME_SORT!NODE_SORT!NET_NAME!REFDES!" ) != std::string::npos )
1217 currentSection = SECTION::NET_NODES;
1218 else if( line.find(
"SYM_TYPE!SYM_NAME!REFDES!SYM_MIRROR!" ) != std::string::npos )
1219 currentSection = SECTION::SYM_PLACEMENT;
1220 else if( line.find(
"CLASS!SUBCLASS!RECORD_TAG!GRAPHIC_DATA_NAME!" ) != std::string::npos )
1221 currentSection = SECTION::GRAPHICS;
1223 currentSection = SECTION::UNKNOWN;
1228 if( line[0] !=
'S' )
1231 auto fields =
SplitAlgLine( wxString::FromUTF8( line ) );
1233 switch( currentSection )
1235 case SECTION::NET_NODES:
1238 if( fields.size() >= 5 )
1240 wxString netName = fields[3];
1241 wxString refdes = fields[4];
1243 if( !netName.empty() )
1247 if( !refdes.empty() )
1254 case SECTION::SYM_PLACEMENT:
1257 if( fields.size() >= 4 )
1259 wxString symType = fields[1];
1260 wxString symName = fields[2];
1261 wxString refdes = fields[3];
1263 if( symType == wxT(
"PACKAGE" ) && !refdes.empty() )
1265 data.
refDes.insert( refdes );
1272 case SECTION::GRAPHICS:
1278 if( fields.size() < 16 || fields[1] != wxT(
"BOUNDARY" ) )
1281 wxString closureType = fields[15];
1283 if( closureType != wxT(
"SHAPE" ) )
1286 wxString layer = fields[2];
1294 if( fields.size() > 23 )
1295 netName = fields[23];
1297 auto key = std::make_pair( layer, recordId );
1298 auto& zone = zoneMap[key];
1300 zone.recordId = recordId;
1302 if( !netName.empty() )
1303 zone.netName = netName;
1305 double x1 = 0, y1 = 0, x2 = 0, y2 = 0;
1307 if( fields.size() > 9 )
1309 fields[6].ToDouble( &x1 );
1310 fields[7].ToDouble( &y1 );
1311 fields[8].ToDouble( &x2 );
1312 fields[9].ToDouble( &y2 );
1313 zone.AddPoint( x1, y1 );
1314 zone.AddPoint( x2, y2 );
1324 for(
auto& [key, zone] : zoneMap )
1346 std::vector<BRD_ALG_PAIR> boardsWithAlg;
1348 for(
const auto& boardDir : std::filesystem::directory_iterator( dataPath ) )
1350 if( !boardDir.is_directory() )
1353 std::filesystem::path boardPath;
1354 std::filesystem::path algPath;
1356 for(
const auto& entry : std::filesystem::directory_iterator( boardDir ) )
1358 if( !entry.is_regular_file() )
1361 if( entry.path().extension() ==
".brd" )
1362 boardPath = entry.path();
1363 else if( entry.path().extension() ==
".alg" )
1364 algPath = entry.path();
1366 if( !boardPath.empty() && !algPath.empty() )
1368 boardsWithAlg.push_back( { boardPath.string(), algPath.string() } );
1374 return boardsWithAlg;
1385 BOOST_REQUIRE_GT( boardsWithAlg.size(), 0u );
1387 for(
const auto& [brdFile, algFile] : boardsWithAlg )
1392 BOOST_REQUIRE_GT( algData.
netNames.size(), 0u );
1394 BOARD* board = GetCachedBoard( brdFile );
1397 std::set<wxString> boardNets;
1401 if( net->GetNetCode() > 0 )
1402 boardNets.insert( net->GetNetname() );
1405 int missingNets = 0;
1407 for(
const wxString& algNet : algData.
netNames )
1409 if( boardNets.find( algNet ) == boardNets.end() )
1413 if( missingNets <= 10 )
1419 << boardNets.size() <<
", missing " << missingNets );
1433 BOOST_REQUIRE_GT( boardsWithAlg.size(), 0u );
1435 for(
const auto& [brdFile, algFile] : boardsWithAlg )
1440 BOOST_REQUIRE_GT( algData.
refDes.size(), 0u );
1442 BOARD* board = GetCachedBoard( brdFile );
1445 std::set<wxString> boardRefDes;
1448 boardRefDes.insert( fp->GetReference() );
1450 int missingRefDes = 0;
1451 int extraRefDes = 0;
1453 for(
const wxString& algRef : algData.
refDes )
1455 if( boardRefDes.find( algRef ) == boardRefDes.end() )
1459 if( missingRefDes <= 10 )
1464 for(
const wxString& boardRef : boardRefDes )
1466 if( algData.
refDes.find( boardRef ) == algData.
refDes.end() )
1470 if( extraRefDes <= 10 )
1476 <<
" components, board has " << boardRefDes.size()
1477 <<
", missing " << missingRefDes
1478 <<
", extra " << extraRefDes );
1490 std::vector<std::string> boards = GetAllBoardFiles();
1492 for(
const std::string& boardPath : boards )
1494 std::string boardName = std::filesystem::path( boardPath ).filename().string();
1495 BOARD* board = GetCachedBoard( boardPath );
1502 int zeroWidthCount = 0;
1511 if( track->GetWidth() <= 0 )
1515 if( zeroWidthCount <= 5 )
1518 << track->GetStart().x / 1000000.0 <<
", "
1519 << track->GetStart().y / 1000000.0 <<
")" );
1559 double minX = std::numeric_limits<double>::max();
1560 double minY = std::numeric_limits<double>::max();
1561 double maxX = std::numeric_limits<double>::lowest();
1562 double maxY = std::numeric_limits<double>::lowest();
1575 std::ifstream file( aPath );
1577 if( !file.is_open() )
1582 while( std::getline( file, line ) )
1584 if( line.empty() || line[0] !=
'S' )
1589 if( fields.size() < 10 )
1592 bool isDesignOutline = ( fields[1] == wxT(
"BOARD GEOMETRY" )
1593 && fields[2] == wxT(
"DESIGN_OUTLINE" ) );
1595 bool isOutline = ( fields[1] == wxT(
"BOARD GEOMETRY" )
1596 && fields[2] == wxT(
"OUTLINE" ) );
1598 if( !isDesignOutline && !isOutline )
1601 wxString shapeType = fields[4];
1604 if( shapeType == wxT(
"LINE" ) && fields.size() >= 10 )
1607 fields[6].ToCDouble( &seg.
x1 );
1608 fields[7].ToCDouble( &seg.
y1 );
1609 fields[8].ToCDouble( &seg.
x2 );
1610 fields[9].ToCDouble( &seg.
y2 );
1615 else if( shapeType == wxT(
"ARC" ) && fields.size() >= 15 )
1618 fields[6].ToCDouble( &seg.
x1 );
1619 fields[7].ToCDouble( &seg.
y1 );
1620 fields[8].ToCDouble( &seg.
x2 );
1621 fields[9].ToCDouble( &seg.
y2 );
1622 fields[10].ToCDouble( &seg.
centerX );
1623 fields[11].ToCDouble( &seg.
centerY );
1624 fields[12].ToCDouble( &seg.
radius );
1625 seg.
clockwise = ( fields[14] == wxT(
"CLOCKWISE" ) );
1630 else if( shapeType == wxT(
"RECTANGLE" ) && fields.size() >= 10 )
1633 fields[6].ToCDouble( &seg.
x1 );
1634 fields[7].ToCDouble( &seg.
y1 );
1635 fields[8].ToCDouble( &seg.
x2 );
1636 fields[9].ToCDouble( &seg.
y2 );
1646 if( isDesignOutline )
1690 BOOST_REQUIRE_GT( testBoards.size(), 0u );
1692 for(
const auto& [brdFile, algFile] : testBoards )
1704 BOARD* board = GetCachedBoard( brdFile );
1707 int edgeCutsCount = 0;
1718 <<
" -> expected Edge_Cuts segments: " << expectedCount );
1736 BOOST_REQUIRE_GT( testBoards.size(), 0u );
1739 const double milToNm = 25400.0;
1742 const int toleranceNm =
static_cast<int>( 2.0 * milToNm );
1744 for(
const auto& [brdFile, algFile] : testBoards )
1756 BOARD* board = GetCachedBoard( brdFile );
1760 bool hasBbox =
false;
1768 boardBbox = item->GetBoundingBox();
1773 boardBbox.
Merge( item->GetBoundingBox() );
1778 BOOST_REQUIRE_MESSAGE( hasBbox,
"Board should have Edge_Cuts outline" );
1781 int algMinXnm =
static_cast<int>( algOutlines.
minX * milToNm );
1782 int algMinYnm =
static_cast<int>( algOutlines.
minY * milToNm );
1783 int algMaxXnm =
static_cast<int>( algOutlines.
maxX * milToNm );
1784 int algMaxYnm =
static_cast<int>( algOutlines.
maxY * milToNm );
1785 int algWidthNm = algMaxXnm - algMinXnm;
1786 int algHeightNm = algMaxYnm - algMinYnm;
1788 int boardWidth = boardBbox.
GetWidth();
1789 int boardHeight = boardBbox.
GetHeight();
1792 << algOutlines.
minX <<
"," << algOutlines.
minY <<
" to "
1793 << algOutlines.
maxX <<
"," << algOutlines.
maxY
1794 <<
" = " << ( algOutlines.
maxX - algOutlines.
minX ) <<
" x "
1795 << ( algOutlines.
maxY - algOutlines.
minY ) );
1797 << boardBbox.
GetLeft() <<
"," << boardBbox.
GetTop() <<
" to "
1799 <<
" = " << boardWidth <<
" x " << boardHeight );
1803 BOOST_CHECK_CLOSE(
static_cast<double>( boardWidth ),
1804 static_cast<double>( algWidthNm ), 3.0 );
1805 BOOST_CHECK_CLOSE(
static_cast<double>( boardHeight ),
1806 static_cast<double>( algHeightNm ), 3.0 );
1823 BOOST_REQUIRE_GT( testBoards.size(), 0u );
1825 const double milToNm = 25400.0;
1826 const int toleranceNm =
static_cast<int>( 2.0 * milToNm );
1828 for(
const auto& [brdFile, algFile] : testBoards )
1838 bool allLines =
true;
1856 BOARD* board = GetCachedBoard( brdFile );
1860 struct ENDPOINT_PAIR
1866 std::vector<ENDPOINT_PAIR> boardSegments;
1876 boardSegments.push_back( { shape->
GetStart(), shape->
GetEnd() } );
1880 std::vector<ENDPOINT_PAIR> algSegments;
1886 VECTOR2I start(
static_cast<int>( seg.x1 * milToNm ),
1887 static_cast<int>( seg.y1 * milToNm ) );
1888 VECTOR2I end(
static_cast<int>( seg.x2 * milToNm ),
1889 static_cast<int>( seg.y2 * milToNm ) );
1890 algSegments.push_back( { start,
end } );
1894 int x1 =
static_cast<int>( seg.x1 * milToNm );
1895 int y1 =
static_cast<int>( seg.y1 * milToNm );
1896 int x2 =
static_cast<int>( seg.x2 * milToNm );
1897 int y2 =
static_cast<int>( seg.y2 * milToNm );
1899 algSegments.push_back( { { x1, y1 }, { x2, y1 } } );
1900 algSegments.push_back( { { x2, y1 }, { x2, y2 } } );
1901 algSegments.push_back( { { x2, y2 }, { x1, y2 } } );
1902 algSegments.push_back( { { x1, y2 }, { x1, y1 } } );
1908 if( boardSegments.size() != algSegments.size() )
1914 int matchedCount = 0;
1916 std::vector<bool> used( boardSegments.size(),
false );
1918 for(
size_t ai = 0; ai < algSegments.size(); ++ai )
1920 const auto& algSeg = algSegments[ai];
1922 int64_t bestDist = std::numeric_limits<int64_t>::max();
1924 for(
size_t bi = 0; bi < boardSegments.size(); ++bi )
1929 const auto& bSeg = boardSegments[bi];
1932 auto dist = [&](
const VECTOR2I& aAlgPt,
const VECTOR2I& aBoardPt ) -> int64_t
1934 int64_t dx =
std::abs(
static_cast<int64_t
>( aAlgPt.
x )
1935 -
static_cast<int64_t
>( aBoardPt.x ) );
1936 int64_t dy =
std::abs(
static_cast<int64_t
>( aAlgPt.
y )
1937 -
static_cast<int64_t
>( aBoardPt.y ) );
1941 int64_t d1 = dist( algSeg.start, bSeg.start ) + dist( algSeg.end, bSeg.end );
1942 int64_t d2 = dist( algSeg.start, bSeg.end ) + dist( algSeg.end, bSeg.start );
1943 int64_t d = std::min( d1, d2 );
1948 bestIdx =
static_cast<int>( bi );
1952 if( bestIdx >= 0 && bestDist < 2LL * toleranceNm )
1954 used[bestIdx] =
true;
1960 << algSeg.start.x / 1000000.0 <<
", "
1961 << algSeg.start.y / 1000000.0 <<
") -> ("
1962 << algSeg.end.x / 1000000.0 <<
", "
1963 << algSeg.end.y / 1000000.0 <<
") mm"
1964 <<
" bestDist=" << bestDist );
1969 <<
" outline segments" );
1983 std::vector<std::string> boards = GetAllBoardFiles();
1985 for(
const std::string& boardPath : boards )
1987 std::string boardName = std::filesystem::path( boardPath ).filename().string();
1988 BOARD* board = GetCachedBoard( boardPath );
1996 int smdWithDrill = 0;
2000 for(
PAD*
pad : fp->Pads() )
2003 bool hasDrill =
pad->GetDrillSizeX() > 0;
2009 if( pthNoDrill <= 5 )
2012 << fp->GetReference() <<
"."
2013 <<
pad->GetNumber() );
2021 if( smdWithDrill <= 5 )
2024 << fp->GetReference() <<
"."
2025 <<
pad->GetNumber() );
2045 BOOST_REQUIRE_GT( boardsWithAlg.size(), 0u );
2047 for(
const auto& [brdFile, algFile] : boardsWithAlg )
2053 BOARD* board = GetCachedBoard( brdFile );
2056 size_t boardCopperZoneLayers = 0;
2058 for(
const ZONE* zone : board->
Zones() )
2060 if( !zone->GetIsRuleArea() )
2061 boardCopperZoneLayers += ( zone->GetLayerSet() &
LSET::AllCuMask() ).count();
2067 <<
" zone polygons, board has " << boardCopperZoneLayers
2068 <<
" copper zone-layers" );
2070 BOOST_CHECK_EQUAL(
static_cast<size_t>( boardCopperZoneLayers ), algZoneCount );
2083 BOOST_REQUIRE_GT( boardsWithAlg.size(), 0u );
2085 for(
const auto& [brdFile, algFile] : boardsWithAlg )
2091 BOARD* board = GetCachedBoard( brdFile );
2094 std::map<wxString, int> algLayerCounts;
2097 algLayerCounts[zone.
layer]++;
2099 std::map<wxString, int> boardLayerCounts;
2101 for(
const ZONE* zone : board->
Zones() )
2103 if( zone->GetIsRuleArea() )
2115 for(
const auto& [layer, count] : algLayerCounts )
2117 auto it = boardLayerCounts.find( layer );
2118 int boardCount = ( it != boardLayerCounts.end() ) ? it->second : 0;
2136 BOOST_REQUIRE_GT( boardsWithAlg.size(), 0u );
2138 for(
const auto& [brdFile, algFile] : boardsWithAlg )
2144 BOARD* board = GetCachedBoard( brdFile );
2148 const double milsToNm = 25400.0;
2150 std::map<wxString, std::vector<double>> algAreas;
2154 double w = ( zone.
maxX - zone.
minX ) * milsToNm;
2155 double h = ( zone.
maxY - zone.
minY ) * milsToNm;
2156 algAreas[zone.
layer].push_back( w * h );
2159 std::map<wxString, std::vector<double>> boardAreas;
2161 for(
const ZONE* zone : board->
Zones() )
2163 if( zone->GetIsRuleArea() )
2166 BOX2I bbox = zone->GetBoundingBox();
2167 double area =
static_cast<double>( bbox.
GetWidth() )
2168 *
static_cast<double>( bbox.
GetHeight() );
2173 boardAreas[board->
GetLayerName( layer )].push_back( area );
2180 for(
auto& [layer, algList] : algAreas )
2182 std::sort( algList.begin(), algList.end() );
2183 auto it = boardAreas.find( layer );
2185 if( it == boardAreas.end() || it->second.size() != algList.size() )
2188 std::sort( it->second.begin(), it->second.end() );
2190 for(
size_t i = 0; i < algList.size(); ++i )
2192 double ref = std::max( algList[i], 1.0 );
2193 double err =
std::abs( it->second[i] - algList[i] ) / ref;
2203 if( mismatched <= 5 )
2206 <<
": alg area " << algList[i] / ( milsToNm * milsToNm )
2207 <<
" sq mils vs board area "
2208 << it->second[i] / ( milsToNm * milsToNm )
2216 << mismatched <<
" mismatched" );
2218 int total = matched + mismatched;
2222 BOOST_CHECK_GT( matched, total * 8 / 10 );
2239 BOARD* board = GetCachedBoard( dataPath );
2245 const std::set<wxString> targetRefs = { wxS(
"J1" ), wxS(
"P5" ), wxS(
"U5" ),
2246 wxS(
"U13" ), wxS(
"C78" ) };
2248 int testedCount = 0;
2249 int failedCount = 0;
2253 if( targetRefs.find( fp->GetReference() ) == targetRefs.end() )
2259 bool hasFab =
false;
2261 for(
BOARD_ITEM* item : fp->GraphicalItems() )
2263 if( item->GetLayer() == fabLayer )
2267 fabBbox = item->GetBoundingBox();
2272 fabBbox.
Merge( item->GetBoundingBox() );
2277 if( !hasFab || fp->Pads().empty() )
2282 BOX2I testBbox = fabBbox;
2289 for(
PAD*
pad : fp->Pads() )
2293 if( !testBbox.
Contains( padCenter ) )
2297 <<
" at (" << padCenter.
x / 1e6 <<
", "
2298 << padCenter.
y / 1e6 <<
") mm is outside F.Fab bbox" );
2305 BOOST_CHECK_GE( testedCount, 4 );
2319 BOARD* board = GetCachedBoard( dataPath );
2324 wxString ref = fp->GetReference();
2326 if( ref != wxS(
"P6" ) && ref != wxS(
"P10" ) )
2331 for(
PAD*
pad : fp->Pads() )
2335 if( !
pad->GetNumber().ToLong( &padNum ) )
2339 if( padNum < 1 || padNum > 19 )
2343 BOX2I bbox =
pad->GetBoundingBox();
2348 if( bboxW == bboxH )
2353 BOOST_CHECK_MESSAGE( bboxW > bboxH,
2354 ref <<
" pad " <<
pad->GetNumber()
2355 <<
" should be visually wider than tall: "
2356 << bboxW / 1e6 <<
" x " << bboxH / 1e6 <<
" mm" );
2375 BOARD* board = GetCachedBoard( dataPath );
2378 int oblongCount = 0;
2382 for(
PAD*
pad : fp->Pads() )
2386 if( drillSize.
x <= 0 || drillSize.
y <= 0 )
2389 if( drillSize.
x == drillSize.
y )
2399 <<
" slot: " << drillSize.
x / 1e6 <<
" x "
2400 << drillSize.
y / 1e6 <<
" mm"
2401 <<
" attr=" <<
static_cast<int>(
pad->GetAttribute() ) );
2420 BOARD* board = GetCachedBoard( dataPath );
2428 if( fp->GetReference() == wxT(
"J1" ) )
2435 BOOST_REQUIRE_MESSAGE( j1 !=
nullptr,
"Footprint J1 must exist in BeagleBone_Black_RevC" );
2439 BOOST_CHECK_CLOSE( orientation.
AsDegrees(), 90.0, 0.1 );
2451 BOARD* board = GetCachedBoard( dataPath );
2456 BOOST_CHECK( netSettings->HasNetclass( wxS(
"W20mil" ) ) );
2457 BOOST_CHECK( netSettings->HasNetclass( wxS(
"W24mil" ) ) );
2459 auto nc20 = netSettings->GetNetClassByName( wxS(
"W20mil" ) );
2460 auto nc24 = netSettings->GetNetClassByName( wxS(
"W24mil" ) );
2475 if( net->GetNetCode() <= 0 )
2483 if( nc->
GetName() == wxS(
"W20mil" ) )
2485 else if( nc->
GetName() == wxS(
"W24mil" ) )
2502 BOARD* board = GetCachedBoard( dataPath );
2508 BOOST_CHECK( netSettings->HasNetclass( wxS(
"DP_HDMI_TXC" ) ) );
2509 BOOST_CHECK( netSettings->HasNetclass( wxS(
"DP_USB0" ) ) );
2512 int hdmiTxcCount = 0;
2516 if( net->GetNetCode() <= 0 )
2521 if( nc && nc->
GetName() == wxS(
"DP_HDMI_TXC" ) )
2537 BOARD* board = GetCachedBoard( dataPath );
2543 BOOST_CHECK( netSettings->HasNetclass( wxS(
"MG_DDR_DQ0" ) ) );
2544 BOOST_CHECK( netSettings->HasNetclass( wxS(
"MG_DDR_ADD" ) ) );
2552 if( net->GetNetCode() <= 0 )
2560 if( nc->
GetName() == wxS(
"MG_DDR_DQ0" ) )
2562 else if( nc->
GetName() == wxS(
"MG_DDR_ADD" ) )
2579 BOARD* board = GetCachedBoard( dataPath );
2587 for(
const auto& [
name, nc] : netSettings->GetNetclasses() )
2589 if(
name.StartsWith( wxS(
"DP_" ) ) )
2591 else if(
name.StartsWith( wxS(
"MG_" ) ) )
2608 BOARD* board = GetCachedBoard( dataPath );
2613 for(
const auto& [
name, nc] : netSettings->GetNetclasses() )
2615 BOOST_CHECK_MESSAGE( !
name.StartsWith( wxS(
"DP_" ) ) && !
name.StartsWith( wxS(
"MG_" ) ),
2616 "Simple board should not have match group netclass: " +
name );
2629 BOARD* board = GetCachedBoard( dataPath );
2635 BOOST_CHECK( netSettings->HasNetclass( wxS(
"Allegro_Default" ) ) );
2636 BOOST_CHECK( netSettings->HasNetclass( wxS(
"PWR" ) ) );
2637 BOOST_CHECK( netSettings->HasNetclass( wxS(
"BGA" ) ) );
2638 BOOST_CHECK( netSettings->HasNetclass( wxS(
"90_OHM_DIFF" ) ) );
2639 BOOST_CHECK( netSettings->HasNetclass( wxS(
"100OHM_DIFF" ) ) );
2641 auto ncDefault = netSettings->GetNetClassByName( wxS(
"Allegro_Default" ) );
2642 auto ncPwr = netSettings->GetNetClassByName( wxS(
"PWR" ) );
2656 int defaultCount = 0;
2660 if( net->GetNetCode() <= 0 )
2668 if( nc->
GetName() == wxS(
"Allegro_Default" ) )
2672 BOOST_CHECK_MESSAGE( defaultCount > 0,
"DEFAULT constraint set should have assigned nets (implicit)" );
2684 BOARD* board = GetCachedBoard( dataPath );
2689 BOOST_CHECK( netSettings->HasNetclass( wxS(
"CS_0" ) ) );
2691 auto nc = netSettings->GetNetClassByName( wxS(
"CS_0" ) );
2709 BOARD* board = GetCachedBoard( dataPath );
2715 BOOST_CHECK( netSettings->HasNetclass( wxS(
"CS_0" ) ) );
2718 BOOST_CHECK( netSettings->HasNetclass( wxS(
"W20mil" ) ) );
2719 BOOST_CHECK( netSettings->HasNetclass( wxS(
"W24mil" ) ) );
2722 auto ncCS = netSettings->GetNetClassByName( wxS(
"CS_0" ) );
2729 auto nc20 = netSettings->GetNetClassByName( wxS(
"W20mil" ) );
2730 auto nc24 = netSettings->GetNetClassByName( wxS(
"W24mil" ) );
2747 BOARD* board = GetCachedBoard( dataPath );
2753 auto nc90 = netSettings->GetNetClassByName( wxS(
"90_OHM_DIFF" ) );
2761 auto nc100 = netSettings->GetNetClassByName( wxS(
"100OHM_DIFF" ) );
2769 auto ncBga = netSettings->GetNetClassByName( wxS(
"BGA" ) );
2784 BOARD* board = GetCachedBoard( dataPath );
2790 auto nc = netSettings->GetNetClassByName( wxS(
"DP_90_OHM" ) );
2810 BOARD* rawBoard =
nullptr;
2814 rawBoard = plugin.
LoadBoard( dataPath,
nullptr,
nullptr,
nullptr );
2820 catch(
const std::exception& e )
2827 BOOST_REQUIRE_MESSAGE( rawBoard !=
nullptr,
"LoadBoard with nullptr aAppendToMe must return a valid board" );
2829 std::unique_ptr<BOARD> board( rawBoard );
2831 BOOST_CHECK_GT( board->GetNetCount(), 0 );
2832 BOOST_CHECK_GT( board->Footprints().size(), 0 );
2833 BOOST_CHECK_GT( board->Tracks().size(), 0 );
2850 std::vector<std::string> boards = GetAllBoardFiles();
2852 for(
const std::string& boardPath : boards )
2854 std::string boardName = std::filesystem::path( boardPath ).filename().string();
2855 BOARD* board = GetCachedBoard( boardPath );
2862 int inconsistentCount = 0;
2866 const bool onBottom = fp->IsFlipped();
2868 for(
PAD*
pad : fp->Pads() )
2873 LSET layers =
pad->GetLayerSet();
2877 if( onBottom && hasTopCopper && !hasBotCopper )
2879 inconsistentCount++;
2881 <<
pad->GetNumber() <<
" is on bottom footprint but SMD "
2882 <<
"pad has F.Cu without B.Cu" );
2884 else if( !onBottom && hasBotCopper && !hasTopCopper )
2886 inconsistentCount++;
2888 <<
pad->GetNumber() <<
" is on top footprint but SMD "
2889 <<
"pad has B.Cu without F.Cu" );
2910 std::vector<std::string> boards = GetAllBoardFiles();
2912 for(
const std::string& boardPath : boards )
2914 std::string boardName = std::filesystem::path( boardPath ).filename().string();
2915 BOARD* board = GetCachedBoard( boardPath );
2922 int inconsistentCount = 0;
2927 bool hasSmd =
false;
2930 for(
PAD*
pad : fp->Pads() )
2938 if( !hasSmd || hasTH )
2941 const bool onBottom = fp->IsFlipped();
2943 for(
BOARD_ITEM* item : fp->GraphicalItems() )
2950 bool wrongSide =
false;
2959 inconsistentCount++;
2961 boardName <<
": " << fp->GetReference() <<
" is "
2962 << ( onBottom ?
"bottom" :
"top" ) <<
"-side SMD but has "
2963 << item->GetClass() <<
" on "
2985 BOARD* board = GetCachedBoard( dataPath );
2995 std::vector<SLOT_CHECK> checks = {
2996 { wxS(
"P6" ), wxS(
"20" ) },
2997 { wxS(
"P6" ), wxS(
"21" ) },
2998 { wxS(
"P3" ), wxS(
"6" ) },
2999 { wxS(
"P1" ), wxS(
"1" ) },
3000 { wxS(
"P1" ), wxS(
"2" ) },
3001 { wxS(
"P1" ), wxS(
"3" ) },
3004 for(
const auto& check : checks )
3012 if( candidate->GetReference() == check.fpRef )
3019 BOOST_REQUIRE_MESSAGE( fp !=
nullptr,
"Footprint " << check.fpRef <<
" should exist" );
3023 for(
PAD* candidate : fp->
Pads() )
3025 if( candidate->GetNumber() == check.padNum )
3032 BOOST_REQUIRE_MESSAGE(
pad !=
nullptr,
3033 "Pad " << check.padNum <<
" should exist on " << check.fpRef );
3039 <<
": pad=" << padSize.
x <<
"x" << padSize.
y
3040 <<
" drill=" << drillSize.
x <<
"x" << drillSize.
y );
3043 if( drillSize.
x != drillSize.
y )
3045 bool padIsTaller = ( padSize.
y > padSize.
x );
3046 bool drillIsTaller = ( drillSize.
y > drillSize.
x );
3048 BOOST_CHECK_MESSAGE( padIsTaller == drillIsTaller,
3049 "Drill slot should match pad orientation" );
3064 BOARD* board = GetCachedBoard( dataPath );
3067 int filledZoneCount = 0;
3068 int totalCopperZones = 0;
3070 for(
const ZONE* zone : board->
Zones() )
3072 if( zone->GetIsRuleArea() || zone->GetNetCode() == 0 )
3077 if( zone->IsFilled() )
3082 <<
" layers=" << zone->GetLayerSet().count() );
3087 <<
", filled: " << filledZoneCount );
3089 BOOST_CHECK_GT( totalCopperZones, 0 );
3090 BOOST_CHECK_GT( filledZoneCount, 0 );
3102 BOARD* board = GetCachedBoard( dataPath );
3105 int teardropZones = 0;
3107 for(
const ZONE* zone : board->
Zones() )
3109 if( zone->IsTeardropArea() )
3113 BOOST_CHECK_GT( teardropZones, 1000 );
3117 int padsWithTeardrops = 0;
3122 for(
const PAD*
pad : fp->Pads() )
3126 if(
pad->GetTeardropsEnabled() )
3127 padsWithTeardrops++;
3131 BOOST_CHECK_GT( padsWithTeardrops, 0 );
3132 BOOST_TEST_MESSAGE(
"Pads with teardrops enabled: " << padsWithTeardrops <<
" / " << totalPads );
3134 int viasWithTeardrops = 0;
3144 if(
static_cast<const PCB_VIA*
>( track )->GetTeardropsEnabled() )
3145 viasWithTeardrops++;
3148 BOOST_CHECK_GT( viasWithTeardrops, 0 );
3149 BOOST_TEST_MESSAGE(
"Vias with teardrops enabled: " << viasWithTeardrops <<
" / " << totalVias );
3161 BOARD* board = GetCachedBoard( dataPath );
3164 int teardropZones = 0;
3166 for(
const ZONE* zone : board->
Zones() )
3168 if( zone->IsTeardropArea() )
3174 int padsWithTeardrops = 0;
3178 for(
const PAD*
pad : fp->Pads() )
3180 if(
pad->GetTeardropsEnabled() )
3181 padsWithTeardrops++;
3202 BOARD* rawBoard = plugin.
LoadBoard( dataPath,
nullptr,
nullptr,
nullptr );
3206 std::unique_ptr<BOARD> board( rawBoard );
3208 BOOST_CHECK_MESSAGE( board->m_LegacyNetclassesLoaded,
3209 "m_LegacyNetclassesLoaded must be true after Allegro import" );
3210 BOOST_CHECK_MESSAGE( board->m_LegacyDesignSettingsLoaded,
3211 "m_LegacyDesignSettingsLoaded must be true after Allegro import" );
3221 std::vector<std::string> boards = GetAllBoardFiles();
3223 for(
const std::string& boardPath : boards )
3225 std::string boardName = std::filesystem::path( boardPath ).filename().string();
3226 BOARD* board = GetCachedBoard( boardPath );
3234 const auto& netclasses = netSettings->GetNetclasses();
3238 for(
const auto& [
name, nc] : netclasses )
3241 << nc->GetTrackWidth() <<
" clearance="
3242 << nc->GetClearance() );
3246 if( !
name.StartsWith( wxS(
"DP_" ) )
3247 && !
name.StartsWith( wxS(
"MG_" ) )
3248 && !
name.StartsWith( wxS(
"W" ) ) )
3250 BOOST_CHECK_MESSAGE( nc->HasTrackWidth(),
3251 name <<
" should have a track width" );
3252 BOOST_CHECK_MESSAGE( nc->GetTrackWidth() > 0,
3253 name <<
" track width should be positive" );
3269 BOARD* board = GetCachedBoard( dataPath );
3281 ExpectedNC expectedSets[] = {
3282 {
"Allegro_Default", 120650, 101600 },
3283 {
"PWR", 381000, 101600 },
3284 {
"BGA", 76200, 101600 },
3285 {
"90_OHM_DIFF", 114300, 101600 },
3286 {
"100OHM_DIFF", 95250, 101600 },
3289 for(
const auto&
expected : expectedSets )
3293 BOOST_CHECK_MESSAGE( netSettings->HasNetclass( ncName ),
3294 "Missing netclass: " <<
expected.name );
3296 auto nc = netSettings->GetNetClassByName( ncName );
3298 BOOST_REQUIRE_MESSAGE( nc,
"Cannot retrieve netclass: " <<
expected.name );
3304 BOOST_CHECK( netSettings->HasNetclass( wxS(
"DP_USB0" ) ) );
3305 BOOST_CHECK( netSettings->HasNetclass( wxS(
"DP_USB1" ) ) );
3306 BOOST_CHECK( netSettings->HasNetclass( wxS(
"DP_HDMI_TX0" ) ) );
3309 BOOST_CHECK( netSettings->HasNetclass( wxS(
"MG_DDR_ADD" ) ) );
3310 BOOST_CHECK( netSettings->HasNetclass( wxS(
"MG_DDR_DQ0" ) ) );
3311 BOOST_CHECK( netSettings->HasNetclass( wxS(
"MG_DDR_DQ1" ) ) );
3314 BOOST_CHECK( netSettings->HasNetclass( wxS(
"W8mil" ) ) );
3316 auto ncW8 = netSettings->GetNetClassByName( wxS(
"W8mil" ) );
3322 int assignedCount = 0;
3326 if( net->GetNetCode() <= 0 )
3335 BOOST_CHECK_MESSAGE( assignedCount > 0,
3336 "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
std::vector< VECTOR2I > GetPolyPoints() const
Duplicate the polygon outlines into a flat list of VECTOR2I points.
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
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
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::array< SEG, 4 > BoxToSegs(const BOX2I &aBox)
Decompose a BOX2 into four segments.
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.
Utility functions for working with shapes.
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 void AssertOutlineValid(const BOARD &aBoard)
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.
static unsigned CountOutlineElements(const BOARD &board)
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