7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-20 23:41:40 +00:00

Implement Component Classes

- Adds Component Class field to SCH_DIRECTIVE_LABEL
- Adds SCH_SYMBOLs to SCH_RULE_AREA item lists
- SCH_SYMBOLs resolve Component Class directives
- Netlist exporter / importer handles Component Class names
- Adds DRC expressions and functions
- Adds QA check for component class netlist export
This commit is contained in:
JamesJCode 2024-09-27 20:48:12 +01:00
parent ae96ac6d2e
commit d64a112971
37 changed files with 1827 additions and 19 deletions

View File

@ -745,6 +745,7 @@ set( PCB_COMMON_SRCS
${CMAKE_SOURCE_DIR}/pcbnew/teardrop/teardrop_parameters.cpp #needed by board_design_settings.cpp
${CMAKE_SOURCE_DIR}/pcbnew/router/pns_meander.cpp #needed by board_design_settings.cpp
${CMAKE_SOURCE_DIR}/pcbnew/board.cpp
${CMAKE_SOURCE_DIR}/pcbnew/component_class_manager.cpp #needed by board.cpp
${CMAKE_SOURCE_DIR}/pcbnew/board_item.cpp
${CMAKE_SOURCE_DIR}/pcbnew/pcb_dimension.cpp
${CMAKE_SOURCE_DIR}/pcbnew/pcb_shape.cpp

View File

@ -1,6 +1,8 @@
class
code
comp
components
component_classes
datasheet
date
description

View File

@ -65,6 +65,7 @@ center
chamfer
chamfer_ratio
circle
class
clearance
clearance_min
color
@ -73,6 +74,7 @@ column_count
column_widths
comment
company
component_classes
connect
connect_pads
copperpour

View File

@ -414,6 +414,21 @@ XNODE* NETLIST_EXPORTER_XML::makeSymbols( unsigned aCtl )
xsheetpath->AddAttribute( wxT( "names" ), sheet.PathHumanReadable() );
xsheetpath->AddAttribute( wxT( "tstamps" ), sheet.PathAsString() );
// Node for component class
std::vector<wxString> compClassNames =
getComponentClassNamesForAllSymbolUnits( symbol, sheet, sheetList );
if( compClassNames.size() > 0 )
{
XNODE* xcompclasslist;
xcomp->AddChild( xcompclasslist = node( wxT( "component_classes" ) ) );
for( const wxString& compClass : compClassNames )
{
xcompclasslist->AddChild( node( wxT( "class" ), UnescapeString( compClass ) ) );
}
}
XNODE* xunits; // Node for extra units
xcomp->AddChild( xunits = node( wxT( "tstamps" ) ) );
@ -445,6 +460,49 @@ XNODE* NETLIST_EXPORTER_XML::makeSymbols( unsigned aCtl )
}
std::vector<wxString> NETLIST_EXPORTER_XML::getComponentClassNamesForAllSymbolUnits(
SCH_SYMBOL* aSymbol, const SCH_SHEET_PATH& aSymbolSheet, const SCH_SHEET_LIST& aSheetList )
{
std::unordered_set<wxString> compClassNames = aSymbol->GetComponentClassNames( &aSymbolSheet );
int primaryUnit = aSymbol->GetUnitSelection( &aSymbolSheet );
if( aSymbol->GetUnitCount() > 1 )
{
wxString ref = aSymbol->GetRef( &aSymbolSheet );
for( const SCH_SHEET_PATH& sheet : aSheetList )
{
for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
{
SCH_SYMBOL* symbol2 = static_cast<SCH_SYMBOL*>( item );
wxString ref2 = symbol2->GetRef( &sheet );
int otherUnit = symbol2->GetUnitSelection( &sheet );
if( ref2.CmpNoCase( ref ) != 0 )
continue;
if( otherUnit == primaryUnit )
continue;
std::unordered_set<wxString> otherClassNames =
symbol2->GetComponentClassNames( &sheet );
compClassNames.insert( otherClassNames.begin(), otherClassNames.end() );
}
}
}
std::vector<wxString> sortedCompClassNames( compClassNames.begin(), compClassNames.end() );
std::sort( sortedCompClassNames.begin(), sortedCompClassNames.end(),
[]( const wxString& str1, const wxString& str2 )
{
return str1.Cmp( str2 ) < 0;
} );
return sortedCompClassNames;
}
XNODE* NETLIST_EXPORTER_XML::makeDesignHeader()
{
SCH_SCREEN* screen;

View File

@ -133,6 +133,14 @@ protected:
void addSymbolFields( XNODE* aNode, SCH_SYMBOL* aSymbol, const SCH_SHEET_PATH& aSheet,
const SCH_SHEET_LIST& aSheetList);
/**
* Finds all component class names attached to any sub-unit of a given symbol
*/
std::vector<wxString>
getComponentClassNamesForAllSymbolUnits( SCH_SYMBOL* aSymbol,
const SCH_SHEET_PATH& aSymbolSheet,
const SCH_SHEET_LIST& aSheetList );
bool m_resolveTextVars; // Export textVar references resolved
private:

View File

@ -183,12 +183,19 @@ void SCH_FIELD::SetId( int aId )
// We can't use defined IDs for labels because there can be multiple net class
// assignments.
if( GetCanonicalName() == wxT( "Netclass" ) )
if( GetCanonicalName() == wxT( "Netclass" )
|| GetCanonicalName() == wxT( "Component Class" ) )
{
SetLayer( LAYER_NETCLASS_REFS );
}
else if( GetCanonicalName() == wxT( "Intersheetrefs" ) )
{
SetLayer( LAYER_INTERSHEET_REFS );
}
else
{
SetLayer( LAYER_FIELDS );
}
}
}

View File

@ -1002,7 +1002,7 @@ const BOX2I SCH_LABEL_BASE::GetBoundingBox() const
for( const SCH_FIELD& field : m_fields )
{
if( field.IsVisible() )
if( field.IsVisible() && field.GetText() != wxEmptyString )
{
BOX2I fieldBBox = field.GetBoundingBox();
@ -1734,6 +1734,9 @@ void SCH_DIRECTIVE_LABEL::AutoplaceFields( SCH_SCREEN* aScreen, bool aManual )
for( SCH_FIELD& field : m_fields )
{
if( field.GetText() == wxEmptyString )
continue;
switch( GetSpinStyle() )
{
default:

View File

@ -267,6 +267,10 @@ void SCH_RULE_AREA::RefreshContainedItemsAndDirectives(
addContainedItem( areaItem );
}
}
else if( areaItem->IsType( { SCH_SYMBOL_T } ) )
{
addContainedItem( areaItem );
}
}
}
@ -316,7 +320,7 @@ const std::unordered_set<SCH_ITEM*>& SCH_RULE_AREA::GetContainedItems() const
}
const std::unordered_set<SCH_DIRECTIVE_LABEL*> SCH_RULE_AREA::GetDirectives() const
const std::unordered_set<SCH_DIRECTIVE_LABEL*>& SCH_RULE_AREA::GetDirectives() const
{
return m_directives;
}

View File

@ -89,7 +89,7 @@ public:
const std::unordered_set<SCH_ITEM*>& GetContainedItems() const;
/// @brief Returns the set of all directive labels attached to the rule area border
const std::unordered_set<SCH_DIRECTIVE_LABEL*> GetDirectives() const;
const std::unordered_set<SCH_DIRECTIVE_LABEL*>& GetDirectives() const;
/// @brief Resolves the netclass of this rule area from connected directive labels
/// @returns The resolved netclass (if any), and the SCH_ITEM providing the declaration

View File

@ -40,6 +40,7 @@
#include <settings/settings_manager.h>
#include <sch_plotter.h>
#include <string_utils.h>
#include <sch_rule_area.h>
#include <utility>
@ -2872,6 +2873,38 @@ bool SCH_SYMBOL::IsNormal() const
}
std::unordered_set<wxString> SCH_SYMBOL::GetComponentClassNames( const SCH_SHEET_PATH* aPath ) const
{
std::unordered_set<wxString> componentClass;
auto getComponentClassFields = [&]( const auto& fields )
{
for( const SCH_FIELD& field : fields )
{
if( field.GetCanonicalName() == wxT( "Component Class" ) )
{
if( field.GetShownText( aPath, false ) != wxEmptyString )
componentClass.insert( field.GetShownText( aPath, false ) );
}
}
};
// First get component classes set on the symbol itself
getComponentClassFields( m_fields );
// Now get component classes set on any enclosing rule areas
for( const SCH_RULE_AREA* ruleArea : m_rule_areas_cache )
{
for( const SCH_DIRECTIVE_LABEL* label : ruleArea->GetDirectives() )
{
getComponentClassFields( label->GetFields() );
}
}
return componentClass;
}
bool SCH_SYMBOL::operator==( const SCH_ITEM& aOther ) const
{
if( Type() != aOther.Type() )

View File

@ -901,6 +901,9 @@ public:
double Similarity( const SCH_ITEM& aOther ) const override;
/// Returns the component classes this symbol belongs in
std::unordered_set<wxString> GetComponentClassNames( const SCH_SHEET_PATH* aPath ) const;
bool operator==( const SCH_ITEM& aOther ) const override;
private:

View File

@ -481,12 +481,13 @@ TOOL_ACTION EE_ACTIONS::placeLabel( TOOL_ACTION_ARGS()
.Icon( BITMAPS::add_label )
.Flags( AF_ACTIVATE ) );
TOOL_ACTION EE_ACTIONS::placeClassLabel( TOOL_ACTION_ARGS()
.Name( "eeschema.InteractiveDrawing.placeClassLabel" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Place Net Class Directives" ) )
.Icon( BITMAPS::add_class_flag )
.Flags( AF_ACTIVATE ) );
TOOL_ACTION
EE_ACTIONS::placeClassLabel( TOOL_ACTION_ARGS()
.Name( "eeschema.InteractiveDrawing.placeClassLabel" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Place Directive Labels" ) )
.Icon( BITMAPS::add_class_flag )
.Flags( AF_ACTIVATE ) );
TOOL_ACTION EE_ACTIONS::placeHierLabel( TOOL_ACTION_ARGS()
.Name( "eeschema.InteractiveDrawing.placeHierarchicalLabel" )

View File

@ -1546,6 +1546,8 @@ SCH_TEXT* SCH_DRAWING_TOOLS::createNewText( const VECTOR2I& aPosition, int aType
labelItem = new SCH_DIRECTIVE_LABEL( aPosition );
labelItem->SetShape( m_lastNetClassFlagShape );
labelItem->GetFields().emplace_back( SCH_FIELD( {0,0}, 0, labelItem, wxT( "Netclass" ) ) );
labelItem->GetFields().emplace_back(
SCH_FIELD( { 0, 0 }, 0, labelItem, wxT( "Component Class" ) ) );
labelItem->GetFields().back().SetItalic( true );
labelItem->GetFields().back().SetVisible( true );
textItem = labelItem;

View File

@ -37,6 +37,7 @@
class BOARD;
class BOARD_DESIGN_SETTINGS;
class BOARD_ITEM_CONTAINER;
class COMPONENT_CLASS;
class SHAPE_POLY_SET;
class SHAPE_SEGMENT;
class PCB_BASE_FRAME;
@ -79,11 +80,8 @@ class BOARD_ITEM : public EDA_ITEM
{
public:
BOARD_ITEM( BOARD_ITEM* aParent, KICAD_T idtype, PCB_LAYER_ID aLayer = F_Cu ) :
EDA_ITEM( aParent, idtype, false, true ),
m_layer( aLayer ),
m_isKnockout( false ),
m_isLocked( false ),
m_group( nullptr )
EDA_ITEM( aParent, idtype, false, true ), m_layer( aLayer ), m_isKnockout( false ),
m_isLocked( false ), m_group( nullptr ), m_componentClass( nullptr )
{
}
@ -419,6 +417,12 @@ public:
bool operator() ( const BOARD_ITEM* a, const BOARD_ITEM* b ) const;
};
void SetComponentClass( const COMPONENT_CLASS* aClass ) { m_componentClass = aClass; }
const COMPONENT_CLASS* GetComponentClass() const { return m_componentClass; }
wxString GetComponentClassAsString() const;
protected:
/**
* Return a string (to be shown to the user) describing a layer mask.
@ -434,6 +438,8 @@ protected:
bool m_isLocked;
PCB_GROUP* m_group;
const COMPONENT_CLASS* m_componentClass;
};
#ifndef SWIG

View File

@ -316,6 +316,7 @@ set( PCBNEW_CLASS_SRCS
array_pad_number_provider.cpp
build_BOM_from_board.cpp
cleanup_item.cpp
component_class_manager.cpp
convert_shape_list_to_polygon.cpp
cross-probing.cpp
edit.cpp

View File

@ -27,6 +27,7 @@
#include <board_item_container.h>
#include <board_stackup_manager/board_stackup.h>
#include <component_class_manager.h>
#include <embedded_files.h>
#include <common.h> // Needed for stl hash extensions
#include <convert_shape_list_to_polygon.h> // for OUTLINE_ERROR_HANDLER
@ -1262,6 +1263,11 @@ public:
*/
void EmbedFonts() override;
/**
* Gets the component class manager
*/
COMPONENT_CLASS_MANAGER& GetComponentClassManager() { return m_componentClassManager; }
// --------- Item order comparators ---------
struct cmp_items
@ -1377,6 +1383,8 @@ private:
std::vector<BOARD_LISTENER*> m_listeners;
bool m_embedFonts;
COMPONENT_CLASS_MANAGER m_componentClassManager;
};

View File

@ -374,6 +374,17 @@ wxString BOARD_ITEM::GetParentAsString() const
}
wxString BOARD_ITEM::GetComponentClassAsString() const
{
if( m_componentClass )
{
return m_componentClass->GetFullName();
}
return wxEmptyString;
}
static struct BOARD_ITEM_DESC
{
BOARD_ITEM_DESC()
@ -413,6 +424,13 @@ static struct BOARD_ITEM_DESC
BOARD_ITEM* item = dynamic_cast<BOARD_ITEM*>( aItem );
return item && item->GetBoard() && !item->GetBoard()->IsFootprintHolder();
} );
// Used only in DRC engine
propMgr.AddProperty( new PROPERTY<BOARD_ITEM, wxString>(
_HKI( "ComponentClass" ), NO_SETTER( BOARD_ITEM, wxString ),
&BOARD_ITEM::GetComponentClassAsString ) )
.SetIsHiddenFromLibraryEditors()
.SetIsHiddenFromPropertiesManager();
}
} _BOARD_ITEM_DESC;

View File

@ -0,0 +1,145 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <utility>
#include <component_class_manager.h>
void COMPONENT_CLASS::AddConstituentClass( COMPONENT_CLASS* componentClass )
{
m_constituentClasses.push_back( componentClass );
}
bool COMPONENT_CLASS::ContainsClassName( const wxString& className ) const
{
if( m_constituentClasses.size() == 0 )
return false;
if( m_constituentClasses.size() == 1 )
return m_name == className;
return std::any_of( m_constituentClasses.begin(), m_constituentClasses.end(),
[&className]( const COMPONENT_CLASS* testClass )
{
return testClass->GetFullName() == className;
} );
}
wxString COMPONENT_CLASS::GetName() const
{
if( m_constituentClasses.size() == 0 )
return wxT( "<None>" );
if( m_constituentClasses.size() == 1 )
return m_name;
wxASSERT( m_constituentClasses.size() >= 2 );
wxString name;
if( m_constituentClasses.size() == 2 )
{
name.Printf( _( "%s and %s" ), m_constituentClasses[0]->GetName(),
m_constituentClasses[1]->GetName() );
}
else if( m_constituentClasses.size() == 3 )
{
name.Printf( _( "%s, %s and %s" ), m_constituentClasses[0]->GetName(),
m_constituentClasses[1]->GetName(), m_constituentClasses[2]->GetName() );
}
else if( m_constituentClasses.size() > 3 )
{
name.Printf( _( "%s, %s and %d more" ), m_constituentClasses[0]->GetName(),
m_constituentClasses[1]->GetName(),
static_cast<int>( m_constituentClasses.size() - 2 ) );
}
return name;
}
bool COMPONENT_CLASS::IsEmpty() const
{
return m_constituentClasses.size() == 0;
}
COMPONENT_CLASS_MANAGER::COMPONENT_CLASS_MANAGER()
{
m_noneClass = std::make_unique<COMPONENT_CLASS>( wxEmptyString );
}
COMPONENT_CLASS*
COMPONENT_CLASS_MANAGER::GetEffectiveComponentClass( std::unordered_set<wxString>& classNames )
{
if( classNames.size() == 0 )
return m_noneClass.get();
auto getOrCreateClass = [this]( const wxString& className )
{
if( !m_classes.count( className ) )
{
std::unique_ptr<COMPONENT_CLASS> newClass =
std::make_unique<COMPONENT_CLASS>( className );
newClass->AddConstituentClass( newClass.get() );
m_classes[className] = std::move( newClass );
}
return m_classes[className].get();
};
if( classNames.size() == 1 )
{
return getOrCreateClass( *classNames.begin() );
}
std::vector<wxString> sortedClassNames( classNames.begin(), classNames.end() );
std::sort( sortedClassNames.begin(), sortedClassNames.end(),
[]( const wxString& str1, const wxString& str2 )
{
return str1.Cmp( str2 ) < 0;
} );
wxString fullName = sortedClassNames[0];
for( std::size_t i = 1; i < sortedClassNames.size(); ++i )
{
fullName += ",";
fullName += sortedClassNames[i];
}
if( !m_effectiveClasses.count( fullName ) )
{
std::unique_ptr<COMPONENT_CLASS> effClass = std::make_unique<COMPONENT_CLASS>( fullName );
for( const wxString& className : sortedClassNames )
{
effClass->AddConstituentClass( getOrCreateClass( className ) );
}
m_effectiveClasses[fullName] = std::move( effClass );
}
return m_effectiveClasses[fullName].get();
}

View File

@ -0,0 +1,100 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PCBNEW_COMPONENT_CLASS_MANAGER_H
#define PCBNEW_COMPONENT_CLASS_MANAGER_H
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <wx/string.h>
#include <board_item.h>
/*
* A lightweight representation of a component class. The membership within
* m_consituentClasses allows determination of the type of class this is:
*
* m_constituentClasses.size() == 0: This is a null class (no assigment).
* m_name is empty.
* m_constituentClasses.size() == 1: This is an atomic class. The constituent class
* pointer refers to itself. m_name contains the name of the atomic class
* m_constituentClasses.size() > 1: This is a composite class. The constituent class
* pointers refer to all atomic members. m_name contains a comma-delimited list of
* all atomic member class names.
*/
class COMPONENT_CLASS
{
public:
COMPONENT_CLASS( const wxString& name ) : m_name( name ) {}
/// Fetches the display name of this component class
wxString GetName() const;
/// Fetches the full name of this component class
const wxString& GetFullName() const { return m_name; }
/// Adds a constituent component class to an effective component class
void AddConstituentClass( COMPONENT_CLASS* componentClass );
/// Determines if this (effective) component class contains a specific sub-class
bool ContainsClassName( const wxString& className ) const;
/// Determines if this (effective) component class is empty (i.e. no classes defined)
bool IsEmpty() const;
/// Fetches a vector of the constituent classes for this (effective) class
const std::vector<COMPONENT_CLASS*>& GetConstituentClasses() const
{
return m_constituentClasses;
}
private:
/// The full name of the component class
wxString m_name;
/// The COMPONENT_CLASS objects contributing to this complete component class
std::vector<COMPONENT_CLASS*> m_constituentClasses;
};
class COMPONENT_CLASS_MANAGER
{
public:
COMPONENT_CLASS_MANAGER();
/// @brief Gets an effective component class for the given constituent class names
/// @param classes The names of the constituent component classes
/// @return Effective COMPONENT_CLASS object
COMPONENT_CLASS* GetEffectiveComponentClass( std::unordered_set<wxString>& classNames );
/// Returns the unassigned component class
const COMPONENT_CLASS* GetNoneComponentClass() const { return m_noneClass.get(); }
protected:
/// All individual component classes
std::unordered_map<wxString, std::unique_ptr<COMPONENT_CLASS>> m_classes;
/// Generated effective component classes
std::unordered_map<wxString, std::unique_ptr<COMPONENT_CLASS>> m_effectiveClasses;
/// The class to represent an unassigned component class
std::unique_ptr<COMPONENT_CLASS> m_noneClass;
};
#endif

View File

@ -1584,6 +1584,11 @@ void FOOTPRINT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_I
aList.emplace_back( _( "Rotation" ), wxString::Format( wxT( "%.4g" ),
GetOrientation().AsDegrees() ) );
if( m_componentClass )
{
aList.emplace_back( _( "Component Class" ), m_componentClass->GetName() );
}
msg.Printf( _( "Footprint: %s" ), m_fpid.GetUniStringLibId() );
msg2.Printf( _( "3D-Shape: %s" ), m_3D_Drawings.empty() ? _( "<none>" )
: m_3D_Drawings.front().m_Filename );

View File

@ -147,6 +147,7 @@ FOOTPRINT* BOARD_NETLIST_UPDATER::addNewFootprint( COMPONENT* aComponent )
}
FOOTPRINT* footprint = m_frame->LoadFootprint( aComponent->GetFPID() );
footprint->SetComponentClass( m_board->GetComponentClassManager().GetNoneComponentClass() );
if( footprint == nullptr )
{
@ -201,6 +202,40 @@ FOOTPRINT* BOARD_NETLIST_UPDATER::addNewFootprint( COMPONENT* aComponent )
}
void BOARD_NETLIST_UPDATER::updateComponentClass( FOOTPRINT* aFootprint, COMPONENT* aNewComponent )
{
// Get the existing component class
wxString curClassName;
if( const COMPONENT_CLASS* curClass = aFootprint->GetComponentClass() )
curClassName = curClass->GetFullName();
// Calculate the new component class
COMPONENT_CLASS* newClass = m_board->GetComponentClassManager().GetEffectiveComponentClass(
aNewComponent->GetComponentClassNames() );
wxString newClassName = newClass->GetFullName();
if( curClassName == newClassName )
return;
wxString msg;
if( m_isDryRun )
{
msg.Printf( _( "Change %s component class from %s to %s." ), aFootprint->GetReference(),
curClassName, newClassName );
}
else
{
aFootprint->SetComponentClass( newClass );
msg.Printf( _( "Changed %s component class from %s to %s." ), aFootprint->GetReference(),
curClassName, newClassName );
}
m_reporter->Report( msg, RPT_SEVERITY_ACTION );
}
FOOTPRINT* BOARD_NETLIST_UPDATER::replaceFootprint( NETLIST& aNetlist, FOOTPRINT* aFootprint,
COMPONENT* aNewComponent )
{
@ -395,8 +430,11 @@ bool BOARD_NETLIST_UPDATER::updateFootprintParameters( FOOTPRINT* aPcbFootprint,
for( PCB_FIELD* field : aPcbFootprint->GetFields() )
{
// These fields are individually checked above
if( field->IsReference() || field->IsValue() || field->IsFootprint() )
if( field->IsReference() || field->IsValue() || field->IsFootprint()
|| field->IsComponentClass() )
{
continue;
}
fpFieldsAsMap[field->GetName()] = field->GetText();
}
@ -407,6 +445,9 @@ bool BOARD_NETLIST_UPDATER::updateFootprintParameters( FOOTPRINT* aPcbFootprint,
compFields.erase( GetCanonicalFieldName( VALUE_FIELD ) );
compFields.erase( GetCanonicalFieldName( FOOTPRINT_FIELD ) );
// Remove any component class fields - these are not editable in the pcb editor
compFields.erase( wxT( "Component Class" ) );
// Fields are stored as an ordered map, but we don't (yet) support reordering
// the footprint fields to match the symbol, so we manually check the fields
// in the order they are stored in the symbol.
@ -1214,6 +1255,7 @@ bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist )
updateFootprintParameters( tmp, component );
updateComponentPadConnections( tmp, component );
updateComponentClass( tmp, component );
}
matchCount++;
@ -1236,6 +1278,7 @@ bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist )
updateFootprintParameters( footprint, component );
updateComponentPadConnections( footprint, component );
updateComponentClass( footprint, component );
}
}
else if( matchCount > 1 )

View File

@ -111,6 +111,8 @@ private:
bool updateComponentPadConnections( FOOTPRINT* aFootprint, COMPONENT* aNewComponent );
void updateComponentClass( FOOTPRINT* aFootprint, COMPONENT* aNewComponent );
void cacheCopperZoneConnections();
bool updateCopperZoneNets( NETLIST& aNetlist );

View File

@ -280,13 +280,14 @@ void KICAD_NETLIST_PARSER::parseNet()
void KICAD_NETLIST_PARSER::parseComponent()
{
/* Parses a section like
/* Parses a section like
* (comp (ref P1)
* (value DB25FEMALE)
* (footprint DB25FC)
* (libsource (lib conn) (part DB25))
* (property (name PINCOUNT) (value 25))
* (sheetpath (names /) (tstamps /))
* (component_classes (class (name "CLASS")))
* (tstamp 68183921-93a5-49ac-91b0-49d05a0e1647))
*
* other fields (unused) are skipped
@ -305,6 +306,7 @@ void KICAD_NETLIST_PARSER::parseComponent()
std::vector<KIID> uuids;
std::map<wxString, wxString> properties;
nlohmann::ordered_map<wxString, wxString> fields;
std::unordered_set<wxString> componentClasses;
// The token comp was read, so the next data is (ref P1)
while( (token = NextTok() ) != T_RIGHT )
@ -469,6 +471,24 @@ void KICAD_NETLIST_PARSER::parseComponent()
break;
case T_component_classes:
{
while( ( token = NextTok() ) != T_RIGHT )
{
if( token != T_LEFT )
Expecting( T_LEFT );
if( ( token = NextTok() ) != T_class )
Expecting( T_class );
NeedSYMBOLorNUMBER();
componentClasses.insert( From_UTF8( CurText() ) );
NeedRIGHT();
}
break;
}
default:
// Skip not used data (i.e all other tokens)
skipCurrent();
@ -491,6 +511,7 @@ void KICAD_NETLIST_PARSER::parseComponent()
component->SetProperties( properties );
component->SetFields( fields );
component->SetHumanReadablePath( humanSheetPath );
component->SetComponentClassNames( componentClasses );
m_netlist->AddComponent( component );
}

View File

@ -29,6 +29,7 @@
#include <boost/ptr_container/ptr_vector.hpp>
#include <wx/arrstr.h>
#include <nlohmann/json.hpp>
#include <unordered_set>
#include <lib_id.h>
#include <footprint.h>
@ -175,6 +176,13 @@ public:
void SetHumanReadablePath( const wxString& aPath ) { m_humanReadablePath = aPath; }
const wxString& GetHumanReadablePath() const { return m_humanReadablePath; }
void SetComponentClassNames( const std::unordered_set<wxString>& aClassNames )
{
m_componentClassNames = aClassNames;
}
std::unordered_set<wxString>& GetComponentClassNames() { return m_componentClassNames; }
private:
std::vector<COMPONENT_NET> m_nets; ///< list of nets shared by the component pins
@ -215,6 +223,9 @@ private:
/// Component-specific user fields found in the netlist.
nlohmann::ordered_map<wxString, wxString> m_fields;
/// Component classes for this footprint
std::unordered_set<wxString> m_componentClassNames;
static COMPONENT_NET m_emptyNet;
};

View File

@ -2484,6 +2484,7 @@ void PCB_EDIT_FRAME::ExchangeFootprint( FOOTPRINT* aExisting, FOOTPRINT* aNew,
aNew->SetSheetfile( aExisting->GetSheetfile() );
aNew->SetSheetname( aExisting->GetSheetname() );
aNew->SetFilters( aExisting->GetFilters() );
aNew->SetComponentClass( aExisting->GetComponentClass() );
aCommit.Remove( aExisting );
aCommit.Add( aNew );

Some files were not shown because too many files have changed in this diff Show More