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