80 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
84 int emptyRefDesCount = 0;
85 int validRefDesCount = 0;
87 for(
FOOTPRINT* fp : board->Footprints() )
89 wxString refdes = fp->GetReference();
91 if( refdes.IsEmpty() )
97 BOOST_TEST_MESSAGE(
"Valid RefDes: " << validRefDesCount <<
", Empty: " << emptyRefDesCount );
100 BOOST_CHECK_GT( validRefDesCount, emptyRefDesCount );
109 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
113 int validPadCount = 0;
114 int zeroPadCount = 0;
115 int hugePadCount = 0;
117 for(
FOOTPRINT* fp : board->Footprints() )
119 for(
PAD*
pad : fp->Pads() )
123 if( size.
x == 0 || size.
y == 0 )
127 <<
pad->GetNumber() );
129 else if( size.
x > 50000000 || size.
y > 50000000 )
133 <<
": " << size.
x / 1000000.0 <<
"mm x "
134 << size.
y / 1000000.0 <<
"mm" );
144 <<
", Huge: " << hugePadCount );
156 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
160 int validViaCount = 0;
161 int suspiciousViaCount = 0;
164 const int HARDCODED_SIZE = 1000000;
166 for(
PCB_TRACK* track : board->Tracks() )
171 int width =
via->GetWidth(
F_Cu );
173 if( width == HARDCODED_SIZE )
175 suspiciousViaCount++;
177 else if( width > 0 && width < 10000000 )
184 BOOST_TEST_MESSAGE(
"Valid vias: " << validViaCount <<
", Hardcoded-size vias: " << suspiciousViaCount );
187 if( suspiciousViaCount > 0 )
189 BOOST_WARN_MESSAGE(
false,
"Found " << suspiciousViaCount <<
" vias with hardcoded 1mm size" );
199 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
203 int validTrackCount = 0;
204 int zeroTrackCount = 0;
206 for(
PCB_TRACK* track : board->Tracks() )
210 int width = track->GetWidth();
214 else if( width > 0 && width < 10000000 )
219 BOOST_TEST_MESSAGE(
"Valid tracks: " << validTrackCount <<
", Zero-width: " << zeroTrackCount );
230 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
234 int numberedPads = 0;
235 int unnumberedPads = 0;
237 for(
FOOTPRINT* fp : board->Footprints() )
239 for(
PAD*
pad : fp->Pads() )
241 if(
pad->GetNumber().IsEmpty() )
248 BOOST_TEST_MESSAGE(
"Numbered pads: " << numberedPads <<
", Unnumbered: " << unnumberedPads );
252 if( unnumberedPads > 0 )
254 BOOST_WARN_MESSAGE(
false,
"Found " << unnumberedPads <<
" pads without numbers" );
276 std::vector<SEG> outlineSegs;
300 outlineSegs.push_back( seg );
308 for(
size_t i = 0; i < polyPoints.size() - 1; i++ )
311 VECTOR2I end = polyPoints[( i + 1 ) % polyPoints.size()];
312 outlineSegs.emplace_back( start,
end );
322 false,
"Unexpected shape type in board outline: " <<
static_cast<int>( shape->
GetShape() ) );
327 if( !outlineSegs.empty() )
331 int connectedCount = 0;
333 for(
const SEG& seg : outlineSegs )
335 for(
const SEG& other : outlineSegs )
341 if( seg.A == other.A || seg.A == other.B )
345 if( seg.B == other.A || seg.B == other.B )
353 BOOST_CHECK_GE( connectedCount, outlineSegs.size() * 2 );
363 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
373 BOOST_CHECK_GE( outlineSegmentCount, 1 );
384 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
390 bool hasBbox =
false;
398 boardBbox = item->GetBoundingBox();
403 boardBbox.
Merge( item->GetBoundingBox() );
408 BOOST_REQUIRE_MESSAGE( hasBbox,
"Board should have an outline" );
414 BOX2I testBbox = boardBbox;
417 for(
FOOTPRINT* fp : board->Footprints() )
419 for(
PAD*
pad : fp->Pads() )
423 if( testBbox.
Contains( padCenter ) )
431 <<
pad->GetNumber() <<
" at ("
432 << padCenter.
x / 1000000.0 <<
", "
433 << padCenter.
y / 1000000.0 <<
") mm" );
438 BOOST_TEST_MESSAGE(
"Pads inside outline: " << padsInside <<
", outside: " << padsOutside );
442 if( padsOutside > 0 )
444 BOOST_WARN_MESSAGE(
false,
"Found " << padsOutside <<
" pads outside board outline" );
448 BOOST_CHECK_GT( padsInside, padsOutside );
458 BOOST_CHECK_EXCEPTION(
459 LoadAllegroBoard(
"v13_header/v13_header.brd" ),
IO_ERROR,
462 wxString msg = e.
What();
464 return msg.Contains( wxS(
"predates Allegro 16.0" ) )
465 && msg.Contains( wxS(
"Allegro PCB Design" ) );
477 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"rects/rects.brd" );
483 ZONE* zone = board->Zones().front();
489 int copperPolyCount = 0;
490 int copperPolyWithNet = 0;
518 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"copper_text/copper_text.brd" );
521 int copperTextCount = 0;
522 bool foundTestingText =
false;
534 if(
text->GetText() == wxS(
"TESTING" ) )
536 foundTestingText =
true;
543 BOOST_CHECK_MESSAGE( foundTestingText,
"Board should contain 'TESTING' text on F.Cu" );
552 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"TRS80_POWER/TRS80_POWER.brd" );
554 const auto netOf = [](
const BOARD_ITEM* aItem )
562 if( aFirst->
Type() != aSecond->Type() || aFirst->
GetLayer() != aSecond->GetLayer()
563 || netOf( aFirst ) != netOf( aSecond ) )
570 return static_cast<const PCB_SHAPE*
>( aFirst )->Compare(
571 static_cast<const PCB_SHAPE*
>( aSecond ) ) == 0;
576 return static_cast<const PCB_TEXT*
>( aFirst )->Compare(
577 static_cast<const PCB_TEXT*
>( aSecond ) ) == 0;
583 const auto countCoincident = [&](
const DRAWINGS& aItems )
587 for(
size_t ii = 0; ii < aItems.size(); ++ii )
589 for(
size_t jj = ii + 1; jj < aItems.size(); ++jj )
591 if( coincident( aItems[ii], aItems[jj] ) )
604 for(
FOOTPRINT* footprint : board->Footprints() )
614 const auto collectIds = [](
const BOARD& aBoard )
616 std::vector<wxString> ids;
618 std::function<void(
const BOARD_ITEM* )> walk =
621 ids.push_back( aItem->m_Uuid.AsString() );
627 aItem->RunOnChildren(
635 for(
const BOARD_ITEM* item :
const_cast<BOARD&
>( aBoard ).GetItemSet() )
638 std::sort( ids.begin(), ids.end() );
642 std::unique_ptr<BOARD> first = LoadAllegroBoard(
"ProiectBoard/ProiectBoard.brd" );
643 std::unique_ptr<BOARD> second = LoadAllegroBoard(
"ProiectBoard/ProiectBoard.brd" );
645 const std::vector<wxString> firstIds = collectIds( *first );
646 const std::vector<wxString> secondIds = collectIds( *second );
650 BOOST_CHECK( firstIds == secondIds );
652 BOOST_CHECK( std::adjacent_find( firstIds.begin(), firstIds.end() ) == firstIds.end() );
660 std::unique_ptr<BOARD> board = LoadAllegroBoard(
"led_youtube/led_youtube.brd" );
663 std::map<wxString, FP_3DMODEL> models;
665 for(
FOOTPRINT* fp : board->Footprints() )
667 BOOST_REQUIRE_EQUAL( fp->Models().size(), 1u );
668 models.emplace( fp->Models().front().m_Filename, fp->Models().front() );
671 BOOST_REQUIRE_EQUAL( models.size(), 3u );
674 BOOST_REQUIRE_EQUAL( models.count( wxS(
"22272021.stp" ) ), 1u );
677 const FP_3DMODEL& conn = models.at( wxS(
"22272021.stp" ) );
679 BOOST_CHECK_CLOSE( conn.
m_Offset.
x, 0.02, 1e-6 );
680 BOOST_CHECK_CLOSE( conn.
m_Offset.
y, -1.27, 1e-6 );
681 BOOST_CHECK_CLOSE( conn.
m_Offset.
z, 1.580007, 1e-6 );
682 BOOST_CHECK_CLOSE( conn.
m_Rotation.
x, -90.0, 1e-6 );
684 BOOST_CHECK_CLOSE( conn.
m_Rotation.
z, -90.0, 1e-6 );
723 std::vector<std::string> boards;
729 for(
const auto& boardDir : std::filesystem::directory_iterator( dataPath ) )
731 if( !boardDir.is_directory() )
734 for(
const auto& entry : std::filesystem::directory_iterator( boardDir ) )
736 if( entry.is_regular_file() && entry.path().extension() ==
".brd" && entry.file_size() > 0 )
738 std::string
name = entry.path().filename().string();
741 if(
name !=
"v13_header.brd" )
743 boards.push_back( boardDir.path().string() +
"/" +
name );
749 catch(
const std::filesystem::filesystem_error& e )
754 std::sort( boards.begin(), boards.end() );
773 BOARD* board = GetCachedBoard( dataPath );
776 const std::vector<wxString> expectedLayers = { wxS(
"TOP" ), wxS(
"LYR2_GND" ),
777 wxS(
"LYR5_PWR" ), wxS(
"BOTTOM" ) };
779 for(
const wxString& layerName : expectedLayers )
786 "Layer " << layerName <<
" should exist" );
788 const ZONE* largest =
nullptr;
789 double largestArea = 0;
793 if( zone->GetIsRuleArea() )
796 if( zone->GetNetCode() == 0 )
799 if( !zone->GetLayerSet().Contains( layerId ) )
802 BOX2I bbox = zone->GetBoundingBox();
803 double area =
static_cast<double>( bbox.
GetWidth() )
804 *
static_cast<double>( bbox.
GetHeight() );
806 if( area > largestArea )
813 BOOST_REQUIRE_MESSAGE( largest !=
nullptr,
814 "Should find a netted copper zone on " << layerName );
826 std::vector<std::string> boards = GetAllBoardFiles();
828 for(
const std::string& boardPath : boards )
830 std::string boardName = std::filesystem::path( boardPath ).filename().string();
831 BOARD* board = GetCachedBoard( boardPath );
838 int negativePadCount = 0;
842 for(
PAD*
pad : fp->Pads() )
846 if( size.
x < 0 || size.
y < 0 )
850 <<
" pad " <<
pad->GetNumber() <<
": " << size.
x <<
" x "
868 std::vector<std::string> boards = GetAllBoardFiles();
870 for(
const std::string& boardPath : boards )
872 std::string boardName = std::filesystem::path( boardPath ).filename().string();
873 BOARD* board = GetCachedBoard( boardPath );
880 int invalidViaCount = 0;
887 int drill =
via->GetDrill();
888 int width =
via->GetWidth(
F_Cu );
894 <<
via->GetPosition().x / 1000000.0 <<
", "
895 <<
via->GetPosition().y / 1000000.0
896 <<
") has drill " << drill / 1000000.0
897 <<
"mm > width " << width / 1000000.0 <<
"mm" );
914 std::vector<std::string> boards = GetAllBoardFiles();
916 for(
const std::string& boardPath : boards )
918 std::string boardName = std::filesystem::path( boardPath ).filename().string();
919 BOARD* board = GetCachedBoard( boardPath );
926 int misclassifiedSmdCount = 0;
927 int correctSmdCount = 0;
928 int correctThCount = 0;
932 for(
PAD*
pad : fp->Pads() )
934 bool hasDrill =
pad->GetDrillSizeX() > 0 &&
pad->GetDrillSizeY() > 0;
939 misclassifiedSmdCount++;
941 <<
"." <<
pad->GetNumber()
942 <<
" has no drill but is marked as PTH (should be SMD)" );
956 <<
", Correct TH=" << correctThCount
957 <<
", Misclassified=" << misclassifiedSmdCount );
971 std::vector<std::string> boards = GetAllBoardFiles();
973 for(
const std::string& boardPath : boards )
975 std::string boardName = std::filesystem::path( boardPath ).filename().string();
976 BOARD* board = GetCachedBoard( boardPath );
983 int quadPackageCount = 0;
984 int packagesWithRotatedPads = 0;
985 int packagesWithUnrotatedPads = 0;
989 wxString refdes = fp->GetReference().Upper();
992 if( !refdes.StartsWith(
"U" ) )
996 if( fp->Pads().size() < 16 )
1003 for(
PAD*
pad : fp->Pads() )
1014 padBounds.
Merge( pos );
1022 if( width == 0 || height == 0 )
1025 double aspectRatio =
static_cast<double>( std::max( width, height ) ) /
1026 static_cast<double>( std::min( width, height ) );
1028 if( aspectRatio > 2.0 )
1034 std::set<int> uniqueAngles;
1036 for(
PAD*
pad : fp->Pads() )
1040 int degrees =
static_cast<int>( angle.
AsDegrees() + 0.5 ) % 360;
1041 uniqueAngles.insert( degrees );
1046 if( uniqueAngles.size() >= 2 )
1048 packagesWithRotatedPads++;
1050 <<
" has " << uniqueAngles.size() <<
" unique pad orientations" );
1054 packagesWithUnrotatedPads++;
1056 <<
" has only " << uniqueAngles.size()
1057 <<
" unique pad orientation (may be missing rotation)" );
1061 if( quadPackageCount > 0 )
1064 <<
" potential quad packages, "
1065 << packagesWithRotatedPads <<
" with rotated pads, "
1066 << packagesWithUnrotatedPads <<
" without" );
1070 if( packagesWithRotatedPads == 0 && quadPackageCount > 0 )
1072 BOOST_WARN_MESSAGE(
false, boardName <<
" has no packages with rotated pads" );
1089 BOARD* board = GetCachedBoard( dataPath );
1090 BOOST_REQUIRE_MESSAGE( board !=
nullptr,
"BeagleBone_Black_RevC.brd should load successfully" );
1097 if( fp->GetReference() ==
"C78" )
1104 BOOST_REQUIRE_MESSAGE( c78 !=
nullptr,
"Footprint C78 should exist in BeagleBone Black" );
1111 BOOST_CHECK_MESSAGE( fpLayer ==
B_Cu,
"C78 should be on the bottom copper layer (B_Cu), got "
1113 BOOST_CHECK_MESSAGE( c78->
IsFlipped(),
"C78 should be flipped (IsFlipped() == true)" );
1117 int bottomCount = 0;
1121 if( fp->GetLayer() ==
F_Cu )
1123 else if( fp->GetLayer() ==
B_Cu )
1127 BOOST_TEST_MESSAGE(
"Footprints on top: " << topCount <<
", on bottom: " << bottomCount );
1130 BOOST_CHECK_GT( topCount, 0 );
1131 BOOST_CHECK_GT( bottomCount, 0 );
1141 std::vector<std::string> boards = GetAllBoardFiles();
1143 for(
const std::string& boardPath : boards )
1145 std::string boardName = std::filesystem::path( boardPath ).filename().string();
1146 BOARD* board = GetCachedBoard( boardPath );
1154 int disconnectedArcs = 0;
1157 std::map<int, std::vector<VECTOR2I>> netEndpoints;
1161 int netCode = track->GetNetCode();
1165 netEndpoints[netCode].push_back( track->GetStart() );
1166 netEndpoints[netCode].push_back( track->GetEnd() );
1170 netEndpoints[netCode].push_back( track->GetPosition() );
1177 for(
PAD*
pad : fp->Pads() )
1179 int netCode =
pad->GetNetCode();
1182 netEndpoints[netCode].push_back(
pad->GetPosition() );
1200 bool startConnected =
false;
1201 bool endConnected =
false;
1202 const int tolerance = 1000;
1204 for(
const VECTOR2I& pt : netEndpoints[netCode] )
1206 if( ( pt - arcStart ).EuclideanNorm() < tolerance )
1207 startConnected =
true;
1209 if( ( pt - arcEnd ).EuclideanNorm() < tolerance )
1210 endConnected =
true;
1215 if( !startConnected && !endConnected && netEndpoints[netCode].size() > 2 )
1219 << arcStart.
x / 1000000.0 <<
", "
1220 << arcStart.
y / 1000000.0 <<
") to ("
1221 << arcEnd.
x / 1000000.0 <<
", "
1222 << arcEnd.
y / 1000000.0
1223 <<
") appears disconnected from net " << netCode );
1230 << disconnectedArcs <<
" disconnected" );
1237 BOOST_CHECK_LE( disconnectedArcs, arcCount / 5 );
1289 std::vector<wxString> fields;
1292 for(
size_t i = 0; i < aLine.size(); ++i )
1294 if( aLine[i] ==
'!' )
1296 fields.push_back( current );
1301 current += aLine[i];
1305 if( !current.empty() )
1306 fields.push_back( current );
1318 wxString tag = aTag.BeforeFirst(
' ' );
1320 return static_cast<int>( val );
1326 std::ifstream file( aPath );
1328 if( !file.is_open() )
1339 SECTION currentSection = SECTION::UNKNOWN;
1345 while( std::getline( file, line ) )
1347 if( line.empty() || line[0] ==
'J' )
1350 if( line[0] ==
'A' )
1352 if( line.find(
"NET_NAME_SORT!NODE_SORT!NET_NAME!REFDES!" ) != std::string::npos )
1353 currentSection = SECTION::NET_NODES;
1354 else if( line.find(
"SYM_TYPE!SYM_NAME!REFDES!SYM_MIRROR!" ) != std::string::npos )
1355 currentSection = SECTION::SYM_PLACEMENT;
1356 else if( line.find(
"CLASS!SUBCLASS!RECORD_TAG!GRAPHIC_DATA_NAME!" ) != std::string::npos )
1357 currentSection = SECTION::GRAPHICS;
1359 currentSection = SECTION::UNKNOWN;
1364 if( line[0] !=
'S' )
1367 auto fields =
SplitAlgLine( wxString::FromUTF8( line ) );
1369 switch( currentSection )
1371 case SECTION::NET_NODES:
1374 if( fields.size() >= 5 )
1376 wxString netName = fields[3];
1377 wxString refdes = fields[4];
1379 if( !netName.empty() )
1383 if( !refdes.empty() )
1390 case SECTION::SYM_PLACEMENT:
1393 if( fields.size() >= 4 )
1395 wxString symType = fields[1];
1396 wxString symName = fields[2];
1397 wxString refdes = fields[3];
1399 if( symType == wxT(
"PACKAGE" ) && !refdes.empty() )
1401 data.
refDes.insert( refdes );
1408 case SECTION::GRAPHICS:
1414 if( fields.size() < 16 || fields[1] != wxT(
"BOUNDARY" ) )
1417 wxString closureType = fields[15];
1419 if( closureType != wxT(
"SHAPE" ) )
1422 wxString layer = fields[2];
1430 if( fields.size() > 23 )
1431 netName = fields[23];
1433 auto key = std::make_pair( layer, recordId );
1434 auto& zone = zoneMap[key];
1436 zone.recordId = recordId;
1438 if( !netName.empty() )
1439 zone.netName = netName;
1441 double x1 = 0, y1 = 0, x2 = 0, y2 = 0;
1443 if( fields.size() > 9 )
1445 fields[6].ToDouble( &x1 );
1446 fields[7].ToDouble( &y1 );
1447 fields[8].ToDouble( &x2 );
1448 fields[9].ToDouble( &y2 );
1449 zone.AddPoint( x1, y1 );
1450 zone.AddPoint( x2, y2 );
1460 for(
auto& [key, zone] : zoneMap )
1482 std::vector<BRD_ALG_PAIR> boardsWithAlg;
1484 for(
const auto& boardDir : std::filesystem::directory_iterator( dataPath ) )
1486 if( !boardDir.is_directory() )
1489 std::filesystem::path boardPath;
1490 std::filesystem::path algPath;
1492 for(
const auto& entry : std::filesystem::directory_iterator( boardDir ) )
1494 if( !entry.is_regular_file() )
1497 if( entry.path().extension() ==
".brd" )
1498 boardPath = entry.path();
1499 else if( entry.path().extension() ==
".alg" )
1500 algPath = entry.path();
1502 if( !boardPath.empty() && !algPath.empty() )
1504 boardsWithAlg.push_back( { boardPath.string(), algPath.string() } );
1510 return boardsWithAlg;
1521 BOOST_REQUIRE_GT( boardsWithAlg.size(), 0u );
1523 for(
const auto& [brdFile, algFile] : boardsWithAlg )
1528 BOOST_REQUIRE_GT( algData.
netNames.size(), 0u );
1530 BOARD* board = GetCachedBoard( brdFile );
1533 std::set<wxString> boardNets;
1537 if( net->GetNetCode() > 0 )
1538 boardNets.insert( net->GetNetname() );
1541 int missingNets = 0;
1543 for(
const wxString& algNet : algData.
netNames )
1545 if( boardNets.find( algNet ) == boardNets.end() )
1549 if( missingNets <= 10 )
1555 << boardNets.size() <<
", missing " << missingNets );
1569 BOOST_REQUIRE_GT( boardsWithAlg.size(), 0u );
1571 for(
const auto& [brdFile, algFile] : boardsWithAlg )
1576 BOOST_REQUIRE_GT( algData.
refDes.size(), 0u );
1578 BOARD* board = GetCachedBoard( brdFile );
1581 std::set<wxString> boardRefDes;
1584 boardRefDes.insert( fp->GetReference() );
1586 int missingRefDes = 0;
1587 int extraRefDes = 0;
1589 for(
const wxString& algRef : algData.
refDes )
1591 if( boardRefDes.find( algRef ) == boardRefDes.end() )
1595 if( missingRefDes <= 10 )
1600 for(
const wxString& boardRef : boardRefDes )
1602 if( algData.
refDes.find( boardRef ) == algData.
refDes.end() )
1606 if( extraRefDes <= 10 )
1612 <<
" components, board has " << boardRefDes.size()
1613 <<
", missing " << missingRefDes
1614 <<
", extra " << extraRefDes );
1626 std::vector<std::string> boards = GetAllBoardFiles();
1628 for(
const std::string& boardPath : boards )
1630 std::string boardName = std::filesystem::path( boardPath ).filename().string();
1631 BOARD* board = GetCachedBoard( boardPath );
1638 int zeroWidthCount = 0;
1647 if( track->GetWidth() <= 0 )
1651 if( zeroWidthCount <= 5 )
1654 << track->GetStart().x / 1000000.0 <<
", "
1655 << track->GetStart().y / 1000000.0 <<
")" );
1695 double minX = std::numeric_limits<double>::max();
1696 double minY = std::numeric_limits<double>::max();
1697 double maxX = std::numeric_limits<double>::lowest();
1698 double maxY = std::numeric_limits<double>::lowest();
1711 std::ifstream file( aPath );
1713 if( !file.is_open() )
1718 while( std::getline( file, line ) )
1720 if( line.empty() || line[0] !=
'S' )
1725 if( fields.size() < 10 )
1728 bool isDesignOutline = ( fields[1] == wxT(
"BOARD GEOMETRY" )
1729 && fields[2] == wxT(
"DESIGN_OUTLINE" ) );
1731 bool isOutline = ( fields[1] == wxT(
"BOARD GEOMETRY" )
1732 && fields[2] == wxT(
"OUTLINE" ) );
1734 if( !isDesignOutline && !isOutline )
1737 wxString shapeType = fields[4];
1740 if( shapeType == wxT(
"LINE" ) && fields.size() >= 10 )
1743 fields[6].ToCDouble( &seg.
x1 );
1744 fields[7].ToCDouble( &seg.
y1 );
1745 fields[8].ToCDouble( &seg.
x2 );
1746 fields[9].ToCDouble( &seg.
y2 );
1751 else if( shapeType == wxT(
"ARC" ) && fields.size() >= 15 )
1754 fields[6].ToCDouble( &seg.
x1 );
1755 fields[7].ToCDouble( &seg.
y1 );
1756 fields[8].ToCDouble( &seg.
x2 );
1757 fields[9].ToCDouble( &seg.
y2 );
1758 fields[10].ToCDouble( &seg.
centerX );
1759 fields[11].ToCDouble( &seg.
centerY );
1760 fields[12].ToCDouble( &seg.
radius );
1761 seg.
clockwise = ( fields[14] == wxT(
"CLOCKWISE" ) );
1766 else if( shapeType == wxT(
"RECTANGLE" ) && fields.size() >= 10 )
1769 fields[6].ToCDouble( &seg.
x1 );
1770 fields[7].ToCDouble( &seg.
y1 );
1771 fields[8].ToCDouble( &seg.
x2 );
1772 fields[9].ToCDouble( &seg.
y2 );
1782 if( isDesignOutline )
1826 BOOST_REQUIRE_GT( testBoards.size(), 0u );
1828 for(
const auto& [brdFile, algFile] : testBoards )
1840 BOARD* board = GetCachedBoard( brdFile );
1843 int edgeCutsCount = 0;
1854 <<
" -> expected Edge_Cuts segments: " << expectedCount );
1872 BOOST_REQUIRE_GT( testBoards.size(), 0u );
1875 const double milToNm = 25400.0;
1878 const int toleranceNm =
static_cast<int>( 2.0 * milToNm );
1880 for(
const auto& [brdFile, algFile] : testBoards )
1892 BOARD* board = GetCachedBoard( brdFile );
1896 bool hasBbox =
false;
1904 boardBbox = item->GetBoundingBox();
1909 boardBbox.
Merge( item->GetBoundingBox() );
1914 BOOST_REQUIRE_MESSAGE( hasBbox,
"Board should have Edge_Cuts outline" );
1917 int algMinXnm =
static_cast<int>( algOutlines.
minX * milToNm );
1918 int algMinYnm =
static_cast<int>( algOutlines.
minY * milToNm );
1919 int algMaxXnm =
static_cast<int>( algOutlines.
maxX * milToNm );
1920 int algMaxYnm =
static_cast<int>( algOutlines.
maxY * milToNm );
1921 int algWidthNm = algMaxXnm - algMinXnm;
1922 int algHeightNm = algMaxYnm - algMinYnm;
1924 int boardWidth = boardBbox.
GetWidth();
1925 int boardHeight = boardBbox.
GetHeight();
1928 << algOutlines.
minX <<
"," << algOutlines.
minY <<
" to "
1929 << algOutlines.
maxX <<
"," << algOutlines.
maxY
1930 <<
" = " << ( algOutlines.
maxX - algOutlines.
minX ) <<
" x "
1931 << ( algOutlines.
maxY - algOutlines.
minY ) );
1933 << boardBbox.
GetLeft() <<
"," << boardBbox.
GetTop() <<
" to "
1935 <<
" = " << boardWidth <<
" x " << boardHeight );
1939 BOOST_CHECK_CLOSE(
static_cast<double>( boardWidth ),
1940 static_cast<double>( algWidthNm ), 3.0 );
1941 BOOST_CHECK_CLOSE(
static_cast<double>( boardHeight ),
1942 static_cast<double>( algHeightNm ), 3.0 );
1959 BOOST_REQUIRE_GT( testBoards.size(), 0u );
1961 const double milToNm = 25400.0;
1962 const int toleranceNm =
static_cast<int>( 2.0 * milToNm );
1964 for(
const auto& [brdFile, algFile] : testBoards )
1974 bool allLines =
true;
1992 BOARD* board = GetCachedBoard( brdFile );
1996 struct ENDPOINT_PAIR
2002 std::vector<ENDPOINT_PAIR> boardSegments;
2012 boardSegments.push_back( { shape->
GetStart(), shape->
GetEnd() } );
2016 std::vector<ENDPOINT_PAIR> algSegments;
2022 VECTOR2I start(
static_cast<int>( seg.x1 * milToNm ),
2023 static_cast<int>( seg.y1 * milToNm ) );
2024 VECTOR2I end(
static_cast<int>( seg.x2 * milToNm ),
2025 static_cast<int>( seg.y2 * milToNm ) );
2026 algSegments.push_back( { start,
end } );
2030 int x1 =
static_cast<int>( seg.x1 * milToNm );
2031 int y1 =
static_cast<int>( seg.y1 * milToNm );
2032 int x2 =
static_cast<int>( seg.x2 * milToNm );
2033 int y2 =
static_cast<int>( seg.y2 * milToNm );
2035 algSegments.push_back( { { x1, y1 }, { x2, y1 } } );
2036 algSegments.push_back( { { x2, y1 }, { x2, y2 } } );
2037 algSegments.push_back( { { x2, y2 }, { x1, y2 } } );
2038 algSegments.push_back( { { x1, y2 }, { x1, y1 } } );
2044 if( boardSegments.size() != algSegments.size() )
2050 int matchedCount = 0;
2052 std::vector<bool> used( boardSegments.size(),
false );
2054 for(
size_t ai = 0; ai < algSegments.size(); ++ai )
2056 const auto& algSeg = algSegments[ai];
2058 int64_t bestDist = std::numeric_limits<int64_t>::max();
2060 for(
size_t bi = 0; bi < boardSegments.size(); ++bi )
2065 const auto& bSeg = boardSegments[bi];
2068 auto dist = [&](
const VECTOR2I& aAlgPt,
const VECTOR2I& aBoardPt ) -> int64_t
2070 int64_t dx =
std::abs(
static_cast<int64_t
>( aAlgPt.
x )
2071 -
static_cast<int64_t
>( aBoardPt.x ) );
2072 int64_t dy =
std::abs(
static_cast<int64_t
>( aAlgPt.
y )
2073 -
static_cast<int64_t
>( aBoardPt.y ) );
2077 int64_t d1 = dist( algSeg.start, bSeg.start ) + dist( algSeg.end, bSeg.end );
2078 int64_t d2 = dist( algSeg.start, bSeg.end ) + dist( algSeg.end, bSeg.start );
2079 int64_t d = std::min( d1, d2 );
2084 bestIdx =
static_cast<int>( bi );
2088 if( bestIdx >= 0 && bestDist < 2LL * toleranceNm )
2090 used[bestIdx] =
true;
2096 << algSeg.start.x / 1000000.0 <<
", "
2097 << algSeg.start.y / 1000000.0 <<
") -> ("
2098 << algSeg.end.x / 1000000.0 <<
", "
2099 << algSeg.end.y / 1000000.0 <<
") mm"
2100 <<
" bestDist=" << bestDist );
2105 <<
" outline segments" );
2119 std::vector<std::string> boards = GetAllBoardFiles();
2121 for(
const std::string& boardPath : boards )
2123 std::string boardName = std::filesystem::path( boardPath ).filename().string();
2124 BOARD* board = GetCachedBoard( boardPath );
2132 int smdWithDrill = 0;
2136 for(
PAD*
pad : fp->Pads() )
2139 bool hasDrill =
pad->GetDrillSizeX() > 0;
2145 if( pthNoDrill <= 5 )
2148 << fp->GetReference() <<
"."
2149 <<
pad->GetNumber() );
2157 if( smdWithDrill <= 5 )
2160 << fp->GetReference() <<
"."
2161 <<
pad->GetNumber() );
2181 BOOST_REQUIRE_GT( boardsWithAlg.size(), 0u );
2183 for(
const auto& [brdFile, algFile] : boardsWithAlg )
2189 BOARD* board = GetCachedBoard( brdFile );
2192 size_t boardCopperZoneLayers = 0;
2194 for(
const ZONE* zone : board->
Zones() )
2196 if( !zone->GetIsRuleArea() )
2197 boardCopperZoneLayers += ( zone->GetLayerSet() &
LSET::AllCuMask() ).count();
2203 <<
" zone polygons, board has " << boardCopperZoneLayers
2204 <<
" copper zone-layers" );
2206 BOOST_CHECK_EQUAL(
static_cast<size_t>( boardCopperZoneLayers ), algZoneCount );
2219 BOOST_REQUIRE_GT( boardsWithAlg.size(), 0u );
2221 for(
const auto& [brdFile, algFile] : boardsWithAlg )
2227 BOARD* board = GetCachedBoard( brdFile );
2230 std::map<wxString, int> algLayerCounts;
2233 algLayerCounts[zone.
layer]++;
2235 std::map<wxString, int> boardLayerCounts;
2237 for(
const ZONE* zone : board->
Zones() )
2239 if( zone->GetIsRuleArea() )
2251 for(
const auto& [layer, count] : algLayerCounts )
2253 auto it = boardLayerCounts.find( layer );
2254 int boardCount = ( it != boardLayerCounts.end() ) ? it->second : 0;
2272 BOOST_REQUIRE_GT( boardsWithAlg.size(), 0u );
2274 for(
const auto& [brdFile, algFile] : boardsWithAlg )
2280 BOARD* board = GetCachedBoard( brdFile );
2284 const double milsToNm = 25400.0;
2286 std::map<wxString, std::vector<double>> algAreas;
2290 double w = ( zone.
maxX - zone.
minX ) * milsToNm;
2291 double h = ( zone.
maxY - zone.
minY ) * milsToNm;
2292 algAreas[zone.
layer].push_back( w * h );
2295 std::map<wxString, std::vector<double>> boardAreas;
2297 for(
const ZONE* zone : board->
Zones() )
2299 if( zone->GetIsRuleArea() )
2302 BOX2I bbox = zone->GetBoundingBox();
2303 double area =
static_cast<double>( bbox.
GetWidth() )
2304 *
static_cast<double>( bbox.
GetHeight() );
2309 boardAreas[board->
GetLayerName( layer )].push_back( area );
2316 for(
auto& [layer, algList] : algAreas )
2318 std::sort( algList.begin(), algList.end() );
2319 auto it = boardAreas.find( layer );
2321 if( it == boardAreas.end() || it->second.size() != algList.size() )
2324 std::sort( it->second.begin(), it->second.end() );
2326 for(
size_t i = 0; i < algList.size(); ++i )
2328 double ref = std::max( algList[i], 1.0 );
2329 double err =
std::abs( it->second[i] - algList[i] ) / ref;
2339 if( mismatched <= 5 )
2342 <<
": alg area " << algList[i] / ( milsToNm * milsToNm )
2343 <<
" sq mils vs board area "
2344 << it->second[i] / ( milsToNm * milsToNm )
2352 << mismatched <<
" mismatched" );
2354 int total = matched + mismatched;
2358 BOOST_CHECK_GT( matched, total * 8 / 10 );
2375 BOARD* board = GetCachedBoard( dataPath );
2381 const std::set<wxString> targetRefs = { wxS(
"J1" ), wxS(
"P5" ), wxS(
"U5" ),
2382 wxS(
"U13" ), wxS(
"C78" ) };
2384 int testedCount = 0;
2385 int failedCount = 0;
2389 if( targetRefs.find( fp->GetReference() ) == targetRefs.end() )
2395 bool hasFab =
false;
2397 for(
BOARD_ITEM* item : fp->GraphicalItems() )
2399 if( item->GetLayer() == fabLayer )
2403 fabBbox = item->GetBoundingBox();
2408 fabBbox.
Merge( item->GetBoundingBox() );
2413 if( !hasFab || fp->Pads().empty() )
2418 BOX2I testBbox = fabBbox;
2425 for(
PAD*
pad : fp->Pads() )
2429 if( !testBbox.
Contains( padCenter ) )
2433 <<
" at (" << padCenter.
x / 1e6 <<
", "
2434 << padCenter.
y / 1e6 <<
") mm is outside F.Fab bbox" );
2441 BOOST_CHECK_GE( testedCount, 4 );
2455 BOARD* board = GetCachedBoard( dataPath );
2460 wxString ref = fp->GetReference();
2462 if( ref != wxS(
"P6" ) && ref != wxS(
"P10" ) )
2467 for(
PAD*
pad : fp->Pads() )
2471 if( !
pad->GetNumber().ToLong( &padNum ) )
2475 if( padNum < 1 || padNum > 19 )
2479 BOX2I bbox =
pad->GetBoundingBox();
2484 if( bboxW == bboxH )
2489 BOOST_CHECK_MESSAGE( bboxW > bboxH,
2490 ref <<
" pad " <<
pad->GetNumber()
2491 <<
" should be visually wider than tall: "
2492 << bboxW / 1e6 <<
" x " << bboxH / 1e6 <<
" mm" );
2511 BOARD* board = GetCachedBoard( dataPath );
2514 int oblongCount = 0;
2518 for(
PAD*
pad : fp->Pads() )
2522 if( drillSize.
x <= 0 || drillSize.
y <= 0 )
2525 if( drillSize.
x == drillSize.
y )
2535 <<
" slot: " << drillSize.
x / 1e6 <<
" x "
2536 << drillSize.
y / 1e6 <<
" mm"
2537 <<
" attr=" <<
static_cast<int>(
pad->GetAttribute() ) );
2556 BOARD* board = GetCachedBoard( dataPath );
2564 if( fp->GetReference() == wxT(
"J1" ) )
2571 BOOST_REQUIRE_MESSAGE( j1 !=
nullptr,
"Footprint J1 must exist in BeagleBone_Black_RevC" );
2575 BOOST_CHECK_CLOSE( orientation.
AsDegrees(), 90.0, 0.1 );
2591 std::unique_ptr<BOARD> board;
2601 catch(
const std::exception& e )
2606 reporter.PrintAllMessages(
"UIImportPath_NullBoard" );
2608 BOOST_REQUIRE_MESSAGE( board !=
nullptr,
"LoadBoard must return a valid board" );
2610 BOOST_CHECK_GT( board->GetNetCount(), 0 );
2611 BOOST_CHECK_GT( board->Footprints().size(), 0 );
2612 BOOST_CHECK_GT( board->Tracks().size(), 0 );
2629 std::vector<std::string> boards = GetAllBoardFiles();
2631 for(
const std::string& boardPath : boards )
2633 std::string boardName = std::filesystem::path( boardPath ).filename().string();
2634 BOARD* board = GetCachedBoard( boardPath );
2641 int inconsistentCount = 0;
2645 const bool onBottom = fp->IsFlipped();
2647 for(
PAD*
pad : fp->Pads() )
2652 LSET layers =
pad->GetLayerSet();
2656 if( onBottom && hasTopCopper && !hasBotCopper )
2658 inconsistentCount++;
2660 <<
pad->GetNumber() <<
" is on bottom footprint but SMD "
2661 <<
"pad has F.Cu without B.Cu" );
2663 else if( !onBottom && hasBotCopper && !hasTopCopper )
2665 inconsistentCount++;
2667 <<
pad->GetNumber() <<
" is on top footprint but SMD "
2668 <<
"pad has B.Cu without F.Cu" );
2691 std::vector<std::string> boards = {
2695 for(
const std::string& boardPath : boards )
2697 std::string boardName = std::filesystem::path( boardPath ).filename().string();
2698 BOARD* board = GetCachedBoard( boardPath );
2704 int inconsistentCount = 0;
2705 int checkedFootprints = 0;
2710 bool hasSmd =
false;
2713 for(
PAD*
pad : fp->Pads() )
2721 if( !hasSmd || hasTH )
2724 checkedFootprints++;
2726 const bool onBottom = fp->IsFlipped();
2728 for(
BOARD_ITEM* item : fp->GraphicalItems() )
2735 bool wrongSide =
false;
2744 inconsistentCount++;
2746 boardName <<
": " << fp->GetReference() <<
" is "
2747 << ( onBottom ?
"bottom" :
"top" ) <<
"-side SMD but has "
2748 << item->GetClass() <<
" on "
2755 <<
" SMD-only footprints for tech layer consistency" );
2772 BOARD* board = GetCachedBoard( dataPath );
2782 std::vector<SLOT_CHECK> checks = {
2783 { wxS(
"P6" ), wxS(
"20" ) },
2784 { wxS(
"P6" ), wxS(
"21" ) },
2785 { wxS(
"P3" ), wxS(
"6" ) },
2786 { wxS(
"P1" ), wxS(
"1" ) },
2787 { wxS(
"P1" ), wxS(
"2" ) },
2788 { wxS(
"P1" ), wxS(
"3" ) },
2791 for(
const auto& check : checks )
2799 if( candidate->GetReference() == check.fpRef )
2806 BOOST_REQUIRE_MESSAGE( fp !=
nullptr,
"Footprint " << check.fpRef <<
" should exist" );
2810 for(
PAD* candidate : fp->
Pads() )
2812 if( candidate->GetNumber() == check.padNum )
2819 BOOST_REQUIRE_MESSAGE(
pad !=
nullptr,
2820 "Pad " << check.padNum <<
" should exist on " << check.fpRef );
2826 <<
": pad=" << padSize.
x <<
"x" << padSize.
y
2827 <<
" drill=" << drillSize.
x <<
"x" << drillSize.
y );
2830 if( drillSize.
x != drillSize.
y )
2832 bool padIsTaller = ( padSize.
y > padSize.
x );
2833 bool drillIsTaller = ( drillSize.
y > drillSize.
x );
2835 BOOST_CHECK_MESSAGE( padIsTaller == drillIsTaller,
2836 "Drill slot should match pad orientation" );
2851 BOARD* board = GetCachedBoard( dataPath );
2854 int filledZoneCount = 0;
2855 int totalCopperZones = 0;
2857 for(
const ZONE* zone : board->
Zones() )
2859 if( zone->GetIsRuleArea() || zone->GetNetCode() == 0 )
2864 if( zone->IsFilled() )
2869 <<
" layers=" << zone->GetLayerSet().count() );
2874 <<
", filled: " << filledZoneCount );
2876 BOOST_CHECK_GT( totalCopperZones, 0 );
2877 BOOST_CHECK_GT( filledZoneCount, 0 );
2889 BOARD* board = GetCachedBoard( dataPath );
2892 int teardropZones = 0;
2894 for(
const ZONE* zone : board->
Zones() )
2896 if( zone->IsTeardropArea() )
2900 BOOST_CHECK_GT( teardropZones, 1000 );
2904 int padsWithTeardrops = 0;
2909 for(
const PAD*
pad : fp->Pads() )
2913 if(
pad->GetTeardropsEnabled() )
2914 padsWithTeardrops++;
2918 BOOST_CHECK_GT( padsWithTeardrops, 0 );
2919 BOOST_TEST_MESSAGE(
"Pads with teardrops enabled: " << padsWithTeardrops <<
" / " << totalPads );
2921 int viasWithTeardrops = 0;
2931 if(
static_cast<const PCB_VIA*
>( track )->GetTeardropsEnabled() )
2932 viasWithTeardrops++;
2935 BOOST_CHECK_GT( viasWithTeardrops, 0 );
2936 BOOST_TEST_MESSAGE(
"Vias with teardrops enabled: " << viasWithTeardrops <<
" / " << totalVias );
2948 BOARD* board = GetCachedBoard( dataPath );
2951 int teardropZones = 0;
2953 for(
const ZONE* zone : board->
Zones() )
2955 if( zone->IsTeardropArea() )
2961 int padsWithTeardrops = 0;
2965 for(
const PAD*
pad : fp->Pads() )
2967 if(
pad->GetTeardropsEnabled() )
2968 padsWithTeardrops++;
2989 std::unique_ptr<BOARD> board = plugin.
LoadBoard( dataPath );
2993 BOOST_CHECK_MESSAGE( board->m_LegacyNetclassesLoaded,
2994 "m_LegacyNetclassesLoaded must be true after Allegro import" );
2995 BOOST_CHECK_MESSAGE( board->m_LegacyDesignSettingsLoaded,
2996 "m_LegacyDesignSettingsLoaded must be true after Allegro import" );
3006 std::vector<std::string> boards = GetAllBoardFiles();
3008 for(
const std::string& boardPath : boards )
3010 std::string boardName = std::filesystem::path( boardPath ).filename().string();
3011 BOARD* board = GetCachedBoard( boardPath );
3019 const auto& netclasses = netSettings->GetNetclasses();
3023 for(
const auto& [
name, nc] : netclasses )
3026 << nc->GetTrackWidth() <<
" clearance="
3027 << nc->GetClearance() );
3031 if( !
name.StartsWith( wxS(
"DP_" ) )
3032 && !
name.StartsWith( wxS(
"MG_" ) )
3033 && !
name.StartsWith( wxS(
"W" ) ) )
3035 BOOST_CHECK_MESSAGE( nc->HasTrackWidth(),
3036 name <<
" should have a track width" );
3037 BOOST_CHECK_MESSAGE( nc->GetTrackWidth() > 0,
3038 name <<
" track width should be positive" );
General utilities for PCB file IO for QA programs.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
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...
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
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
KICAD_T Type() const
Returns the type of object.
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.
VECTOR3D m_Offset
3D model offset (mm)
VECTOR3D m_Rotation
3D model rotation (degrees)
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.
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.
Handle the data for a net.
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
std::unique_ptr< BOARD > LoadBoard(const wxString &aFileName, const std::map< std::string, UTF8 > *aProperties=nullptr, PROJECT *aProject=nullptr)
Load information from some input file format that this PCB_IO implementation knows about into new BOA...
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.
std::deque< BOARD_ITEM * > DRAWINGS
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()
IbisParser parser & reporter
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_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
@ 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