KiCad PCB EDA Suite
Loading...
Searching...
No Matches
netinfo_list.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include "netinfo.h"
21
22#include <wx/log.h>
23
24#include <board.h>
25#include <board_commit.h>
26#include <footprint.h>
27#include <macros.h>
28#include <pad.h>
29#include <pcb_shape.h>
30#include <pcb_track.h>
31#include <reporter.h>
32#include <string_utils.h>
33#include <trace_helpers.h>
34#include <zone.h>
35#include <unordered_map>
36
37
38// Constructor and destructor
40 m_parent( aParent ),
41 m_newNetCode( 0 )
42{
43 // Make sure that the unconnected net has number 0
44 AppendNet( new NETINFO_ITEM( aParent, wxEmptyString, 0 ) );
45}
46
47
52
53
55{
56 NETNAMES_MAP::iterator it, itEnd;
57
58 for( it = m_netNames.begin(), itEnd = m_netNames.end(); it != itEnd; ++it )
59 delete it->second;
60
61 detachAll();
62}
63
64
66{
67 m_netNames.clear();
68 m_netCodes.clear();
69 m_newNetCode = 0;
70}
71
72
74{
75 NETCODES_MAP::const_iterator result = m_netCodes.find( aNetCode );
76
77 if( result != m_netCodes.end() )
78 return (*result).second;
79
80 return nullptr;
81}
82
83
84NETINFO_ITEM* NETINFO_LIST::GetNetItem( const wxString& aNetName ) const
85{
86 NETNAMES_MAP::const_iterator result = m_netNames.find( aNetName );
87
88 if( result != m_netNames.end() )
89 return (*result).second;
90
91 return nullptr;
92}
93
94
96{
97 bool removed = false;
98
99 for( NETCODES_MAP::iterator i = m_netCodes.begin(); i != m_netCodes.end(); ++i )
100 {
101 if ( i->second == aNet )
102 {
103 removed = true;
104 m_netCodes.erase(i);
105 break;
106 }
107 }
108
109 for( NETNAMES_MAP::iterator i = m_netNames.begin(); i != m_netNames.end(); ++i )
110 {
111 if ( i->second == aNet )
112 {
113 wxASSERT_MSG( removed, wxT( "NETINFO_LIST::RemoveNet: target net found in m_netNames "
114 "but not m_netCodes!" ) );
115 m_netNames.erase(i);
116 break;
117 }
118 }
119
120 if( removed )
121 {
122 m_newNetCode = std::min( m_newNetCode, aNet->m_netCode - 1 );
124 }
125}
126
127
129{
130 NETCODES_MAP existingNets = m_netCodes;
131 std::vector<NETINFO_ITEM*> unusedNets;
132
133 m_netCodes.clear();
134 m_netNames.clear();
135
136 for( const auto& [ netCode, netInfo ] : existingNets )
137 {
138 if( netInfo->IsCurrent() )
139 {
140 m_netNames.insert( std::make_pair( netInfo->GetNetname(), netInfo ) );
141 m_netCodes.insert( std::make_pair( netCode, netInfo ) );
142 }
143 else
144 {
146
147 if( aCommit )
148 aCommit->Removed( netInfo );
149 }
150 }
151}
152
153
155{
156 // if there is a net with such name then just assign the correct number
157 NETINFO_ITEM* sameName = GetNetItem( aNewElement->GetNetname() );
158
159 if( sameName != nullptr )
160 {
161 aNewElement->m_netCode = sameName->GetNetCode();
162
163 return;
164 }
165 else if( aNewElement->m_netCode != (int) m_netCodes.size() || aNewElement->m_netCode < 0 )
166 {
167 // be sure that net codes are consecutive
168 // negative net code means that it has to be auto assigned
169 aNewElement->m_netCode = getFreeNetCode();
170 }
171
172 // net names & codes are supposed to be unique
173 assert( GetNetItem( aNewElement->GetNetname() ) == nullptr );
174 assert( GetNetItem( aNewElement->GetNetCode() ) == nullptr );
175
176 // add an entry for fast look up by a net name using a map
177 m_netNames.insert( std::make_pair( aNewElement->GetNetname(), aNewElement ) );
178 m_netCodes.insert( std::make_pair( aNewElement->GetNetCode(), aNewElement ) );
179
181}
182
183
185{
186 // Preserve any parsed net-chain names and terminal pad UUIDs before clearing. The GUI load
187 // path calls BuildListOfNets() after the board file is parsed (see files.cpp) which was
188 // unintentionally wiping the m_netChain field set by the (net_chains ...) section. Cache and
189 // restore them so persisted chains survive the rebuild.
190 std::unordered_map<int, wxString> preservedNetChains;
191 std::unordered_map<int, KIID> preservedPad0;
192 std::unordered_map<int, KIID> preservedPad1;
193
194 preservedNetChains.reserve( GetNetCount() );
195 preservedPad0.reserve( GetNetCount() );
196 preservedPad1.reserve( GetNetCount() );
197
198 for( NETINFO_ITEM* net : *this )
199 {
200 preservedNetChains[ net->GetNetCode() ] = net->GetNetChain();
201 preservedPad0[ net->GetNetCode() ] = net->GetTerminalPadUuid( 0 );
202 preservedPad1[ net->GetNetCode() ] = net->GetTerminalPadUuid( 1 );
203 }
204
205 // Restore the initial state of NETINFO_ITEMs (except chains & terminal pad UUIDs which we reapply)
206 for( NETINFO_ITEM* net : *this )
207 net->Clear();
208
209 for( NETINFO_ITEM* net : *this )
210 {
211 auto it = preservedNetChains.find( net->GetNetCode() );
212 if( it != preservedNetChains.end() )
213 net->SetNetChain( it->second );
214
215 auto ip0 = preservedPad0.find( net->GetNetCode() );
216 if( ip0 != preservedPad0.end() )
217 net->SetTerminalPadUuid( 0, ip0->second );
218
219 auto ip1 = preservedPad1.find( net->GetNetCode() );
220 if( ip1 != preservedPad1.end() )
221 net->SetTerminalPadUuid( 1, ip1->second );
222 }
223
224 m_parent->SynchronizeNetsAndNetClasses( false );
225 m_parent->SetAreasNetCodesFromNetNames();
226}
227
228
230{
231 std::map<wxString, std::vector<wxString>> shortNameMap;
232
233 for( NETINFO_ITEM* net : *this )
234 shortNameMap[net->m_shortNetname].push_back( net->m_netname );
235
236 for( NETINFO_ITEM* net : *this )
237 {
238 if( shortNameMap[net->m_shortNetname].size() == 1 )
239 {
241 }
242 else
243 {
244 wxArrayString parts = wxSplit( net->m_netname, '/' );
245 std::vector<wxArrayString> aggregateParts;
246 std::optional<size_t> firstNonCommon;
247
248 for( const wxString& longName : shortNameMap[net->m_shortNetname] )
249 aggregateParts.push_back( wxSplit( longName, '/' ) );
250
251 for( size_t ii = 0; ii < parts.size() && !firstNonCommon; ++ii )
252 {
253 for( const wxArrayString& otherParts : aggregateParts )
254 {
255 if( ii < otherParts.size() && otherParts[ii] == parts[ii] )
256 continue;
257
258 firstNonCommon = ii;
259 break;
260 }
261 }
262
263 if( firstNonCommon.value_or( 0 ) > 0 && firstNonCommon.value() < parts.size() )
264 {
265 wxString disambiguatedName;
266
267 for( size_t ii = firstNonCommon.value(); ii < parts.size(); ++ii )
268 {
269 if( !disambiguatedName.IsEmpty() )
270 disambiguatedName += wxS( "/" );
271
272 disambiguatedName += parts[ii];
273 }
274
275 net->m_displayNetname = UnescapeString( disambiguatedName );
276 }
277 else
278 {
280 }
281 }
282 }
283
285}
286
287
288#if defined(DEBUG)
289void NETINFO_LIST::Show() const
290{
291 int i = 0;
292 NETNAMES_MAP::const_iterator it, itEnd;
293
294 for( it = m_netNames.begin(), itEnd = m_netNames.end(); it != itEnd; ++it )
295 {
296 wxLogDebug( wxT( "[%d]: netcode:%d netname:<%s>\n" ),
297 i++,
298 it->second->GetNetCode(),
299 TO_UTF8( it->second->GetNetname() ) );
300 }
301}
302#endif
303
304
306{
307 do
308 {
309 if( m_newNetCode < 0 )
310 m_newNetCode = 0;
311 } while( m_netCodes.count( ++m_newNetCode ) != 0 );
312
313 return m_newNetCode;
314}
315
316
317bool NETINFO_LIST::RenameNets( const std::map<wxString, wxString>& aNewNames, REPORTER& aReporter )
318{
319 if( aNewNames.empty() )
320 return true;
321
322 // Validate against a copy so a rejected batch leaves the live lookup untouched.
323 NETNAMES_MAP finalNames = m_netNames;
324 std::vector<std::pair<NETINFO_ITEM*, wxString>> renames;
325 size_t missing = 0;
326
327 for( const auto& [source, target] : aNewNames )
328 {
329 NETINFO_ITEM* net = GetNetItem( source );
330
331 if( !net )
332 {
333 // A caller may legitimately offer names for nets this board does not have, but a run
334 // where most names miss usually means the two sides qualify hierarchical names
335 // differently.
336 wxLogTrace( traceImportNetNames, wxS( "no net named '%s' to rename to '%s'" ), source,
337 target );
338 ++missing;
339 continue;
340 }
341
342 if( net->GetNetCode() <= 0 || target.IsEmpty() )
343 {
344 aReporter.Report( wxString::Format( _( "Cannot rename net '%s' to '%s': net zero and empty "
345 "names are reserved for unconnected items." ),
346 source, target ), RPT_SEVERITY_ERROR );
347 return false;
348 }
349
350 if( source == target )
351 continue;
352
353 renames.emplace_back( net, target );
354 finalNames.erase( source );
355 }
356
357 wxLogTrace( traceImportNetNames, wxS( "renaming %zu of %zu nets, %zu not on this board" ),
358 renames.size(), aNewNames.size(), missing );
359
360 if( renames.empty() )
361 return true;
362
363 for( const auto& [net, target] : renames )
364 {
365 if( !finalNames.emplace( target, net ).second )
366 {
367 aReporter.Report( wxString::Format( _( "Cannot rename net '%s' to '%s': another net would "
368 "have the same name." ),
369 net->GetNetname(), target ), RPT_SEVERITY_ERROR );
370 return false;
371 }
372 }
373
374 // Removing and re-adding nets would disconnect copper and can reassign net codes.
375 for( const auto& [net, target] : renames )
376 net->SetNetname( target );
377
378 m_netNames.swap( finalNames );
380
381 return true;
382}
383
384
385const int NETINFO_LIST::UNCONNECTED = 0;
386const int NETINFO_LIST::ORPHANED = -1;
COMMIT & Removed(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Definition commit.h:92
Handle the data for a net.
Definition netinfo.h:50
wxString m_shortNetname
Short net name, like vout from /sheet/subsheet/vout.
Definition netinfo.h:202
const wxString & GetNetChain() const
Definition netinfo.h:122
const KIID & GetTerminalPadUuid(int aIndex) const
Definition netinfo.h:128
wxString m_displayNetname
Unescaped netname for display.
Definition netinfo.h:204
const wxString & GetNetname() const
Definition netinfo.h:110
void Clear()
Set all fields to their default values.
void SetTerminalPadUuid(int aIndex, const KIID &aUuid)
Definition netinfo.h:127
int GetNetCode() const
Definition netinfo.h:104
int m_netCode
A number equivalent to the net name.
Definition netinfo.h:200
void SetNetChain(const wxString &aNetChain)
Definition netinfo.h:123
wxString m_netname
Full net name like /sheet/subsheet/vout used by Eeschema.
Definition netinfo.h:201
int getFreeNetCode()
Return the first available net code that is not used by any other net.
void RemoveUnusedNets(BOARD_COMMIT *aCommit)
friend class BOARD
Definition netinfo.h:232
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition netinfo.h:280
NETCODES_MAP m_netCodes
map of <int, NETINFO_ITEM*> is NOT owner
Definition netinfo.h:413
static const int ORPHANED
Constant that forces initialization of a netinfo item to the NETINFO_ITEM ORPHANED (typically -1) whe...
Definition netinfo.h:284
int m_newNetCode
possible value for new net code assignment
Definition netinfo.h:415
unsigned GetNetCount() const
Definition netinfo.h:254
void detachAll()
Drop all entries from the lookup maps without freeing the items.
void RemoveNet(NETINFO_ITEM *aNet)
Remove a net from the net list.
BOARD * m_parent
Definition netinfo.h:410
bool RenameNets(const std::map< wxString, wxString > &aNewNames, REPORTER &aReporter)
Rename nets in place, keeping the name lookup in sync.
NETINFO_ITEM * GetNetItem(int aNetCode) const
NETINFO_LIST(BOARD *aParent)
void clear()
Delete the list of nets (and free memory).
NETNAMES_MAP m_netNames
map of <wxString, NETINFO_ITEM*>, is NETINFO_ITEM owner
Definition netinfo.h:412
void AppendNet(NETINFO_ITEM *aNewElement)
Add aNewElement to the end of the net list.
bool m_DisplayNetnamesDirty
Definition netinfo.h:407
void RebuildDisplayNetnames() const
void buildListOfNets()
Rebuild the list of NETINFO_ITEMs.
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:102
#define _(s)
const wxChar *const traceImportNetNames
Flag to enable tracing of imported net-name reconciliation between a schematic and its board.
This file contains miscellaneous commonly used macros and functions.
std::map< int, NETINFO_ITEM * > NETCODES_MAP
Definition netinfo.h:225
std::map< wxString, NETINFO_ITEM * > NETNAMES_MAP
Definition netinfo.h:224
@ RPT_SEVERITY_ERROR
wxString UnescapeString(const wxString &aSource)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
wxString result
Test unit parsing edge cases and error handling.
wxLogTrace helper definitions.