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
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;
496}
497
498
499const std::map<wxString, std::shared_ptr<NETCLASS>>& NET_SETTINGS::GetNetclasses() const
500{
501 return m_netClasses;
502}
503
504
505const std::map<wxString, std::shared_ptr<NETCLASS>>& NET_SETTINGS::GetCompositeNetclasses() const
506{
508}
509
510
512{
513 m_netClasses.clear();
514 m_impicitNetClasses.clear();
516}
517
518
519const std::map<wxString, std::set<wxString>>& NET_SETTINGS::GetNetclassLabelAssignments() const
520{
522}
523
524
526{
528}
529
530
531void NET_SETTINGS::ClearNetclassLabelAssignment( const wxString& netName )
532{
533 m_netClassLabelAssignments.erase( netName );
534}
535
536
537void NET_SETTINGS::SetNetclassLabelAssignment( const wxString& netName,
538 const std::set<wxString>& netclasses )
539{
540 m_netClassLabelAssignments[netName] = netclasses;
541}
542
543
545 const std::set<wxString>& netclasses )
546{
547 m_netClassLabelAssignments[netName].insert( netclasses.begin(), netclasses.end() );
548}
549
550
551bool NET_SETTINGS::HasNetclassLabelAssignment( const wxString& netName ) const
552{
553 return m_netClassLabelAssignments.find( netName ) != m_netClassLabelAssignments.end();
554}
555
556
557void NET_SETTINGS::SetNetclassPatternAssignment( const wxString& pattern, const wxString& netclass )
558{
559 // Replace existing assignment if we have one
560 for( auto& assignment : m_netClassPatternAssignments )
561 {
562 if( assignment.first->GetPattern() == pattern )
563 {
564 assignment.second = netclass;
566 return;
567 }
568 }
569
570 // No assignment, add a new one
572 { std::make_unique<EDA_COMBINED_MATCHER>( pattern, CTX_NETCLASS ), netclass } );
573
575}
576
577
579 std::vector<std::pair<std::unique_ptr<EDA_COMBINED_MATCHER>, wxString>>&& netclassPatterns )
580{
581 m_netClassPatternAssignments = std::move( netclassPatterns );
583}
584
585
586std::vector<std::pair<std::unique_ptr<EDA_COMBINED_MATCHER>, wxString>>&
588{
590}
591
592
594{
596}
597
598
599void NET_SETTINGS::ClearCacheForNet( const wxString& netName )
600{
601 if( m_effectiveNetclassCache.count( netName ) )
602 {
603 wxString compositeNetclassName = m_effectiveNetclassCache[netName]->GetName();
604 m_compositeNetClasses.erase( compositeNetclassName );
605 m_effectiveNetclassCache.erase( netName );
606 }
607}
608
609
611{
613 m_compositeNetClasses.clear();
614}
615
616
617void NET_SETTINGS::SetNetColorAssignment( const wxString& netName, const KIGFX::COLOR4D& color )
618{
619 m_netColorAssignments[netName] = color;
620}
621
622
623const std::map<wxString, KIGFX::COLOR4D>& NET_SETTINGS::GetNetColorAssignments() const
624{
626}
627
628
630{
631 m_netColorAssignments.clear();
632}
633
634
635bool NET_SETTINGS::HasEffectiveNetClass( const wxString& aNetName ) const
636{
637 return m_effectiveNetclassCache.count( aNetName ) > 0;
638}
639
640
641std::shared_ptr<NETCLASS> NET_SETTINGS::GetCachedEffectiveNetClass( const wxString& aNetName ) const
642{
643 return m_effectiveNetclassCache.at( aNetName );
644}
645
646
647std::shared_ptr<NETCLASS> NET_SETTINGS::GetEffectiveNetClass( const wxString& aNetName )
648{
649 // Lambda to fetch an explicit netclass. Returns a nullptr if not found
650 auto getExplicitNetclass = [this]( const wxString& netclass ) -> std::shared_ptr<NETCLASS>
651 {
652 if( netclass == NETCLASS::Default )
653 return m_defaultNetClass;
654
655 auto ii = m_netClasses.find( netclass );
656
657 if( ii == m_netClasses.end() )
658 return {};
659 else
660 return ii->second;
661 };
662
663 // Lambda to fetch or create an implicit netclass (defined with a label, but not configured)
664 // These are needed as while they do not provide any netclass parameters, they do now appear in
665 // DRC matching strings as an assigned netclass.
666 auto getOrAddImplicitNetcless = [this]( const wxString& netclass ) -> std::shared_ptr<NETCLASS>
667 {
668 auto ii = m_impicitNetClasses.find( netclass );
669
670 if( ii == m_impicitNetClasses.end() )
671 {
672 std::shared_ptr<NETCLASS> nc = std::make_shared<NETCLASS>( netclass, false );
673 nc->SetPriority( std::numeric_limits<int>().max() - 1 ); // Priority > default netclass
674 m_impicitNetClasses[netclass] = nc;
675 return nc;
676 }
677 else
678 {
679 return ii->second;
680 }
681 };
682
683 // <no net> is forced to be part of the default netclass.
684 if( aNetName.IsEmpty() )
685 return m_defaultNetClass;
686
687 // First check if we have a cached resolved netclass
688 auto cacheItr = m_effectiveNetclassCache.find( aNetName );
689
690 if( cacheItr != m_effectiveNetclassCache.end() )
691 return cacheItr->second;
692
693 // No cache found - build a vector of all netclasses assigned to or matching this net
694 std::vector<std::shared_ptr<NETCLASS>> resolvedNetclasses;
695
696 // First find explicit netclass assignments
697 auto it = m_netClassLabelAssignments.find( aNetName );
698
699 if( it != m_netClassLabelAssignments.end() && it->second.size() > 0 )
700 {
701 for( const wxString& netclassName : it->second )
702 {
703 std::shared_ptr<NETCLASS> netclass = getExplicitNetclass( netclassName );
704
705 if( netclass )
706 {
707 resolvedNetclasses.push_back( std::move( netclass ) );
708 }
709 else
710 {
711 resolvedNetclasses.push_back(
712 getOrAddImplicitNetcless( netclassName ) );
713 }
714 }
715 }
716
717 // Now find any pattern-matched netclass assignments
718 for( const auto& [matcher, netclassName] : m_netClassPatternAssignments )
719 {
720 if( matcher->StartsWith( aNetName ) )
721 {
722 std::shared_ptr<NETCLASS> netclass = getExplicitNetclass( netclassName );
723
724 if( netclass )
725 {
726 resolvedNetclasses.push_back( std::move( netclass ) );
727 }
728 else
729 {
730 resolvedNetclasses.push_back( getOrAddImplicitNetcless( netclassName ) );
731 }
732 }
733 }
734
735 // Handle zero resolved netclasses
736 if( resolvedNetclasses.size() == 0 )
737 {
739
740 return m_defaultNetClass;
741 }
742
743 // Make and cache the effective netclass. Note that makeEffectiveNetclass will add the default
744 // netclass to resolvedNetclasses if it is needed to complete the netclass paramters set. It
745 // will also sort resolvedNetclasses by priority order.
746 std::vector<NETCLASS*> netclassPtrs;
747
748 for( std::shared_ptr<NETCLASS>& nc : resolvedNetclasses )
749 netclassPtrs.push_back( nc.get() );
750
751 wxString name;
752 name.Printf( "Effective for net: %s", aNetName );
753 std::shared_ptr<NETCLASS> effectiveNetclass = std::make_shared<NETCLASS>( name, false );
754 makeEffectiveNetclass( effectiveNetclass, netclassPtrs );
755
756 if( netclassPtrs.size() == 1 )
757 {
758 // No defaults were added - just return the primary netclass
759 m_effectiveNetclassCache[aNetName] = resolvedNetclasses[0];
760 return resolvedNetclasses[0];
761 }
762 else
763 {
764 effectiveNetclass->SetConstituentNetclasses( std::move( netclassPtrs ) );
765
766 m_compositeNetClasses[effectiveNetclass->GetName()] = effectiveNetclass;
767 m_effectiveNetclassCache[aNetName] = effectiveNetclass;
768
769 return effectiveNetclass;
770 }
771}
772
773
775{
776 for( auto& [ncName, nc] : m_compositeNetClasses )
777 {
778 // Note this needs to be a copy in case we now need to add the default netclass
779 std::vector<NETCLASS*> constituents = nc->GetConstituentNetclasses();
780
781 wxASSERT( constituents.size() > 0 );
782
783 // If the last netclass is Default, remove it (it will be re-added if still needed)
784 if( ( *constituents.rbegin() )->GetName() == NETCLASS::Default )
785 {
786 constituents.pop_back();
787 }
788
789 // Remake the netclass from original constituents
790 nc->ResetParameters();
791 makeEffectiveNetclass( nc, constituents );
792 nc->SetConstituentNetclasses( std::move( constituents ) );
793 }
794}
795
796
797void NET_SETTINGS::makeEffectiveNetclass( std::shared_ptr<NETCLASS>& effectiveNetclass,
798 std::vector<NETCLASS*>& constituentNetclasses ) const
799{
800 // Sort the resolved netclasses by priority (highest first), with same-priority netclasses
801 // ordered alphabetically
802 std::sort( constituentNetclasses.begin(), constituentNetclasses.end(),
803 []( NETCLASS* nc1, NETCLASS* nc2 )
804 {
805 int p1 = nc1->GetPriority();
806 int p2 = nc2->GetPriority();
807
808 if( p1 < p2 )
809 return true;
810
811 if (p1 == p2)
812 return nc1->GetName().Cmp( nc2->GetName() ) < 0;
813
814 return false;
815 } );
816
817 // Iterate from lowest priority netclass and fill effective netclass parameters
818 for( auto itr = constituentNetclasses.rbegin(); itr != constituentNetclasses.rend(); ++itr )
819 {
820 NETCLASS* nc = *itr;
821
822 if( nc->HasClearance() )
823 {
824 effectiveNetclass->SetClearance( nc->GetClearance() );
825 effectiveNetclass->SetClearanceParent( nc );
826 }
827
828 if( nc->HasTrackWidth() )
829 {
830 effectiveNetclass->SetTrackWidth( nc->GetTrackWidth() );
831 effectiveNetclass->SetTrackWidthParent( nc );
832 }
833
834 if( nc->HasViaDiameter() )
835 {
836 effectiveNetclass->SetViaDiameter( nc->GetViaDiameter() );
837 effectiveNetclass->SetViaDiameterParent( nc );
838 }
839
840 if( nc->HasViaDrill() )
841 {
842 effectiveNetclass->SetViaDrill( nc->GetViaDrill() );
843 effectiveNetclass->SetViaDrillParent( nc );
844 }
845
846 if( nc->HasuViaDiameter() )
847 {
848 effectiveNetclass->SetuViaDiameter( nc->GetuViaDiameter() );
849 effectiveNetclass->SetuViaDiameterParent( nc );
850 }
851
852 if( nc->HasuViaDrill() )
853 {
854 effectiveNetclass->SetuViaDrill( nc->GetuViaDrill() );
855 effectiveNetclass->SetuViaDrillParent( nc );
856 }
857
858 if( nc->HasDiffPairWidth() )
859 {
860 effectiveNetclass->SetDiffPairWidth( nc->GetDiffPairWidth() );
861 effectiveNetclass->SetDiffPairWidthParent( nc );
862 }
863
864 if( nc->HasDiffPairGap() )
865 {
866 effectiveNetclass->SetDiffPairGap( nc->GetDiffPairGap() );
867 effectiveNetclass->SetDiffPairGapParent( nc );
868 }
869
870 if( nc->HasDiffPairViaGap() )
871 {
872 effectiveNetclass->SetDiffPairViaGap( nc->GetDiffPairViaGap() );
873 effectiveNetclass->SetDiffPairViaGapParent( nc );
874 }
875
876 if( nc->HasWireWidth() )
877 {
878 effectiveNetclass->SetWireWidth( nc->GetWireWidth() );
879 effectiveNetclass->SetWireWidthParent( nc );
880 }
881
882 if( nc->HasBusWidth() )
883 {
884 effectiveNetclass->SetBusWidth( nc->GetBusWidth() );
885 effectiveNetclass->SetBusWidthParent( nc );
886 }
887
888 if( nc->HasLineStyle() )
889 {
890 effectiveNetclass->SetLineStyle( nc->GetLineStyle() );
891 effectiveNetclass->SetLineStyleParent( nc );
892 }
893
894 COLOR4D pcbColor = nc->GetPcbColor();
895
896 if( pcbColor != COLOR4D::UNSPECIFIED )
897 {
898 effectiveNetclass->SetPcbColor( pcbColor );
899 effectiveNetclass->SetPcbColorParent( nc );
900 }
901
902 COLOR4D schColor = nc->GetSchematicColor();
903
904 if( schColor != COLOR4D::UNSPECIFIED )
905 {
906 effectiveNetclass->SetSchematicColor( schColor );
907 effectiveNetclass->SetSchematicColorParent( nc );
908 }
909 }
910
911 // Fill in any required defaults
912 if( addMissingDefaults( effectiveNetclass.get() ) )
913 constituentNetclasses.push_back( m_defaultNetClass.get() );
914}
915
916
918{
919 bool addedDefault = false;
920
921 if( !nc->HasClearance() )
922 {
923 addedDefault = true;
924 nc->SetClearance( m_defaultNetClass->GetClearance() );
926 }
927
928 if( !nc->HasTrackWidth() )
929 {
930 addedDefault = true;
931 nc->SetTrackWidth( m_defaultNetClass->GetTrackWidth() );
933 }
934
935 if( !nc->HasViaDiameter() )
936 {
937 addedDefault = true;
938 nc->SetViaDiameter( m_defaultNetClass->GetViaDiameter() );
940 }
941
942 if( !nc->HasViaDrill() )
943 {
944 addedDefault = true;
945 nc->SetViaDrill( m_defaultNetClass->GetViaDrill() );
947 }
948
949 if( !nc->HasuViaDiameter() )
950 {
951 addedDefault = true;
952 nc->SetuViaDiameter( m_defaultNetClass->GetuViaDiameter() );
954 }
955
956 if( !nc->HasuViaDrill() )
957 {
958 addedDefault = true;
959 nc->SetuViaDrill( m_defaultNetClass->GetuViaDrill() );
961 }
962
963 if( !nc->HasDiffPairWidth() )
964 {
965 addedDefault = true;
966 nc->SetDiffPairWidth( m_defaultNetClass->GetDiffPairWidth() );
968 }
969
970 if( !nc->HasDiffPairGap() )
971 {
972 addedDefault = true;
973 nc->SetDiffPairGap( m_defaultNetClass->GetDiffPairGap() );
975 }
976
977 // Currently this is only on the default netclass, and not editable in the setup panel
978 // if( !nc->HasDiffPairViaGap() )
979 // {
980 // addedDefault = true;
981 // nc->SetDiffPairViaGap( m_defaultNetClass->GetDiffPairViaGap() );
982 // nc->SetDiffPairViaGapParent( m_defaultNetClass.get() );
983 // }
984
985 if( !nc->HasWireWidth() )
986 {
987 addedDefault = true;
988 nc->SetWireWidth( m_defaultNetClass->GetWireWidth() );
990 }
991
992 if( !nc->HasBusWidth() )
993 {
994 addedDefault = true;
995 nc->SetBusWidth( m_defaultNetClass->GetBusWidth() );
997 }
998
999 return addedDefault;
1000}
1001
1002
1003std::shared_ptr<NETCLASS> NET_SETTINGS::GetNetClassByName( const wxString& aNetClassName ) const
1004{
1005 auto ii = m_netClasses.find( aNetClassName );
1006
1007 if( ii == m_netClasses.end() )
1008 return m_defaultNetClass;
1009 else
1010 return ii->second;
1011}
1012
1013
1014static bool isSuperSubOverbar( wxChar c )
1015{
1016 return c == '_' || c == '^' || c == '~';
1017}
1018
1019
1020bool NET_SETTINGS::ParseBusVector( const wxString& aBus, wxString* aName,
1021 std::vector<wxString>* aMemberList )
1022{
1023 auto isDigit = []( wxChar c )
1024 {
1025 static wxString digits( wxT( "0123456789" ) );
1026 return digits.Contains( c );
1027 };
1028
1029 size_t busLen = aBus.length();
1030 size_t i = 0;
1031 wxString prefix;
1032 wxString suffix;
1033 wxString tmp;
1034 long begin = 0;
1035 long end = 0;
1036 int braceNesting = 0;
1037
1038 prefix.reserve( busLen );
1039
1040 // Parse prefix
1041 //
1042 for( ; i < busLen; ++i )
1043 {
1044 if( aBus[i] == '{' )
1045 {
1046 if( i > 0 && isSuperSubOverbar( aBus[i-1] ) )
1047 braceNesting++;
1048 else
1049 return false;
1050 }
1051 else if( aBus[i] == '}' )
1052 {
1053 braceNesting--;
1054 }
1055
1056 if( aBus[i] == ' ' || aBus[i] == ']' )
1057 return false;
1058
1059 if( aBus[i] == '[' )
1060 break;
1061
1062 prefix += aBus[i];
1063 }
1064
1065 // Parse start number
1066 //
1067 i++; // '[' character
1068
1069 if( i >= busLen )
1070 return false;
1071
1072 for( ; i < busLen; ++i )
1073 {
1074 if( aBus[i] == '.' && i + 1 < busLen && aBus[i+1] == '.' )
1075 {
1076 tmp.ToLong( &begin );
1077 i += 2;
1078 break;
1079 }
1080
1081 if( !isDigit( aBus[i] ) )
1082 return false;
1083
1084 tmp += aBus[i];
1085 }
1086
1087 // Parse end number
1088 //
1089 tmp = wxEmptyString;
1090
1091 if( i >= busLen )
1092 return false;
1093
1094 for( ; i < busLen; ++i )
1095 {
1096 if( aBus[i] == ']' )
1097 {
1098 tmp.ToLong( &end );
1099 ++i;
1100 break;
1101 }
1102
1103 if( !isDigit( aBus[i] ) )
1104 return false;
1105
1106 tmp += aBus[i];
1107 }
1108
1109 // Parse suffix
1110 //
1111 for( ; i < busLen; ++i )
1112 {
1113 if( aBus[i] == '}' )
1114 {
1115 braceNesting--;
1116 suffix += aBus[i];
1117 }
1118 else
1119 {
1120 return false;
1121 }
1122 }
1123
1124 if( braceNesting != 0 )
1125 return false;
1126
1127 if( begin == end )
1128 return false;
1129 else if( begin > end )
1130 std::swap( begin, end );
1131
1132 if( aName )
1133 *aName = prefix;
1134
1135 if( aMemberList )
1136 {
1137 for( long idx = begin; idx <= end; ++idx )
1138 {
1139 wxString str = prefix;
1140 str << idx;
1141 str << suffix;
1142
1143 aMemberList->emplace_back( str );
1144 }
1145 }
1146
1147 return true;
1148}
1149
1150
1151bool NET_SETTINGS::ParseBusGroup( const wxString& aGroup, wxString* aName,
1152 std::vector<wxString>* aMemberList )
1153{
1154 size_t groupLen = aGroup.length();
1155 size_t i = 0;
1156 wxString prefix;
1157 wxString tmp;
1158 int braceNesting = 0;
1159
1160 prefix.reserve( groupLen );
1161
1162 // Parse prefix
1163 //
1164 for( ; i < groupLen; ++i )
1165 {
1166 if( aGroup[i] == '{' )
1167 {
1168 if( i > 0 && isSuperSubOverbar( aGroup[i-1] ) )
1169 braceNesting++;
1170 else
1171 break;
1172 }
1173 else if( aGroup[i] == '}' )
1174 {
1175 braceNesting--;
1176 }
1177
1178 if( aGroup[i] == ' ' || aGroup[i] == '[' || aGroup[i] == ']' )
1179 return false;
1180
1181 prefix += aGroup[i];
1182 }
1183
1184 if( braceNesting != 0 )
1185 return false;
1186
1187 if( aName )
1188 *aName = prefix;
1189
1190 // Parse members
1191 //
1192 i++; // '{' character
1193
1194 if( i >= groupLen )
1195 return false;
1196
1197 for( ; i < groupLen; ++i )
1198 {
1199 if( aGroup[i] == '{' )
1200 {
1201 if( i > 0 && isSuperSubOverbar( aGroup[i-1] ) )
1202 braceNesting++;
1203 else
1204 return false;
1205 }
1206 else if( aGroup[i] == '}' )
1207 {
1208 if( braceNesting )
1209 {
1210 braceNesting--;
1211 }
1212 else
1213 {
1214 if( aMemberList && !tmp.IsEmpty() )
1215 aMemberList->push_back( EscapeString( tmp, CTX_NETNAME ) );
1216
1217 return true;
1218 }
1219 }
1220
1221 // Commas aren't strictly legal, but we can be pretty sure what the author had in mind.
1222 if( aGroup[i] == ' ' || aGroup[i] == ',' )
1223 {
1224 if( aMemberList && !tmp.IsEmpty() )
1225 aMemberList->push_back( EscapeString( tmp, CTX_NETNAME ) );
1226
1227 tmp.Clear();
1228 continue;
1229 }
1230
1231 tmp += aGroup[i];
1232 }
1233
1234 return false;
1235}
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