KiCad PCB EDA Suite
Loading...
Searching...
No Matches
net_settings.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 (C) 2020 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Jon Evans <[email protected]>
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <algorithm>
23#include <limits>
24
25#include <nlohmann/json.hpp>
26
28#include <settings/parameters.h>
30#include <string_utils.h>
31#include <base_units.h>
32
33
34// const int netSettingsSchemaVersion = 0;
35// const int netSettingsSchemaVersion = 1; // new overbar syntax
36// const int netSettingsSchemaVersion = 2; // exclude buses from netclass members
37// const int netSettingsSchemaVersion = 3; // netclass assignment patterns
38const int netSettingsSchemaVersion = 4; // netclass ordering
39
40
41static std::optional<int> getInPcbUnits( const nlohmann::json& aObj, const std::string& aKey,
42 std::optional<int> aDefault = std::optional<int>() )
43{
44 if( aObj.contains( aKey ) && aObj[aKey].is_number() )
45 return pcbIUScale.mmToIU( aObj[aKey].get<double>() );
46 else
47 return aDefault;
48};
49
50
51static std::optional<int> getInSchUnits( const nlohmann::json& aObj, const std::string& aKey,
52 std::optional<int> aDefault = std::optional<int>() )
53{
54 if( aObj.contains( aKey ) && aObj[aKey].is_number() )
55 return schIUScale.MilsToIU( aObj[aKey].get<double>() );
56 else
57 return aDefault;
58};
59
60
61NET_SETTINGS::NET_SETTINGS( JSON_SETTINGS* aParent, const std::string& aPath ) :
62 NESTED_SETTINGS( "net_settings", netSettingsSchemaVersion, aParent, aPath, false )
63{
64 m_defaultNetClass = std::make_shared<NETCLASS>( NETCLASS::Default, true );
65 m_defaultNetClass->SetDescription( _( "This is the default net class." ) );
66 m_defaultNetClass->SetPriority( std::numeric_limits<int>::max() );
67
68 auto saveNetclass =
69 []( nlohmann::json& json_array, const std::shared_ptr<NETCLASS>& nc )
70 {
71 // Note: we're in common/, but we do happen to know which of these
72 // fields are used in which units system.
73 nlohmann::json nc_json = { { "name", nc->GetName().ToUTF8() },
74 { "priority", nc->GetPriority() },
75 { "schematic_color", nc->GetSchematicColor( true ) },
76 { "pcb_color", nc->GetPcbColor( true ) } };
77
78 auto saveInPcbUnits =
79 []( nlohmann::json& json, const std::string& aKey, int aValue )
80 {
81 json.push_back( { aKey, pcbIUScale.IUTomm( aValue ) } );
82 };
83
84 if( nc->HasWireWidth() )
85 nc_json.push_back(
86 { "wire_width", schIUScale.IUToMils( nc->GetWireWidth() ) } );
87
88 if( nc->HasBusWidth() )
89 nc_json.push_back( { "bus_width", schIUScale.IUToMils( nc->GetBusWidth() ) } );
90
91 if( nc->HasLineStyle() )
92 nc_json.push_back( { "line_style", nc->GetLineStyle() } );
93
94 if( nc->HasClearance() )
95 saveInPcbUnits( nc_json, "clearance", nc->GetClearance() );
96
97 if( nc->HasTrackWidth() )
98 saveInPcbUnits( nc_json, "track_width", nc->GetTrackWidth() );
99
100 if( nc->HasViaDiameter() )
101 saveInPcbUnits( nc_json, "via_diameter", nc->GetViaDiameter() );
102
103 if( nc->HasViaDrill() )
104 saveInPcbUnits( nc_json, "via_drill", nc->GetViaDrill() );
105
106 if( nc->HasuViaDiameter() )
107 saveInPcbUnits( nc_json, "microvia_diameter", nc->GetuViaDiameter() );
108
109 if( nc->HasuViaDrill() )
110 saveInPcbUnits( nc_json, "microvia_drill", nc->GetuViaDrill() );
111
112 if( nc->HasDiffPairWidth() )
113 saveInPcbUnits( nc_json, "diff_pair_width", nc->GetDiffPairWidth() );
114
115 if( nc->HasDiffPairGap() )
116 saveInPcbUnits( nc_json, "diff_pair_gap", nc->GetDiffPairGap() );
117
118 if( nc->HasDiffPairViaGap() )
119 saveInPcbUnits( nc_json, "diff_pair_via_gap", nc->GetDiffPairViaGap() );
120
121 json_array.push_back( nc_json );
122 };
123
124 auto readNetClass =
125 []( const nlohmann::json& entry )
126 {
127 wxString name = entry["name"];
128
129 std::shared_ptr<NETCLASS> nc = std::make_shared<NETCLASS>( name, false );
130
131 int priority = entry["priority"];
132 nc->SetPriority( priority );
133
134 if( auto value = getInPcbUnits( entry, "clearance" ) )
135 nc->SetClearance( *value );
136
137 if( auto value = getInPcbUnits( entry, "track_width" ) )
138 nc->SetTrackWidth( *value );
139
140 if( auto value = getInPcbUnits( entry, "via_diameter" ) )
141 nc->SetViaDiameter( *value );
142
143 if( auto value = getInPcbUnits( entry, "via_drill" ) )
144 nc->SetViaDrill( *value );
145
146 if( auto value = getInPcbUnits( entry, "microvia_diameter" ) )
147 nc->SetuViaDiameter( *value );
148
149 if( auto value = getInPcbUnits( entry, "microvia_drill" ) )
150 nc->SetuViaDrill( *value );
151
152 if( auto value = getInPcbUnits( entry, "diff_pair_width" ) )
153 nc->SetDiffPairWidth( *value );
154
155 if( auto value = getInPcbUnits( entry, "diff_pair_gap" ) )
156 nc->SetDiffPairGap( *value );
157
158 if( auto value = getInPcbUnits( entry, "diff_pair_via_gap" ) )
159 nc->SetDiffPairViaGap( *value );
160
161 if( auto value = getInSchUnits( entry, "wire_width" ) )
162 nc->SetWireWidth( *value );
163
164 if( auto value = getInSchUnits( entry, "bus_width" ) )
165 nc->SetBusWidth( *value );
166
167 if( entry.contains( "line_style" ) && entry["line_style"].is_number() )
168 nc->SetLineStyle( entry["line_style"].get<int>() );
169
170 if( entry.contains( "pcb_color" ) && entry["pcb_color"].is_string() )
171 nc->SetPcbColor( entry["pcb_color"].get<KIGFX::COLOR4D>() );
172
173 if( entry.contains( "schematic_color" )
174 && entry["schematic_color"].is_string() )
175 {
176 nc->SetSchematicColor( entry["schematic_color"].get<KIGFX::COLOR4D>() );
177 }
178
179 return nc;
180 };
181
182 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "classes",
183 [&]() -> nlohmann::json
184 {
185 nlohmann::json ret = nlohmann::json::array();
186
187 if( m_defaultNetClass )
188 saveNetclass( ret, m_defaultNetClass );
189
190 for( const auto& [name, netclass] : m_netClasses )
191 saveNetclass( ret, netclass );
192
193 return ret;
194 },
195 [&]( const nlohmann::json& aJson )
196 {
197 if( !aJson.is_array() )
198 return;
199
200 m_netClasses.clear();
201
202 for( const nlohmann::json& entry : aJson )
203 {
204 if( !entry.is_object() || !entry.contains( "name" ) )
205 continue;
206
207 std::shared_ptr<NETCLASS> nc = readNetClass( entry );
208
209 if( nc->IsDefault() )
210 m_defaultNetClass = nc;
211 else
212 m_netClasses[nc->GetName()] = nc;
213 }
214 },
215 {} ) );
216
217 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "net_colors",
218 [&]() -> nlohmann::json
219 {
220 nlohmann::json ret = {};
221
222 for( const auto& [netname, color] : m_netColorAssignments )
223 {
224 std::string key( netname.ToUTF8() );
225 ret[ std::move( key ) ] = color;
226 }
227
228 return ret;
229 },
230 [&]( const nlohmann::json& aJson )
231 {
232 if( !aJson.is_object() )
233 return;
234
235 m_netColorAssignments.clear();
236
237 for( const auto& pair : aJson.items() )
238 {
239 wxString key( pair.key().c_str(), wxConvUTF8 );
240 m_netColorAssignments[std::move( key )] = pair.value().get<KIGFX::COLOR4D>();
241 }
242 },
243 {} ) );
244
245 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "netclass_assignments",
246 [&]() -> nlohmann::json
247 {
248 nlohmann::json ret = {};
249
250 for( const auto& [netname, netclassNames] : m_netClassLabelAssignments )
251 {
252 nlohmann::json netclassesJson = nlohmann::json::array();
253
254 for( const auto& netclass : netclassNames )
255 {
256 std::string netclassStr( netclass.ToUTF8() );
257 netclassesJson.push_back( std::move( netclassStr ) );
258 }
259
260 std::string key( netname.ToUTF8() );
261 ret[std::move( key )] = netclassesJson;
262 }
263
264 return ret;
265 },
266 [&]( const nlohmann::json& aJson )
267 {
268 if( !aJson.is_object() )
269 return;
270
271 m_netClassLabelAssignments.clear();
272
273 for( const auto& pair : aJson.items() )
274 {
275 wxString key( pair.key().c_str(), wxConvUTF8 );
276
277 for( const auto& netclassName : pair.value() )
278 m_netClassLabelAssignments[key].insert( netclassName.get<wxString>() );
279 }
280 },
281 {} ) );
282
283 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "netclass_patterns",
284 [&]() -> nlohmann::json
285 {
286 nlohmann::json ret = nlohmann::json::array();
287
288 for( const auto& [matcher, netclassName] : m_netClassPatternAssignments )
289 {
290 nlohmann::json pattern_json = {
291 { "pattern", matcher->GetPattern().ToUTF8() },
292 { "netclass", netclassName.ToUTF8() }
293 };
294
295 ret.push_back( std::move( pattern_json ) );
296 }
297
298 return ret;
299 },
300 [&]( const nlohmann::json& aJson )
301 {
302 if( !aJson.is_array() )
303 return;
304
305 m_netClassPatternAssignments.clear();
306
307 for( const nlohmann::json& entry : aJson )
308 {
309 if( !entry.is_object() )
310 continue;
311
312 if( entry.contains( "pattern" ) && entry["pattern"].is_string()
313 && entry.contains( "netclass" ) && entry["netclass"].is_string() )
314 {
315 wxString pattern = entry["pattern"].get<wxString>();
316 wxString netclass = entry["netclass"].get<wxString>();
317
318 m_netClassPatternAssignments.push_back(
319 { std::make_unique<EDA_COMBINED_MATCHER>( pattern, CTX_NETCLASS ),
320 netclass } );
321 }
322 }
323 },
324 {} ) );
325
326 registerMigration( 0, 1, std::bind( &NET_SETTINGS::migrateSchema0to1, this ) );
327 registerMigration( 1, 2, std::bind( &NET_SETTINGS::migrateSchema1to2, this ) );
328 registerMigration( 2, 3, std::bind( &NET_SETTINGS::migrateSchema2to3, this ) );
329 registerMigration( 3, 4, std::bind( &NET_SETTINGS::migrateSchema3to4, this ) );
330}
331
332
334{
335 // Release early before destroying members
336 if( m_parent )
337 {
339 m_parent = nullptr;
340 }
341}
342
343
344bool NET_SETTINGS::operator==( const NET_SETTINGS& aOther ) const
345{
346 if( !std::equal( std::begin( m_netClasses ), std::end( m_netClasses ),
347 std::begin( aOther.m_netClasses ) ) )
348 return false;
349
350 if( !std::equal( std::begin( m_netClassPatternAssignments ),
352 std::begin( aOther.m_netClassPatternAssignments ) ) )
353 return false;
354
355 if( !std::equal( std::begin( m_netClassLabelAssignments ),
356 std::end( m_netClassLabelAssignments ),
357 std::begin( aOther.m_netClassLabelAssignments ) ) )
358 return false;
359
360
361 if( !std::equal( std::begin( m_netColorAssignments ), std::end( m_netColorAssignments ),
362 std::begin( aOther.m_netColorAssignments ) ) )
363 return false;
364
365 return true;
366}
367
368
370{
371 if( m_internals->contains( "classes" ) && m_internals->At( "classes" ).is_array() )
372 {
373 for( auto& netClass : m_internals->At( "classes" ).items() )
374 {
375 if( netClass.value().contains( "nets" ) && netClass.value()["nets"].is_array() )
376 {
377 nlohmann::json migrated = nlohmann::json::array();
378
379 for( auto& net : netClass.value()["nets"].items() )
380 migrated.push_back( ConvertToNewOverbarNotation( net.value().get<wxString>() ) );
381
382 netClass.value()["nets"] = migrated;
383 }
384 }
385 }
386
387 return true;
388}
389
390
392{
393 return true;
394}
395
396
398{
399 if( m_internals->contains( "classes" ) && m_internals->At( "classes" ).is_array() )
400 {
401 nlohmann::json patterns = nlohmann::json::array();
402
403 for( auto& netClass : m_internals->At( "classes" ).items() )
404 {
405 if( netClass.value().contains( "name" )
406 && netClass.value().contains( "nets" )
407 && netClass.value()["nets"].is_array() )
408 {
409 wxString netClassName = netClass.value()["name"].get<wxString>();
410
411 for( auto& net : netClass.value()["nets"].items() )
412 {
413 nlohmann::json pattern_json = {
414 { "pattern", net.value().get<wxString>() },
415 { "netclass", netClassName }
416 };
417
418 patterns.push_back( pattern_json );
419 }
420 }
421 }
422
423 m_internals->SetFromString( "netclass_patterns", patterns );
424 }
425
426 return true;
427}
428
429
431{
432 // Add priority field to netclasses
433 if( m_internals->contains( "classes" ) && m_internals->At( "classes" ).is_array() )
434 {
435 int priority = 0;
436
437 for( auto& netClass : m_internals->At( "classes" ).items() )
438 {
439 if( netClass.value()["name"].get<wxString>() == NETCLASS::Default )
440 netClass.value()["priority"] = std::numeric_limits<int>::max();
441 else
442 netClass.value()["priority"] = priority++;
443 }
444 }
445
446 // Move netclass assignments to a list
447 if( m_internals->contains( "netclass_assignments" )
448 && m_internals->At( "netclass_assignments" ).is_object() )
449 {
450 nlohmann::json migrated = {};
451
452 for( const auto& pair : m_internals->At( "netclass_assignments" ).items() )
453 {
454 nlohmann::json netclassesJson = nlohmann::json::array();
455
456 if( pair.value().get<wxString>() != wxEmptyString )
457 netclassesJson.push_back( pair.value() );
458
459 migrated[pair.key()] = netclassesJson;
460 }
461
462 m_internals->SetFromString( "netclass_assignments", migrated );
463 }
464
465 return true;
466}
467
468
469void NET_SETTINGS::SetDefaultNetclass( std::shared_ptr<NETCLASS> netclass )
470{
471 m_defaultNetClass = netclass;
472}
473
474
475std::shared_ptr<NETCLASS> NET_SETTINGS::GetDefaultNetclass()
476{
477 return m_defaultNetClass;
478}
479
480
481bool NET_SETTINGS::HasNetclass( const wxString& netclassName ) const
482{
483 return m_netClasses.find( netclassName ) != m_netClasses.end();
484}
485
486
487void NET_SETTINGS::SetNetclass( const wxString& netclassName, std::shared_ptr<NETCLASS>& netclass )
488{
489 m_netClasses[netclassName] = netclass;
490}
491
492
493void NET_SETTINGS::SetNetclasses( const std::map<wxString, std::shared_ptr<NETCLASS>>& netclasses )
494{
495 m_netClasses = netclasses;
497}
498
499
500const std::map<wxString, std::shared_ptr<NETCLASS>>& NET_SETTINGS::GetNetclasses() const
501{
502 return m_netClasses;
503}
504
505
506const std::map<wxString, std::shared_ptr<NETCLASS>>& NET_SETTINGS::GetCompositeNetclasses() const
507{
509}
510
511
513{
514 m_netClasses.clear();
515 m_impicitNetClasses.clear();
517}
518
519
520const std::map<wxString, std::set<wxString>>& NET_SETTINGS::GetNetclassLabelAssignments() const
521{
523}
524
525
527{
529}
530
531
532void NET_SETTINGS::ClearNetclassLabelAssignment( const wxString& netName )
533{
534 m_netClassLabelAssignments.erase( netName );
535}
536
537
538void NET_SETTINGS::SetNetclassLabelAssignment( const wxString& netName,
539 const std::set<wxString>& netclasses )
540{
541 m_netClassLabelAssignments[netName] = netclasses;
542}
543
544
546 const std::set<wxString>& netclasses )
547{
548 m_netClassLabelAssignments[netName].insert( netclasses.begin(), netclasses.end() );
549}
550
551
552bool NET_SETTINGS::HasNetclassLabelAssignment( const wxString& netName ) const
553{
554 return m_netClassLabelAssignments.find( netName ) != m_netClassLabelAssignments.end();
555}
556
557
558void NET_SETTINGS::SetNetclassPatternAssignment( const wxString& pattern, const wxString& netclass )
559{
560 // Replace existing assignment if we have one
561 for( auto& assignment : m_netClassPatternAssignments )
562 {
563 if( assignment.first->GetPattern() == pattern )
564 {
565 assignment.second = netclass;
567 return;
568 }
569 }
570
571 // No assignment, add a new one
573 { std::make_unique<EDA_COMBINED_MATCHER>( pattern, CTX_NETCLASS ), netclass } );
574
576}
577
578
580 std::vector<std::pair<std::unique_ptr<EDA_COMBINED_MATCHER>, wxString>>&& netclassPatterns )
581{
582 m_netClassPatternAssignments = std::move( netclassPatterns );
584}
585
586
587std::vector<std::pair<std::unique_ptr<EDA_COMBINED_MATCHER>, wxString>>&
589{
591}
592
593
595{
597}
598
599
600void NET_SETTINGS::ClearCacheForNet( const wxString& netName )
601{
602 if( m_effectiveNetclassCache.count( netName ) )
603 {
604 wxString compositeNetclassName = m_effectiveNetclassCache[netName]->GetName();
605 m_compositeNetClasses.erase( compositeNetclassName );
606 m_effectiveNetclassCache.erase( netName );
607 }
608}
609
610
612{
614 m_compositeNetClasses.clear();
615}
616
617
618void NET_SETTINGS::SetNetColorAssignment( const wxString& netName, const KIGFX::COLOR4D& color )
619{
620 m_netColorAssignments[netName] = color;
621}
622
623
624const std::map<wxString, KIGFX::COLOR4D>& NET_SETTINGS::GetNetColorAssignments() const
625{
627}
628
629
631{
632 m_netColorAssignments.clear();
633}
634
635
636bool NET_SETTINGS::HasEffectiveNetClass( const wxString& aNetName ) const
637{
638 return m_effectiveNetclassCache.count( aNetName ) > 0;
639}
640
641
642std::shared_ptr<NETCLASS> NET_SETTINGS::GetCachedEffectiveNetClass( const wxString& aNetName ) const
643{
644 return m_effectiveNetclassCache.at( aNetName );
645}
646
647
648std::shared_ptr<NETCLASS> NET_SETTINGS::GetEffectiveNetClass( const wxString& aNetName )
649{
650 // Lambda to fetch an explicit netclass. Returns a nullptr if not found
651 auto getExplicitNetclass = [this]( const wxString& netclass ) -> std::shared_ptr<NETCLASS>
652 {
653 if( netclass == NETCLASS::Default )
654 return m_defaultNetClass;
655
656 auto ii = m_netClasses.find( netclass );
657
658 if( ii == m_netClasses.end() )
659 return {};
660 else
661 return ii->second;
662 };
663
664 // Lambda to fetch or create an implicit netclass (defined with a label, but not configured)
665 // These are needed as while they do not provide any netclass parameters, they do now appear in
666 // DRC matching strings as an assigned netclass.
667 auto getOrAddImplicitNetcless = [this]( const wxString& netclass ) -> std::shared_ptr<NETCLASS>
668 {
669 auto ii = m_impicitNetClasses.find( netclass );
670
671 if( ii == m_impicitNetClasses.end() )
672 {
673 std::shared_ptr<NETCLASS> nc = std::make_shared<NETCLASS>( netclass, false );
674 nc->SetPriority( std::numeric_limits<int>::max() - 1 ); // Priority > default netclass
675 m_impicitNetClasses[netclass] = nc;
676 return nc;
677 }
678 else
679 {
680 return ii->second;
681 }
682 };
683
684 // <no net> is forced to be part of the default netclass.
685 if( aNetName.IsEmpty() )
686 return m_defaultNetClass;
687
688 // First check if we have a cached resolved netclass
689 auto cacheItr = m_effectiveNetclassCache.find( aNetName );
690
691 if( cacheItr != m_effectiveNetclassCache.end() )
692 return cacheItr->second;
693
694 // No cache found - build a vector of all netclasses assigned to or matching this net
695 std::vector<std::shared_ptr<NETCLASS>> resolvedNetclasses;
696
697 // First find explicit netclass assignments
698 auto it = m_netClassLabelAssignments.find( aNetName );
699
700 if( it != m_netClassLabelAssignments.end() && it->second.size() > 0 )
701 {
702 for( const wxString& netclassName : it->second )
703 {
704 std::shared_ptr<NETCLASS> netclass = getExplicitNetclass( netclassName );
705
706 if( netclass )
707 {
708 resolvedNetclasses.push_back( std::move( netclass ) );
709 }
710 else
711 {
712 resolvedNetclasses.push_back(
713 getOrAddImplicitNetcless( netclassName ) );
714 }
715 }
716 }
717
718 // Now find any pattern-matched netclass assignments
719 for( const auto& [matcher, netclassName] : m_netClassPatternAssignments )
720 {
721 if( matcher->StartsWith( aNetName ) )
722 {
723 std::shared_ptr<NETCLASS> netclass = getExplicitNetclass( netclassName );
724
725 if( netclass )
726 {
727 resolvedNetclasses.push_back( std::move( netclass ) );
728 }
729 else
730 {
731 resolvedNetclasses.push_back( getOrAddImplicitNetcless( netclassName ) );
732 }
733 }
734 }
735
736 // Handle zero resolved netclasses
737 if( resolvedNetclasses.size() == 0 )
738 {
740
741 return m_defaultNetClass;
742 }
743
744 // Make and cache the effective netclass. Note that makeEffectiveNetclass will add the default
745 // netclass to resolvedNetclasses if it is needed to complete the netclass paramters set. It
746 // will also sort resolvedNetclasses by priority order.
747 std::vector<NETCLASS*> netclassPtrs;
748
749 for( std::shared_ptr<NETCLASS>& nc : resolvedNetclasses )
750 netclassPtrs.push_back( nc.get() );
751
752 wxString name;
753 name.Printf( "Effective for net: %s", aNetName );
754 std::shared_ptr<NETCLASS> effectiveNetclass = std::make_shared<NETCLASS>( name, false );
755 makeEffectiveNetclass( effectiveNetclass, netclassPtrs );
756
757 if( netclassPtrs.size() == 1 )
758 {
759 // No defaults were added - just return the primary netclass
760 m_effectiveNetclassCache[aNetName] = resolvedNetclasses[0];
761 return resolvedNetclasses[0];
762 }
763 else
764 {
765 effectiveNetclass->SetConstituentNetclasses( std::move( netclassPtrs ) );
766
767 m_compositeNetClasses[effectiveNetclass->GetName()] = effectiveNetclass;
768 m_effectiveNetclassCache[aNetName] = effectiveNetclass;
769
770 return effectiveNetclass;
771 }
772}
773
774
776{
777 for( auto& [ncName, nc] : m_compositeNetClasses )
778 {
779 // Note this needs to be a copy in case we now need to add the default netclass
780 std::vector<NETCLASS*> constituents = nc->GetConstituentNetclasses();
781
782 wxASSERT( constituents.size() > 0 );
783
784 // If the last netclass is Default, remove it (it will be re-added if still needed)
785 if( ( *constituents.rbegin() )->GetName() == NETCLASS::Default )
786 {
787 constituents.pop_back();
788 }
789
790 // Remake the netclass from original constituents
791 nc->ResetParameters();
792 makeEffectiveNetclass( nc, constituents );
793 nc->SetConstituentNetclasses( std::move( constituents ) );
794 }
795}
796
797
798void NET_SETTINGS::makeEffectiveNetclass( std::shared_ptr<NETCLASS>& effectiveNetclass,
799 std::vector<NETCLASS*>& constituentNetclasses ) const
800{
801 // Sort the resolved netclasses by priority (highest first), with same-priority netclasses
802 // ordered alphabetically
803 std::sort( constituentNetclasses.begin(), constituentNetclasses.end(),
804 []( NETCLASS* nc1, NETCLASS* nc2 )
805 {
806 int p1 = nc1->GetPriority();
807 int p2 = nc2->GetPriority();
808
809 if( p1 < p2 )
810 return true;
811
812 if (p1 == p2)
813 return nc1->GetName().Cmp( nc2->GetName() ) < 0;
814
815 return false;
816 } );
817
818 // Iterate from lowest priority netclass and fill effective netclass parameters
819 for( auto itr = constituentNetclasses.rbegin(); itr != constituentNetclasses.rend(); ++itr )
820 {
821 NETCLASS* nc = *itr;
822
823 if( nc->HasClearance() )
824 {
825 effectiveNetclass->SetClearance( nc->GetClearance() );
826 effectiveNetclass->SetClearanceParent( nc );
827 }
828
829 if( nc->HasTrackWidth() )
830 {
831 effectiveNetclass->SetTrackWidth( nc->GetTrackWidth() );
832 effectiveNetclass->SetTrackWidthParent( nc );
833 }
834
835 if( nc->HasViaDiameter() )
836 {
837 effectiveNetclass->SetViaDiameter( nc->GetViaDiameter() );
838 effectiveNetclass->SetViaDiameterParent( nc );
839 }
840
841 if( nc->HasViaDrill() )
842 {
843 effectiveNetclass->SetViaDrill( nc->GetViaDrill() );
844 effectiveNetclass->SetViaDrillParent( nc );
845 }
846
847 if( nc->HasuViaDiameter() )
848 {
849 effectiveNetclass->SetuViaDiameter( nc->GetuViaDiameter() );
850 effectiveNetclass->SetuViaDiameterParent( nc );
851 }
852
853 if( nc->HasuViaDrill() )
854 {
855 effectiveNetclass->SetuViaDrill( nc->GetuViaDrill() );
856 effectiveNetclass->SetuViaDrillParent( nc );
857 }
858
859 if( nc->HasDiffPairWidth() )
860 {
861 effectiveNetclass->SetDiffPairWidth( nc->GetDiffPairWidth() );
862 effectiveNetclass->SetDiffPairWidthParent( nc );
863 }
864
865 if( nc->HasDiffPairGap() )
866 {
867 effectiveNetclass->SetDiffPairGap( nc->GetDiffPairGap() );
868 effectiveNetclass->SetDiffPairGapParent( nc );
869 }
870
871 if( nc->HasDiffPairViaGap() )
872 {
873 effectiveNetclass->SetDiffPairViaGap( nc->GetDiffPairViaGap() );
874 effectiveNetclass->SetDiffPairViaGapParent( nc );
875 }
876
877 if( nc->HasWireWidth() )
878 {
879 effectiveNetclass->SetWireWidth( nc->GetWireWidth() );
880 effectiveNetclass->SetWireWidthParent( nc );
881 }
882
883 if( nc->HasBusWidth() )
884 {
885 effectiveNetclass->SetBusWidth( nc->GetBusWidth() );
886 effectiveNetclass->SetBusWidthParent( nc );
887 }
888
889 if( nc->HasLineStyle() )
890 {
891 effectiveNetclass->SetLineStyle( nc->GetLineStyle() );
892 effectiveNetclass->SetLineStyleParent( nc );
893 }
894
895 COLOR4D pcbColor = nc->GetPcbColor();
896
897 if( pcbColor != COLOR4D::UNSPECIFIED )
898 {
899 effectiveNetclass->SetPcbColor( pcbColor );
900 effectiveNetclass->SetPcbColorParent( nc );
901 }
902
903 COLOR4D schColor = nc->GetSchematicColor();
904
905 if( schColor != COLOR4D::UNSPECIFIED )
906 {
907 effectiveNetclass->SetSchematicColor( schColor );
908 effectiveNetclass->SetSchematicColorParent( nc );
909 }
910 }
911
912 // Fill in any required defaults
913 if( addMissingDefaults( effectiveNetclass.get() ) )
914 constituentNetclasses.push_back( m_defaultNetClass.get() );
915}
916
917
919{
920 bool addedDefault = false;
921
922 if( !nc->HasClearance() )
923 {
924 addedDefault = true;
925 nc->SetClearance( m_defaultNetClass->GetClearance() );
927 }
928
929 if( !nc->HasTrackWidth() )
930 {
931 addedDefault = true;
932 nc->SetTrackWidth( m_defaultNetClass->GetTrackWidth() );
934 }
935
936 if( !nc->HasViaDiameter() )
937 {
938 addedDefault = true;
939 nc->SetViaDiameter( m_defaultNetClass->GetViaDiameter() );
941 }
942
943 if( !nc->HasViaDrill() )
944 {
945 addedDefault = true;
946 nc->SetViaDrill( m_defaultNetClass->GetViaDrill() );
948 }
949
950 if( !nc->HasuViaDiameter() )
951 {
952 addedDefault = true;
953 nc->SetuViaDiameter( m_defaultNetClass->GetuViaDiameter() );
955 }
956
957 if( !nc->HasuViaDrill() )
958 {
959 addedDefault = true;
960 nc->SetuViaDrill( m_defaultNetClass->GetuViaDrill() );
962 }
963
964 if( !nc->HasDiffPairWidth() )
965 {
966 addedDefault = true;
967 nc->SetDiffPairWidth( m_defaultNetClass->GetDiffPairWidth() );
969 }
970
971 if( !nc->HasDiffPairGap() )
972 {
973 addedDefault = true;
974 nc->SetDiffPairGap( m_defaultNetClass->GetDiffPairGap() );
976 }
977
978 // Currently this is only on the default netclass, and not editable in the setup panel
979 // if( !nc->HasDiffPairViaGap() )
980 // {
981 // addedDefault = true;
982 // nc->SetDiffPairViaGap( m_defaultNetClass->GetDiffPairViaGap() );
983 // nc->SetDiffPairViaGapParent( m_defaultNetClass.get() );
984 // }
985
986 if( !nc->HasWireWidth() )
987 {
988 addedDefault = true;
989 nc->SetWireWidth( m_defaultNetClass->GetWireWidth() );
991 }
992
993 if( !nc->HasBusWidth() )
994 {
995 addedDefault = true;
996 nc->SetBusWidth( m_defaultNetClass->GetBusWidth() );
998 }
999
1000 return addedDefault;
1001}
1002
1003
1004std::shared_ptr<NETCLASS> NET_SETTINGS::GetNetClassByName( const wxString& aNetClassName ) const
1005{
1006 auto ii = m_netClasses.find( aNetClassName );
1007
1008 if( ii == m_netClasses.end() )
1009 return m_defaultNetClass;
1010 else
1011 return ii->second;
1012}
1013
1014
1015static bool isSuperSubOverbar( wxChar c )
1016{
1017 return c == '_' || c == '^' || c == '~';
1018}
1019
1020
1021bool NET_SETTINGS::ParseBusVector( const wxString& aBus, wxString* aName,
1022 std::vector<wxString>* aMemberList )
1023{
1024 auto isDigit = []( wxChar c )
1025 {
1026 static wxString digits( wxT( "0123456789" ) );
1027 return digits.Contains( c );
1028 };
1029
1030 size_t busLen = aBus.length();
1031 size_t i = 0;
1032 wxString prefix;
1033 wxString suffix;
1034 wxString tmp;
1035 long begin = 0;
1036 long end = 0;
1037 int braceNesting = 0;
1038
1039 prefix.reserve( busLen );
1040
1041 // Parse prefix
1042 //
1043 for( ; i < busLen; ++i )
1044 {
1045 if( aBus[i] == '{' )
1046 {
1047 if( i > 0 && isSuperSubOverbar( aBus[i-1] ) )
1048 braceNesting++;
1049 else
1050 return false;
1051 }
1052 else if( aBus[i] == '}' )
1053 {
1054 braceNesting--;
1055 }
1056
1057 if( aBus[i] == ' ' || aBus[i] == ']' )
1058 return false;
1059
1060 if( aBus[i] == '[' )
1061 break;
1062
1063 prefix += aBus[i];
1064 }
1065
1066 // Parse start number
1067 //
1068 i++; // '[' character
1069
1070 if( i >= busLen )
1071 return false;
1072
1073 for( ; i < busLen; ++i )
1074 {
1075 if( aBus[i] == '.' && i + 1 < busLen && aBus[i+1] == '.' )
1076 {
1077 tmp.ToLong( &begin );
1078 i += 2;
1079 break;
1080 }
1081
1082 if( !isDigit( aBus[i] ) )
1083 return false;
1084
1085 tmp += aBus[i];
1086 }
1087
1088 // Parse end number
1089 //
1090 tmp = wxEmptyString;
1091
1092 if( i >= busLen )
1093 return false;
1094
1095 for( ; i < busLen; ++i )
1096 {
1097 if( aBus[i] == ']' )
1098 {
1099 tmp.ToLong( &end );
1100 ++i;
1101 break;
1102 }
1103
1104 if( !isDigit( aBus[i] ) )
1105 return false;
1106
1107 tmp += aBus[i];
1108 }
1109
1110 // Parse suffix
1111 //
1112 for( ; i < busLen; ++i )
1113 {
1114 if( aBus[i] == '}' )
1115 {
1116 braceNesting--;
1117 suffix += aBus[i];
1118 }
1119 else
1120 {
1121 return false;
1122 }
1123 }
1124
1125 if( braceNesting != 0 )
1126 return false;
1127
1128 if( begin == end )
1129 return false;
1130 else if( begin > end )
1131 std::swap( begin, end );
1132
1133 if( aName )
1134 *aName = prefix;
1135
1136 if( aMemberList )
1137 {
1138 for( long idx = begin; idx <= end; ++idx )
1139 {
1140 wxString str = prefix;
1141 str << idx;
1142 str << suffix;
1143
1144 aMemberList->emplace_back( str );
1145 }
1146 }
1147
1148 return true;
1149}
1150
1151
1152bool NET_SETTINGS::ParseBusGroup( const wxString& aGroup, wxString* aName,
1153 std::vector<wxString>* aMemberList )
1154{
1155 size_t groupLen = aGroup.length();
1156 size_t i = 0;
1157 wxString prefix;
1158 wxString tmp;
1159 int braceNesting = 0;
1160
1161 prefix.reserve( groupLen );
1162
1163 // Parse prefix
1164 //
1165 for( ; i < groupLen; ++i )
1166 {
1167 if( aGroup[i] == '{' )
1168 {
1169 if( i > 0 && isSuperSubOverbar( aGroup[i-1] ) )
1170 braceNesting++;
1171 else
1172 break;
1173 }
1174 else if( aGroup[i] == '}' )
1175 {
1176 braceNesting--;
1177 }
1178
1179 if( aGroup[i] == ' ' || aGroup[i] == '[' || aGroup[i] == ']' )
1180 return false;
1181
1182 prefix += aGroup[i];
1183 }
1184
1185 if( braceNesting != 0 )
1186 return false;
1187
1188 if( aName )
1189 *aName = prefix;
1190
1191 // Parse members
1192 //
1193 i++; // '{' character
1194
1195 if( i >= groupLen )
1196 return false;
1197
1198 for( ; i < groupLen; ++i )
1199 {
1200 if( aGroup[i] == '{' )
1201 {
1202 if( i > 0 && isSuperSubOverbar( aGroup[i-1] ) )
1203 braceNesting++;
1204 else
1205 return false;
1206 }
1207 else if( aGroup[i] == '}' )
1208 {
1209 if( braceNesting )
1210 {
1211 braceNesting--;
1212 }
1213 else
1214 {
1215 if( aMemberList && !tmp.IsEmpty() )
1216 aMemberList->push_back( EscapeString( tmp, CTX_NETNAME ) );
1217
1218 return true;
1219 }
1220 }
1221
1222 // Commas aren't strictly legal, but we can be pretty sure what the author had in mind.
1223 if( aGroup[i] == ' ' || aGroup[i] == ',' )
1224 {
1225 if( aMemberList && !tmp.IsEmpty() )
1226 aMemberList->push_back( EscapeString( tmp, CTX_NETNAME ) );
1227
1228 tmp.Clear();
1229 continue;
1230 }
1231
1232 tmp += aGroup[i];
1233 }
1234
1235 return false;
1236}
int color
Definition: DXF_plotter.cpp:60
const char * name
Definition: DXF_plotter.cpp:59
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:110
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
void ReleaseNestedSettings(NESTED_SETTINGS *aSettings)
Saves and frees a nested settings object, if it exists within this one.
std::unique_ptr< JSON_SETTINGS_INTERNALS > m_internals
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
NESTED_SETTINGS is a JSON_SETTINGS that lives inside a JSON_SETTINGS.
JSON_SETTINGS * m_parent
A pointer to the parent object to load and store from.
A collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:45
void SetViaDiameter(int aDia)
Definition: netclass.h:132
void SetViaDrill(int aSize)
Definition: netclass.h:140
bool HasLineStyle() const
Definition: netclass.h:230
int GetViaDiameter() const
Definition: netclass.h:130
int GetViaDrill() const
Definition: netclass.h:138
void SetWireWidthParent(NETCLASS *parent)
Definition: netclass.h:205
static const char Default[]
the name of the default NETCLASS
Definition: netclass.h:47
void SetuViaDrillParent(NETCLASS *parent)
Definition: netclass.h:158
bool HasBusWidth() const
Definition: netclass.h:208
bool HasuViaDrill() const
Definition: netclass.h:153
void SetDiffPairWidthParent(NETCLASS *parent)
Definition: netclass.h:166
void SetuViaDiameter(int aSize)
Definition: netclass.h:148
void SetDiffPairWidth(int aSize)
Definition: netclass.h:164
int HasViaDrill() const
Definition: netclass.h:137
int GetDiffPairViaGap() const
Definition: netclass.h:178
void SetViaDrillParent(NETCLASS *parent)
Definition: netclass.h:142
void SetDiffPairGapParent(NETCLASS *parent)
Definition: netclass.h:174
int GetDiffPairGap() const
Definition: netclass.h:170
int GetuViaDrill() const
Definition: netclass.h:154
bool HasViaDiameter() const
Definition: netclass.h:129
int GetLineStyle() const
Definition: netclass.h:231
bool HasDiffPairWidth() const
Definition: netclass.h:161
bool HasuViaDiameter() const
Definition: netclass.h:145
void SetTrackWidthParent(NETCLASS *parent)
Definition: netclass.h:126
int GetuViaDiameter() const
Definition: netclass.h:146
bool HasTrackWidth() const
Definition: netclass.h:121
void SetViaDiameterParent(NETCLASS *parent)
Definition: netclass.h:134
int GetDiffPairWidth() const
Definition: netclass.h:162
void SetuViaDrill(int aSize)
Definition: netclass.h:156
int GetWireWidth() const
Definition: netclass.h:201
void SetDiffPairGap(int aSize)
Definition: netclass.h:172
void SetBusWidthParent(NETCLASS *parent)
Definition: netclass.h:213
void SetClearance(int aClearance)
Definition: netclass.h:116
COLOR4D GetPcbColor(bool aIsForSave=false) const
Definition: netclass.h:186
bool HasDiffPairGap() const
Definition: netclass.h:169
COLOR4D GetSchematicColor(bool aIsForSave=false) const
Definition: netclass.h:216
void SetBusWidth(int aWidth)
Definition: netclass.h:211
void SetClearanceParent(NETCLASS *parent)
Definition: netclass.h:118
int GetTrackWidth() const
Definition: netclass.h:122
void SetWireWidth(int aWidth)
Definition: netclass.h:203
bool HasWireWidth() const
Definition: netclass.h:200
int GetClearance() const
Definition: netclass.h:114
void SetuViaDiameterParent(NETCLASS *parent)
Definition: netclass.h:150
void SetTrackWidth(int aWidth)
Definition: netclass.h:124
bool HasDiffPairViaGap() const
Definition: netclass.h:177
int GetBusWidth() const
Definition: netclass.h:209
bool HasClearance() const
Definition: netclass.h:113
NET_SETTINGS stores various net-related settings in a project context.
Definition: net_settings.h:39
void ClearAllCaches()
Clears the effective netclass cache for all nets.
std::map< wxString, std::shared_ptr< NETCLASS > > m_compositeNetClasses
Map of netclass names to netclass definitions for.
Definition: net_settings.h:222
bool addMissingDefaults(NETCLASS *nc) const
Adds any missing fields to the given netclass from the default netclass.
void ClearNetColorAssignments()
Clears all net name to color assignments Calling user is responsible for resetting the effective netc...
bool operator==(const NET_SETTINGS &aOther) const
void ClearCacheForNet(const wxString &netName)
Clears effective netclass cache for the given net.
std::shared_ptr< NETCLASS > GetEffectiveNetClass(const wxString &aNetName)
Fetches the effective (may be aggregate) netclass for the given net name.
bool HasEffectiveNetClass(const wxString &aNetName) const
Determines if an effective netclass for the given net name has been cached.
void ClearNetclassLabelAssignments()
Clears all net name to netclasses assignments Calling user is responsible for resetting the effective...
void ClearNetclassLabelAssignment(const wxString &netName)
Clears a specific net name to netclass assignment Calling user is responsible for resetting the effec...
void ClearNetclassPatternAssignments()
Clears all netclass pattern assignments.
std::map< wxString, KIGFX::COLOR4D > m_netColorAssignments
A map of fully-qualified net names to colors used in the board context.
Definition: net_settings.h:241
void SetNetclasses(const std::map< wxString, std::shared_ptr< NETCLASS > > &netclasses)
Sets all netclass Calling this method will reset the effective netclass calculation caches.
bool HasNetclassLabelAssignment(const wxString &netName) const
Determines if a given net name has netclasses assigned.
void SetNetclassLabelAssignment(const wxString &netName, const std::set< wxString > &netclasses)
Sets a net name to netclasses assignment Calling user is responsible for resetting the effective netc...
std::shared_ptr< NETCLASS > m_defaultNetClass
The default netclass.
Definition: net_settings.h:208
virtual ~NET_SETTINGS()
static bool ParseBusGroup(const wxString &aGroup, wxString *name, std::vector< wxString > *aMemberList)
Parse a bus group label into the name and a list of components.
void ClearNetclasses()
Clears all netclasses Calling this method will reset the effective netclass calculation caches.
std::map< wxString, std::shared_ptr< NETCLASS > > m_impicitNetClasses
Map of netclass names to netclass definitions for implicit netclasses.
Definition: net_settings.h:230
const std::map< wxString, std::shared_ptr< NETCLASS > > & GetCompositeNetclasses() const
Gets all composite (multiple assignment / missing defaults) netclasses.
std::vector< std::pair< std::unique_ptr< EDA_COMBINED_MATCHER >, wxString > > m_netClassPatternAssignments
List of net class pattern assignments.
Definition: net_settings.h:218
bool migrateSchema3to4()
bool migrateSchema0to1()
std::map< wxString, std::shared_ptr< NETCLASS > > m_effectiveNetclassCache
Cache of nets to pattern-matched netclasses.
Definition: net_settings.h:233
void SetNetclassPatternAssignments(std::vector< std::pair< std::unique_ptr< EDA_COMBINED_MATCHER >, wxString > > &&netclassPatterns)
Sets all netclass pattern assignments Calling user is responsible for resetting the effective netclas...
void SetNetclassPatternAssignment(const wxString &pattern, const wxString &netclass)
Sets a netclass pattern assignment Calling this method will reset the effective netclass calculation ...
bool migrateSchema2to3()
std::map< wxString, std::shared_ptr< NETCLASS > > m_netClasses
Map of netclass names to netclass definitions.
Definition: net_settings.h:211
const std::map< wxString, std::set< wxString > > & GetNetclassLabelAssignments() const
Gets all current net name to netclasses assignments.
const std::map< wxString, std::shared_ptr< NETCLASS > > & GetNetclasses() const
Gets all netclasses.
std::shared_ptr< NETCLASS > GetDefaultNetclass()
Gets the default netclass for the project.
static bool ParseBusVector(const wxString &aBus, wxString *aName, std::vector< wxString > *aMemberList)
Parse a bus vector (e.g.
const std::map< wxString, KIGFX::COLOR4D > & GetNetColorAssignments() const
Gets all net name to color assignments.
bool migrateSchema1to2()
std::vector< std::pair< std::unique_ptr< EDA_COMBINED_MATCHER >, wxString > > & GetNetclassPatternAssignments()
Gets the netclass pattern assignments.
void RecomputeEffectiveNetclasses()
Recomputes the internal values of all aggregate effective netclasses Called when a value of a user-de...
std::shared_ptr< NETCLASS > GetCachedEffectiveNetClass(const wxString &aNetName) const
Returns an already cached effective netclass for the given net name.
std::map< wxString, std::set< wxString > > m_netClassLabelAssignments
Map of net names to resolved netclasses.
Definition: net_settings.h:214
void SetNetclass(const wxString &netclassName, std::shared_ptr< NETCLASS > &netclass)
Sets the given netclass Calling user is responsible for resetting the effective netclass calculation ...
void makeEffectiveNetclass(std::shared_ptr< NETCLASS > &effectiveNetclass, std::vector< NETCLASS * > &netclasses) const
Creates an effective aggregate netclass from the given constituent netclasses.
void AppendNetclassLabelAssignment(const wxString &netName, const std::set< wxString > &netclasses)
Apppends to a net name to netclasses assignment Calling user is responsible for resetting the effecti...
void SetDefaultNetclass(std::shared_ptr< NETCLASS > netclass)
Sets the default netclass for the project Calling user is responsible for resetting the effective net...
std::shared_ptr< NETCLASS > GetNetClassByName(const wxString &aNetName) const
Get a NETCLASS object from a given Netclass name string.
void SetNetColorAssignment(const wxString &netName, const KIGFX::COLOR4D &color)
Sets a net to color assignment Calling user is responsible for resetting the effective netclass calcu...
NET_SETTINGS(JSON_SETTINGS *aParent, const std::string &aPath)
bool HasNetclass(const wxString &netclassName) const
Determines if the given netclass exists.
Like a normal param, but with custom getter and setter functions.
Definition: parameters.h:295
bool isDigit(char cc)
Definition: dsnlexer.cpp:458
#define _(s)
@ CTX_NETCLASS
nlohmann::json json
Definition: gerbview.cpp:47
static bool isSuperSubOverbar(wxChar c)
const int netSettingsSchemaVersion
static std::optional< int > getInSchUnits(const nlohmann::json &aObj, const std::string &aKey, std::optional< int > aDefault=std::optional< int >())
static std::optional< int > getInPcbUnits(const nlohmann::json &aObj, const std::string &aKey, std::optional< int > aDefault=std::optional< int >())
wxString ConvertToNewOverbarNotation(const wxString &aOldStr)
Convert the old ~...~ overbar notation to the new ~{...} one.
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_NETNAME
Definition: string_utils.h:53
constexpr double IUTomm(int iu) const
Definition: base_units.h:86
constexpr int IUToMils(int iu) const
Definition: base_units.h:99
constexpr int MilsToIU(int mils) const
Definition: base_units.h:93
constexpr int mmToIU(double mm) const
Definition: base_units.h:88
VECTOR2I end