55#include <wx/numformatter.h>
56#include <wx/mstream.h>
74 catch(
const std::exception& e )
76 std::cerr << e.what() << std::endl;
86 { wxS(
"ODB_VERSION_MAJOR" ), wxS(
"8" ) },
87 { wxS(
"ODB_VERSION_MINOR" ), wxS(
"1" ) },
88 { wxS(
"ODB_SOURCE" ), wxS(
"KiCad EDA" ) },
89 { wxS(
"CREATION_DATE" ), wxDateTime::Now().Format(
"%Y%m%d.%H%M%S" ) },
90 { wxS(
"SAVE_DATE" ), wxDateTime::Now().Format(
"%Y%m%d.%H%M%S" ) },
91 { wxS(
"SAVE_APP" ), wxString::Format( wxS(
"KiCad EDA %s" ),
GetBuildVersion() ) } };
128 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
129 std::set<PCB_LAYER_ID> added_layers;
133 for(
int i = 0; i < stackup.
GetCount(); i++ )
137 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
141 if( ly_name.IsEmpty() )
163 m_plugin->GetLayerNameList().emplace_back(
178 if( added_layers.find( layer ) != added_layers.end() )
182 added_layers.insert( layer );
296 m_plugin->GetLayerNameList().emplace_back( std::make_pair( aLayer, aMLayer.
m_layerName ) );
303 std::map<ODB_DRILL_SPAN, std::vector<BOARD_ITEM*>>& drill_layers =
m_plugin->GetDrillLayerItemsMap();
305 std::map<std::pair<PCB_LAYER_ID, PCB_LAYER_ID>, std::vector<BOARD_ITEM*>>& slot_holes =
308 drill_layers.clear();
311 std::map<ODB_DRILL_SPAN, wxString>& span_names =
m_plugin->GetDrillSpanNameMap();
314 bool has_pth_layer =
false;
315 bool has_npth_layer =
false;
322 has_pth_layer =
true;
325 drill_layers[platedSpan].push_back(
via );
327 std::set<ODB_DRILL_SPAN> addedBackdrillSpans;
332 && ( aDrill.size.x > 0 || aDrill.size.y > 0 ) )
336 if( addedBackdrillSpans.insert( backSpan ).second )
337 drill_layers[backSpan].push_back(
via );
341 addBackdrillSpan(
via->Padstack().SecondaryDrill() );
342 addBackdrillSpan(
via->Padstack().TertiaryDrill() );
348 if( fp->IsFlipped() )
353 for(
PAD*
pad : fp->Pads() )
356 has_pth_layer =
true;
358 has_npth_layer =
true;
363 slot_holes[std::make_pair(
F_Cu,
B_Cu )].push_back(
pad );
364 else if(
pad->HasHole() )
367 drill_layers[padSpan].push_back(
pad );
375 drill_layers[npthSpan];
381 drill_layers[platedSpan];
384 int backdrillIndex = 1;
389 auto it = span_names.find( aSpan );
391 if( it != span_names.end() )
396 if( aSpan.m_IsBackdrill )
398 name.Printf( wxT(
"drill%d" ), backdrillIndex++ );
402 wxString platedLabel = aSpan.m_IsNonPlated ? wxT(
"non-plated" ) : wxT(
"plated" );
403 name.Printf( wxT(
"drill_%s_%s-%s" ), platedLabel,
404 m_board->GetLayerName( aSpan.TopLayer() ),
405 m_board->GetLayerName( aSpan.BottomLayer() ) );
409 span_names[aSpan] = legalName;
414 auto InitDrillMatrix =
417 wxString dLayerName = assignName( aSpan );
423 matrix.
m_span.emplace( std::make_pair(
427 if( aSpan.m_IsBackdrill )
431 m_plugin->GetLayerNameList().emplace_back(
435 for(
const auto& entry : drill_layers )
436 InitDrillMatrix( entry.first );
446 if( aCompSide ==
F_Cu )
449 m_plugin->GetLayerNameList().emplace_back(
457 m_plugin->GetLayerNameList().emplace_back(
464 auto& auxilliary_layers =
m_plugin->GetAuxilliaryLayerItemsMap();
472 if(
via->Padstack().IsFilled().value_or(
false ) )
475 via->BottomLayer() )]
479 if(
via->Padstack().IsCapped().value_or(
false ) )
482 via->BottomLayer() )]
488 if(
via->Padstack().IsPlugged( layer ).value_or(
false ) )
495 if(
via->Padstack().IsCovered( layer ).value_or(
false ) )
502 if(
via->Padstack().IsTented( layer ).value_or(
false ) )
513 [&]( std::tuple<ODB_AUX_LAYER_TYPE, PCB_LAYER_ID, PCB_LAYER_ID> aLayerPair )
515 wxString featureName =
"";
516 switch( std::get<0>( aLayerPair ) )
530 dLayerName = wxString::Format(
"%s_%s-%s", featureName,
531 m_board->GetLayerName( std::get<1>( aLayerPair ) ),
532 m_board->GetLayerName( std::get<2>( aLayerPair ) ) );
536 if(
m_board->IsFrontLayer( std::get<1>( aLayerPair ) ) )
537 dLayerName = wxString::Format(
"%s_front", featureName );
538 else if(
m_board->IsBackLayer( std::get<1>( aLayerPair ) ) )
539 dLayerName = wxString::Format(
"%s_back", featureName );
551 matrix.
m_span.emplace( std::make_pair(
554 m_board->GetLayerName( std::get<2>( aLayerPair ) ) ) ) );
561 m_plugin->GetLayerNameList().emplace_back(
566 m_plugin->GetLayerNameList().emplace_back(
567 std::make_pair( std::get<1>( aLayerPair ), matrix.
m_layerName ) );
571 for(
const auto& [layer_pair, vec] : auxilliary_layers )
573 InitAuxMatrix( layer_pair );
581 std::map<wxString, std::vector<size_t>> name_to_indices;
587 name_to_indices[layerName].push_back( i );
591 for(
auto& [layerName, indices] : name_to_indices )
593 if( indices.size() > 1 )
596 for(
size_t count = 0; count < indices.size(); ++count )
598 size_t idx = indices[count];
599 wxString newLayerName = wxString::Format(
"%s_%zu",
m_matrixLayers[idx].m_layerName, count + 1 );
602 if( newLayerName.length() > 64 )
606 size_t suffixLen = wxString::Format(
"_%zu", count + 1 ).length();
608 if( suffixLen < baseName.length() )
610 baseName.Truncate( 64 - suffixLen );
611 newLayerName = wxString::Format(
"%s_%zu", baseName, count + 1 );
642 if( layer.m_addType.has_value() )
651 if( layer.m_diType.has_value() )
664 if( layer.m_span.has_value() )
676 std::map<
int, std::vector<BOARD_ITEM*>>& aMap,
677 const PCB_LAYER_ID& aLayerID,
const wxString& aLayerName ) :
681 m_featuresMgr = std::make_unique<FEATURES_MANAGER>( aBoard, aPlugin, aLayerName );
718 std::vector<BOARD_ITEM*>& vec =
m_layerItems[net->GetNetCode()];
720 std::stable_sort( vec.begin(), vec.end(),
723 if( a->GetParentFootprint() == b->GetParentFootprint() )
724 return a->Type() < b->Type();
726 return a->GetParentFootprint() < b->GetParentFootprint();
746 return m_compBot.value().AddComponent( aFp, aPkg );
755 return m_compTop.value().AddComponent( aFp, aPkg );
762 std::map<ODB_DRILL_SPAN, std::vector<BOARD_ITEM*>>& drill_layers =
765 std::map<std::pair<PCB_LAYER_ID, PCB_LAYER_ID>, std::vector<BOARD_ITEM*>>& slot_holes =
768 std::map<ODB_DRILL_SPAN, wxString>& span_names =
m_plugin->GetDrillSpanNameMap();
777 std::optional<ODB_DRILL_SPAN> matchedSpan;
779 for(
const auto& [span,
name] : span_names )
788 bool useLegacyMatching = !matchedSpan.has_value();
789 bool isBackdrillLayer = matchedSpan.has_value() && matchedSpan->m_IsBackdrill;
790 bool isNonPlatedLayer = matchedSpan.has_value() && matchedSpan->m_IsNonPlated;
791 bool isNPTHLayer = matchedSpan.has_value() && matchedSpan->m_IsNonPlated
792 && !matchedSpan->m_IsBackdrill;
793 bool isPlatedDrillLayer = matchedSpan.has_value() && !matchedSpan->m_IsNonPlated
794 && !matchedSpan->m_IsBackdrill;
796 if( matchedSpan.has_value() && ( isNPTHLayer || isPlatedDrillLayer ) )
801 auto slotIt = slot_holes.find( matchedSpan->Pair() );
803 if( slotIt != slot_holes.end() )
814 if( isNPTHLayer != padIsNPTH )
817 m_tools.value().AddDrillTool( padIsNPTH ? wxT(
"NON_PLATED" ) : wxT(
"PLATED" ),
818 std::min(
pad->GetDrillSizeX(),
pad->GetDrillSizeY() ) );
824 else if( useLegacyMatching )
826 bool is_npth_layer =
false;
827 wxString plated_name = wxT(
"plated" );
831 is_npth_layer =
true;
832 plated_name = wxT(
"non-plated" );
835 for(
const auto& [layer_pair, vec] : slot_holes )
837 wxString dLayerName = wxString::Format( wxT(
"drill_%s_%s-%s" ), plated_name,
838 m_board->GetLayerName( layer_pair.first ),
839 m_board->GetLayerName( layer_pair.second ) );
858 : wxT(
"NON_PLATED" ),
859 std::min(
pad->GetDrillSizeX(),
pad->GetDrillSizeY() ) );
869 if( matchedSpan.has_value() )
871 auto drillIt = drill_layers.find( *matchedSpan );
873 if( drillIt != drill_layers.end() )
881 if( isBackdrillLayer )
885 return aDrill.start == matchedSpan->m_StartLayer
886 && aDrill.end == matchedSpan->m_EndLayer
887 && ( aDrill.size.x > 0 || aDrill.size.y > 0 );
895 if( drillMatches( secondary ) )
897 else if( drillMatches( tertiary ) )
902 int diameter = drill->
size.
x;
904 if( drill->
size.
y > 0 )
906 diameter = ( diameter > 0 ) ? std::min( diameter, drill->
size.
y )
913 m_tools.value().AddDrillTool( wxT(
"NON_PLATED" ), diameter, wxT(
"BLIND" ) );
915 else if( isNonPlatedLayer )
917 m_tools.value().AddDrillTool( wxT(
"NON_PLATED" ),
via->GetDrillValue() );
921 m_tools.value().AddDrillTool( wxT(
"VIA" ),
via->GetDrillValue() );
932 if( isNPTHLayer && !padIsNPTH )
935 if( !isNonPlatedLayer && padIsNPTH )
938 int drillSize =
pad->GetDrillSizeX();
940 if(
pad->GetDrillSizeX() !=
pad->GetDrillSizeY() )
941 drillSize = std::min(
pad->GetDrillSizeX(),
pad->GetDrillSizeY() );
943 wxString typeLabel = ( padIsNPTH || isNonPlatedLayer ) ? wxT(
"NON_PLATED" )
945 wxString type2 = isBackdrillLayer ? wxT(
"BLIND" ) : wxT(
"STANDARD" );
947 m_tools.value().AddDrillTool( typeLabel, drillSize, type2 );
956 bool is_npth_layer =
false;
957 wxString plated_name = wxT(
"plated" );
961 is_npth_layer =
true;
962 plated_name = wxT(
"non-plated" );
965 for(
const auto& [span, vec] : drill_layers )
967 wxString dLayerName = wxString::Format( wxT(
"drill_%s_%s-%s" ), plated_name,
968 m_board->GetLayerName( span.TopLayer() ),
969 m_board->GetLayerName( span.BottomLayer() ) );
975 if( item->Type() ==
PCB_VIA_T && !is_npth_layer )
979 m_tools.value().AddDrillTool( wxT(
"VIA" ),
via->GetDrillValue() );
995 : wxT(
"NON_PLATED" ),
996 pad->GetDrillSizeX() );
1010 auto& auxilliary_layers =
m_plugin->GetAuxilliaryLayerItemsMap();
1017 for(
const auto& [layer_pair, vec] : auxilliary_layers )
1019 wxString featureName =
"";
1020 switch( std::get<0>( layer_pair ) )
1030 wxString dLayerName;
1034 dLayerName = wxString::Format(
"%s_%s-%s", featureName,
1035 m_board->GetLayerName( std::get<1>( layer_pair ) ),
1036 m_board->GetLayerName( std::get<2>( layer_pair ) ) );
1040 if(
m_board->IsFrontLayer( std::get<1>( layer_pair ) ) )
1041 dLayerName = wxString::Format(
"%s_front", featureName );
1042 else if(
m_board->IsBackLayer( std::get<1>( layer_pair ) ) )
1043 dLayerName = wxString::Format(
"%s_back", featureName );
1074 layer_entity_ptr->InitEntityData();
1103 m_compTop->Write( fileproxy.GetStream() );
1107 m_compBot->Write( fileproxy.GetStream() );
1116 m_featuresMgr->GenerateFeatureFile( fileproxy.GetStream() );
1124 std::ostream& ost = fileproxy.
GetStream();
1135 if( item->GetBrdLayerId() ==
m_layerID )
1148 wxString dielectricName = wxString::Format(
"DIELECTRIC_%d",
1149 item->GetDielectricLayerId() );
1171 double copperThicknessMM =
static_cast<double>( thickness ) /
pcbIUScale.mmToIU( 1.0 );
1172 double thicknessOz = copperThicknessMM / 0.035;
1180 if( epsilonR > 0.0 )
1190 if( lossTangent > 0.0 )
1198 if( !material.IsEmpty() )
1210 m_tools.value().GenerateFile( fileproxy.GetStream() );
1236 if( fp->IsFlipped() )
1243 wxLogTrace(
traceOdbppIo, wxT(
"Failed to add component data" ) );
1249 std::shared_ptr<FOOTPRINT> fp_pkg =
m_edaData.GetEdaFootprints().at( j );
1255 if( fp->Pads().empty() )
1260 for(
int i = 0; i < (int) fp->Pads().size(); ++i )
1262 PAD*
pad = fp->Pads()[i];
1269 comp.m_index,
comp.m_toeprints.size() );
1271 m_plugin->GetPadSubnetMap().emplace(
pad, &subnet );
1275 auto& toep =
comp.m_toeprints.emplace_back( pin_ref );
1277 toep.m_net_num = eda_net.
m_index;
1278 toep.m_subnet_num = subnet.
m_index;
1284 if(
pad->IsFlipped() )
1285 toep.m_mirror = wxT(
"M" );
1287 toep.m_mirror = wxT(
"N" );
1301 m_plugin->GetViaTraceSubnetMap().emplace( track, subnet );
1314 m_plugin->GetPlaneSubnetMap().emplace( std::piecewise_construct,
1315 std::forward_as_tuple( layer, zone ),
1316 std::forward_as_tuple( &subnet ) );
1353 if( !
m_board->GetBoardPolygonOutlines( board_outline,
true ) )
1354 wxLogTrace(
traceOdbppIo,
"Failed to get board outline" );
1356 if( !
m_profile->AddContour( board_outline, 0 ) )
1357 wxLogTrace(
traceOdbppIo,
"Failed to add polygon to profile" );
1359 m_profile->GenerateProfileFeatures( fileproxy.GetStream() );
1371 {
"X_ORIGIN",
"0" },
1372 {
"Y_ORIGIN",
"0" },
1373 {
"TOP_ACTIVE",
"0" },
1374 {
"BOTTOM_ACTIVE",
"0" },
1375 {
"RIGHT_ACTIVE",
"0" },
1376 {
"LEFT_ACTIVE",
"0" },
1377 {
"AFFECTING_BOM",
"" },
1378 {
"AFFECTING_BOM_CHANGED",
"0" },
1383 for(
const auto& [key, value] :
m_stephdr )
1398 layerEntity->GenerateFiles( writer );
1407 m_edaData.Write( fileproxy.GetStream() );
1415 m_netlist.Write( fileproxy.GetStream() );
1427 catch(
const std::exception& e )
1429 std::cerr << e.what() << std::endl;
1441 std::map<PCB_LAYER_ID, std::map<int, std::vector<BOARD_ITEM*>>>& elements =
m_plugin->GetLayerElementsMap();
1443 std::for_each(
m_board->Tracks().begin(),
m_board->Tracks().end(),
1444 [&layers, &elements](
PCB_TRACK* aTrack )
1446 if( aTrack->Type() == PCB_VIA_T )
1448 PCB_VIA* via = static_cast<PCB_VIA*>( aTrack );
1450 for( PCB_LAYER_ID layer : layers )
1452 if( via->FlashLayer( layer ) )
1453 elements[layer][via->GetNetCode()].push_back( via );
1458 elements[aTrack->GetLayer()][aTrack->GetNetCode()].push_back( aTrack );
1462 std::for_each( m_board->Zones().begin(), m_board->Zones().end(),
1463 [&elements](
ZONE* zone )
1465 for( PCB_LAYER_ID layer : zone->GetLayerSet() )
1466 elements[layer][zone->GetNetCode()].push_back( zone );
1469 for(
BOARD_ITEM* item : m_board->Drawings() )
1474 elements[layer][conn_it->GetNetCode()].push_back( conn_it );
1479 elements[layer][0].push_back( item );
1483 for(
FOOTPRINT* fp : m_board->Footprints() )
1485 for(
PCB_FIELD* field : fp->GetFields() )
1486 elements[field->GetLayer()][0].push_back( field );
1488 for(
BOARD_ITEM* item : fp->GraphicalItems() )
1491 elements[layer][0].push_back( item );
1494 for(
PAD*
pad : fp->Pads() )
1506 if( onSolderMaskLayer )
1507 margin.
x = margin.
y =
pad->GetSolderMaskExpansion( padLayer );
1509 if( onSolderPasteLayer )
1510 margin =
pad->GetSolderPasteMargin( padLayer );
1512 VECTOR2I padPlotsSize =
pad->GetSize( padLayer ) + margin * 2;
1514 if( onCopperLayer && !
pad->IsOnCopperLayer() )
1517 if( onCopperLayer && !
pad->FlashLayer( layer ) )
1521 && ( padPlotsSize.
x <= 0 || padPlotsSize.
y <= 0 ) )
1526 elements[layer][
pad->GetNetCode()].push_back(
pad );
1531 for(
const auto& [layerID, layerName] : m_plugin->GetLayerNameList() )
1533 std::shared_ptr<ODB_LAYER_ENTITY> layer_entity_ptr = std::make_shared<ODB_LAYER_ENTITY>(
1534 m_board, m_plugin, elements[layerID], layerID, layerName );
1536 m_layerEntityMap.emplace( layerName, layer_entity_ptr );
constexpr EDA_IU_SCALE pcbIUScale
@ BS_ITEM_TYPE_DIELECTRIC
wxString GetBuildVersion()
Get the full KiCad version string.
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.
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.
wxString GetTypeName() const
int GetSublayersCount() const
double GetEpsilonR(int aDielectricSubLayer=0) const
bool HasEpsilonRValue() const
wxString GetLayerName() const
bool HasLossTangentValue() const
PCB_LAYER_ID GetBrdLayerId() const
int GetThickness(int aDielectricSubLayer=0) const
BOARD_STACKUP_ITEM_TYPE GetType() const
wxString GetMaterial(int aDielectricSubLayer=0) const
int GetDielectricLayerId() const
double GetLossTangent(int aDielectricSubLayer=0) const
Manage layers needed to make a physical board.
const std::vector< BOARD_STACKUP_ITEM * > & GetList() const
bool SynchronizeWithBoard(BOARD_DESIGN_SETTINGS *aSettings)
Synchronize the BOARD_STACKUP_ITEM* list with the board.
Information pertinent to a Pcbnew printed circuit board.
T & AddSubnet(Args &&... args)
const std::shared_ptr< PIN > GetEdaPkgPin(size_t aPadIndex) const
KICAD_T Type() const
Returns the type of object.
LSET is a set of PCB_LAYER_IDs.
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Handle the data for a net.
Container for NETINFO_ITEM elements, which are the nets.
virtual std::string GetEntityName()=0
virtual bool CreateDirectoryTree(ODB_TREE_WRITER &writer)
ODB_ENTITY_BASE(BOARD *aBoard, PCB_IO_ODBPP *aPlugin)
std::ostream & GetStream()
void GenFeatures(ODB_TREE_WRITER &writer)
void GenComponents(ODB_TREE_WRITER &writer)
wxString m_matrixLayerName
void InitAuxilliaryData()
std::optional< COMPONENTS_MANAGER > m_compTop
virtual void GenerateFiles(ODB_TREE_WRITER &writer) override
std::optional< COMPONENTS_MANAGER > m_compBot
std::optional< ODB_DRILL_TOOLS > m_tools
void GenTools(ODB_TREE_WRITER &writer)
std::map< int, std::vector< BOARD_ITEM * > > m_layerItems
ODB_LAYER_ENTITY(BOARD *aBoard, PCB_IO_ODBPP *aPlugin, std::map< int, std::vector< BOARD_ITEM * > > &aMap, const PCB_LAYER_ID &aLayerID, const wxString &aLayerName)
ODB_COMPONENT & InitComponentData(const FOOTPRINT *aFp, const EDA_DATA::PACKAGE &aPkg)
virtual void InitEntityData() override
void GenAttrList(ODB_TREE_WRITER &writer)
std::unique_ptr< FEATURES_MANAGER > m_featuresMgr
void AddStep(const wxString &aStepName)
void InitMatrixLayerData()
std::vector< MATRIX_LAYER > m_matrixLayers
void AddMatrixLayerField(MATRIX_LAYER &aMLayer, PCB_LAYER_ID aLayer)
virtual void GenerateFiles(ODB_TREE_WRITER &writer) override
std::map< wxString, unsigned int > m_matrixSteps
void AddAuxilliaryMatrixLayer()
void EnsureUniqueLayerNames()
void AddDrillMatrixLayer()
virtual void InitEntityData() override
void AddCOMPMatrixLayer(PCB_LAYER_ID aCompSide)
std::vector< std::pair< wxString, wxString > > m_info
virtual void GenerateFiles(ODB_TREE_WRITER &writer) override
virtual std::string GetEntityName() override
std::unordered_map< wxString, wxString > m_stephdr
void GenerateProfileFile(ODB_TREE_WRITER &writer)
void GenerateStepHeaderFile(ODB_TREE_WRITER &writer)
void GenerateEdaFiles(ODB_TREE_WRITER &writer)
virtual void InitEntityData() override
void GenerateLayerFiles(ODB_TREE_WRITER &writer)
std::map< wxString, std::shared_ptr< ODB_LAYER_ENTITY > > m_layerEntityMap
std::unique_ptr< FEATURES_MANAGER > m_profile
virtual bool CreateDirectoryTree(ODB_TREE_WRITER &writer) override
void GenerateNetlistsFiles(ODB_TREE_WRITER &writer)
virtual void GenerateFiles(ODB_TREE_WRITER &writer) override
void WriteEquationLine(const std::string &var, int value)
ARRAY_PROXY MakeArrayProxy(const std::string &aStr)
void write_line_enum(const std::string &var, const T &value)
const wxString GetRootPath() const
void CreateEntityDirectory(const wxString &aPareDir, const wxString &aSubDir=wxEmptyString)
ODB_FILE_WRITER CreateFileProxy(const wxString &aFileName)
void SetCurrentPath(const wxString &aDir)
const wxString GetCurrentPath() const
static std::string m_unitsStr
Represent a set of closed polygons.
Handle a list of polygons defining a copper zone.
bool IsDrillSlot(const PAD &aPad)
Whether a pad's hole is a slot rather than a round drill.
static constexpr EDA_ANGLE ANGLE_360
const wxChar *const traceOdbppIo
size_t hash_fp_item(const EDA_ITEM *aItem, int aFlags)
Calculate hash of an EDA_ITEM.
Hashing functions for EDA_ITEMs.
@ REL_COORD
Use coordinates relative to the parent object.
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
bool IsValidLayer(int aLayerId)
Test whether a given integer is a valid layer index, i.e.
wxString Data2String(double aVal)
std::pair< wxString, wxString > AddXY(const VECTOR2I &aVec)
wxString GenLegalEntityName(const wxString &aStr)
wxString Double2String(double aVal)
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
@ PTH
Plated through hole pad.
std::optional< ODB_SUBTYPE > m_addType
std::optional< ODB_DIELECTRIC_TYPE > m_diType
std::optional< std::pair< wxString, wxString > > m_span
The properties of a padstack drill.
VECTOR2I size
Drill diameter (x == y) or slot dimensions (x != y)
wxLogTrace helper definitions.
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_PAD_T
class PAD, a pad in a footprint
VECTOR2< int32_t > VECTOR2I