KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_rule_editor_utils.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) 2024 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
25#include <reporter.h>
27#include <drc/drc_rule_parser.h>
28#include <drc/drc_rule.h>
40#include <board.h>
41#include <wx/ffile.h>
42#include <wx/regex.h>
43#include <unordered_map>
44
45using CODE_MAP = std::unordered_map<DRC_RULE_EDITOR_CONSTRAINT_NAME, const char*>;
46using REVERSE_CODE_MAP = std::unordered_map<wxString, DRC_RULE_EDITOR_CONSTRAINT_NAME, wxStringHash, wxStringEqual>;
47
48static const CODE_MAP sCodeMap = { { BASIC_CLEARANCE, "clearance" },
49 { BOARD_OUTLINE_CLEARANCE, "edge_clearance" },
50 { MINIMUM_CLEARANCE, "clearance" },
51 { MINIMUM_ITEM_CLEARANCE, "clearance" },
52 { CREEPAGE_DISTANCE, "creepage" },
53 { MINIMUM_CONNECTION_WIDTH, "connection_width" },
54 { MINIMUM_TRACK_WIDTH, "track_width" },
55 { COPPER_TO_HOLE_CLEARANCE, "hole_clearance" },
56 { HOLE_TO_HOLE_CLEARANCE, "hole_to_hole" },
57 { MINIMUM_THERMAL_RELIEF_SPOKE_COUNT, "thermal_spoke_width" },
58 { MINIMUM_ANNULAR_WIDTH, "annular_width" },
59 { COPPER_TO_EDGE_CLEARANCE, "edge_clearance" },
60 { COURTYARD_CLEARANCE, "courtyard_clearance" },
61 { PHYSICAL_CLEARANCE, "physical_clearance" },
62 { MINIMUM_THROUGH_HOLE, "hole" },
63 { HOLE_SIZE, "hole" },
64 { HOLE_TO_HOLE_DISTANCE, "hole_to_hole" },
65 { MINIMUM_UVIA_HOLE, "hole" },
66 { MINIMUM_UVIA_DIAMETER, "via_diameter" },
67 { MINIMUM_VIA_DIAMETER, "via_diameter" },
68 { VIA_STYLE, "via_style" },
69 { MINIMUM_TEXT_HEIGHT_AND_THICKNESS, "text_height" },
70 { SILK_TO_SILK_CLEARANCE, "silk_clearance" },
71 { SILK_TO_SOLDERMASK_CLEARANCE, "silk_clearance" },
72 { MINIMUM_SOLDERMASK_SILVER, "solder_mask_sliver" },
73 { SOLDERMASK_EXPANSION, "solder_mask_expansion" },
74 { SOLDERPASTE_EXPANSION, "solder_paste_abs_margin" },
75 { MAXIMUM_ALLOWED_DEVIATION, "maximum_allowed_deviation" },
76 { MINIMUM_ANGULAR_RING, "annular_width" },
77 { MATCHED_LENGTH_DIFF_PAIR, "length" },
78 { ROUTING_DIFF_PAIR, "diff_pair_gap" },
79 { ROUTING_WIDTH, "track_width" },
80 { MAXIMUM_VIA_COUNT, "via_count" },
81 { ABSOLUTE_LENGTH, "length" },
82 { PERMITTED_LAYERS, "permitted_layers" },
83 { ALLOWED_ORIENTATION, "allowed_orientation" },
84 { VIAS_UNDER_SMD, "vias_under_smd" } };
85
87{
89 for( const auto& [type, code] : sCodeMap )
90 map.emplace( wxString::FromUTF8( code ), type );
91 return map;
92}();
93
94static std::vector<DRC_RULE_EDITOR_UTILS::RuleConverter>& GetRuleConverters()
95{
96 static std::vector<DRC_RULE_EDITOR_UTILS::RuleConverter> converters;
97 return converters;
98}
99
101{
102 GetRuleConverters().insert( GetRuleConverters().begin(), aConverter );
103}
104
106{
107 switch( aType )
108 {
109 case CLEARANCE_CONSTRAINT: return "clearance";
110 case EDGE_CLEARANCE_CONSTRAINT: return "edge_clearance";
111 case HOLE_CLEARANCE_CONSTRAINT: return "hole_clearance";
112 case HOLE_TO_HOLE_CONSTRAINT: return "hole_to_hole";
113 case HOLE_SIZE_CONSTRAINT: return "hole_size";
114 case TRACK_WIDTH_CONSTRAINT: return "track_width";
115 case ANNULAR_WIDTH_CONSTRAINT: return "annular_width";
116 case VIA_DIAMETER_CONSTRAINT: return "via_diameter";
117 case DISALLOW_CONSTRAINT: return "disallow";
118 case COURTYARD_CLEARANCE_CONSTRAINT: return "courtyard_clearance";
119 case SILK_CLEARANCE_CONSTRAINT: return "silk_clearance";
120 case TEXT_HEIGHT_CONSTRAINT: return "text_height";
121 case TEXT_THICKNESS_CONSTRAINT: return "text_thickness";
122 case TRACK_ANGLE_CONSTRAINT: return "track_angle";
123 case TRACK_SEGMENT_LENGTH_CONSTRAINT: return "track_segment_length";
124 case CONNECTION_WIDTH_CONSTRAINT: return "connection_width";
125 case VIA_DANGLING_CONSTRAINT: return "via_dangling";
126 case ZONE_CONNECTION_CONSTRAINT: return "zone_connection";
127 case THERMAL_RELIEF_GAP_CONSTRAINT: return "thermal_relief_gap";
128 case THERMAL_SPOKE_WIDTH_CONSTRAINT: return "thermal_spoke_width";
129 case MIN_RESOLVED_SPOKES_CONSTRAINT: return "min_resolved_spokes";
130 case SOLDER_MASK_EXPANSION_CONSTRAINT: return "solder_mask_expansion";
131 case SOLDER_PASTE_ABS_MARGIN_CONSTRAINT: return "solder_paste_abs_margin";
132 case SOLDER_PASTE_REL_MARGIN_CONSTRAINT: return "solder_paste_rel_margin";
133 case LENGTH_CONSTRAINT: return "length";
134 case SKEW_CONSTRAINT: return "skew";
135 case VIA_COUNT_CONSTRAINT: return "via_count";
136 case DIFF_PAIR_GAP_CONSTRAINT: return "diff_pair_gap";
137 case MAX_UNCOUPLED_CONSTRAINT: return "diff_pair_uncoupled";
138 case PHYSICAL_CLEARANCE_CONSTRAINT: return "physical_clearance";
139 case PHYSICAL_HOLE_CLEARANCE_CONSTRAINT: return "physical_hole_clearance";
140 case BRIDGED_MASK_CONSTRAINT: return "bridged_mask";
141 case ASSERTION_CONSTRAINT: return "assertion";
142 default: return "";
143 }
144}
145
147{
148 static bool initialized = false;
149 if( initialized )
150 return;
151 initialized = true;
152
153 // Generic Converter
155 []( const std::shared_ptr<DRC_RULE>& aRule ) -> std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>
156 {
157 if( aRule->m_Constraints.empty() ) return nullptr;
158
159 const auto& constraint = aRule->m_Constraints[0];
160 wxString code = GetConstraintCodeFromType( constraint.m_Type );
161
162 if( code.IsEmpty() ) return nullptr;
163
164 if( sCodeReverse.count( code ) )
165 {
166 auto type = sCodeReverse.at( code );
167
169 {
170 double val = constraint.GetValue().Min() / 1000000.0;
171 auto data = std::make_shared<DRC_RE_NUMERIC_INPUT_CONSTRAINT_DATA>( 0, 0, val, aRule->m_Name );
172 data->SetConstraintCode( code );
173 return data;
174 }
176 {
177 auto data = std::make_shared<DRC_RE_BOOL_INPUT_CONSTRAINT_DATA>( 0, 0, true, aRule->m_Name );
178 data->SetConstraintCode( code );
179 return data;
180 }
181 else if( code == "track_width" )
182 {
183 double minW = constraint.GetValue().Min() / 1000000.0;
184 double optW = constraint.GetValue().Opt() / 1000000.0;
185 double maxW = constraint.GetValue().Max() / 1000000.0;
186
187 auto data = std::make_shared<DRC_RE_ROUTING_WIDTH_CONSTRAINT_DATA>( 0, 0, aRule->m_Name, minW, optW, maxW );
188 data->SetConstraintCode( code );
189 return data;
190 }
191 }
192 return nullptr;
193 } );
194
195 // Via Style Converter
197 []( const std::shared_ptr<DRC_RULE>& aRule ) -> std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>
198 {
199 auto diaConstraint = aRule->FindConstraint( VIA_DIAMETER_CONSTRAINT );
200 auto holeConstraint = aRule->FindConstraint( HOLE_SIZE_CONSTRAINT );
201
202 if( diaConstraint && holeConstraint )
203 {
204 double minDia = diaConstraint->GetValue().Min() / 1000000.0;
205 double optDia = diaConstraint->GetValue().Opt() / 1000000.0;
206 double maxDia = diaConstraint->GetValue().Max() / 1000000.0;
207
208 double minDrill = holeConstraint->GetValue().Min() / 1000000.0;
209 double optDrill = holeConstraint->GetValue().Opt() / 1000000.0;
210 double maxDrill = holeConstraint->GetValue().Max() / 1000000.0;
211
212 auto data = std::make_shared<DRC_RE_VIA_STYLE_CONSTRAINT_DATA>( 0, 0, aRule->m_Name,
213 minDia, maxDia, optDia, minDrill, maxDrill, optDrill );
214 data->SetConstraintCode( "via_style" );
215 return data;
216 }
217 return nullptr;
218 } );
219}
220
221
223{
224 auto it = sCodeMap.find( aConstraintType );
225 if( it != sCodeMap.end() )
226 return wxString::FromUTF8( it->second );
227
228 return wxString();
229}
230
231
232std::optional<DRC_RULE_EDITOR_CONSTRAINT_NAME> DRC_RULE_EDITOR_UTILS::GetConstraintTypeFromCode( const wxString& aCode )
233{
234 auto it = sCodeReverse.find( aCode );
235 if( it != sCodeReverse.end() )
236 return it->second;
237
238 return std::nullopt;
239}
240
241
246
247
249{
250 if( !aData )
251 return false;
252
253 auto type = GetConstraintTypeFromCode( aCode );
254 if( type )
255 {
256 aData->SetConstraintCode( GetConstraintCode( *type ) );
257 return true;
258 }
259
260 aData->SetConstraintCode( aCode );
261 return false;
262}
263
264
266{
267 switch( aConstraintType )
268 {
269 case VIAS_UNDER_SMD: return true;
270 default: return false;
271 }
272}
273
274
312
313
314bool DRC_RULE_EDITOR_UTILS::ValidateNumericCtrl( wxTextCtrl* aTextCtrl, std::string aLabel, bool aCanBeZero,
315 int* aErrorCount, std::string* aValidationMessage )
316{
317 VALIDATOR_NUMERIC_CTRL validator( aCanBeZero );
318 aTextCtrl->SetValidator( validator );
319
320 if( !aTextCtrl->Validate() )
321 {
322 VALIDATOR_NUMERIC_CTRL* v = static_cast<VALIDATOR_NUMERIC_CTRL*>( aTextCtrl->GetValidator() );
323
324 switch( v->GetValidationState() )
325 {
327 {
328 ( *aErrorCount )++;
329 *aValidationMessage +=
330 DRC_RULE_EDITOR_UTILS::FormatErrorMessage( *aErrorCount, aLabel + " should not be empty !!" );
331 return false;
332 }
334 {
335 ( *aErrorCount )++;
336 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
337 *aErrorCount, "The value of " + aLabel + " should be valid numeric value !!" );
338 return false;
339 }
341 {
342 ( *aErrorCount )++;
343 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
344 *aErrorCount, "The value of " + aLabel + " must be greater than 0 !!" );
345 return false;
346 }
347 default: break;
348 }
349 }
350
351 return true;
352}
353
354
355bool DRC_RULE_EDITOR_UTILS::ValidateIntegerCtrl( wxTextCtrl* aTextCtrl, std::string aLabel, bool aCanBeZero,
356 int* aErrorCount, std::string* aValidationMessage )
357{
358 VALIDATOR_NUMERIC_CTRL validator( aCanBeZero, true );
359 aTextCtrl->SetValidator( validator );
360
361 if( !aTextCtrl->Validate() )
362 {
363 VALIDATOR_NUMERIC_CTRL* v = static_cast<VALIDATOR_NUMERIC_CTRL*>( aTextCtrl->GetValidator() );
364
365 switch( v->GetValidationState() )
366 {
368 {
369 ( *aErrorCount )++;
370 *aValidationMessage +=
371 DRC_RULE_EDITOR_UTILS::FormatErrorMessage( *aErrorCount, aLabel + " should not be empty !!" );
372 return false;
373 }
375 {
376 ( *aErrorCount )++;
377 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
378 *aErrorCount, "The value of " + aLabel + " should be valid integer value !!" );
379 return false;
380 }
382 {
383 ( *aErrorCount )++;
384 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
385 *aErrorCount, "The value of " + aLabel + " must be greater than 0 !!" );
386 return false;
387 }
388 default: break;
389 }
390 }
391
392 return true;
393}
394
395
396bool DRC_RULE_EDITOR_UTILS::ValidateComboCtrl( wxComboBox* aComboBox, std::string aLabel, int* aErrorCount,
397 std::string* aValidationMessage )
398{
399 VALIDATOR_COMBO_CTRL cmbCtrlValidator;
400 aComboBox->SetValidator( cmbCtrlValidator );
401
402 if( !aComboBox->Validate() )
403 {
404 VALIDATOR_COMBO_CTRL* v = static_cast<VALIDATOR_COMBO_CTRL*>( aComboBox->GetValidator() );
405
406 switch( v->GetValidationState() )
407 {
409 {
410 ( *aErrorCount )++;
411 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage( *aErrorCount, "Please choose " + aLabel );
412 return false;
413 }
414 default: break;
415 }
416 }
417
418 return true;
419}
420
421
422bool DRC_RULE_EDITOR_UTILS::ValidateMinMaxCtrl( wxTextCtrl* aMinTextCtrl, wxTextCtrl* aMaxTextCtrl,
423 std::string aMinLabel, std::string aMaxLabel, int* aErrorCount,
424 std::string* aValidationMessage )
425{
426 aMinTextCtrl->SetName( "min" );
427 aMaxTextCtrl->SetName( "max" );
428
429 aMinTextCtrl->SetValidator( VALIDATE_MIN_MAX_CTRL( aMinTextCtrl, aMaxTextCtrl ) );
430
431 if( !aMinTextCtrl->Validate() )
432 {
433 VALIDATE_MIN_MAX_CTRL* v = static_cast<VALIDATE_MIN_MAX_CTRL*>( aMinTextCtrl->GetValidator() );
434
435 switch( v->GetValidationState() )
436 {
438 {
439 ( *aErrorCount )++;
440 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
441 *aErrorCount, aMinLabel + " value cannot be greater than " + aMaxLabel + " value" );
442 return false;
443 }
444 default: break;
445 }
446 }
447
448 aMinTextCtrl->SetName( "text" );
449 aMaxTextCtrl->SetName( "text" );
450
451 return true;
452}
453
454
455bool DRC_RULE_EDITOR_UTILS::ValidateMinPreferredMaxCtrl( wxTextCtrl* aMinTextCtrl, wxTextCtrl* aPreferredTextCtrl,
456 wxTextCtrl* aMaxTextCtrl, std::string aMinLabel,
457 std::string aPreferredLabel, std::string aMaxLabel,
458 int* aErrorCount, std::string* aValidationMessage )
459{
460 aMinTextCtrl->SetName( "min" );
461 aPreferredTextCtrl->SetName( "preferred" );
462 aMaxTextCtrl->SetName( "max" );
463
464 aMinTextCtrl->SetValidator( VALIDATE_MIN_PREFERRED_MAX_CTRL( aMinTextCtrl, aPreferredTextCtrl, aMaxTextCtrl ) );
465
466 if( !aMinTextCtrl->Validate() )
467 {
469 static_cast<VALIDATE_MIN_PREFERRED_MAX_CTRL*>( aMinTextCtrl->GetValidator() );
470
471 switch( v->GetValidationState() )
472 {
474 {
475 ( *aErrorCount )++;
476 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
477 *aErrorCount, aMinLabel + " value cannot be greater than " + aPreferredLabel + " value" );
478 return false;
479 }
481 {
482 ( *aErrorCount )++;
483 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
484 *aErrorCount, aPreferredLabel + " value cannot be greater than " + aMaxLabel + " value" );
485 return false;
486 }
488 {
489 ( *aErrorCount )++;
490 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
491 *aErrorCount, aMinLabel + " value cannot be greater than " + aMaxLabel + " value" );
492 return false;
493 }
494 default: break;
495 }
496 }
497
498 aMinTextCtrl->SetName( "text" );
499 aPreferredTextCtrl->SetName( "text" );
500 aMaxTextCtrl->SetName( "text" );
501
502 return true;
503}
504
505
506bool DRC_RULE_EDITOR_UTILS::ValidateCheckBoxCtrls( const std::vector<wxCheckBox*>& aCheckboxes, std::string aLabel,
507 int* aErrorCount, std::string* aValidationMessage )
508{
509 VALIDATE_CHECKBOX_LIST validator( aCheckboxes );
510
511 aCheckboxes[0]->SetValidator( validator );
512
513 if( !aCheckboxes[0]->Validate() )
514 {
515 VALIDATE_CHECKBOX_LIST* v = static_cast<VALIDATE_CHECKBOX_LIST*>( aCheckboxes[0]->GetValidator() );
516
517 switch( v->GetValidationState() )
518 {
520 {
521 ( *aErrorCount )++;
522 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
523 *aErrorCount, "Please select at least one option from " + aLabel + " list" );
524 return false;
525 }
526 default: break;
527 }
528 }
529
530 return true;
531}
532
533
534std::string DRC_RULE_EDITOR_UTILS::FormatErrorMessage( const int& aErrorCount, const std::string aErrorMessage )
535{
536 return std::to_string( aErrorCount ) + ". " + aErrorMessage + "\n";
537}
538
539
540// ==================== Pure Validators (No GUI Dependencies) ====================
541
542bool DRC_RULE_EDITOR_UTILS::ValidateNumericValue( double aValue, bool aCanBeZero, const std::string& aLabel,
543 VALIDATION_RESULT* aResult )
544{
545 if( !aCanBeZero && aValue <= 0.0 )
546 {
547 aResult->AddError( "The value of " + aLabel + " must be greater than 0" );
548 return false;
549 }
550
551 return true;
552}
553
554
555bool DRC_RULE_EDITOR_UTILS::ValidateNumericString( const std::string& aValueStr, bool aCanBeZero,
556 bool aIntegerOnly, const std::string& aLabel,
557 VALIDATION_RESULT* aResult )
558{
559 if( aValueStr.empty() )
560 {
561 aResult->AddError( aLabel + " should not be empty" );
562 return false;
563 }
564
565 try
566 {
567 if( aIntegerOnly )
568 {
569 size_t pos;
570 long intVal = std::stol( aValueStr, &pos );
571
572 if( pos != aValueStr.length() )
573 {
574 aResult->AddError( "The value of " + aLabel + " should be a valid integer value" );
575 return false;
576 }
577
578 if( !aCanBeZero && intVal <= 0 )
579 {
580 aResult->AddError( "The value of " + aLabel + " must be greater than 0" );
581 return false;
582 }
583 }
584 else
585 {
586 size_t pos;
587 double floatVal = std::stod( aValueStr, &pos );
588
589 if( pos != aValueStr.length() )
590 {
591 aResult->AddError( "The value of " + aLabel + " should be a valid numeric value" );
592 return false;
593 }
594
595 if( !aCanBeZero && floatVal <= 0.0 )
596 {
597 aResult->AddError( "The value of " + aLabel + " must be greater than 0" );
598 return false;
599 }
600 }
601 }
602 catch( const std::exception& )
603 {
604 if( aIntegerOnly )
605 aResult->AddError( "The value of " + aLabel + " should be a valid integer value" );
606 else
607 aResult->AddError( "The value of " + aLabel + " should be a valid numeric value" );
608
609 return false;
610 }
611
612 return true;
613}
614
615
616bool DRC_RULE_EDITOR_UTILS::ValidateMinMax( double aMin, double aMax, const std::string& aMinLabel,
617 const std::string& aMaxLabel, VALIDATION_RESULT* aResult )
618{
619 if( aMin > aMax )
620 {
621 aResult->AddError( aMinLabel + " value cannot be greater than " + aMaxLabel + " value" );
622 return false;
623 }
624
625 return true;
626}
627
628
629bool DRC_RULE_EDITOR_UTILS::ValidateMinPreferredMax( double aMin, double aPreferred, double aMax,
630 const std::string& aMinLabel,
631 const std::string& aPrefLabel,
632 const std::string& aMaxLabel,
633 VALIDATION_RESULT* aResult )
634{
635 bool valid = true;
636
637 if( aMin > aPreferred )
638 {
639 aResult->AddError( aMinLabel + " value cannot be greater than " + aPrefLabel + " value" );
640 valid = false;
641 }
642
643 if( aPreferred > aMax )
644 {
645 aResult->AddError( aPrefLabel + " value cannot be greater than " + aMaxLabel + " value" );
646 valid = false;
647 }
648
649 if( aMin > aMax )
650 {
651 aResult->AddError( aMinLabel + " value cannot be greater than " + aMaxLabel + " value" );
652 valid = false;
653 }
654
655 return valid;
656}
657
658
659bool DRC_RULE_EDITOR_UTILS::ValidateAtLeastOneSelected( const std::vector<bool>& aSelected,
660 const std::string& aLabel,
661 VALIDATION_RESULT* aResult )
662{
663 for( bool selected : aSelected )
664 {
665 if( selected )
666 return true;
667 }
668
669 aResult->AddError( "Please select at least one option from " + aLabel + " list" );
670 return false;
671}
672
673
674bool DRC_RULE_EDITOR_UTILS::ValidateSelection( int aSelectionIndex, const std::string& aLabel,
675 VALIDATION_RESULT* aResult )
676{
677 if( aSelectionIndex < 0 )
678 {
679 aResult->AddError( "Please choose " + aLabel );
680 return false;
681 }
682
683 return true;
684}
685
686
687std::vector<std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>> DRC_RULE_EDITOR_UTILS::ParseRules( const wxString& aRules )
688{
690
691 std::vector<std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>> rules;
692 std::vector<std::shared_ptr<DRC_RULE>> parsedRules;
693
694 wxString rulesText = aRules;
695 if( !rulesText.Contains( "(version" ) )
696 rulesText.Prepend( "(version 1)\n" );
697
698 try
699 {
700 DRC_RULES_PARSER parser( rulesText, "Rule Editor Source" );
701 parser.Parse( parsedRules, nullptr );
702 }
703 catch( const IO_ERROR& )
704 {
705 }
706
707 for( const auto& rule : parsedRules )
708 {
709 std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA> data;
710
711 for( const auto& converter : GetRuleConverters() )
712 {
713 data = converter( rule );
714 if( data )
715 break;
716 }
717
718 if( !data )
719 {
720 auto customData = std::make_shared<DRC_RE_CUSTOM_RULE_CONSTRAINT_DATA>( 0, 0, rule->m_Name );
721 customData->SetRuleText( wxString::Format( "(rule \"%s\" ...)", rule->m_Name ) );
722 data = customData;
723 }
724
725 if( rule->m_Condition )
726 data->SetRuleCondition( rule->m_Condition->GetExpression() );
727
728 rules.push_back( data );
729 }
730
731 return rules;
732}
733
734bool DRC_RULE_EDITOR_UTILS::SaveRules( const wxString& aFilename,
735 const std::vector<std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>>& aRules,
736 const BOARD* aBoard )
737{
738 wxFFile file( aFilename, "w" );
739
740 if( !file.IsOpened() )
741 return false;
742
743 file.Write( "(version 1)\n" );
744
745 for( const auto& data : aRules )
746 {
747 if( !data )
748 continue;
749
751 ctx.ruleName = data->GetRuleName();
752 ctx.comment = data->GetComment();
753 ctx.conditionExpression = data->GetRuleCondition();
754 ctx.constraintCode = data->GetConstraintCode();
755
756 std::vector<PCB_LAYER_ID> layers = data->GetLayers();
757
758 if( !layers.empty() && aBoard )
759 {
760 wxString layerStr = "(layer";
761
762 for( PCB_LAYER_ID layer : layers )
763 layerStr += " \"" + aBoard->GetLayerName( layer ) + "\"";
764
765 layerStr += ")";
766 ctx.layerClause = layerStr;
767 }
768
769 wxString ruleText = data->GenerateRule( ctx );
770 file.Write( ruleText + "\n" );
771 }
772
773 file.Close();
774 return true;
775}
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:730
void Parse(std::vector< std::shared_ptr< DRC_RULE > > &aRules, REPORTER *aReporter)
static bool ValidateMinPreferredMax(double aMin, double aPreferred, double aMax, const std::string &aMinLabel, const std::string &aPrefLabel, const std::string &aMaxLabel, VALIDATION_RESULT *aResult)
Validates that min <= preferred <= max.
static bool ValidateMinMaxCtrl(wxTextCtrl *aMinTextCtrl, wxTextCtrl *aMaxTextCtrl, std::string aMinLabel, std::string aMaxLabel, int *aErrorCount, std::string *aValidationMessage)
Validates the minimum and maximum value controls, ensuring that the minimum value is not greater than...
static bool ValidateMinMax(double aMin, double aMax, const std::string &aMinLabel, const std::string &aMaxLabel, VALIDATION_RESULT *aResult)
Validates that min <= max.
static bool ValidateNumericValue(double aValue, bool aCanBeZero, const std::string &aLabel, VALIDATION_RESULT *aResult)
Validates a numeric value.
static bool IsNumericInputType(const DRC_RULE_EDITOR_CONSTRAINT_NAME &aConstraintType)
static wxString ConstraintToKicadDrc(DRC_RULE_EDITOR_CONSTRAINT_NAME aType)
Convert a constraint type into the keyword used in a .kicad_drc file.
static bool ValidateComboCtrl(wxComboBox *aComboBox, std::string aLabel, int *aErrorCount, std::string *aValidationMessage)
Validates a combo box control, ensuring that a selection has been made.
static wxString GetConstraintCode(DRC_RULE_EDITOR_CONSTRAINT_NAME aConstraintType)
Translate a rule tree node type into the keyword used by the rules file for that constraint.
static bool ConstraintFromKicadDrc(const wxString &aCode, DRC_RE_BASE_CONSTRAINT_DATA *aData)
Populate a constraint data object using a keyword from a .kicad_drc file.
static bool ValidateSelection(int aSelectionIndex, const std::string &aLabel, VALIDATION_RESULT *aResult)
Validates that a selection has been made (index >= 0).
static bool ValidateNumericString(const std::string &aValueStr, bool aCanBeZero, bool aIntegerOnly, const std::string &aLabel, VALIDATION_RESULT *aResult)
Validates that a string represents a valid numeric value.
static std::optional< DRC_RULE_EDITOR_CONSTRAINT_NAME > GetConstraintTypeFromCode(const wxString &aCode)
Resolve a constraint keyword from a rules file into the corresponding rule tree enumeration value.
static bool SaveRules(const wxString &aFilename, const std::vector< std::shared_ptr< DRC_RE_BASE_CONSTRAINT_DATA > > &aRules, const BOARD *aBoard)
static void RegisterRuleConverter(RuleConverter aConverter)
static bool ValidateIntegerCtrl(wxTextCtrl *aTextCtrl, std::string aLabel, bool aCanBeZero, int *aErrorCount, std::string *aValidationMessage)
Validates an integer input control, ensuring the value is a valid integer, non-empty,...
static bool ValidateNumericCtrl(wxTextCtrl *aTextCtrl, std::string aLabel, bool aCanBeZero, int *aErrorCount, std::string *aValidationMessage)
Validates a numeric input control, checking if the value is valid, non-empty, and greater than zero.
std::function< std::shared_ptr< DRC_RE_BASE_CONSTRAINT_DATA >(const std::shared_ptr< DRC_RULE > &)> RuleConverter
static bool ValidateCheckBoxCtrls(const std::vector< wxCheckBox * > &aCheckboxes, std::string aLabel, int *aErrorCount, std::string *aValidationMessage)
Validates a list of checkboxes, ensuring that at least one option is selected.
static std::string FormatErrorMessage(const int &aErrorCount, const std::string aErrorMessage)
static bool ValidateAtLeastOneSelected(const std::vector< bool > &aSelected, const std::string &aLabel, VALIDATION_RESULT *aResult)
Validates that at least one option is selected.
static bool ValidateMinPreferredMaxCtrl(wxTextCtrl *aMinTextCtrl, wxTextCtrl *aPreferredTextCtrl, wxTextCtrl *aMaxTextCtrl, std::string aMinLabel, std::string aPreferredLabel, std::string aMaxLabel, int *aErrorCount, std::string *aValidationMessage)
Validates the minimum, preferred, and maximum value controls, ensuring that:
static bool IsBoolInputType(const DRC_RULE_EDITOR_CONSTRAINT_NAME &aConstraintType)
static std::vector< std::shared_ptr< DRC_RE_BASE_CONSTRAINT_DATA > > ParseRules(const wxString &aRules)
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
VALIDATION_STATE GetValidationState() const
VALIDATION_STATE GetValidationState() const
VALIDATION_STATE GetValidationState() const
VALIDATION_STATE GetValidationState() const
DRC_CONSTRAINT_T
Definition drc_rule.h:47
@ ANNULAR_WIDTH_CONSTRAINT
Definition drc_rule.h:61
@ BRIDGED_MASK_CONSTRAINT
Definition drc_rule.h:83
@ COURTYARD_CLEARANCE_CONSTRAINT
Definition drc_rule.h:55
@ VIA_DIAMETER_CONSTRAINT
Definition drc_rule.h:70
@ ZONE_CONNECTION_CONSTRAINT
Definition drc_rule.h:62
@ DIFF_PAIR_GAP_CONSTRAINT
Definition drc_rule.h:73
@ VIA_DANGLING_CONSTRAINT
Definition drc_rule.h:82
@ DISALLOW_CONSTRAINT
Definition drc_rule.h:69
@ TRACK_WIDTH_CONSTRAINT
Definition drc_rule.h:59
@ SILK_CLEARANCE_CONSTRAINT
Definition drc_rule.h:56
@ EDGE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:53
@ MIN_RESOLVED_SPOKES_CONSTRAINT
Definition drc_rule.h:65
@ TRACK_SEGMENT_LENGTH_CONSTRAINT
Definition drc_rule.h:60
@ TEXT_THICKNESS_CONSTRAINT
Definition drc_rule.h:58
@ LENGTH_CONSTRAINT
Definition drc_rule.h:71
@ VIA_COUNT_CONSTRAINT
Definition drc_rule.h:76
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:78
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:49
@ THERMAL_SPOKE_WIDTH_CONSTRAINT
Definition drc_rule.h:64
@ CONNECTION_WIDTH_CONSTRAINT
Definition drc_rule.h:80
@ THERMAL_RELIEF_GAP_CONSTRAINT
Definition drc_rule.h:63
@ MAX_UNCOUPLED_CONSTRAINT
Definition drc_rule.h:74
@ ASSERTION_CONSTRAINT
Definition drc_rule.h:79
@ SKEW_CONSTRAINT
Definition drc_rule.h:72
@ HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:51
@ SOLDER_PASTE_ABS_MARGIN_CONSTRAINT
Definition drc_rule.h:67
@ SOLDER_MASK_EXPANSION_CONSTRAINT
Definition drc_rule.h:66
@ TRACK_ANGLE_CONSTRAINT
Definition drc_rule.h:81
@ HOLE_SIZE_CONSTRAINT
Definition drc_rule.h:54
@ TEXT_HEIGHT_CONSTRAINT
Definition drc_rule.h:57
@ PHYSICAL_CLEARANCE_CONSTRAINT
Definition drc_rule.h:77
@ SOLDER_PASTE_REL_MARGIN_CONSTRAINT
Definition drc_rule.h:68
@ HOLE_TO_HOLE_CONSTRAINT
Definition drc_rule.h:52
DRC_RULE_EDITOR_CONSTRAINT_NAME
@ MINIMUM_SOLDERMASK_SILVER
@ ALLOWED_ORIENTATION
@ MINIMUM_ITEM_CLEARANCE
@ SILK_TO_SILK_CLEARANCE
@ MINIMUM_TRACK_WIDTH
@ ROUTING_DIFF_PAIR
@ HOLE_TO_HOLE_CLEARANCE
@ SOLDERPASTE_EXPANSION
@ SILK_TO_SOLDERMASK_CLEARANCE
@ MINIMUM_ANGULAR_RING
@ MINIMUM_UVIA_HOLE
@ BOARD_OUTLINE_CLEARANCE
@ COURTYARD_CLEARANCE
@ MINIMUM_CONNECTION_WIDTH
@ SOLDERMASK_EXPANSION
@ MAXIMUM_VIA_COUNT
@ MINIMUM_ANNULAR_WIDTH
@ PHYSICAL_CLEARANCE
@ MINIMUM_THROUGH_HOLE
@ CREEPAGE_DISTANCE
@ ABSOLUTE_LENGTH
@ MINIMUM_CLEARANCE
@ MINIMUM_THERMAL_RELIEF_SPOKE_COUNT
@ BASIC_CLEARANCE
@ PERMITTED_LAYERS
@ MINIMUM_TEXT_HEIGHT_AND_THICKNESS
@ COPPER_TO_HOLE_CLEARANCE
@ MAXIMUM_ALLOWED_DEVIATION
@ MINIMUM_UVIA_DIAMETER
@ HOLE_TO_HOLE_DISTANCE
@ MATCHED_LENGTH_DIFF_PAIR
@ COPPER_TO_EDGE_CLEARANCE
@ MINIMUM_VIA_DIAMETER
static wxString GetConstraintCodeFromType(DRC_CONSTRAINT_T aType)
std::unordered_map< DRC_RULE_EDITOR_CONSTRAINT_NAME, const char * > CODE_MAP
static void RegisterDefaultConverters()
static const CODE_MAP sCodeMap
static const REVERSE_CODE_MAP sCodeReverse
std::unordered_map< wxString, DRC_RULE_EDITOR_CONSTRAINT_NAME, wxStringHash, wxStringEqual > REVERSE_CODE_MAP
static std::vector< DRC_RULE_EDITOR_UTILS::RuleConverter > & GetRuleConverters()
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
Result of a validation operation.
void AddError(const std::string &aError)