36#include <compoundfilereader.h>
76 const CFB::COMPOUND_FILE_ENTRY* aEntry )
95 std::vector<const ZONE*> ruleAreas;
99 if( zone->GetIsRuleArea() )
100 ruleAreas.push_back( zone );
105 for(
const ZONE* zone : footprint->Zones() )
107 if( zone->GetIsRuleArea() )
108 ruleAreas.push_back( zone );
133 ALTIUM_PCB importer( &board,
nullptr, layerMappingHandler );
135 const std::vector<int> netcodes = { 1, 2, 3 };
138 BOOST_CHECK_THROW( getNetCode( importer, netcodes, 3 ),
IO_ERROR );
146 std::string properties =
"|BOLD=TRUE|TEXTLINEWIDTH=6mil";
147 properties.push_back(
'\0' );
149 const uint16_t recordHeader = 1;
150 const uint32_t propertySize =
static_cast<uint32_t
>( properties.size() );
151 const size_t recordSize =
sizeof( recordHeader ) +
sizeof( propertySize ) + properties.size();
153 std::unique_ptr<char[]> content = std::make_unique<char[]>( recordSize );
155 std::memcpy( content.get(), &recordHeader,
sizeof( recordHeader ) );
156 std::memcpy( content.get() +
sizeof( recordHeader ), &propertySize,
sizeof( propertySize ) );
157 std::memcpy( content.get() +
sizeof( recordHeader ) +
sizeof( propertySize ), properties.data(),
176 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
183 for(
FOOTPRINT* footprint : board->Footprints() )
185 const int expected = footprint->GetLikelyAttribute();
191 wxString::Format( wxT(
"Footprint %s has mounting style %d, expected %d" ),
201 BOOST_CHECK_GT( smd, 0 );
202 BOOST_CHECK_GT( throughHole, 0 );
211 const CFB::COMPOUND_FILE_ENTRY* data = file.
FindStream( {
"ExtendedPrimitiveInformation",
"Data" } );
217 ALTIUM_PCB importer( &board,
nullptr, layerMappingHandler );
219 parseExtendedPrimitiveInformation( importer, file, data );
221 std::vector<std::pair<PCB_LAYER_ID, int>> front =
224 BOOST_REQUIRE_EQUAL( front.size(), 1 );
228 std::vector<std::pair<PCB_LAYER_ID, int>> back =
231 BOOST_REQUIRE_EQUAL( back.size(), 1 );
239 constexpr uint32_t subrecordSize = 57;
240 constexpr size_t recordSize = 1 +
sizeof( subrecordSize ) + subrecordSize;
241 std::unique_ptr<char[]> content = std::make_unique<char[]>( recordSize );
244 auto append = [&](
auto aValue )
246 std::memcpy( content.get() + offset, &aValue,
sizeof( aValue ) );
247 offset +=
sizeof( aValue );
251 append( subrecordSize );
253 append( uint8_t{ 0 } );
254 append( uint8_t{ 0 } );
255 append( uint16_t{ 0 } );
258 append( uint32_t{ 0 } );
259 append( int32_t{ 0 } );
260 append( int32_t{ 0 } );
261 append( uint32_t{ 100000 } );
262 append(
double{ 0.0 } );
263 append(
double{ 360.0 } );
264 append( uint32_t{ 10000 } );
265 append( uint16_t{ 0 } );
266 append( uint8_t{ 0 } );
267 append( uint32_t{ 0 } );
269 append( uint8_t{ 0 } );
271 BOOST_REQUIRE_EQUAL( offset, recordSize );
274 AARC6 sourceArc( reader );
277 ALTIUM_PCB importer( &board,
nullptr, layerMappingHandler );
279 convertConnectedArc( importer, sourceArc,
F_Cu );
281 BOOST_REQUIRE_EQUAL( board.
Tracks().size(), 2 );
283 std::vector<const PCB_ARC*> arcs;
287 BOOST_REQUIRE_EQUAL( track->Type(),
PCB_ARC_T );
288 arcs.push_back(
static_cast<const PCB_ARC*
>( track ) );
291 for(
const PCB_ARC* arc : arcs )
293 BOOST_CHECK_CLOSE(
std::abs( arc->GetAngle().AsDegrees() ), 180.0, 1e-6 );
294 BOOST_CHECK_CLOSE( arc->GetRadius(),
pcbIUScale.mmToIU( 0.254 ), 1e-6 );
299 BOOST_CHECK( arcs[0]->GetStart() == arcs[1]->GetEnd() );
300 BOOST_CHECK( arcs[0]->GetEnd() == arcs[1]->GetStart() );
301 BOOST_CHECK( board.
Drawings().empty() );
312 +
"plugins/altium/eDP_adapter_dvt1_source/eDP_adapter_dvt1.PcbDoc";
315 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
320 BOOST_CHECK( board->GetNetCount() > 0 );
321 BOOST_CHECK( board->Footprints().size() > 0 );
330 for(
const char*
name : {
"HiFive/HiFive1.B01.PcbDoc",
"eDP_adapter_dvt1_source/eDP_adapter_dvt1.PcbDoc",
331 "issue24456/Fastino_Ground_Isolator.PcbDoc",
"issue25362/OpenRex_V1I1_PCB_reduced.PcbDoc" } )
340 for(
FOOTPRINT* footprint : board->Footprints() )
347 footprint->BuildCourtyardCaches( &onError );
349 closed += footprint->GetCourtyard(
F_CrtYd ).OutlineCount();
350 closed += footprint->GetCourtyard(
B_CrtYd ).OutlineCount();
357 BOOST_CHECK_GT( closed, 0 );
364 for(
const char*
name : {
"HiFive/HiFive1.B01.PcbDoc",
"eDP_adapter_dvt1_source/eDP_adapter_dvt1.PcbDoc",
365 "issue13750/altium2kicad_region_soldermask_expansion.PcbDoc",
366 "issue24456/Fastino_Ground_Isolator.PcbDoc",
"issue24654/PCB1.PcbDoc",
367 "issue24847/PCB1.PcbDoc",
"issue25362/OpenRex_V1I1_PCB_reduced.PcbDoc" } )
384 board->GetOutlinesChainingEpsilon(),
false, &onError );
388 BOOST_CHECK( built );
400 std::string dataPath =
403 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
406 BOOST_REQUIRE_GT( board->Footprints().size(), 0 );
408 std::vector<FOOTPRINT*> cached = m_altiumPlugin.GetImportedCachedLibraryFootprints();
411 std::vector<std::unique_ptr<FOOTPRINT>> owned;
414 owned.emplace_back( fp );
418 std::set<FOOTPRINT*> boardFootprints( board->Footprints().begin(), board->Footprints().end() );
423 BOOST_CHECK_MESSAGE( boardFootprints.count( fp ) == 0,
424 "GetImportedCachedLibraryFootprints returned a board-owned footprint" );
436 std::string dataPath =
439 std::set<wxString> mappedLayerNames;
441 m_altiumPlugin.RegisterCallback(
442 [&](
const std::vector<INPUT_LAYER_DESC>& aLayers )
445 mappedLayerNames.insert( layer.Name );
450 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
453 BOOST_CHECK( mappedLayerNames.count( wxS(
"Internal Plane 1" ) ) );
454 BOOST_CHECK( mappedLayerNames.count( wxS(
"Internal Plane 2" ) ) );
456 for(
int plane = 3; plane <= 16; ++plane )
458 wxString
name = wxString::Format( wxS(
"Internal Plane %d" ), plane );
459 BOOST_CHECK_MESSAGE( !mappedLayerNames.count(
name ),
460 wxString::Format(
"Unused layer '%s' reached the mapper",
name ) );
474 std::string dataPath =
477 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
482 int keepOutLayer = 0;
485 for(
const ZONE* zone : collectRuleAreas( *board ) )
487 const bool tracks = zone->GetDoNotAllowTracks();
488 const bool vias = zone->GetDoNotAllowVias();
489 const bool pads = zone->GetDoNotAllowPads();
490 const bool fills = zone->GetDoNotAllowZoneFills();
491 const bool footprints = zone->GetDoNotAllowFootprints();
493 if( fills && !tracks && !vias && !pads && !footprints )
495 else if( fills && tracks && vias && pads && !footprints )
497 else if( !fills && !tracks && !vias && !pads && !footprints )
518 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
525 for(
const ZONE* zone : collectRuleAreas( *board ) )
527 const bool tracks = zone->GetDoNotAllowTracks();
528 const bool vias = zone->GetDoNotAllowVias();
529 const bool pads = zone->GetDoNotAllowPads();
530 const bool fills = zone->GetDoNotAllowZoneFills();
532 if( vias && !tracks && !pads && !fills )
534 else if( vias && tracks && pads && fills )
555 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
560 std::shared_ptr<NET_SETTINGS> netSettings = board->GetDesignSettings().m_NetSettings;
565 auto& patternAssignments = netSettings->GetNetclassPatternAssignments();
568 BOOST_REQUIRE_MESSAGE( patternAssignments.size() > 0,
569 "Test file must have netclass pattern assignments" );
573 bool foundAssignedNet =
false;
577 if( net->GetNetCode() <= 0 )
581 NETCLASS* directNetclass = net->GetNetClass();
584 std::shared_ptr<NETCLASS> effectiveNetclass =
585 netSettings->GetEffectiveNetClass( net->GetNetname() );
592 directNetclass !=
nullptr,
593 wxString::Format(
"Net '%s' should have a direct netclass assignment",
594 net->GetNetname() ) );
598 foundAssignedNet =
true;
604 wxString::Format(
"Net '%s' should not have default netclass, "
605 "expected effective class or component",
606 net->GetNetname() ) );
612 BOOST_CHECK_MESSAGE( foundAssignedNet,
613 "At least one net should have a non-default netclass assigned" );
624 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
631 board->Add(
new NETINFO_ITEM( board.get(), wxT(
"__ALTIUM_UNNAMED_NET_2" ), -1 ),
652 std::string dataPath =
655 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
657 std::shared_ptr<NET_SETTINGS> netSettings = board->GetDesignSettings().m_NetSettings;
658 std::shared_ptr<NETCLASS> defaultNetclass = netSettings->GetDefaultNetclass();
664 auto it = netSettings->GetNetclasses().find( wxT(
"50R" ) );
669 BOOST_CHECK( board->m_LegacyDesignSettingsLoaded );
682 [
this](
const std::string& aRelativePath )
685 m_altiumPlugin.SetReporter( &
reporter );
687 std::unique_ptr<BOARD> board =
689 m_altiumPlugin.SetReporter(
nullptr );
691 std::vector<wxString> hits;
695 if(
message.text.Contains( wxS(
"does not define" ) ) )
696 hits.push_back(
message.text );
702 std::vector<wxString> hiFive = messagesFor(
"plugins/altium/HiFive/HiFive1.B01.PcbDoc" );
704 BOOST_REQUIRE_EQUAL( hiFive.size(), 1 );
705 BOOST_CHECK( hiFive[0].Contains( wxS(
"'PWR'" ) ) );
708 BOOST_CHECK_EQUAL( messagesFor(
"plugins/altium/issue24456/Fastino_Ground_Isolator.PcbDoc" ).size(), 0 );
719 auto makeWidthRule = [](
int aPriority,
bool aEnabled,
const wxString& aScope2,
int aWidth )
733 std::shared_ptr<NETCLASS> sig = std::make_shared<NETCLASS>( wxT(
"SIG" ),
false );
738 std::map<ALTIUM_RULE_KIND, std::vector<ARULE6>> rules;
740 makeWidthRule( 1,
true, wxT(
"All" ), 100 ),
741 makeWidthRule( 2,
true, wxT(
"All" ), 200 ),
748 sig->SetTrackWidth( std::optional<int>() );
755 sig->SetTrackWidth( std::optional<int>() );
759 BOOST_CHECK( !sig->HasTrackWidth() );
769 const std::string& aRelativePath )
773 std::unique_ptr<BOARD> board = aPlugin.
LoadBoard( dataPath,
nullptr );
777 int fillZoneCount = 0;
778 int fillZonesWithClearance = 0;
780 for(
ZONE* zone : board->Zones() )
782 if( !zone->IsOnCopperLayer() || zone->GetIsRuleArea() || zone->IsTeardropArea() )
787 if( zone->GetLocalClearance().has_value() && zone->GetLocalClearance().value() > 0 )
788 fillZonesWithClearance++;
791 BOOST_CHECK_GT( fillZoneCount, 0 );
793 BOOST_CHECK_MESSAGE( fillZonesWithClearance == fillZoneCount,
794 wxString::Format(
"%s: %d/%d copper fill zones have clearance set",
795 aRelativePath, fillZonesWithClearance,
803 m_altiumPlugin,
"plugins/altium/eDP_adapter_dvt1_source/eDP_adapter_dvt1.PcbDoc" );
810 "plugins/altium/HiFive/HiFive1.B01.PcbDoc" );
855 auto makeRule = [](
int aPriority,
const wxString& aScope1,
const wxString& aScope2,
867 std::vector<ARULE6> rules = {
868 makeRule( 1, wxT(
"InPolygon And InNet('GND')" ), wxT(
"All" ), 100 ),
869 makeRule( 2, wxT(
"InPolygon" ), wxT(
"All" ), 200 ),
870 makeRule( 3, wxT(
"All" ), wxT(
"All" ), 300 ),
871 makeRule( 4, wxT(
"All" ), wxT(
"All" ), 400 ),
879 rules.erase( rules.begin() );
885 rules.erase( rules.begin() );
892 makeRule( 1, wxT(
"InPolygon And InNet('GND')" ), wxT(
"All" ), 100 ),
893 makeRule( 2, wxT(
"InPolygon" ), wxT(
"All" ), 200 ),
895 rules[0].enabled =
false;
916 +
"plugins/altium/issue24456/Fastino_Ground_Isolator.PcbDoc";
918 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
923 int frontExposed = 0;
926 for(
PCB_TRACK* track : board->Tracks() )
941 BOOST_REQUIRE_GT( viaCount, 0 );
945 BOOST_CHECK_MESSAGE( frontExposed == 0,
946 wxString::Format(
"%d of %d vias left front-exposed despite a "
947 "hole-referenced mask",
948 frontExposed, viaCount ) );
949 BOOST_CHECK_MESSAGE( backExposed == 0,
950 wxString::Format(
"%d of %d vias left back-exposed despite a "
951 "hole-referenced mask",
952 backExposed, viaCount ) );
957 const uint32_t holeSize = 300000;
958 const int landWidth = 600000;
961 holeSize, 500000, landWidth ) );
963 holeSize, 30000, landWidth ) );
965 holeSize, 0, landWidth ) );
969 holeSize, 30000, landWidth ) );
975 bool rotationSupported;
978 BOOST_CHECK( rotationSupported );
981 BOOST_CHECK( rotationSupported );
984 BOOST_CHECK( !rotationSupported );
998 +
"plugins/altium/issue24456/Fastino_Ground_Isolator.PcbDoc";
1000 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
1008 BOOST_CHECK( board->GetStackupOrDefault() == stackup );
1010 int dielectricCount = 0;
1011 int dielectricWithTangent = 0;
1018 for(
int sub = 0; sub < item->GetSublayersCount(); sub++ )
1021 if( item->GetThickness( sub ) <= 0 )
1026 double tangent = item->GetLossTangent( sub );
1030 dielectricWithTangent++;
1033 BOOST_CHECK_CLOSE( tangent, 0.020, 1e-6 );
1038 BOOST_REQUIRE_GT( dielectricCount, 0 );
1042 BOOST_CHECK_MESSAGE( dielectricWithTangent == dielectricCount,
1043 wxString::Format(
"Only %d of %d dielectric sublayers received a loss "
1044 "tangent from the Altium stackup",
1045 dielectricWithTangent, dielectricCount ) );
1058 std::string pcbDoc = dataDir +
"Fastino_Ground_Isolator.PcbDoc";
1059 std::string prjPcb = dataDir +
"Fastino_Ground_Isolator.PrjPcb";
1065 std::map<std::string, UTF8> props;
1066 props[
"project_file"] = prjPcb;
1068 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( pcbDoc, &props, &
project );
1070 const std::map<wxString, wxString>& textVars =
project.GetTextVars();
1078 BOOST_CHECK_EQUAL( textVars.at( wxS(
"PROJECT_NAME" ) ), wxS(
"Fastino Ground Isolator" ) );
1089 board->SetProject( &
project,
true );
1091 bool sawResolvedBoardText =
false;
1097 if(
text &&
text->GetText().Contains( wxS(
"${PCB_REVISION}" ) ) )
1100 BOOST_CHECK( !shown.Contains( wxS(
"${PCB_REVISION}" ) ) );
1101 BOOST_CHECK( shown.Contains( wxS(
"A" ) ) );
1102 sawResolvedBoardText =
true;
1106 BOOST_CHECK( sawResolvedBoardText );
1117 std::string pcbDoc = dataDir +
"Fastino_Ground_Isolator.PcbDoc";
1118 std::string prjPcb = dataDir +
"Fastino_Ground_Isolator.PrjPcb";
1123 project.GetTextVars()[wxS(
"PCB_REVISION" )] = wxS(
"user-set" );
1125 std::map<std::string, UTF8> props;
1126 props[
"project_file"] = prjPcb;
1128 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( pcbDoc, &props, &
project );
1151 +
"plugins/altium/issue24456/Fastino_Ground_Isolator.PcbDoc";
1153 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
1156 std::vector<PCB_TEXT*> copperTexts;
1157 std::vector<PCB_TEXT*> maskTexts;
1168 copperTexts.push_back(
text );
1170 maskTexts.push_back(
text );
1173 BOOST_REQUIRE_MESSAGE( !copperTexts.empty(),
"Board must contain copper-layer text" );
1174 BOOST_REQUIRE_MESSAGE( !maskTexts.empty(),
"Board must contain soldermask-layer text" );
1179 const int tolerance = 1000;
1181 int matchedPairs = 0;
1183 for(
PCB_TEXT* copper : copperTexts )
1187 if( copper->GetText() != mask->GetText()
1188 || copper->GetTextAngle() != mask->GetTextAngle()
1189 || copper->IsMirrored() != mask->IsMirrored() )
1203 BOOST_CHECK_MESSAGE(
1205 wxString::Format(
"Copper/mask copies of '%s' diverge by (%d, %d) IU",
1210 BOOST_CHECK_MESSAGE( matchedPairs > 0,
1211 "Expected at least one coincident copper/soldermask text pair" );
1227 std::string dataPath =
1230 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
1234 int tuningCount = 0;
1235 int singleCount = 0;
1236 int diffPairCount = 0;
1238 std::set<wxString> patternNames;
1248 patternNames.insert( pattern->
GetName() );
1252 "Imported tuning pattern wraps no copper" );
1257 std::set<int> memberNets;
1262 BOOST_CHECK( item->GetParentGroup() == pattern );
1265 memberNets.insert( bci->GetNetCode() );
1288 const std::set<wxString> expectedNames = {
1289 wxT(
"Interactive Length Tunings" ),
1290 wxT(
"Interactive Length Tunings 1" ),
1291 wxT(
"Interactive Length Tunings 2" ),
1292 wxT(
"Interactive Length Tunings 3" ),
1293 wxT(
"Interactive Diffpair Length Tunings" ),
1294 wxT(
"Interactive Diffpair Length Tunings 1" ),
1295 wxT(
"Interactive Diffpair Length Tunings 2" ),
1296 wxT(
"Interactive Diffpair Length Tunings 3" ),
1299 BOOST_CHECK( patternNames == expectedNames );
1314 std::string dataPath =
1317 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
1332 BOOST_REQUIRE_MESSAGE( pattern->
GetBaseLine().has_value(),
1333 "Imported tuning pattern has no baseline" );
1334 BOOST_REQUIRE_GT( pattern->
GetBaseLine()->PointCount(), 1 );
1345 "Imported diff-pair tuning pattern has no coupled baseline" );
1351 "Imported tuning pattern is not attributed to a net" );
1354 for(
int i = 0; i < baseLine.
PointCount(); ++i )
1356 BOOST_CHECK_MESSAGE( pattern->
HitTest( baseLine.
CPoint( i ), 0 ),
1357 "Tuning pattern is not hittable on its own baseline" );
1363 "Tuning pattern bounding box does not cover its baseline" );
1367 BOOST_CHECK_MESSAGE( bbox.
Contains( item->GetBoundingBox() ),
1368 "Tuning pattern bounding box does not cover its member copper" );
1383 +
"plugins/altium/issue24847/PCB1.PcbDoc";
1385 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
1388 BOOST_REQUIRE_GT( board->Footprints().size(), 0 );
1392 int keepoutZoneCount = 0;
1394 for(
FOOTPRINT* footprint : board->Footprints() )
1396 const VECTOR2I fpPos = footprint->GetPosition();
1398 for(
ZONE* zone : footprint->Zones() )
1402 const VECTOR2I zoneCenter = zone->GetBoundingBox().GetCenter();
1403 const double distMm = ( zoneCenter - fpPos ).EuclideanNorm() / 1e6;
1406 <<
" at (" << fpPos.
x <<
"," << fpPos.
y
1407 <<
") keepout center (" << zoneCenter.
x <<
","
1408 << zoneCenter.
y <<
") dist " << distMm <<
" mm" );
1412 BOOST_CHECK_MESSAGE( distMm < 2.0,
1413 "Keepout in footprint " << footprint->GetReference().ToStdString()
1414 <<
" is " << distMm <<
" mm from its footprint origin" );
1429 +
"plugins/altium/issue13750/"
1430 "altium2kicad_region_soldermask_expansion.PcbDoc";
1432 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
1435 std::vector<PCB_SHAPE*> copperPolys;
1436 std::vector<PCB_SHAPE*> maskPolys;
1449 copperPolys.push_back( shape );
1451 maskPolys.push_back( shape );
1455 BOOST_REQUIRE_EQUAL( copperPolys.size(), 2 );
1456 BOOST_REQUIRE_EQUAL( maskPolys.size(), 1 );
1461 int exactMatches = 0;
1475 BOOST_CHECK_MESSAGE( exactMatches == 1,
"F_Mask relief aperture must exactly match exactly one copper region" );
1483 std::string dataPath =
1486 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
1488 int regionCount = 0;
1489 int connectedCount = 0;
1491 for(
FOOTPRINT* footprint : board->Footprints() )
1493 for(
PAD*
pad : footprint->Pads() )
1503 if(
pad->GetNetCode() > 0 )
1506 BOOST_CHECK( !
pad->GetNetname().IsEmpty() );
1511 BOOST_REQUIRE_GT( regionCount, 0 );
1512 BOOST_CHECK_GT( connectedCount, 0 );
1519 std::string dataPath =
1522 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
1526 for(
FOOTPRINT* footprint : board->Footprints() )
1528 for(
PAD*
pad : footprint->Pads() )
1533 &&
pad->GetNetCode() > 0 && !
pad->GetNumber().IsEmpty() )
1541 BOOST_CHECK_GT( joined, 0 );
1552 std::string dataPath =
1555 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
1557 int regionCount = 0;
1559 for(
FOOTPRINT* footprint : board->Footprints() )
1561 if( footprint->GetOrientation().IsZero() )
1564 for(
PAD*
pad : footprint->Pads() )
1579 BOOST_CHECK_MESSAGE( absolute.
IsZero(),
1580 wxString::Format( wxT(
"Region pad in %s is rotated %.1f degrees" ),
1581 footprint->GetReference(), absolute.
AsDegrees() ) );
1582 BOOST_CHECK( !
pad->GetFPRelativeOrientation().IsZero() );
1586 BOOST_REQUIRE_GT( regionCount, 0 );
1593 const std::string& aRelativePath,
1594 double aExpectedXmm,
double aExpectedYmm )
1598 std::unique_ptr<BOARD> board = aPlugin.
LoadBoard( dataPath,
nullptr );
1607 BOX2I outline = board->GetBoardEdgesBoundingBox();
1609 BOOST_REQUIRE_GT( outline.
GetArea(), 0 );
1616 const double toleranceMm = 1.0;
1618 BOOST_CHECK_MESSAGE(
std::abs( offsetXmm - aExpectedXmm ) < toleranceMm,
1619 wxString::Format(
"%s: origin sits %.3f mm right of the outline corner, "
1621 aRelativePath, offsetXmm, aExpectedXmm ) );
1623 BOOST_CHECK_MESSAGE(
std::abs( offsetYmm - aExpectedYmm ) < toleranceMm,
1624 wxString::Format(
"%s: origin sits %.3f mm below the outline corner, "
1626 aRelativePath, offsetYmm, aExpectedYmm ) );
1635 "plugins/altium/eDP_adapter_dvt1_source/eDP_adapter_dvt1.PcbDoc",
1650 +
"plugins/altium/issue25362/OpenRex_V1I1_PCB_reduced.PcbDoc";
1652 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
1654 BOOST_REQUIRE_EQUAL( board->Footprints().size(), 1 );
1656 FOOTPRINT* footprint = board->Footprints().front();
1661 const std::shared_ptr<EMBEDDED_FILES::EMBEDDED_FILE>& file =
1669 const std::string step( file->decompressedData.begin(), file->decompressedData.end() );
1671 BOOST_REQUIRE_EQUAL( step.size(), 126391u );
1672 BOOST_CHECK( step.starts_with(
"ISO-10303-21;" ) );
1673 BOOST_CHECK( step.ends_with(
"END-ISO-10303-21;\r\n" ) );
1677 BOOST_CHECK_GT( file->compressedEncodedData.size(), 0 );
1678 BOOST_CHECK( file->Validate() );
1681 BOOST_REQUIRE_EQUAL( footprint->
Models().size(), 2 );
1693 std::map<wxString, wxString> props = {
1694 { wxT(
"VX0" ), wxT(
"3481.9999mil" ) }, { wxT(
"VY0" ), wxT(
"2818.9999mil" ) },
1695 { wxT(
"VX1" ), wxT(
"3506.9999mil" ) }, { wxT(
"VY1" ), wxT(
"2843.9999mil" ) },
1696 { wxT(
"VX2" ), wxT(
"-111339.9634mil" ) }, { wxT(
"VY2" ), wxT(
"2834mil" ) },
1697 { wxT(
"VX3" ), wxT(
"3756.9998mil" ) }, { wxT(
"VY3" ), wxT(
"2834mil" ) },
1698 { wxT(
"VX4" ), wxT(
"3771.9999mil" ) }, { wxT(
"VY4" ), wxT(
"2818.9999mil" ) },
1699 { wxT(
"VX5" ), wxT(
"3772mil" ) }, { wxT(
"VY5" ), wxT(
"2634mil" ) },
1700 { wxT(
"VX6" ), wxT(
"3757mil" ) }, { wxT(
"VY6" ), wxT(
"2619mil" ) },
1701 { wxT(
"VX7" ), wxT(
"3614.5mil" ) }, { wxT(
"VY7" ), wxT(
"2619.0001mil" ) },
1702 { wxT(
"VX8" ), wxT(
"3583.0001mil" ) }, { wxT(
"VY8" ), wxT(
"2587.5mil" ) },
1703 { wxT(
"VX9" ), wxT(
"3573.9998mil" ) }, { wxT(
"VY9" ), wxT(
"2587.4999mil" ) },
1704 { wxT(
"VX10" ), wxT(
"3542.5005mil" ) }, { wxT(
"VY10" ), wxT(
"2619.0001mil" ) },
1705 { wxT(
"VX11" ), wxT(
"3522mil" ) }, { wxT(
"VY11" ), wxT(
"2619mil" ) },
1706 { wxT(
"VX12" ), wxT(
"3497mil" ) }, { wxT(
"VY12" ), wxT(
"2619mil" ) },
1707 { wxT(
"VX13" ), wxT(
"3482mil" ) }, { wxT(
"VY13" ), wxT(
"2634mil" ) },
1708 { wxT(
"VX14" ), wxT(
"3481.9999mil" ) }, { wxT(
"VY14" ), wxT(
"2818.9999mil" ) },
1711 std::vector<ALTIUM_VERTICE> vertices;
1717 BOOST_REQUIRE_EQUAL( vertices.size(), 14 );
1722 bbox.
Merge( vertex.position );
1747 std::map<std::string, UTF8> props;
1748 props[
"sch0"] = dataDir +
"altium_import_netname.SchDoc";
1751 std::unique_ptr<BOARD> board = plugin.
LoadBoard( dataDir +
"altium_import_netname.CSPcbDoc", &props );
1753 BOOST_CHECK( board->FindNet( wxT(
"all_low_letter" ) ) );
1754 BOOST_CHECK( board->FindNet( wxT(
"UperCamelCase" ) ) );
1755 BOOST_CHECK( board->FindNet( wxT(
"lowerCamelCase" ) ) );
1756 BOOST_CHECK( board->FindNet( wxT(
"ALL_BIG_LETTER" ) ) );
1757 BOOST_CHECK( board->FindNet( wxT(
"GND" ) ) );
1758 BOOST_CHECK( !board->FindNet( wxT(
"ALL_LOW_LETTER" ) ) );
1761 std::unique_ptr<BOARD> standaloneBoard = standalonePlugin.
LoadBoard( dataDir +
"altium_import_netname.CSPcbDoc" );
1763 BOOST_CHECK( standaloneBoard->FindNet( wxT(
"ALL_LOW_LETTER" ) ) );
1764 BOOST_CHECK( !standaloneBoard->FindNet( wxT(
"all_low_letter" ) ) );
bool altiumScopeExprMatchesPolygon(const wxString &aExpr)
Return true if an Altium rule scope expression targets polygon pour primitives (matches InPolygon,...
void altium_parse_polygons(std::map< wxString, wxString > &aProps, std::vector< ALTIUM_VERTICE > &aVertices, int *aDiscarded)
Read the VX/VY/KIND/R/SA/EA/CX/CY vertex series out of a polygon or board outline record.
VECTOR2I altiumSlotDrillSize(uint32_t aHoleSize, uint32_t aSlotSize, double aSlotRotation, bool &aRotationSupported)
Convert an Altium slot's independent rotation and dimensions to KiCad's cardinal drill shape.
const ARULE6 * selectAltiumPolygonRule(const std::vector< ARULE6 > &aRulesByPriorityAsc)
Select the highest Altium-priority rule whose scope references polygons.
bool altiumViaSideIsTented(bool aTentFlag, bool aManual, bool aFromHole, uint32_t aHoleSize, int32_t aMaskExpansion, int aLandDiameter)
Decide whether one side of an Altium via should be tented when imported into KiCad.
const uint16_t ALTIUM_NET_UNCONNECTED
const uint16_t ALTIUM_POLYGON_NONE
const int ALTIUM_COMPONENT_NONE
wxString AltiumUnnamedNetName(const BOARD &aBoard, int &aCounter)
Invent a placeholder name for an Altium net that has none.
void ApplyAltiumNetclassRules(const std::map< ALTIUM_RULE_KIND, std::vector< ARULE6 > > &aRulesByKind, NET_SETTINGS &aNetSettings, std::vector< const ARULE6 * > *aUnresolved)
Copy the values of Altium rules scoped to a single netclass onto that netclass.
constexpr EDA_IU_SCALE pcbIUScale
General utilities for PCB file IO for QA programs.
@ BS_ITEM_TYPE_DIELECTRIC
size_t GetRemainingBytes() const
const CFB::COMPOUND_FILE_ENTRY * FindStream(const std::vector< std::string > &aStreamPath) const
std::vector< int > m_altiumToKicadNetcodes
std::vector< std::pair< PCB_LAYER_ID, int > > HelperGetSolderAndPasteMaskExpansions(const ALTIUM_RECORD aType, const int aPrimitiveIndex, const ALTIUM_LAYER aAltiumLayer)
void ParseExtendedPrimitiveInformationData(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
int GetNetCode(uint16_t aId) const
void ConvertArcs6ToBoardItemOnLayer(const AARC6 &aElem, PCB_LAYER_ID aLayer)
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
Container for design settings for a BOARD object.
std::shared_ptr< NET_SETTINGS > m_NetSettings
const VECTOR2I & GetGridOrigin() const
const VECTOR2I & GetAuxOrigin() const
BOARD_STACKUP & GetStackupDescriptor()
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Manage one layer needed to make a physical board.
Manage layers needed to make a physical board.
const std::vector< BOARD_STACKUP_ITEM * > & GetList() const
Information pertinent to a Pcbnew printed circuit board.
const ZONES & Zones() const
const FOOTPRINTS & Footprints() const
const TRACKS & Tracks() const
BOARD_DESIGN_SETTINGS & GetDesignSettings()
const DRAWINGS & Drawings() const
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 ecoord_type GetArea() const
Return the area of the rectangle.
constexpr size_type GetHeight() const
constexpr coord_type GetLeft() const
constexpr bool Contains(const Vec &aPoint) const
constexpr coord_type GetTop() const
SHAPE_POLY_SET & GetPolyShape()
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
const std::map< wxString, std::shared_ptr< EMBEDDED_FILE > > & EmbeddedFileMap() const
Provide an iterable view of the file collection.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Custom REPORTER that captures all messages for later analysis in the unit test framework.
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.
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
NET_SETTINGS stores various net-related settings in a project context.
void SetNetclass(const wxString &netclassName, std::shared_ptr< NETCLASS > &netclass)
Sets the given netclass Calling user is responsible for resetting the effective netclass calculation ...
VECTOR2I GetPosition() const override
std::unordered_set< BOARD_ITEM * > GetBoardItems() const
static std::map< wxString, PCB_LAYER_ID > DefaultLayerMappingCallback(const std::vector< INPUT_LAYER_DESC > &aInputLayerDescriptionVector)
Return the automapped layers.
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 & GetEnd() const
LENGTH_TUNING_MODE GetTuningMode() const
const wxString & GetLastNetName() const
const std::optional< SHAPE_LINE_CHAIN > & GetBaseLine() const
int GetMaxAmplitude() const
int GetDiffPairGap() const
const std::optional< SHAPE_LINE_CHAIN > & GetBaseLineCoupled() const
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Container for project specific data.
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Load a project or sets up a new project with a specified path.
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int PointCount() const
Return the number of points (vertices) in this line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
const VECTOR2I & CLastPoint() const
Return the last point in the line chain.
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
Represent a set of closed polygons.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
int OutlineCount() const
Return the number of outlines in the set.
SHAPE_POLY_SET CloneDropTriangulation() const
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
Handle a list of polygons defining a copper zone.
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, RESOLUTION_CONTEXT aContext)
bool BuildBoardPolygonOutlines(BOARD *aBoard, SHAPE_POLY_SET &aOutlines, int aErrorMax, int aChainingEpsilon, bool aInferOutlineIfNecessary, OUTLINE_ERROR_HANDLER *aErrorHandler, bool aAllowUseArcsInPolygons)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
const std::function< void(const wxString &msg, BOARD_ITEM *itemA, BOARD_ITEM *itemB, const VECTOR2I &pt)> OUTLINE_ERROR_HANDLER
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
std::function< std::map< wxString, PCB_LAYER_ID >(const std::vector< INPUT_LAYER_DESC > &)> LAYER_MAPPING_HANDLER
Pointer to a function that takes a map of source and KiCad layers and returns a re-mapped version.
static int getNetCode(ALTIUM_PCB &aImporter, const std::vector< int > &aNetcodes, uint16_t aId)
ALTIUM_PCB_IMPORT_FIXTURE()=default
static std::vector< std::pair< PCB_LAYER_ID, int > > getMaskExpansions(ALTIUM_PCB &aImporter, ALTIUM_RECORD aType, int aPrimitiveIndex, ALTIUM_LAYER aLayer)
static void parseExtendedPrimitiveInformation(ALTIUM_PCB &aImporter, const ALTIUM_PCB_COMPOUND_FILE &aFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
static void convertConnectedArc(ALTIUM_PCB &aImporter, const AARC6 &aArc, PCB_LAYER_ID aLayer)
static std::vector< const ZONE * > collectRuleAreas(const BOARD &aBoard)
PCB_IO_ALTIUM_DESIGNER m_altiumPlugin
static void checkAllCopperFillZonesHaveClearance(PCB_IO_ALTIUM_DESIGNER &aPlugin, const std::string &aRelativePath)
Verify that copper zones in imported Altium boards have non-zero local clearance values derived from ...
static void checkImportedOriginOffset(PCB_IO_ALTIUM_DESIGNER &aPlugin, const std::string &aRelativePath, double aExpectedXmm, double aExpectedYmm)
BOOST_AUTO_TEST_CASE(NetCodeRejectsIdPastEnd)
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
IbisParser parser & reporter
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