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",
151 matrix.
m_diType.emplace( ODB_DIELECTRIC_TYPE::CORE );
153 matrix.
m_diType.emplace( ODB_DIELECTRIC_TYPE::PREPREG );
155 matrix.
m_type = ODB_TYPE::DIELECTRIC;
160 std::make_pair( PCB_LAYER_ID::UNDEFINED_LAYER, matrix.
m_layerName ) );
176 if( added_layers.find( layer ) != added_layers.end() )
180 added_layers.insert( layer );
199 case B_Paste: aMLayer.
m_type = ODB_TYPE::SOLDER_PASTE;
break;
203 case B_Mask: aMLayer.
m_type = ODB_TYPE::SOLDER_MASK;
break;
262 aMLayer.
m_type = ODB_TYPE::DOCUMENT;
268 aMLayer.
m_type = ODB_TYPE::SIGNAL;
273 aMLayer.
m_type = ODB_TYPE::UNDEFINED;
280 if( aMLayer.
m_type != ODB_TYPE::UNDEFINED )
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() )
319 if( !has_pth_layer &&
pad->GetAttribute() == PAD_ATTRIB::PTH )
320 has_pth_layer =
true;
321 if( !has_npth_layer &&
pad->GetAttribute() == PAD_ATTRIB::NPTH )
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,
341 matrix.
m_type = ODB_TYPE::DRILL;
344 matrix.
m_span.emplace( std::make_pair(
349 std::make_pair( PCB_LAYER_ID::UNDEFINED_LAYER, matrix.
m_layerName ) );
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 );
370 matrix.
m_type = ODB_TYPE::COMPONENT;
373 if( aCompSide ==
F_Cu )
377 std::make_pair( PCB_LAYER_ID::UNDEFINED_LAYER, matrix.
m_layerName ) );
385 std::make_pair( PCB_LAYER_ID::UNDEFINED_LAYER, matrix.
m_layerName ) );
399 if(
via->Padstack().IsFilled().value_or(
false ) )
401 auxilliary_layers[std::make_tuple( ODB_AUX_LAYER_TYPE::FILLING,
via->TopLayer(),
402 via->BottomLayer() )]
406 if(
via->Padstack().IsCapped().value_or(
false ) )
408 auxilliary_layers[std::make_tuple( ODB_AUX_LAYER_TYPE::CAPPING,
via->TopLayer(),
409 via->BottomLayer() )]
415 if(
via->Padstack().IsPlugged( layer ).value_or(
false ) )
417 auxilliary_layers[std::make_tuple( ODB_AUX_LAYER_TYPE::PLUGGING, layer,
418 PCB_LAYER_ID::UNDEFINED_LAYER )]
422 if(
via->Padstack().IsCovered( layer ).value_or(
false ) )
424 auxilliary_layers[std::make_tuple( ODB_AUX_LAYER_TYPE::COVERING, layer,
425 PCB_LAYER_ID::UNDEFINED_LAYER )]
429 if(
via->Padstack().IsTented( layer ).value_or(
false ) )
431 auxilliary_layers[std::make_tuple( ODB_AUX_LAYER_TYPE::TENTING, layer,
432 PCB_LAYER_ID::UNDEFINED_LAYER )]
440 [&]( std::tuple<ODB_AUX_LAYER_TYPE, PCB_LAYER_ID, PCB_LAYER_ID> aLayerPair )
442 wxString featureName =
"";
443 switch( std::get<0>( aLayerPair ) )
445 case ODB_AUX_LAYER_TYPE::TENTING: featureName =
"tenting";
break;
446 case ODB_AUX_LAYER_TYPE::COVERING: featureName =
"covering";
break;
447 case ODB_AUX_LAYER_TYPE::PLUGGING: featureName =
"plugging";
break;
448 case ODB_AUX_LAYER_TYPE::FILLING: featureName =
"filling";
break;
449 case ODB_AUX_LAYER_TYPE::CAPPING: featureName =
"capping";
break;
455 if( std::get<2>( aLayerPair ) != PCB_LAYER_ID::UNDEFINED_LAYER )
457 dLayerName = wxString::Format(
"%s_%s-%s", featureName,
464 dLayerName = wxString::Format(
"%s_front", featureName );
465 else if(
IsBackLayer( std::get<1>( aLayerPair ) ) )
466 dLayerName = wxString::Format(
"%s_back", featureName );
472 matrix.
m_type = ODB_TYPE::DOCUMENT;
476 if( std::get<2>( aLayerPair ) != PCB_LAYER_ID::UNDEFINED_LAYER )
478 matrix.
m_span.emplace( std::make_pair(
486 if( std::get<2>( aLayerPair ) != PCB_LAYER_ID::UNDEFINED_LAYER )
489 std::make_pair( PCB_LAYER_ID::UNDEFINED_LAYER, matrix.
m_layerName ) );
494 std::make_pair( std::get<1>( aLayerPair ), matrix.
m_layerName ) );
498 for(
const auto& [layer_pair, vec] : auxilliary_layers )
500 InitAuxMatrix( layer_pair );
525 if( layer.m_addType.has_value() )
534 if( layer.m_diType.has_value() )
547 if( layer.m_span.has_value() )
559 std::map<
int, std::vector<BOARD_ITEM*>>& aMap,
560 const PCB_LAYER_ID& aLayerID,
const wxString& aLayerName ) :
561 ODB_ENTITY_BASE( aBoard, aPlugin ), m_layerItems( aMap ), m_layerID( aLayerID ),
562 m_matrixLayerName( aLayerName )
564 m_featuresMgr = std::make_unique<FEATURES_MANAGER>( aBoard, aPlugin, aLayerName );
586 if(
m_layerID != PCB_LAYER_ID::UNDEFINED_LAYER )
601 std::vector<BOARD_ITEM*>& vec =
m_layerItems[net->GetNetCode()];
603 std::stable_sort( vec.begin(), vec.end(),
606 if( a->GetParentFootprint() == b->GetParentFootprint() )
607 return a->Type() < b->Type();
609 return a->GetParentFootprint() < b->GetParentFootprint();
629 return m_compBot.value().AddComponent( aFp, aPkg );
638 return m_compTop.value().AddComponent( aFp, aPkg );
645 std::map<std::pair<PCB_LAYER_ID, PCB_LAYER_ID>, std::vector<BOARD_ITEM*>>& drill_layers =
648 std::map<std::pair<PCB_LAYER_ID, PCB_LAYER_ID>, std::vector<BOARD_ITEM*>>& slot_holes =
658 bool is_npth_layer =
false;
659 wxString plated_name =
"plated";
663 is_npth_layer =
true;
664 plated_name =
"non-plated";
668 for(
const auto& [layer_pair, vec] : slot_holes )
670 wxString dLayerName = wxString::Format(
"drill_%s_%s-%s", plated_name,
682 if( ( is_npth_layer &&
pad->GetAttribute() == PAD_ATTRIB::PTH )
683 || ( !is_npth_layer &&
pad->GetAttribute() == PAD_ATTRIB::NPTH ) )
689 pad->GetAttribute() == PAD_ATTRIB::PTH ?
"PLATED" :
"NON_PLATED",
691 std::min(
pad->GetDrillSizeX(),
pad->GetDrillSizeY() ) ) );
702 for(
const auto& [layer_pair, vec] : drill_layers )
704 wxString dLayerName = wxString::Format(
"drill_%s_%s-%s", plated_name,
712 if( item->Type() ==
PCB_VIA_T && !is_npth_layer )
716 m_tools.value().AddDrillTools(
"VIA",
726 if( ( is_npth_layer &&
pad->GetAttribute() == PAD_ATTRIB::PTH )
727 || ( !is_npth_layer &&
pad->GetAttribute() == PAD_ATTRIB::NPTH ) )
733 pad->GetAttribute() == PAD_ATTRIB::PTH ?
"PLATED" :
"NON_PLATED",
755 for(
const auto& [layer_pair, vec] : auxilliary_layers )
757 wxString featureName =
"";
758 switch( std::get<0>( layer_pair ) )
760 case ODB_AUX_LAYER_TYPE::TENTING: featureName =
"tenting";
break;
761 case ODB_AUX_LAYER_TYPE::COVERING: featureName =
"covering";
break;
762 case ODB_AUX_LAYER_TYPE::PLUGGING: featureName =
"plugging";
break;
763 case ODB_AUX_LAYER_TYPE::FILLING: featureName =
"filling";
break;
764 case ODB_AUX_LAYER_TYPE::CAPPING: featureName =
"capping";
break;
769 bool drill_value =
false;
771 if( std::get<2>( layer_pair ) != PCB_LAYER_ID::UNDEFINED_LAYER )
774 dLayerName = wxString::Format(
"%s_%s-%s", featureName,
781 dLayerName = wxString::Format(
"%s_front", featureName );
782 else if(
IsBackLayer( std::get<1>( layer_pair ) ) )
783 dLayerName = wxString::Format(
"%s_back", featureName );
814 layer_entity_ptr->InitEntityData();
843 m_compTop->Write( fileproxy.GetStream() );
847 m_compBot->Write( fileproxy.GetStream() );
870 m_tools.value().GenerateFile( fileproxy.GetStream() );
896 if( fp->IsFlipped() )
903 wxLogError(
_(
"Failed to add component data" ) );
915 ODB_COMPONENT& comp = iter->second->InitComponentData( fp, eda_pkg );
917 for(
int i = 0; i < fp->Pads().size(); ++i )
932 auto& toep = comp.
m_toeprints.emplace_back( pin_ref );
934 toep.m_net_num = eda_net.m_index;
935 toep.m_subnet_num = subnet.m_index;
940 (
ANGLE_360 -
pad->GetOrientation() ).Normalize().AsDegrees() );
942 if(
pad->IsFlipped() )
943 toep.m_mirror = wxT(
"M" );
945 toep.m_mirror = wxT(
"N" );
971 std::forward_as_tuple( layer, zone ),
972 std::forward_as_tuple( &subnet ) );
1011 wxLogError(
"Failed to get board outline" );
1014 if( !
m_profile->AddContour( board_outline, 0 ) )
1016 wxLogError(
"Failed to add polygon to profile" );
1019 m_profile->GenerateProfileFeatures( fileproxy.GetStream() );
1031 {
"X_ORIGIN",
"0" },
1032 {
"Y_ORIGIN",
"0" },
1033 {
"TOP_ACTIVE",
"0" },
1034 {
"BOTTOM_ACTIVE",
"0" },
1035 {
"RIGHT_ACTIVE",
"0" },
1036 {
"LEFT_ACTIVE",
"0" },
1037 {
"AFFECTING_BOM",
"" },
1038 {
"AFFECTING_BOM_CHANGED",
"0" },
1043 for(
const auto& [key, value] :
m_stephdr )
1058 layerEntity->GenerateFiles( writer );
1087 catch(
const std::exception& e )
1089 std::cerr << e.what() << std::endl;
1102 std::map<PCB_LAYER_ID, std::map<int, std::vector<BOARD_ITEM*>>>& elements =
1106 [&layers, &elements](
PCB_TRACK* aTrack )
1108 if( aTrack->Type() == PCB_VIA_T )
1110 PCB_VIA* via = static_cast<PCB_VIA*>( aTrack );
1112 for( PCB_LAYER_ID layer : layers )
1114 if( via->FlashLayer( layer ) )
1115 elements[layer][via->GetNetCode()].push_back( via );
1120 elements[aTrack->GetLayer()][aTrack->GetNetCode()].push_back( aTrack );
1124 std::for_each( m_board->Zones().begin(), m_board->Zones().end(),
1125 [&elements](
ZONE* zone )
1127 LSEQ zone_layers = zone->GetLayerSet().Seq();
1129 for( PCB_LAYER_ID layer : zone_layers )
1131 elements[layer][zone->GetNetCode()].push_back( zone );
1135 for(
BOARD_ITEM* item : m_board->Drawings() )
1138 elements[conn_it->GetLayer()][conn_it->GetNetCode()].push_back( conn_it );
1140 elements[item->GetLayer()][0].push_back( item );
1143 for(
FOOTPRINT* fp : m_board->Footprints() )
1145 for(
PCB_FIELD* field : fp->GetFields() )
1146 elements[field->GetLayer()][0].push_back( field );
1148 for(
BOARD_ITEM* item : fp->GraphicalItems() )
1149 elements[item->GetLayer()][0].push_back( item );
1151 for(
PAD*
pad : fp->Pads() )
1153 LSEQ pad_layers =
pad->GetLayerSet().Seq();
1160 bool onSolderPasteLayer =
1163 if( onSolderMaskLayer )
1166 if( onSolderPasteLayer )
1171 if( onCopperLayer && !
pad->IsOnCopperLayer() )
1174 if( onCopperLayer && !
pad->FlashLayer( layer ) )
1178 && ( padPlotsSize.
x <= 0 || padPlotsSize.
y <= 0 ) )
1181 elements[layer][
pad->GetNetCode()].push_back(
pad );
1186 for(
const auto& [layerID, layerName] : m_plugin->GetLayerNameList() )
1188 std::shared_ptr<ODB_LAYER_ENTITY> layer_entity_ptr = std::make_shared<ODB_LAYER_ENTITY>(
1189 m_board, m_plugin, elements[layerID], layerID, layerName );
1191 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.
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr, bool aAllowUseArcsInPolygons=false, bool aIncludeNPTHAsOutlines=false)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
const NETINFO_LIST & GetNetInfo() const
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
const ZONES & Zones() const
const FOOTPRINTS & Footprints() const
const TRACKS & Tracks() const
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
T & AddSubnet(Args &&... args)
const std::shared_ptr< PIN > GetEdaPkgPin(size_t aPadIndex) const
NET & GetNet(size_t aNetcode)
const PACKAGE & GetPackage(size_t aHash) const
void AddNET(const NETINFO_ITEM *aNet)
void AddPackage(const FOOTPRINT *aFp)
void Write(std::ostream &ost) const
std::vector< std::shared_ptr< FOOTPRINT > > GetEdaFootprints() const
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
LSET is a set of PCB_LAYER_IDs.
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
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)
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 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
void Write(std::ostream &aStream)
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
std::map< std::pair< PCB_LAYER_ID, ZONE * >, EDA_DATA::SUB_NET_PLANE * > & GetPlaneSubnetMap()
std::map< PCB_TRACK *, EDA_DATA::SUB_NET * > & GetViaTraceSubnetMap()
std::vector< std::pair< PCB_LAYER_ID, wxString > > & GetLayerNameList()
std::map< std::pair< PCB_LAYER_ID, PCB_LAYER_ID >, std::vector< BOARD_ITEM * > > & GetSlotHolesMap()
std::map< const PAD *, EDA_DATA::SUB_NET_TOEPRINT * > & GetPadSubnetMap()
std::map< PCB_LAYER_ID, std::map< int, std::vector< BOARD_ITEM * > > > & GetLayerElementsMap()
std::map< std::tuple< ODB_AUX_LAYER_TYPE, PCB_LAYER_ID, PCB_LAYER_ID >, std::vector< BOARD_ITEM * > > & GetAuxilliaryLayerItemsMap()
static std::string m_unitsStr
std::map< std::pair< PCB_LAYER_ID, PCB_LAYER_ID >, std::vector< BOARD_ITEM * > > & GetDrillLayerItemsMap()
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 IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
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)
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