Don't save netcodes to files.

They're an internal implementation detail.
This commit is contained in:
Jeff Young
2025-10-29 12:33:40 +00:00
parent 5e41d63bd0
commit b335ce6e2c
7 changed files with 112 additions and 300 deletions
-7
View File
@@ -126,9 +126,6 @@ void CLIPBOARD_IO::SaveSelection( const PCB_SELECTION& aSelected, bool isFootpri
if( aSelected.HasReferencePoint() )
refPoint = aSelected.GetReferencePoint();
// Prepare net mapping that assures that net codes saved in a file are consecutive integers
m_mapping->SetBoard( m_board );
auto deleteUnselectedCells =
[]( PCB_TABLE* aTable )
{
@@ -333,7 +330,6 @@ void CLIPBOARD_IO::SaveSelection( const PCB_SELECTION& aSelected, bool isFootpri
m_formatter.Quotew( GetMajorMinorVersion() ).c_str() );
formatBoardLayers( m_board );
formatNetInformation( m_board );
for( EDA_ITEM* item : aSelected )
{
@@ -485,9 +481,6 @@ void CLIPBOARD_IO::SaveBoard( const wxString& aFileName, BOARD* aBoard,
m_board = aBoard; // after init()
// Prepare net mapping that assures that net codes saved in a file are consecutive integers
m_mapping->SetBoard( aBoard );
m_formatter.Print( "(kicad_pcb (version %d) (generator \"pcbnew\") (generator_version %s)",
SEXPR_BOARD_FILE_VERSION,
m_formatter.Quotew( GetMajorMinorVersion() ).c_str() );
-118
View File
@@ -192,124 +192,6 @@ private:
};
class NETINFO_MAPPING
{
public:
NETINFO_MAPPING()
{
m_board = nullptr;
}
/**
* Set a BOARD object that is used to prepare the net code map.
*/
void SetBoard( const BOARD* aBoard )
{
m_board = aBoard;
Update();
}
/**
* Prepare a mapping for net codes so they can be saved as consecutive numbers.
*
* To retrieve a mapped net code, use translateNet() function after calling this.
*/
void Update();
/**
* Translate net number according to the map prepared by Update() function.
*
* It allows one to have items stored with consecutive net codes.
*
* @param aNetCode is an old net code.
* @return Net code that follows the mapping.
*/
int Translate( int aNetCode ) const;
/// Wrapper class, so you can iterate through NETINFO_ITEM*s, not
/// std::pair<int/wxString, NETINFO_ITEM*>
class iterator
{
public:
iterator( std::map<int, int>::const_iterator aIter, const NETINFO_MAPPING* aMapping ) :
m_iterator( aIter ), m_mapping( aMapping )
{
}
/// pre-increment operator
const iterator& operator++()
{
++m_iterator;
return *this;
}
/// post-increment operator
iterator operator++( int )
{
iterator ret = *this;
++m_iterator;
return ret;
}
NETINFO_ITEM* operator*() const;
NETINFO_ITEM* operator->() const;
bool operator!=( const iterator& aOther ) const
{
return m_iterator != aOther.m_iterator;
}
bool operator==( const iterator& aOther ) const
{
return m_iterator == aOther.m_iterator;
}
private:
std::map<int, int>::const_iterator m_iterator;
const NETINFO_MAPPING* m_mapping;
};
/**
* Return iterator to the first entry in the mapping.
*
* @note The entry is a pointer to the original NETINFO_ITEM object, this it contains
* not mapped net code.
*/
iterator begin() const
{
return iterator( m_netMapping.begin(), this );
}
/**
* Return iterator to the last entry in the mapping.
*
* @note The entry is a pointer to the original NETINFO_ITEM object, this it contains
* not mapped net code.
*/
iterator end() const
{
return iterator( m_netMapping.end(), this );
}
/**
* @return Number of mapped nets (i.e. not empty nets for a given BOARD object).
*/
int GetSize() const
{
return m_netMapping.size();
}
private:
const BOARD* m_board; ///< Board for which mapping is prepared
std::map<int, int> m_netMapping; ///< Map that allows saving net codes with consecutive
///< numbers (for compatibility reasons)
};
#if 0
// waiting for swig to support std::unordered_map, see
// http://www.swig.org/Doc3.0/CPlusPlus11.html
-70
View File
@@ -275,75 +275,5 @@ int NETINFO_LIST::getFreeNetCode()
}
int NETINFO_MAPPING::Translate( int aNetCode ) const
{
std::map<int, int>::const_iterator value = m_netMapping.find( aNetCode );
if( value != m_netMapping.end() )
return value->second;
// There was no entry for the given net code
return aNetCode;
}
void NETINFO_MAPPING::Update()
{
// Collect all the used nets
std::set<int> nets;
// Be sure that the unconnected gets 0 and is mapped as 0
nets.insert( 0 );
// Zones
for( ZONE* zone : m_board->Zones() )
nets.insert( zone->GetNetCode() );
// Tracks
for( PCB_TRACK* track : m_board->Tracks() )
nets.insert( track->GetNetCode() );
for( BOARD_ITEM* item : m_board->Drawings() )
{
if( item->Type() != PCB_SHAPE_T )
continue;
PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
if( shape->GetNetCode() > 0 )
nets.insert( shape->GetNetCode() );
}
// footprints/pads
for( FOOTPRINT* footprint : m_board->Footprints() )
{
for( PAD* pad : footprint->Pads() )
nets.insert( pad->GetNetCode() );
}
// Prepare the new mapping
m_netMapping.clear();
// Now the nets variable stores all the used net codes (not only for pads) and we are ready to
// assign new consecutive net numbers
int newNetCode = 0;
for( auto net : nets )
m_netMapping[net] = newNetCode++;
}
NETINFO_ITEM* NETINFO_MAPPING::iterator::operator*() const
{
return m_mapping->m_board->FindNet( m_iterator->first );
}
NETINFO_ITEM* NETINFO_MAPPING::iterator::operator->() const
{
return m_mapping->m_board->FindNet( m_iterator->first );
}
const int NETINFO_LIST::UNCONNECTED = 0;
const int NETINFO_LIST::ORPHANED = -1;
@@ -310,9 +310,6 @@ void PCB_IO_KICAD_SEXPR::SaveBoard( const wxString& aFileName, BOARD* aBoard,
else
m_board->GetEmbeddedFiles()->ClearEmbeddedFonts();
// Prepare net mapping that assures that net codes saved in a file are consecutive integers
m_mapping->SetBoard( aBoard );
PRETTIFIED_FILE_OUTPUTFORMATTER formatter( aFileName );
m_out = &formatter; // no ownership
@@ -691,20 +688,6 @@ void PCB_IO_KICAD_SEXPR::formatBoardLayers( const BOARD* aBoard ) const
}
void PCB_IO_KICAD_SEXPR::formatNetInformation( const BOARD* aBoard ) const
{
for( NETINFO_ITEM* net : *m_mapping )
{
if( net == nullptr ) // Skip not actually existing nets (orphan nets)
continue;
m_out->Print( "(net %d %s)",
m_mapping->Translate( net->GetNetCode() ),
m_out->Quotew( net->GetNetname() ).c_str() );
}
}
void PCB_IO_KICAD_SEXPR::formatProperties( const BOARD* aBoard ) const
{
for( const std::pair<const wxString, wxString>& prop : aBoard->GetProperties() )
@@ -728,9 +711,6 @@ void PCB_IO_KICAD_SEXPR::formatHeader( const BOARD* aBoard ) const
// Properties
formatProperties( aBoard );
// Save net codes and names
formatNetInformation( aBoard );
}
@@ -1078,7 +1058,7 @@ void PCB_IO_KICAD_SEXPR::format( const PCB_SHAPE* aShape ) const
}
if( aShape->GetNetCode() > 0 )
m_out->Print( "(net %d)", m_mapping->Translate( aShape->GetNetCode() ) );
m_out->Print( "(net %s)", m_out->Quotew( aShape->GetNetname() ).c_str() );
KICAD_FORMAT::FormatUuid( m_out, aShape->m_Uuid );
m_out->Print( ")" );
@@ -1731,11 +1711,8 @@ void PCB_IO_KICAD_SEXPR::format( const PAD* aPad ) const
formatCornerProperties( PADSTACK::ALL_LAYERS );
// Unconnected pad is default net so don't save it.
if( !( m_ctl & CTL_OMIT_PAD_NETS ) && aPad->GetNetCode() != NETINFO_LIST::UNCONNECTED )
{
m_out->Print( "(net %d %s)", m_mapping->Translate( aPad->GetNetCode() ),
m_out->Quotew( aPad->GetNetname() ).c_str() );
}
if( !( m_ctl & CTL_OMIT_PAD_NETS ) && aPad->GetNetCode() > 0 )
m_out->Print( "(net %s)", m_out->Quotew( aPad->GetNetname() ).c_str() );
// Pin functions and types are closely related to nets, so if CTL_OMIT_NETS is set, omit
// them as well (for instance when saved from library editor).
@@ -2637,7 +2614,7 @@ void PCB_IO_KICAD_SEXPR::format( const PCB_TRACK* aTrack ) const
}
}
m_out->Print( "(net %d)", m_mapping->Translate( aTrack->GetNetCode() ) );
m_out->Print( "(net %s)", m_out->Quotew( aTrack->GetNetname() ).c_str() );
KICAD_FORMAT::FormatUuid( m_out, aTrack->m_Uuid );
m_out->Print( ")" );
@@ -2646,16 +2623,10 @@ void PCB_IO_KICAD_SEXPR::format( const PCB_TRACK* aTrack ) const
void PCB_IO_KICAD_SEXPR::format( const ZONE* aZone ) const
{
// Save the NET info.
// For keepout and non copper zones, net code and net name are irrelevant
// so be sure a dummy value is stored, just for ZONE compatibility
// (perhaps netcode and netname should be not stored)
m_out->Print( "(zone" );
bool has_no_net = aZone->GetIsRuleArea() || !aZone->IsOnCopperLayer();
m_out->Print( "(zone (net %d) (net_name %s)",
has_no_net ? 0 : m_mapping->Translate( aZone->GetNetCode() ),
m_out->Quotew( has_no_net ? wxString( wxT("") ) : aZone->GetNetname() ).c_str() );
if( aZone->IsOnCopperLayer() && !aZone->GetIsRuleArea() && aZone->GetNetCode() > 0 )
m_out->Print( "(net %s)", m_out->Quotew( aZone->GetNetname() ).c_str() );
if( aZone->IsLocked() )
KICAD_FORMAT::FormatBool( m_out, "locked", true );
@@ -2898,8 +2869,7 @@ void PCB_IO_KICAD_SEXPR::format( const ZONE_LAYER_PROPERTIES& aZoneLayerProperti
PCB_IO_KICAD_SEXPR::PCB_IO_KICAD_SEXPR( int aControlFlags ) : PCB_IO( wxS( "KiCad" ) ),
m_cache( nullptr ),
m_ctl( aControlFlags ),
m_mapping( new NETINFO_MAPPING() )
m_ctl( aControlFlags )
{
init( nullptr );
m_out = &m_sf;
@@ -2909,7 +2879,6 @@ PCB_IO_KICAD_SEXPR::PCB_IO_KICAD_SEXPR( int aControlFlags ) : PCB_IO( wxS( "KiCa
PCB_IO_KICAD_SEXPR::~PCB_IO_KICAD_SEXPR()
{
delete m_cache;
delete m_mapping;
}
@@ -44,7 +44,6 @@ class BOARD_ITEM;
class FP_CACHE;
class LSET;
class PCB_IO_KICAD_SEXPR_PARSER;
class NETINFO_MAPPING;
class BOARD_DESIGN_SETTINGS;
class PCB_DIMENSION_BASE;
class PCB_POINT;
@@ -196,7 +195,8 @@ class PCB_IO_KICAD_SEXPR; // forward decl
//#define SEXPR_BOARD_FILE_VERSION 20250909 // footprint unit metadata (units/pins)
//#define SEXPR_BOARD_FILE_VERSION 20250914 // Add support for PCB_BARCODE objects
//#define SEXPR_BOARD_FILE_VERSION 20250926 // Split via types into blind/buried/through
#define SEXPR_BOARD_FILE_VERSION 20251027 // Store pad-to-die delays with correct scaling
//#define SEXPR_BOARD_FILE_VERSION 20251027 // Store pad-to-die delays with correct scaling
#define SEXPR_BOARD_FILE_VERSION 20251028 // Stop writing netcodes; they're an internal implementation detail
#define BOARD_FILE_HOST_VERSION 20200825 ///< Earlier files than this include the host tag
#define LEGACY_ARC_FORMATTING 20210925 ///< These were the last to use old arc formatting
@@ -432,9 +432,6 @@ protected:
/// formats the board layer information
void formatBoardLayers( const BOARD* aBoard ) const;
/// formats the Nets and Netclasses
void formatNetInformation( const BOARD* aBoard ) const;
/// formats the Nets and Netclasses
void formatProperties( const BOARD* aBoard ) const;
@@ -499,8 +496,6 @@ protected:
STRING_FORMATTER m_sf;
OUTPUTFORMATTER* m_out; ///< output any Format()s to this, no ownership
int m_ctl;
NETINFO_MAPPING* m_mapping; ///< mapping for net codes, so only not empty net codes
///< are stored with consecutive integers as net codes
std::function<bool( wxString aTitle, int aIcon, wxString aMsg, wxString aAction )> m_queryUserCallback;
};
@@ -290,6 +290,54 @@ bool PCB_IO_KICAD_SEXPR_PARSER::parseMaybeAbsentBool( bool aDefaultValue )
}
void PCB_IO_KICAD_SEXPR_PARSER::parseNet( BOARD_CONNECTED_ITEM* aItem )
{
int token = NextTok();
// Legacy files (pre-10.0) will have a netcode instead of a netname. This netcode
// is authoratative (though may be mapped by getNetCode() to prevent collisions).
if( IsNumber( token ) )
{
if( !aItem->SetNetCode( std::max( 0, getNetCode( parseInt() ) ), /* aNoAssert */ true ) )
{
wxLogError( _( "Invalid net ID in\nfile: %s;\nline: %d\noffset: %d." ),
CurSource(), CurLineNumber(), CurOffset() );
}
NeedRIGHT();
return;
}
if( !IsSymbol( token ) )
{
Expecting( "net name" );
return;
}
if( m_board )
{
wxString netName( FromUTF8() );
// Convert overbar syntax from `~...~` to `~{...}`. These were left out of the
// first merge so the version is a bit later.
if( m_requiredVersion < 20210606 )
netName = ConvertToNewOverbarNotation( netName );
NETINFO_ITEM* netinfo = m_board->FindNet( netName );
if( !netinfo )
{
netinfo = new NETINFO_ITEM( m_board, netName );
m_board->Add( netinfo, ADD_MODE::INSERT, true );
}
aItem->SetNet( netinfo );
}
NeedRIGHT();
}
wxString PCB_IO_KICAD_SEXPR_PARSER::GetRequiredVersion()
{
int year, month, day;
@@ -3269,13 +3317,7 @@ PCB_SHAPE* PCB_IO_KICAD_SEXPR_PARSER::parsePCB_SHAPE( BOARD_ITEM* aParent )
break;
case T_net:
if( !shape->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
{
wxLogError( _( "Invalid net ID in\nfile: '%s'\nline: %d\noffset: %d." ),
CurSource(), CurLineNumber(), CurOffset() );
}
NeedRIGHT();
parseNet( shape.get() );
break;
default:
@@ -5422,6 +5464,7 @@ PAD* PCB_IO_KICAD_SEXPR_PARSER::parsePAD( FOOTPRINT* aParent )
VECTOR2I sz;
VECTOR2I pt;
bool foundNet = false;
bool foundNetcode = false;
std::unique_ptr<PAD> pad = std::make_unique<PAD>( aParent );
@@ -5626,16 +5669,29 @@ PAD* PCB_IO_KICAD_SEXPR_PARSER::parsePAD( FOOTPRINT* aParent )
case T_net:
foundNet = true;
if( ! pad->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
token = NextTok();
// Legacy files (pre-10.0) will have a netcode written before the netname. This netcode
// is authoratative (though may be mapped by getNetCode() to prevent collisions).
if( IsNumber( token ) )
{
wxLogError( _( "Invalid net ID in\nfile: %s\nline: %d offset: %d" ),
CurSource(), CurLineNumber(), CurOffset() );
if( !pad->SetNetCode( getNetCode( parseInt() ), /* aNoAssert */ true ) )
{
wxLogError( _( "Invalid net ID in\nfile: %s\nline: %d offset: %d" ),
CurSource(), CurLineNumber(), CurOffset() );
}
foundNetcode = true;
token = NextTok();
}
NeedSYMBOLorNUMBER();
if( !IsSymbol( token ) )
{
Expecting( "net name" );
break;
}
// Test validity of the netname in file for netcodes expected having a net name
if( m_board && pad->GetNetCode() > 0 )
if( m_board )
{
wxString netName( FromUTF8() );
@@ -5644,11 +5700,26 @@ PAD* PCB_IO_KICAD_SEXPR_PARSER::parsePAD( FOOTPRINT* aParent )
if( m_requiredVersion < 20210606 )
netName = ConvertToNewOverbarNotation( netName );
if( netName != m_board->FindNet( pad->GetNetCode() )->GetNetname() )
if( foundNetcode )
{
pad->SetNetCode( NETINFO_LIST::ORPHANED, /* aNoAssert */ true );
wxLogError( _( "Net name doesn't match ID in\nfile: %s\nline: %d offset: %d" ),
CurSource(), CurLineNumber(), CurOffset() );
if( netName != m_board->FindNet( pad->GetNetCode() )->GetNetname() )
{
pad->SetNetCode( NETINFO_LIST::ORPHANED, /* aNoAssert */ true );
wxLogError( _( "Net name doesn't match ID in\nfile: %s\nline: %d offset: %d" ),
CurSource(), CurLineNumber(), CurOffset() );
}
}
else
{
NETINFO_ITEM* netinfo = m_board->FindNet( netName );
if( !netinfo )
{
netinfo = new NETINFO_ITEM( m_board, netName );
m_board->Add( netinfo, ADD_MODE::INSERT, true );
}
pad->SetNet( netinfo );
}
}
@@ -6743,12 +6814,7 @@ PCB_ARC* PCB_IO_KICAD_SEXPR_PARSER::parseARC()
break;
case T_net:
if( !arc->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
{
wxLogError( _( "Invalid net ID in\nfile: %s\nline: %d\noffset: %d." ),
CurSource(), CurLineNumber(), CurOffset() );
}
NeedRIGHT();
parseNet( arc.get() );
break;
case T_tstamp:
@@ -6844,12 +6910,7 @@ PCB_TRACK* PCB_IO_KICAD_SEXPR_PARSER::parsePCB_TRACK()
break;
case T_net:
if( !track->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
{
wxLogError( _( "Invalid net ID in\nfile: '%s'\nline: %d\noffset: %d." ),
CurSource(), CurLineNumber(), CurOffset() );
}
NeedRIGHT();
parseNet( track.get() );
break;
case T_tstamp:
@@ -6959,13 +7020,7 @@ PCB_VIA* PCB_IO_KICAD_SEXPR_PARSER::parsePCB_VIA()
}
case T_net:
if( !via->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
{
wxLogError( _( "Invalid net ID in\nfile: %s\nline: %d\noffset: %d" ),
CurSource(), CurLineNumber(), CurOffset() );
}
NeedRIGHT();
parseNet( via.get() );
break;
case T_remove_unused_layers:
@@ -7255,7 +7310,7 @@ ZONE* PCB_IO_KICAD_SEXPR_PARSER::parseZONE( BOARD_ITEM_CONTAINER* aParent )
int hatchPitch = ZONE::GetDefaultHatchPitch();
T token;
int tmp;
wxString netnameFromfile; // the zone net name find in file
wxString legacyNetnameFromFile; // the (non-authoratative) zone net name found in a legacy file
// bigger scope since each filled_polygon is concatenated in here
std::map<PCB_LAYER_ID, SHAPE_POLY_SET> pts;
@@ -7289,26 +7344,12 @@ ZONE* PCB_IO_KICAD_SEXPR_PARSER::parseZONE( BOARD_ITEM_CONTAINER* aParent )
switch( token )
{
case T_net:
// Init the net code only, not the netname, to be sure
// the zone net name is the name read in file.
// (When mismatch, the user will be prompted in DRC, to fix the actual name)
tmp = getNetCode( parseInt( "net number" ) );
if( tmp < 0 )
tmp = 0;
if( !zone->SetNetCode( tmp, /* aNoAssert */ true ) )
{
wxLogError( _( "Invalid net ID in\nfile: %s;\nline: %d\noffset: %d." ),
CurSource(), CurLineNumber(), CurOffset() );
}
NeedRIGHT();
parseNet( zone.get() );
break;
case T_net_name:
NeedSYMBOLorNUMBER();
netnameFromfile = FromUTF8();
legacyNetnameFromFile = FromUTF8();
NeedRIGHT();
break;
@@ -7939,23 +7980,22 @@ ZONE* PCB_IO_KICAD_SEXPR_PARSER::parseZONE( BOARD_ITEM_CONTAINER* aParent )
if( !zone_has_net )
zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
// Ensure the zone net name is valid, and matches the net code, for copper zones
if( zone_has_net
&& ( !zone->GetNet() || zone->GetNet()->GetNetname() != netnameFromfile ) )
// In legacy files, ensure the zone net name is valid, and matches the net code
if( !legacyNetnameFromFile.IsEmpty() && zone->GetNetname() != legacyNetnameFromFile )
{
// Can happens which old boards, with nonexistent nets ...
// or after being edited by hand
// We try to fix the mismatch.
NETINFO_ITEM* net = m_board->FindNet( netnameFromfile );
NETINFO_ITEM* net = m_board->FindNet( legacyNetnameFromFile );
if( net ) // An existing net has the same net name. use it for the zone
{
zone->SetNetCode( net->GetNetCode() );
}
else // Not existing net: add a new net to keep trace of the zone netname
else // Not existing net: add a new net to keep track of the zone netname
{
int newnetcode = m_board->GetNetCount();
net = new NETINFO_ITEM( m_board, netnameFromfile, newnetcode );
net = new NETINFO_ITEM( m_board, legacyNetnameFromFile, newnetcode );
m_board->Add( net, ADD_MODE::INSERT, true );
// Store the new code mapping
@@ -48,6 +48,7 @@
class PCB_ARC;
class BOARD;
class BOARD_ITEM;
class BOARD_CONNECTED_ITEM;
class BOARD_ITEM_CONTAINER;
class PAD;
class BOARD_DESIGN_SETTINGS;
@@ -397,6 +398,8 @@ private:
std::pair<std::optional<bool>, std::optional<bool>>
parseFrontBackOptBool( bool aLegacy = false );
void parseNet( BOARD_CONNECTED_ITEM* aItem );
/*
* @return if m_appendToExisting, returns new KIID(), otherwise returns CurStr() as KIID.
*/