51#include <wx/numformatter.h> 
   52#include <wx/mstream.h> 
   69    catch( 
const std::exception& e )
 
   71        std::cerr << e.what() << std::endl;
 
 
   81               { wxS( 
"ODB_VERSION_MAJOR" ), wxS( 
"8" ) },
 
   82               { wxS( 
"ODB_VERSION_MINOR" ), wxS( 
"1" ) },
 
   83               { wxS( 
"ODB_SOURCE" ), wxS( 
"KiCad EDA" ) },
 
   84               { wxS( 
"CREATION_DATE" ), wxDateTime::Now().Format( 
"%Y%m%d.%H%M%S" ) },
 
   85               { wxS( 
"SAVE_DATE" ), wxDateTime::Now().Format( 
"%Y%m%d.%H%M%S" ) },
 
   86               { wxS( 
"SAVE_APP" ), wxString::Format( wxS( 
"KiCad EDA %s" ), 
GetBuildVersion() ) } };
 
 
  123    std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
 
  124    std::set<PCB_LAYER_ID>           added_layers;
 
  128    for( 
int i = 0; i < stackup.
GetCount(); i++ )
 
  132        for( 
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
 
  136            if( ly_name.IsEmpty() )
 
  142                    ly_name = wxString::Format( 
"DIELECTRIC_%d",
 
  159                m_plugin->GetLayerNameList().emplace_back(
 
  174        if( added_layers.find( layer ) != added_layers.end() )
 
  178        added_layers.insert( layer );
 
 
  283        m_plugin->GetLayerNameList().emplace_back( std::make_pair( aLayer, aMLayer.
m_layerName ) );
 
 
  290    std::map<std::pair<PCB_LAYER_ID, PCB_LAYER_ID>, std::vector<BOARD_ITEM*>>& drill_layers =
 
  293    std::map<std::pair<PCB_LAYER_ID, PCB_LAYER_ID>, std::vector<BOARD_ITEM*>>& slot_holes =
 
  296    bool has_pth_layer = 
false;
 
  297    bool has_npth_layer = 
false;
 
  304            drill_layers[std::make_pair( 
via->TopLayer(), 
via->BottomLayer() )].push_back( 
via );
 
  312        if( fp->IsFlipped() )
 
  317        for( 
PAD* 
pad : fp->Pads() )
 
  320                has_pth_layer = 
true;
 
  322                has_npth_layer = 
true;
 
  324            if( 
pad->HasHole() && 
pad->GetDrillSizeX() != 
pad->GetDrillSizeY() )
 
  325                slot_holes[std::make_pair( 
F_Cu, 
B_Cu )].push_back( 
pad );
 
  326            else if( 
pad->HasHole() )
 
  327                drill_layers[std::make_pair( 
F_Cu, 
B_Cu )].push_back( 
pad );
 
  333    auto InitDrillMatrix =
 
  334            [&]( 
const wxString& aHasPlated, std::pair<PCB_LAYER_ID, PCB_LAYER_ID> aLayerPair )
 
  336        wxString     dLayerName = wxString::Format( 
"drill_%s_%s-%s", aHasPlated,
 
  337                                                    m_board->GetLayerName( aLayerPair.first ),
 
  338                                                    m_board->GetLayerName( aLayerPair.second ) );
 
  344        matrix.
m_span.emplace( std::make_pair(
 
  348        m_plugin->GetLayerNameList().emplace_back(
 
  353        InitDrillMatrix( 
"non-plated", std::make_pair( 
F_Cu, 
B_Cu ) );
 
  356    if( has_pth_layer && drill_layers.find( std::make_pair( 
F_Cu, 
B_Cu ) ) == drill_layers.end() )
 
  357        InitDrillMatrix( 
"plated", std::make_pair( 
F_Cu, 
B_Cu ) );
 
  360    for( 
const auto& [layer_pair, vec] : drill_layers )
 
  362        InitDrillMatrix( 
"plated", layer_pair );
 
 
  373    if( aCompSide == 
F_Cu )
 
  376        m_plugin->GetLayerNameList().emplace_back(
 
  384        m_plugin->GetLayerNameList().emplace_back(
 
 
  391    auto& auxilliary_layers = 
m_plugin->GetAuxilliaryLayerItemsMap();
 
  399            if( 
via->Padstack().IsFilled().value_or( 
false ) )
 
  402                                                   via->BottomLayer() )]
 
  406            if( 
via->Padstack().IsCapped().value_or( 
false ) )
 
  409                                                   via->BottomLayer() )]
 
  415                if( 
via->Padstack().IsPlugged( layer ).value_or( 
false ) )
 
  422                if( 
via->Padstack().IsCovered( layer ).value_or( 
false ) )
 
  429                if( 
via->Padstack().IsTented( layer ).value_or( 
false ) )
 
  440            [&]( std::tuple<ODB_AUX_LAYER_TYPE, PCB_LAYER_ID, PCB_LAYER_ID> aLayerPair )
 
  442        wxString featureName = 
"";
 
  443        switch( std::get<0>( aLayerPair ) )
 
  457            dLayerName = wxString::Format( 
"%s_%s-%s", featureName,
 
  458                                           m_board->GetLayerName( std::get<1>( aLayerPair ) ),
 
  459                                           m_board->GetLayerName( std::get<2>( aLayerPair ) ) );
 
  463            if( 
m_board->IsFrontLayer( std::get<1>( aLayerPair ) ) )
 
  464                dLayerName = wxString::Format( 
"%s_front", featureName );
 
  465            else if( 
m_board->IsBackLayer( std::get<1>( aLayerPair ) ) )
 
  466                dLayerName = wxString::Format( 
"%s_back", featureName );
 
  478            matrix.
m_span.emplace( std::make_pair(
 
  481                            m_board->GetLayerName( std::get<2>( aLayerPair ) ) ) ) );
 
  488            m_plugin->GetLayerNameList().emplace_back(
 
  493            m_plugin->GetLayerNameList().emplace_back(
 
  494                    std::make_pair( std::get<1>( aLayerPair ), matrix.
m_layerName ) );
 
  498    for( 
const auto& [layer_pair, vec] : auxilliary_layers )
 
  500        InitAuxMatrix( layer_pair );
 
 
  508    std::map<wxString, std::vector<size_t>> name_to_indices;
 
  514        name_to_indices[layerName].push_back( i );
 
  518    for( 
auto& [layerName, indices] : name_to_indices )
 
  520        if( indices.size() > 1 )
 
  523            for( 
size_t count = 0; count < indices.size(); ++count )
 
  525                size_t idx = indices[count];
 
  526                wxString newLayerName = wxString::Format( 
"%s_%zu", 
m_matrixLayers[idx].m_layerName, count + 1 );
 
  529                if( newLayerName.length() > 64 )
 
  533                    size_t suffixLen = wxString::Format( 
"_%zu", count + 1 ).length();
 
  535                    if( suffixLen < baseName.length() )
 
  537                        baseName.Truncate( 64 - suffixLen );
 
  538                        newLayerName = wxString::Format( 
"%s_%zu", baseName, count + 1 );
 
 
  569        if( layer.m_addType.has_value() )
 
  578        if( layer.m_diType.has_value() )
 
  591        if( layer.m_span.has_value() )
 
 
  603                                    std::map<
int, std::vector<BOARD_ITEM*>>& aMap,
 
  604                                    const PCB_LAYER_ID& aLayerID, 
const wxString& aLayerName ) :
 
  608    m_featuresMgr = std::make_unique<FEATURES_MANAGER>( aBoard, aPlugin, aLayerName );
 
 
  645        std::vector<BOARD_ITEM*>& vec = 
m_layerItems[net->GetNetCode()];
 
  647        std::stable_sort( vec.begin(), vec.end(),
 
  650                              if( a->GetParentFootprint() == b->GetParentFootprint() )
 
  651                                  return a->Type() < b->Type();
 
  653                              return a->GetParentFootprint() < b->GetParentFootprint();
 
 
  673        return m_compBot.value().AddComponent( aFp, aPkg );
 
  682        return m_compTop.value().AddComponent( aFp, aPkg );
 
 
  689    std::map<std::pair<PCB_LAYER_ID, PCB_LAYER_ID>, std::vector<BOARD_ITEM*>>& drill_layers =
 
  692    std::map<std::pair<PCB_LAYER_ID, PCB_LAYER_ID>, std::vector<BOARD_ITEM*>>& slot_holes =
 
  702    bool     is_npth_layer = 
false;
 
  703    wxString plated_name = 
"plated";
 
  707        is_npth_layer = 
true;
 
  708        plated_name = 
"non-plated";
 
  712    for( 
const auto& [layer_pair, vec] : slot_holes )
 
  714        wxString dLayerName = wxString::Format( 
"drill_%s_%s-%s", plated_name,
 
  715                                                m_board->GetLayerName( layer_pair.first ),
 
  716                                                m_board->GetLayerName( layer_pair.second ) );
 
  735                                    std::min( 
pad->GetDrillSizeX(), 
pad->GetDrillSizeY() ) ) );
 
  746    for( 
const auto& [layer_pair, vec] : drill_layers )
 
  748        wxString dLayerName = wxString::Format( 
"drill_%s_%s-%s", plated_name,
 
  749                                                m_board->GetLayerName( layer_pair.first ),
 
  750                                                m_board->GetLayerName( layer_pair.second ) );
 
  756                if( item->Type() == 
PCB_VIA_T && !is_npth_layer )
 
  760                    m_tools.value().AddDrillTools( 
"VIA",
 
 
  792    auto& auxilliary_layers = 
m_plugin->GetAuxilliaryLayerItemsMap();
 
  799    for( 
const auto& [layer_pair, vec] : auxilliary_layers )
 
  801        wxString featureName = 
"";
 
  802        switch( std::get<0>( layer_pair ) )
 
  813        bool     drill_value = 
false;
 
  818            dLayerName = wxString::Format( 
"%s_%s-%s", featureName,
 
  819                                           m_board->GetLayerName( std::get<1>( layer_pair ) ),
 
  820                                           m_board->GetLayerName( std::get<2>( layer_pair ) ) );
 
  824            if( 
m_board->IsFrontLayer( std::get<1>( layer_pair ) ) )
 
  825                dLayerName = wxString::Format( 
"%s_front", featureName );
 
  826            else if( 
m_board->IsBackLayer( std::get<1>( layer_pair ) ) )
 
  827                dLayerName = wxString::Format( 
"%s_back", featureName );
 
 
  858        layer_entity_ptr->InitEntityData();
 
 
  887        m_compTop->Write( fileproxy.GetStream() );
 
  891        m_compBot->Write( fileproxy.GetStream() );
 
 
  914    m_tools.value().GenerateFile( fileproxy.GetStream() );
 
 
  940        if( fp->IsFlipped() )
 
  947            wxLogError( 
_( 
"Failed to add component data" ) );
 
  953        std::shared_ptr<FOOTPRINT> fp_pkg = 
m_edaData.GetEdaFootprints().at( j );
 
  959        if( fp->Pads().empty() )
 
  962        ODB_COMPONENT& comp = iter->second->InitComponentData( fp, eda_pkg );
 
  964        for( 
int i = 0; i < fp->Pads().size(); ++i )
 
  975            m_plugin->GetPadSubnetMap().emplace( 
pad, &subnet );
 
  979            auto&                                toep = comp.
m_toeprints.emplace_back( pin_ref );
 
  981            toep.m_net_num = eda_net.m_index;
 
  982            toep.m_subnet_num = subnet.m_index;
 
  987                    ( 
ANGLE_360 - 
pad->GetOrientation() ).Normalize().AsDegrees() );
 
  989            if( 
pad->IsFlipped() )
 
  990                toep.m_mirror = wxT( 
"M" );
 
  992                toep.m_mirror = wxT( 
"N" );
 
  998        auto&              eda_net = 
m_edaData.GetNet( track->GetNetCode() );
 
 1006        m_plugin->GetViaTraceSubnetMap().emplace( track, subnet );
 
 1013            auto& eda_net = 
m_edaData.GetNet( zone->GetNetCode() );
 
 1018            m_plugin->GetPlaneSubnetMap().emplace( std::piecewise_construct,
 
 1019                                                   std::forward_as_tuple( layer, zone ),
 
 1020                                                   std::forward_as_tuple( &subnet ) );
 
 
 1057    if( !
m_board->GetBoardPolygonOutlines( board_outline ) )
 
 1059        wxLogError( 
"Failed to get board outline" );
 
 1062    if( !
m_profile->AddContour( board_outline, 0 ) )
 
 1064        wxLogError( 
"Failed to add polygon to profile" );
 
 1067    m_profile->GenerateProfileFeatures( fileproxy.GetStream() );
 
 
 1079        { 
"X_ORIGIN", 
"0" },
 
 1080        { 
"Y_ORIGIN", 
"0" },
 
 1081        { 
"TOP_ACTIVE", 
"0" },
 
 1082        { 
"BOTTOM_ACTIVE", 
"0" },
 
 1083        { 
"RIGHT_ACTIVE", 
"0" },
 
 1084        { 
"LEFT_ACTIVE", 
"0" },
 
 1085        { 
"AFFECTING_BOM", 
"" },
 
 1086        { 
"AFFECTING_BOM_CHANGED", 
"0" },
 
 1091    for( 
const auto& [key, value] : 
m_stephdr )
 
 
 1106        layerEntity->GenerateFiles( writer );
 
 
 1115    m_edaData.Write( fileproxy.GetStream() );
 
 
 1123    m_netlist.Write( fileproxy.GetStream() );
 
 
 1135    catch( 
const std::exception& e )
 
 1137        std::cerr << e.what() << std::endl;
 
 
 1150    std::map<PCB_LAYER_ID, std::map<int, std::vector<BOARD_ITEM*>>>& elements = 
m_plugin->GetLayerElementsMap();
 
 1152    std::for_each( 
m_board->Tracks().begin(), 
m_board->Tracks().end(),
 
 1153                   [&layers, &elements]( 
PCB_TRACK* aTrack )
 
 1155                       if( aTrack->Type() == PCB_VIA_T )
 
 1157                           PCB_VIA* via = static_cast<PCB_VIA*>( aTrack );
 
 1159                           for( PCB_LAYER_ID layer : layers )
 
 1161                               if( via->FlashLayer( layer ) )
 
 1162                                   elements[layer][via->GetNetCode()].push_back( via );
 
 1167                           elements[aTrack->GetLayer()][aTrack->GetNetCode()].push_back( aTrack );
 
 1171    std::for_each( m_board->Zones().begin(), m_board->Zones().end(),
 
 1172                   [&elements]( 
ZONE* zone )
 
 1174                       for( PCB_LAYER_ID layer : zone->GetLayerSet() )
 
 1175                           elements[layer][zone->GetNetCode()].push_back( zone );
 
 1178    for( 
BOARD_ITEM* item : m_board->Drawings() )
 
 1181            elements[conn_it->GetLayer()][conn_it->GetNetCode()].push_back( conn_it );
 
 1183            elements[item->GetLayer()][0].push_back( item );
 
 1186    for( 
FOOTPRINT* fp : m_board->Footprints() )
 
 1188        for( 
PCB_FIELD* field : fp->GetFields() )
 
 1189            elements[field->GetLayer()][0].push_back( field );
 
 1191        for( 
BOARD_ITEM* item : fp->GraphicalItems() )
 
 1192            elements[item->GetLayer()][0].push_back( item );
 
 1194        for( 
PAD* 
pad : fp->Pads() )
 
 1204                if( onSolderMaskLayer )
 
 1207                if( onSolderPasteLayer )
 
 1212                if( onCopperLayer && !
pad->IsOnCopperLayer() )
 
 1215                if( onCopperLayer && !
pad->FlashLayer( layer ) )
 
 1219                    && ( padPlotsSize.
x <= 0 || padPlotsSize.
y <= 0 ) )
 
 1224                elements[layer][
pad->GetNetCode()].push_back( 
pad );
 
 1229    for( 
const auto& [layerID, layerName] : m_plugin->GetLayerNameList() )
 
 1231        std::shared_ptr<ODB_LAYER_ENTITY> layer_entity_ptr = std::make_shared<ODB_LAYER_ENTITY>(
 
 1232                m_board, m_plugin, elements[layerID], layerID, layerName );
 
 1234        m_layerEntityMap.emplace( layerName, layer_entity_ptr );
 
 
@ 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
 
wxString GetLayerName() const
 
PCB_LAYER_ID GetBrdLayerId() const
 
BOARD_STACKUP_ITEM_TYPE GetType() const
 
int GetDielectricLayerId() 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.
 
const std::shared_ptr< PIN > GetEdaPkgPin(size_t aPadIndex) const
 
LSET is a set of PCB_LAYER_IDs.
 
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
 
Handle the data for a net.
 
Container for NETINFO_ITEM elements, which are the nets.
 
const size_t m_index
! CMP index number on board to be used in SNT(TOP), 0~n-1
 
std::list< TOEPRINT > m_toeprints
 
virtual std::string GetEntityName()=0
 
virtual bool CreateDirectoryTree(ODB_TREE_WRITER &writer)
 
ODB_ENTITY_BASE(BOARD *aBoard, PCB_IO_ODBPP *aPlugin)
 
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 constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
 
static std::string m_unitsStr
 
Represent a set of closed polygons.
 
Handle a list of polygons defining a copper zone.
 
static constexpr EDA_ANGLE ANGLE_360
 
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.
 
std::pair< wxString, wxString > AddXY(const VECTOR2I &aVec)
 
wxString GenLegalEntityName(const wxString &aStr)
 
wxString Double2String(double aVal)
 
wxString SymDouble2String(double aVal)
 
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
 
@ PTH
Plated through hole pad.
 
std::optional< ODB_DIELECTRIC_TYPE > m_diType
 
std::optional< std::pair< wxString, wxString > > m_span
 
@ 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