36#include <compoundfilereader.h>
75 const CFB::COMPOUND_FILE_ENTRY* aEntry )
94 std::vector<const ZONE*> ruleAreas;
98 if( zone->GetIsRuleArea() )
99 ruleAreas.push_back( zone );
104 for(
const ZONE* zone : footprint->Zones() )
106 if( zone->GetIsRuleArea() )
107 ruleAreas.push_back( zone );
132 ALTIUM_PCB importer( &board,
nullptr, layerMappingHandler );
134 const std::vector<int> netcodes = { 1, 2, 3 };
137 BOOST_CHECK_THROW( getNetCode( importer, netcodes, 3 ),
IO_ERROR );
145 std::string properties =
"|BOLD=TRUE|TEXTLINEWIDTH=6mil";
146 properties.push_back(
'\0' );
148 const uint16_t recordHeader = 1;
149 const uint32_t propertySize =
static_cast<uint32_t
>( properties.size() );
150 const size_t recordSize =
sizeof( recordHeader ) +
sizeof( propertySize ) + properties.size();
152 std::unique_ptr<char[]> content = std::make_unique<char[]>( recordSize );
154 std::memcpy( content.get(), &recordHeader,
sizeof( recordHeader ) );
155 std::memcpy( content.get() +
sizeof( recordHeader ), &propertySize,
sizeof( propertySize ) );
156 std::memcpy( content.get() +
sizeof( recordHeader ) +
sizeof( propertySize ), properties.data(),
175 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
182 for(
FOOTPRINT* footprint : board->Footprints() )
184 const int expected = footprint->GetLikelyAttribute();
190 wxString::Format( wxT(
"Footprint %s has mounting style %d, expected %d" ),
200 BOOST_CHECK_GT( smd, 0 );
201 BOOST_CHECK_GT( throughHole, 0 );
210 const CFB::COMPOUND_FILE_ENTRY* data = file.
FindStream( {
"ExtendedPrimitiveInformation",
"Data" } );
216 ALTIUM_PCB importer( &board,
nullptr, layerMappingHandler );
218 parseExtendedPrimitiveInformation( importer, file, data );
220 std::vector<std::pair<PCB_LAYER_ID, int>> front =
223 BOOST_REQUIRE_EQUAL( front.size(), 1 );
227 std::vector<std::pair<PCB_LAYER_ID, int>> back =
230 BOOST_REQUIRE_EQUAL( back.size(), 1 );
238 constexpr uint32_t subrecordSize = 57;
239 constexpr size_t recordSize = 1 +
sizeof( subrecordSize ) + subrecordSize;
240 std::unique_ptr<char[]> content = std::make_unique<char[]>( recordSize );
243 auto append = [&](
auto aValue )
245 std::memcpy( content.get() + offset, &aValue,
sizeof( aValue ) );
246 offset +=
sizeof( aValue );
250 append( subrecordSize );
252 append( uint8_t{ 0 } );
253 append( uint8_t{ 0 } );
254 append( uint16_t{ 0 } );
257 append( uint32_t{ 0 } );
258 append( int32_t{ 0 } );
259 append( int32_t{ 0 } );
260 append( uint32_t{ 100000 } );
261 append(
double{ 0.0 } );
262 append(
double{ 360.0 } );
263 append( uint32_t{ 10000 } );
264 append( uint16_t{ 0 } );
265 append( uint8_t{ 0 } );
266 append( uint32_t{ 0 } );
268 append( uint8_t{ 0 } );
270 BOOST_REQUIRE_EQUAL( offset, recordSize );
273 AARC6 sourceArc( reader );
276 ALTIUM_PCB importer( &board,
nullptr, layerMappingHandler );
278 convertConnectedArc( importer, sourceArc,
F_Cu );
280 BOOST_REQUIRE_EQUAL( board.
Tracks().size(), 2 );
282 std::vector<const PCB_ARC*> arcs;
286 BOOST_REQUIRE_EQUAL( track->Type(),
PCB_ARC_T );
287 arcs.push_back(
static_cast<const PCB_ARC*
>( track ) );
290 for(
const PCB_ARC* arc : arcs )
292 BOOST_CHECK_CLOSE(
std::abs( arc->GetAngle().AsDegrees() ), 180.0, 1e-6 );
293 BOOST_CHECK_CLOSE( arc->GetRadius(),
pcbIUScale.mmToIU( 0.254 ), 1e-6 );
298 BOOST_CHECK( arcs[0]->GetStart() == arcs[1]->GetEnd() );
299 BOOST_CHECK( arcs[0]->GetEnd() == arcs[1]->GetStart() );
300 BOOST_CHECK( board.
Drawings().empty() );
311 +
"plugins/altium/eDP_adapter_dvt1_source/eDP_adapter_dvt1.PcbDoc";
314 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
319 BOOST_CHECK( board->GetNetCount() > 0 );
320 BOOST_CHECK( board->Footprints().size() > 0 );
328 std::string dataPath =
331 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
334 BOOST_REQUIRE_GT( board->Footprints().size(), 0 );
336 std::vector<FOOTPRINT*> cached = m_altiumPlugin.GetImportedCachedLibraryFootprints();
339 std::vector<std::unique_ptr<FOOTPRINT>> owned;
342 owned.emplace_back( fp );
346 std::set<FOOTPRINT*> boardFootprints( board->Footprints().begin(), board->Footprints().end() );
351 BOOST_CHECK_MESSAGE( boardFootprints.count( fp ) == 0,
352 "GetImportedCachedLibraryFootprints returned a board-owned footprint" );
364 std::string dataPath =
367 std::set<wxString> mappedLayerNames;
369 m_altiumPlugin.RegisterCallback(
370 [&](
const std::vector<INPUT_LAYER_DESC>& aLayers )
373 mappedLayerNames.insert( layer.Name );
378 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
381 BOOST_CHECK( mappedLayerNames.count( wxS(
"Internal Plane 1" ) ) );
382 BOOST_CHECK( mappedLayerNames.count( wxS(
"Internal Plane 2" ) ) );
384 for(
int plane = 3; plane <= 16; ++plane )
386 wxString
name = wxString::Format( wxS(
"Internal Plane %d" ), plane );
387 BOOST_CHECK_MESSAGE( !mappedLayerNames.count(
name ),
388 wxString::Format(
"Unused layer '%s' reached the mapper",
name ) );
402 std::string dataPath =
405 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
410 int keepOutLayer = 0;
413 for(
const ZONE* zone : collectRuleAreas( *board ) )
415 const bool tracks = zone->GetDoNotAllowTracks();
416 const bool vias = zone->GetDoNotAllowVias();
417 const bool pads = zone->GetDoNotAllowPads();
418 const bool fills = zone->GetDoNotAllowZoneFills();
419 const bool footprints = zone->GetDoNotAllowFootprints();
421 if( fills && !tracks && !vias && !pads && !footprints )
423 else if( fills && tracks && vias && pads && !footprints )
425 else if( !fills && !tracks && !vias && !pads && !footprints )
446 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
453 for(
const ZONE* zone : collectRuleAreas( *board ) )
455 const bool tracks = zone->GetDoNotAllowTracks();
456 const bool vias = zone->GetDoNotAllowVias();
457 const bool pads = zone->GetDoNotAllowPads();
458 const bool fills = zone->GetDoNotAllowZoneFills();
460 if( vias && !tracks && !pads && !fills )
462 else if( vias && tracks && pads && fills )
483 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
488 std::shared_ptr<NET_SETTINGS> netSettings = board->GetDesignSettings().m_NetSettings;
493 auto& patternAssignments = netSettings->GetNetclassPatternAssignments();
496 BOOST_REQUIRE_MESSAGE( patternAssignments.size() > 0,
497 "Test file must have netclass pattern assignments" );
501 bool foundAssignedNet =
false;
505 if( net->GetNetCode() <= 0 )
509 NETCLASS* directNetclass = net->GetNetClass();
512 std::shared_ptr<NETCLASS> effectiveNetclass =
513 netSettings->GetEffectiveNetClass( net->GetNetname() );
520 directNetclass !=
nullptr,
521 wxString::Format(
"Net '%s' should have a direct netclass assignment",
522 net->GetNetname() ) );
526 foundAssignedNet =
true;
532 wxString::Format(
"Net '%s' should not have default netclass, "
533 "expected effective class or component",
534 net->GetNetname() ) );
540 BOOST_CHECK_MESSAGE( foundAssignedNet,
541 "At least one net should have a non-default netclass assigned" );
552 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
559 board->Add(
new NETINFO_ITEM( board.get(), wxT(
"__ALTIUM_UNNAMED_NET_2" ), -1 ),
580 std::string dataPath =
583 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
585 std::shared_ptr<NET_SETTINGS> netSettings = board->GetDesignSettings().m_NetSettings;
586 std::shared_ptr<NETCLASS> defaultNetclass = netSettings->GetDefaultNetclass();
592 auto it = netSettings->GetNetclasses().find( wxT(
"50R" ) );
597 BOOST_CHECK( board->m_LegacyDesignSettingsLoaded );
610 [
this](
const std::string& aRelativePath )
613 m_altiumPlugin.SetReporter( &
reporter );
615 std::unique_ptr<BOARD> board =
617 m_altiumPlugin.SetReporter(
nullptr );
619 std::vector<wxString> hits;
623 if( message.text.Contains( wxS(
"does not define" ) ) )
624 hits.push_back( message.text );
630 std::vector<wxString> hiFive = messagesFor(
"plugins/altium/HiFive/HiFive1.B01.PcbDoc" );
632 BOOST_REQUIRE_EQUAL( hiFive.size(), 1 );
633 BOOST_CHECK( hiFive[0].Contains( wxS(
"'PWR'" ) ) );
636 BOOST_CHECK_EQUAL( messagesFor(
"plugins/altium/issue24456/Fastino_Ground_Isolator.PcbDoc" ).size(), 0 );
647 auto makeWidthRule = [](
int aPriority,
bool aEnabled,
const wxString& aScope2,
int aWidth )
661 std::shared_ptr<NETCLASS> sig = std::make_shared<NETCLASS>( wxT(
"SIG" ),
false );
666 std::map<ALTIUM_RULE_KIND, std::vector<ARULE6>> rules;
668 makeWidthRule( 1,
true, wxT(
"All" ), 100 ),
669 makeWidthRule( 2,
true, wxT(
"All" ), 200 ),
676 sig->SetTrackWidth( std::optional<int>() );
683 sig->SetTrackWidth( std::optional<int>() );
687 BOOST_CHECK( !sig->HasTrackWidth() );
697 const std::string& aRelativePath )
701 std::unique_ptr<BOARD> board = aPlugin.
LoadBoard( dataPath,
nullptr );
705 int fillZoneCount = 0;
706 int fillZonesWithClearance = 0;
708 for(
ZONE* zone : board->Zones() )
710 if( !zone->IsOnCopperLayer() || zone->GetIsRuleArea() || zone->IsTeardropArea() )
715 if( zone->GetLocalClearance().has_value() && zone->GetLocalClearance().value() > 0 )
716 fillZonesWithClearance++;
719 BOOST_CHECK_GT( fillZoneCount, 0 );
721 BOOST_CHECK_MESSAGE( fillZonesWithClearance == fillZoneCount,
722 wxString::Format(
"%s: %d/%d copper fill zones have clearance set",
723 aRelativePath, fillZonesWithClearance,
731 m_altiumPlugin,
"plugins/altium/eDP_adapter_dvt1_source/eDP_adapter_dvt1.PcbDoc" );
738 "plugins/altium/HiFive/HiFive1.B01.PcbDoc" );
783 auto makeRule = [](
int aPriority,
const wxString& aScope1,
const wxString& aScope2,
795 std::vector<ARULE6> rules = {
796 makeRule( 1, wxT(
"InPolygon And InNet('GND')" ), wxT(
"All" ), 100 ),
797 makeRule( 2, wxT(
"InPolygon" ), wxT(
"All" ), 200 ),
798 makeRule( 3, wxT(
"All" ), wxT(
"All" ), 300 ),
799 makeRule( 4, wxT(
"All" ), wxT(
"All" ), 400 ),
807 rules.erase( rules.begin() );
813 rules.erase( rules.begin() );
820 makeRule( 1, wxT(
"InPolygon And InNet('GND')" ), wxT(
"All" ), 100 ),
821 makeRule( 2, wxT(
"InPolygon" ), wxT(
"All" ), 200 ),
823 rules[0].enabled =
false;
844 +
"plugins/altium/issue24456/Fastino_Ground_Isolator.PcbDoc";
846 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
851 int frontExposed = 0;
854 for(
PCB_TRACK* track : board->Tracks() )
869 BOOST_REQUIRE_GT( viaCount, 0 );
873 BOOST_CHECK_MESSAGE( frontExposed == 0,
874 wxString::Format(
"%d of %d vias left front-exposed despite a "
875 "hole-referenced mask",
876 frontExposed, viaCount ) );
877 BOOST_CHECK_MESSAGE( backExposed == 0,
878 wxString::Format(
"%d of %d vias left back-exposed despite a "
879 "hole-referenced mask",
880 backExposed, viaCount ) );
885 const uint32_t holeSize = 300000;
886 const int landWidth = 600000;
889 holeSize, 500000, landWidth ) );
891 holeSize, 30000, landWidth ) );
893 holeSize, 0, landWidth ) );
897 holeSize, 30000, landWidth ) );
903 bool rotationSupported;
906 BOOST_CHECK( rotationSupported );
909 BOOST_CHECK( rotationSupported );
912 BOOST_CHECK( !rotationSupported );
926 +
"plugins/altium/issue24456/Fastino_Ground_Isolator.PcbDoc";
928 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
936 BOOST_CHECK( board->GetStackupOrDefault() == stackup );
938 int dielectricCount = 0;
939 int dielectricWithTangent = 0;
946 for(
int sub = 0; sub < item->GetSublayersCount(); sub++ )
949 if( item->GetThickness( sub ) <= 0 )
954 double tangent = item->GetLossTangent( sub );
958 dielectricWithTangent++;
961 BOOST_CHECK_CLOSE( tangent, 0.020, 1e-6 );
966 BOOST_REQUIRE_GT( dielectricCount, 0 );
970 BOOST_CHECK_MESSAGE( dielectricWithTangent == dielectricCount,
971 wxString::Format(
"Only %d of %d dielectric sublayers received a loss "
972 "tangent from the Altium stackup",
973 dielectricWithTangent, dielectricCount ) );
986 std::string pcbDoc = dataDir +
"Fastino_Ground_Isolator.PcbDoc";
987 std::string prjPcb = dataDir +
"Fastino_Ground_Isolator.PrjPcb";
993 std::map<std::string, UTF8> props;
994 props[
"project_file"] = prjPcb;
996 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( pcbDoc, &props, &
project );
998 const std::map<wxString, wxString>& textVars =
project.GetTextVars();
1006 BOOST_CHECK_EQUAL( textVars.at( wxS(
"PROJECT_NAME" ) ), wxS(
"Fastino Ground Isolator" ) );
1017 board->SetProject( &
project,
true );
1019 bool sawResolvedBoardText =
false;
1025 if(
text &&
text->GetText().Contains( wxS(
"${PCB_REVISION}" ) ) )
1028 BOOST_CHECK( !shown.Contains( wxS(
"${PCB_REVISION}" ) ) );
1029 BOOST_CHECK( shown.Contains( wxS(
"A" ) ) );
1030 sawResolvedBoardText =
true;
1034 BOOST_CHECK( sawResolvedBoardText );
1045 std::string pcbDoc = dataDir +
"Fastino_Ground_Isolator.PcbDoc";
1046 std::string prjPcb = dataDir +
"Fastino_Ground_Isolator.PrjPcb";
1051 project.GetTextVars()[wxS(
"PCB_REVISION" )] = wxS(
"user-set" );
1053 std::map<std::string, UTF8> props;
1054 props[
"project_file"] = prjPcb;
1056 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( pcbDoc, &props, &
project );
1079 +
"plugins/altium/issue24456/Fastino_Ground_Isolator.PcbDoc";
1081 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
1084 std::vector<PCB_TEXT*> copperTexts;
1085 std::vector<PCB_TEXT*> maskTexts;
1096 copperTexts.push_back(
text );
1098 maskTexts.push_back(
text );
1101 BOOST_REQUIRE_MESSAGE( !copperTexts.empty(),
"Board must contain copper-layer text" );
1102 BOOST_REQUIRE_MESSAGE( !maskTexts.empty(),
"Board must contain soldermask-layer text" );
1107 const int tolerance = 1000;
1109 int matchedPairs = 0;
1111 for(
PCB_TEXT* copper : copperTexts )
1115 if( copper->GetText() != mask->GetText()
1116 || copper->GetTextAngle() != mask->GetTextAngle()
1117 || copper->IsMirrored() != mask->IsMirrored() )
1131 BOOST_CHECK_MESSAGE(
1133 wxString::Format(
"Copper/mask copies of '%s' diverge by (%d, %d) IU",
1138 BOOST_CHECK_MESSAGE( matchedPairs > 0,
1139 "Expected at least one coincident copper/soldermask text pair" );
1155 std::string dataPath =
1158 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
1162 int tuningCount = 0;
1163 int singleCount = 0;
1164 int diffPairCount = 0;
1166 std::set<wxString> patternNames;
1176 patternNames.insert( pattern->
GetName() );
1180 "Imported tuning pattern wraps no copper" );
1185 std::set<int> memberNets;
1190 BOOST_CHECK( item->GetParentGroup() == pattern );
1193 memberNets.insert( bci->GetNetCode() );
1216 const std::set<wxString> expectedNames = {
1217 wxT(
"Interactive Length Tunings" ),
1218 wxT(
"Interactive Length Tunings 1" ),
1219 wxT(
"Interactive Length Tunings 2" ),
1220 wxT(
"Interactive Length Tunings 3" ),
1221 wxT(
"Interactive Diffpair Length Tunings" ),
1222 wxT(
"Interactive Diffpair Length Tunings 1" ),
1223 wxT(
"Interactive Diffpair Length Tunings 2" ),
1224 wxT(
"Interactive Diffpair Length Tunings 3" ),
1227 BOOST_CHECK( patternNames == expectedNames );
1242 std::string dataPath =
1245 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
1260 BOOST_REQUIRE_MESSAGE( pattern->
GetBaseLine().has_value(),
1261 "Imported tuning pattern has no baseline" );
1262 BOOST_REQUIRE_GT( pattern->
GetBaseLine()->PointCount(), 1 );
1273 "Imported diff-pair tuning pattern has no coupled baseline" );
1279 "Imported tuning pattern is not attributed to a net" );
1282 for(
int i = 0; i < baseLine.
PointCount(); ++i )
1284 BOOST_CHECK_MESSAGE( pattern->
HitTest( baseLine.
CPoint( i ), 0 ),
1285 "Tuning pattern is not hittable on its own baseline" );
1291 "Tuning pattern bounding box does not cover its baseline" );
1295 BOOST_CHECK_MESSAGE( bbox.
Contains( item->GetBoundingBox() ),
1296 "Tuning pattern bounding box does not cover its member copper" );
1311 +
"plugins/altium/issue24847/PCB1.PcbDoc";
1313 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
1316 BOOST_REQUIRE_GT( board->Footprints().size(), 0 );
1320 int keepoutZoneCount = 0;
1322 for(
FOOTPRINT* footprint : board->Footprints() )
1324 const VECTOR2I fpPos = footprint->GetPosition();
1326 for(
ZONE* zone : footprint->Zones() )
1330 const VECTOR2I zoneCenter = zone->GetBoundingBox().GetCenter();
1331 const double distMm = ( zoneCenter - fpPos ).EuclideanNorm() / 1e6;
1334 <<
" at (" << fpPos.
x <<
"," << fpPos.
y
1335 <<
") keepout center (" << zoneCenter.
x <<
","
1336 << zoneCenter.
y <<
") dist " << distMm <<
" mm" );
1340 BOOST_CHECK_MESSAGE( distMm < 2.0,
1341 "Keepout in footprint " << footprint->GetReference().ToStdString()
1342 <<
" is " << distMm <<
" mm from its footprint origin" );
1357 +
"plugins/altium/issue13750/"
1358 "altium2kicad_region_soldermask_expansion.PcbDoc";
1360 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
1363 std::vector<PCB_SHAPE*> copperPolys;
1364 std::vector<PCB_SHAPE*> maskPolys;
1377 copperPolys.push_back( shape );
1379 maskPolys.push_back( shape );
1383 BOOST_REQUIRE_EQUAL( copperPolys.size(), 2 );
1384 BOOST_REQUIRE_EQUAL( maskPolys.size(), 1 );
1389 int exactMatches = 0;
1403 BOOST_CHECK_MESSAGE( exactMatches == 1,
"F_Mask relief aperture must exactly match exactly one copper region" );
1411 std::string dataPath =
1414 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
1416 int regionCount = 0;
1417 int connectedCount = 0;
1419 for(
FOOTPRINT* footprint : board->Footprints() )
1421 for(
PAD*
pad : footprint->Pads() )
1430 if(
pad->GetNetCode() > 0 )
1433 BOOST_CHECK( !
pad->GetNetname().IsEmpty() );
1438 BOOST_REQUIRE_GT( regionCount, 0 );
1439 BOOST_CHECK_GT( connectedCount, 0 );
1450 std::string dataPath =
1453 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
1455 int regionCount = 0;
1457 for(
FOOTPRINT* footprint : board->Footprints() )
1459 if( footprint->GetOrientation().IsZero() )
1462 for(
PAD*
pad : footprint->Pads() )
1477 BOOST_CHECK_MESSAGE( absolute.
IsZero(),
1478 wxString::Format( wxT(
"Region pad in %s is rotated %.1f degrees" ),
1479 footprint->GetReference(), absolute.
AsDegrees() ) );
1480 BOOST_CHECK( !
pad->GetFPRelativeOrientation().IsZero() );
1484 BOOST_REQUIRE_GT( regionCount, 0 );
1491 const std::string& aRelativePath,
1492 double aExpectedXmm,
double aExpectedYmm )
1496 std::unique_ptr<BOARD> board = aPlugin.
LoadBoard( dataPath,
nullptr );
1505 BOX2I outline = board->GetBoardEdgesBoundingBox();
1507 BOOST_REQUIRE_GT( outline.
GetArea(), 0 );
1514 const double toleranceMm = 1.0;
1516 BOOST_CHECK_MESSAGE(
std::abs( offsetXmm - aExpectedXmm ) < toleranceMm,
1517 wxString::Format(
"%s: origin sits %.3f mm right of the outline corner, "
1519 aRelativePath, offsetXmm, aExpectedXmm ) );
1521 BOOST_CHECK_MESSAGE(
std::abs( offsetYmm - aExpectedYmm ) < toleranceMm,
1522 wxString::Format(
"%s: origin sits %.3f mm below the outline corner, "
1524 aRelativePath, offsetYmm, aExpectedYmm ) );
1533 "plugins/altium/eDP_adapter_dvt1_source/eDP_adapter_dvt1.PcbDoc",
1548 +
"plugins/altium/issue25362/OpenRex_V1I1_PCB_reduced.PcbDoc";
1550 std::unique_ptr<BOARD> board = m_altiumPlugin.LoadBoard( dataPath,
nullptr );
1552 BOOST_REQUIRE_EQUAL( board->Footprints().size(), 1 );
1554 FOOTPRINT* footprint = board->Footprints().front();
1559 const std::shared_ptr<EMBEDDED_FILES::EMBEDDED_FILE>& file =
1567 const std::string step( file->decompressedData.begin(), file->decompressedData.end() );
1569 BOOST_REQUIRE_EQUAL( step.size(), 126391u );
1570 BOOST_CHECK( step.starts_with(
"ISO-10303-21;" ) );
1571 BOOST_CHECK( step.ends_with(
"END-ISO-10303-21;\r\n" ) );
1575 BOOST_CHECK_GT( file->compressedEncodedData.size(), 0 );
1576 BOOST_CHECK( file->Validate() );
1579 BOOST_REQUIRE_EQUAL( footprint->
Models().size(), 2 );
1591 std::map<wxString, wxString> props = {
1592 { wxT(
"VX0" ), wxT(
"3481.9999mil" ) }, { wxT(
"VY0" ), wxT(
"2818.9999mil" ) },
1593 { wxT(
"VX1" ), wxT(
"3506.9999mil" ) }, { wxT(
"VY1" ), wxT(
"2843.9999mil" ) },
1594 { wxT(
"VX2" ), wxT(
"-111339.9634mil" ) }, { wxT(
"VY2" ), wxT(
"2834mil" ) },
1595 { wxT(
"VX3" ), wxT(
"3756.9998mil" ) }, { wxT(
"VY3" ), wxT(
"2834mil" ) },
1596 { wxT(
"VX4" ), wxT(
"3771.9999mil" ) }, { wxT(
"VY4" ), wxT(
"2818.9999mil" ) },
1597 { wxT(
"VX5" ), wxT(
"3772mil" ) }, { wxT(
"VY5" ), wxT(
"2634mil" ) },
1598 { wxT(
"VX6" ), wxT(
"3757mil" ) }, { wxT(
"VY6" ), wxT(
"2619mil" ) },
1599 { wxT(
"VX7" ), wxT(
"3614.5mil" ) }, { wxT(
"VY7" ), wxT(
"2619.0001mil" ) },
1600 { wxT(
"VX8" ), wxT(
"3583.0001mil" ) }, { wxT(
"VY8" ), wxT(
"2587.5mil" ) },
1601 { wxT(
"VX9" ), wxT(
"3573.9998mil" ) }, { wxT(
"VY9" ), wxT(
"2587.4999mil" ) },
1602 { wxT(
"VX10" ), wxT(
"3542.5005mil" ) }, { wxT(
"VY10" ), wxT(
"2619.0001mil" ) },
1603 { wxT(
"VX11" ), wxT(
"3522mil" ) }, { wxT(
"VY11" ), wxT(
"2619mil" ) },
1604 { wxT(
"VX12" ), wxT(
"3497mil" ) }, { wxT(
"VY12" ), wxT(
"2619mil" ) },
1605 { wxT(
"VX13" ), wxT(
"3482mil" ) }, { wxT(
"VY13" ), wxT(
"2634mil" ) },
1606 { wxT(
"VX14" ), wxT(
"3481.9999mil" ) }, { wxT(
"VY14" ), wxT(
"2818.9999mil" ) },
1609 std::vector<ALTIUM_VERTICE> vertices;
1615 BOOST_REQUIRE_EQUAL( vertices.size(), 14 );
1620 bbox.
Merge( vertex.position );
1645 std::map<std::string, UTF8> props;
1646 props[
"sch0"] = dataDir +
"altium_import_netname.SchDoc";
1649 std::unique_ptr<BOARD> board = plugin.
LoadBoard( dataDir +
"altium_import_netname.CSPcbDoc", &props );
1651 BOOST_CHECK( board->FindNet( wxT(
"all_low_letter" ) ) );
1652 BOOST_CHECK( board->FindNet( wxT(
"UperCamelCase" ) ) );
1653 BOOST_CHECK( board->FindNet( wxT(
"lowerCamelCase" ) ) );
1654 BOOST_CHECK( board->FindNet( wxT(
"ALL_BIG_LETTER" ) ) );
1655 BOOST_CHECK( board->FindNet( wxT(
"GND" ) ) );
1656 BOOST_CHECK( !board->FindNet( wxT(
"ALL_LOW_LETTER" ) ) );
1659 std::unique_ptr<BOARD> standaloneBoard = standalonePlugin.
LoadBoard( dataDir +
"altium_import_netname.CSPcbDoc" );
1661 BOOST_CHECK( standaloneBoard->FindNet( wxT(
"ALL_LOW_LETTER" ) ) );
1662 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
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)
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 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_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