KiCad PCB EDA Suite
Loading...
Searching...
No Matches
conn_navigation.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 modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * 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 "conn_navigation.h"
21#include "conn_facade.h"
22
23#include <advanced_config.h>
24#include <connection_graph.h>
25#include <schematic.h>
26#include <sch_item.h>
27#include <algorithm>
28
29namespace SCH_CONNECTIVITY
30{
31NAVIGATION_QUERY::NAVIGATION_QUERY( const SCHEMATIC& aSchematic ) : m_schematic( aSchematic )
32{}
33
34
36{
37 if( m_paths )
38 return *m_paths;
39
41
42 if( m_schematic.IsValid() && m_schematic.HasHierarchy() )
43 {
44 for( SCH_SHEET_PATH& path : m_schematic.Hierarchy() )
45 {
46 if( path.LastScreen() )
47 {
48 KIID_PATH key = path.PathRef();
49 index.emplace( std::move( key ), std::move( path ) );
50 }
51 }
52 }
53
54 return m_paths.emplace( std::move( index ) );
55}
56
57
58std::vector<wxString> NAVIGATION_QUERY::NetNames() const
59{
60 if( !m_schematic.IsValid() )
61 return {};
62
63 if( ADVANCED_CFG::GetCfg().m_ConnectivityEngine )
64 {
65 auto names = m_schematic.Connectivity().NetNames();
66 std::erase( names, wxString() );
67 return names;
68 }
69
70 std::set<wxString> names;
71
72 for( const auto& [key, subgraphs] : m_schematic.ConnectionGraph()->GetNetMap() )
73 {
74 if( !key.Name.IsEmpty() )
75 names.insert( key.Name );
76 }
77
78 return { names.begin(), names.end() };
79}
80
81
82std::vector<SCH_ITEM*> NAVIGATION_QUERY::WholeNetItems( const std::vector<SCH_ITEM*>& aSeeds,
83 const SCH_SHEET_PATH& aSheet ) const
84{
85 std::set<wxString> names;
86
87 for( SCH_ITEM* seed : aSeeds )
88 {
89 if( !seed )
90 continue;
91
92 if( const auto name = seed->GetConnectionName( &aSheet ); name && !name->IsEmpty() )
93 names.insert( *name );
94 }
95
96 std::unordered_set<SCH_ITEM*> items;
97
98 for( const wxString& name : names )
99 CollectNetItems( name, aSheet, items );
100
101 return { items.begin(), items.end() };
102}
103
104
105std::vector<wxString> NAVIGATION_QUERY::SignalNames( const wxString& aName ) const
106{
107 if( !m_schematic.IsValid() )
108 return {};
109
110 std::set<wxString> names;
111
112 if( ADVANCED_CFG::GetCfg().m_ConnectivityEngine )
113 {
114 const auto group = m_schematic.Connectivity().NetByName( aName );
115
116 if( !group || group->instances.empty() )
117 return {};
118
119 const auto& view = group->instances.front();
120
121 if( view.IsNet() )
122 names.insert( group->name );
123
124 for( const auto& member : view.Members().leaves )
125 {
126 if( member.IsNet() )
127 names.insert( member.Name() );
128 }
129 }
130 else
131 {
132 for( const CONNECTION_SUBGRAPH* subgraph : m_schematic.ConnectionGraph()->GetAllSubgraphs( aName ) )
133 {
134 const SCH_CONNECTION* connection = subgraph->GetDriverConnection();
135
136 if( !connection )
137 continue;
138
139 if( connection->IsNet() )
140 names.insert( connection->Name() );
141
142 for( const auto& member : connection->AllMembers() )
143 {
144 if( member && member->IsNet() )
145 names.insert( member->Name() );
146 }
147 }
148 }
149
150 names.erase( wxString() );
151 return { names.begin(), names.end() };
152}
153
154
155std::set<const CONNECTION_SUBGRAPH*> NAVIGATION_QUERY::netSubgraphs( const wxString& aName,
156 bool aIncludeBusParents,
157 bool aIncludeBusMembers ) const
158{
159 if( !m_schematic.IsValid() )
160 return {};
161
162 const auto& graph = *m_schematic.ConnectionGraph();
163 std::set<const CONNECTION_SUBGRAPH*> subgraphs;
164 std::vector<const CONNECTION_SUBGRAPH*> pending;
165 auto add = [&]( const wxString& name )
166 {
167 for( const CONNECTION_SUBGRAPH* subgraph : graph.GetAllSubgraphs( name ) )
168 {
169 if( subgraph && subgraphs.insert( subgraph ).second )
170 pending.push_back( subgraph );
171 }
172 };
173 add( aName );
174
175 if( aIncludeBusMembers )
176 {
177 for( const wxString& member : SignalNames( aName ) )
178 add( member );
179 }
180
181 if( aIncludeBusParents )
182 {
183 for( const wxString& equivalent : graph.GetEquivalentBusNames( aName ) )
184 add( equivalent );
185
186 for( size_t i = 0; i < pending.size(); ++i )
187 {
188 for( const auto& [member, parents] : pending[i]->GetBusParents() )
189 {
190 for( const CONNECTION_SUBGRAPH* parent : parents )
191 {
192 if( parent )
193 add( parent->GetNetName() );
194 }
195 }
196 }
197 }
198
199 std::erase_if( subgraphs,
200 []( const CONNECTION_SUBGRAPH* subgraph )
201 {
202 return !subgraph->GetSheet().LastScreen() || subgraph->GetItems().empty();
203 } );
204
205 return subgraphs;
206}
207
208
209NET_ITEMS_BY_SHEET NAVIGATION_QUERY::netItemsByEngine( const wxString& aName, bool aIncludeBusParents,
210 bool aIncludeBusMembers ) const
211{
213 const auto& facade = m_schematic.Connectivity();
214 std::set<NODE_ID> visited;
215 std::vector<NET_GROUP> pending;
216 auto add = [&]( NET_GROUP group )
217 {
218 if( !group.instances.empty() && visited.insert( group.instances.front().Component() ).second )
219 pending.push_back( std::move( group ) );
220 };
221
222 if( auto group = facade.NetByName( aName ) )
223 add( std::move( *group ) );
224
225 if( aIncludeBusMembers )
226 {
227 for( auto& group : facade.BusWithMembers( aName ) )
228 add( std::move( group ) );
229 }
230
231 if( aIncludeBusParents )
232 {
233 for( const wxString& equivalent : facade.GetEquivalentBusNames( aName ) )
234 {
235 if( auto group = facade.NetByName( equivalent ) )
236 add( std::move( *group ) );
237 }
238
239 for( size_t i = 0; i < pending.size(); ++i )
240 {
241 for( auto& parent : facade.BundlesOf( pending[i].instances.front().Component() ) )
242 add( std::move( parent ) );
243 }
244 }
245
246 for( const NET_GROUP& group : pending )
247 {
248 for( const NET_VIEW& view : group.instances )
249 {
250 const auto items = view.Items();
251
252 if( items.empty() )
253 continue;
254
255 const auto& index = paths();
256 const auto path = index.find( view.Instance() );
257
258 if( path != index.end() )
259 {
260 auto& collected = result[path->second];
261 collected.insert( collected.end(), items.begin(), items.end() );
262 }
263 }
264 }
265
266 return result;
267}
268
269
270bool NAVIGATION_QUERY::HasNet( const wxString& aName ) const
271{
272 if( ADVANCED_CFG::GetCfg().m_ConnectivityEngine )
273 return !netItemsByEngine( aName, false, false ).empty();
274
275 return !netSubgraphs( aName, false, false ).empty();
276}
277
278
279std::set<KIID_PATH> NAVIGATION_QUERY::NetSheets( const wxString& aName ) const
280{
281 std::set<KIID_PATH> sheets;
282
283 if( ADVANCED_CFG::GetCfg().m_ConnectivityEngine )
284 {
285 for( const auto& [sheet, items] : netItemsByEngine( aName, false, false ) )
286 sheets.insert( sheet.PathRef() );
287
288 return sheets;
289 }
290
291 for( const CONNECTION_SUBGRAPH* subgraph : netSubgraphs( aName, false, false ) )
292 sheets.insert( subgraph->GetSheet().PathRef() );
293
294 return sheets;
295}
296
297
298NET_ITEMS_BY_SHEET NAVIGATION_QUERY::NetItems( const wxString& aName, bool aIncludeBusParents,
299 bool aIncludeBusMembers ) const
300{
302
303 if( ADVANCED_CFG::GetCfg().m_ConnectivityEngine )
304 {
305 result = netItemsByEngine( aName, aIncludeBusParents, aIncludeBusMembers );
306 }
307 else
308 {
309 for( const CONNECTION_SUBGRAPH* subgraph : netSubgraphs( aName, aIncludeBusParents, aIncludeBusMembers ) )
310 {
311 auto& items = result[subgraph->GetSheet()];
312 items.insert( items.end(), subgraph->GetItems().begin(), subgraph->GetItems().end() );
313 }
314 }
315
316 for( auto& [path, items] : result )
317 {
318 std::ranges::sort( items, std::less<>{}, &SCH_ITEM::m_Uuid );
319 items.erase( std::unique( items.begin(), items.end() ), items.end() );
320 }
321
322 return result;
323}
324
325
326void NAVIGATION_QUERY::CollectNetItems( const wxString& aName, const SCH_SHEET_PATH& aSheet,
327 std::unordered_set<SCH_ITEM*>& aItems, bool aIncludeBusParents,
328 bool aIncludeBusMembers ) const
329{
330 if( ADVANCED_CFG::GetCfg().m_ConnectivityEngine )
331 {
332 NET_ITEMS_BY_SHEET result = netItemsByEngine( aName, aIncludeBusParents, aIncludeBusMembers );
333 auto it = result.find( aSheet );
334
335 if( it != result.end() )
336 aItems.insert( it->second.begin(), it->second.end() );
337
338 return;
339 }
340
341 for( const CONNECTION_SUBGRAPH* subgraph : netSubgraphs( aName, aIncludeBusParents, aIncludeBusMembers ) )
342 {
343 if( subgraph->GetSheet() == aSheet )
344 aItems.insert( subgraph->GetItems().begin(), subgraph->GetItems().end() );
345 }
346}
347}
int index
const char * name
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
A subgraph is a set of items that are electrically connected on a single sheet.
const std::set< SCH_ITEM * > & GetItems() const
Provide a read-only reference to the items in the subgraph.
const SCH_SHEET_PATH & GetSheet() const
const KIID m_Uuid
Definition eda_item.h:599
Holds all the data relating to one schematic.
Definition schematic.h:149
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
bool IsNet() const
const std::vector< std::shared_ptr< SCH_CONNECTION > > AllMembers() const
wxString Name(bool aIgnoreSheet=false) const
std::optional< PATH_INDEX > m_paths
void CollectNetItems(const wxString &aName, const SCH_SHEET_PATH &aSheet, std::unordered_set< SCH_ITEM * > &aItems, bool aIncludeBusParents=false, bool aIncludeBusMembers=false) const
bool HasNet(const wxString &aName) const
std::vector< wxString > SignalNames(const wxString &aName) const
std::set< const CONNECTION_SUBGRAPH * > netSubgraphs(const wxString &aName, bool aIncludeBusParents, bool aIncludeBusMembers) const
NET_ITEMS_BY_SHEET NetItems(const wxString &aName, bool aIncludeBusParents, bool aIncludeBusMembers=false) const
std::map< KIID_PATH, SCH_SHEET_PATH > PATH_INDEX
NAVIGATION_QUERY(const SCHEMATIC &aSchematic)
NET_ITEMS_BY_SHEET netItemsByEngine(const wxString &aName, bool aIncludeBusParents, bool aIncludeBusMembers) const
std::vector< SCH_ITEM * > WholeNetItems(const std::vector< SCH_ITEM * > &aSeeds, const SCH_SHEET_PATH &aSheet) const
const PATH_INDEX & paths() const
std::set< KIID_PATH > NetSheets(const wxString &aName) const
std::vector< wxString > NetNames() const
std::vector< SCH_ITEM * > Items() const
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:170
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
SCH_SCREEN * LastScreen()
bool equivalent(SIM_MODEL::DEVICE_T a, SIM_MODEL::DEVICE_T b)
Value keys and the key session of the schematic connectivity engine.
std::map< SCH_SHEET_PATH, std::vector< SCH_ITEM * >, SHEET_PATH_CMP > NET_ITEMS_BY_SHEET
std::string path
wxString result
Test unit parsing edge cases and error handling.