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, see <https://www.gnu.org/licenses/>.
18 */
19
22#include <kiplatform/io.h>
23#include <reporter.h>
25#include <drc/drc_rule_parser.h>
26#include <drc_rules_lexer.h>
27#include <drc/drc_rule.h>
39#include <board.h>
40#include <wx/ffile.h>
41#include <wx/regex.h>
42#include <unordered_map>
43
44using CODE_MAP = std::unordered_map<DRC_RULE_EDITOR_CONSTRAINT_NAME, const char*>;
45using REVERSE_CODE_MAP = std::unordered_map<wxString, DRC_RULE_EDITOR_CONSTRAINT_NAME, wxStringHash, wxStringEqual>;
46
47static const CODE_MAP sCodeMap = { { MINIMUM_CLEARANCE, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_clearance ) },
48 { CREEPAGE_DISTANCE, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_creepage ) },
49 { MINIMUM_CONNECTION_WIDTH, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_connection_width ) },
50 { COPPER_TO_HOLE_CLEARANCE, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_hole_clearance ) },
51 { MINIMUM_THERMAL_RELIEF_SPOKE_COUNT, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_min_resolved_spokes ) },
52 { MINIMUM_ANNULAR_WIDTH, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_annular_width ) },
53 { COPPER_TO_EDGE_CLEARANCE, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_edge_clearance ) },
54 { COURTYARD_CLEARANCE, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_courtyard_clearance ) },
55 { PHYSICAL_CLEARANCE, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_physical_clearance ) },
56 { MINIMUM_DRILL_SIZE, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_hole_size ) },
57 { HOLE_SIZE, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_hole_size ) },
58 { HOLE_TO_HOLE_DISTANCE, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_hole_to_hole ) },
59 { MINIMUM_VIA_DIAMETER, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_via_diameter ) },
60 { VIA_STYLE, "via_style" },
61 { MINIMUM_TEXT_HEIGHT_AND_THICKNESS, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_text_height ) },
62 { SILK_TO_SILK_CLEARANCE, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_silk_clearance ) },
63 { SILK_TO_SOLDERMASK_CLEARANCE, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_silk_clearance ) },
64 { MINIMUM_SOLDERMASK_SLIVER, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_solder_mask_sliver ) },
65 { SOLDERMASK_EXPANSION, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_solder_mask_expansion ) },
66 { SOLDERPASTE_EXPANSION, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_solder_paste_abs_margin ) },
67 { MATCHED_LENGTH_DIFF_PAIR, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_length ) },
68 { ROUTING_DIFF_PAIR, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_diff_pair_gap ) },
69 { ROUTING_WIDTH, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_track_width ) },
70 { MAXIMUM_VIA_COUNT, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_via_count ) },
71 { ABSOLUTE_LENGTH, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_length ) },
72 { PERMITTED_LAYERS, "permitted_layers" },
73 { ALLOWED_ORIENTATION, "allowed_orientation" },
74 { VIAS_UNDER_SMD, "disallow_via" } };
75
77{
79 for( const auto& [type, code] : sCodeMap )
80 map.emplace( wxString::FromUTF8( code ), type );
81 return map;
82}();
83
84static std::vector<DRC_RULE_EDITOR_UTILS::RuleConverter>& GetRuleConverters()
85{
86 static std::vector<DRC_RULE_EDITOR_UTILS::RuleConverter> converters;
87 return converters;
88}
89
91{
92 GetRuleConverters().insert( GetRuleConverters().begin(), aConverter );
93}
94
96{
97 switch( aType )
98 {
99 case CLEARANCE_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_clearance );
100 case EDGE_CLEARANCE_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_edge_clearance );
101 case HOLE_CLEARANCE_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_hole_clearance );
102 case HOLE_TO_HOLE_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_hole_to_hole );
103 case HOLE_SIZE_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_hole_size );
104 case TRACK_WIDTH_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_track_width );
105 case ANNULAR_WIDTH_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_annular_width );
106 case VIA_DIAMETER_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_via_diameter );
107 case DISALLOW_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_disallow );
108 case COURTYARD_CLEARANCE_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_courtyard_clearance );
109 case SILK_CLEARANCE_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_silk_clearance );
110 case TEXT_HEIGHT_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_text_height );
111 case TEXT_THICKNESS_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_text_thickness );
112 case TRACK_ANGLE_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_track_angle );
113 case TRACK_SEGMENT_LENGTH_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_track_segment_length );
114 case CONNECTION_WIDTH_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_connection_width );
115 case VIA_DANGLING_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_via_dangling );
116 case ZONE_CONNECTION_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_zone_connection );
117 case THERMAL_RELIEF_GAP_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_thermal_relief_gap );
118 case THERMAL_SPOKE_WIDTH_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_thermal_spoke_width );
119 case MIN_RESOLVED_SPOKES_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_min_resolved_spokes );
120 case SOLDER_MASK_EXPANSION_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_solder_mask_expansion );
121 case SOLDER_PASTE_ABS_MARGIN_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_solder_paste_abs_margin );
122 case SOLDER_PASTE_REL_MARGIN_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_solder_paste_rel_margin );
123 case LENGTH_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_length );
124 case SKEW_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_skew );
125 case VIA_COUNT_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_via_count );
126 case DIFF_PAIR_GAP_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_diff_pair_gap );
127 case MAX_UNCOUPLED_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_diff_pair_uncoupled );
128 case PHYSICAL_CLEARANCE_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_physical_clearance );
129 case PHYSICAL_HOLE_CLEARANCE_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_physical_hole_clearance );
130 case BRIDGED_MASK_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_bridged_mask );
131 case SOLDER_MASK_SLIVER_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_solder_mask_sliver );
132 case ASSERTION_CONSTRAINT: return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_assertion );
133 default: return "";
134 }
135}
136
138{
139 static bool initialized = false;
140 if( initialized )
141 return;
142 initialized = true;
143
144 // Generic Converter
146 []( const std::shared_ptr<DRC_RULE>& aRule ) -> std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>
147 {
148 if( aRule->m_Constraints.empty() ) return nullptr;
149
150 const auto& constraint = aRule->m_Constraints[0];
151 wxString code = GetConstraintCodeFromType( constraint.m_Type );
152
153 if( code.IsEmpty() ) return nullptr;
154
155 if( sCodeReverse.count( code ) )
156 {
157 auto type = sCodeReverse.at( code );
158
160 {
161 double val = constraint.GetValue().Min() / 1000000.0;
163 data->SetRuleName( aRule->m_Name );
164 data->SetNumericInputValue( val );
165 data->SetConstraintCode( code );
166 return data;
167 }
169 {
170 auto data = std::make_shared<DRC_RE_BOOL_INPUT_CONSTRAINT_DATA>( 0, 0, true, aRule->m_Name );
171 data->SetConstraintCode( code );
172 return data;
173 }
174 else if( code == "track_width" )
175 {
176 double minW = constraint.GetValue().Min() / 1000000.0;
177 double optW = constraint.GetValue().Opt() / 1000000.0;
178 double maxW = constraint.GetValue().Max() / 1000000.0;
179
180 double tol = 0;
181 if( optW > 0 )
182 tol = std::max( optW - minW, maxW - optW );
183
184 auto data =
185 std::make_shared<DRC_RE_ROUTING_WIDTH_CONSTRAINT_DATA>( 0, 0, aRule->m_Name, optW, tol );
186 data->SetConstraintCode( code );
187 return data;
188 }
189 }
190 return nullptr;
191 } );
192
193 // Via Style Converter
195 []( const std::shared_ptr<DRC_RULE>& aRule ) -> std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>
196 {
197 auto diaConstraint = aRule->FindConstraint( VIA_DIAMETER_CONSTRAINT );
198 auto holeConstraint = aRule->FindConstraint( HOLE_SIZE_CONSTRAINT );
199
200 if( diaConstraint && holeConstraint )
201 {
202 double minDia = diaConstraint->GetValue().Min() / 1000000.0;
203 double maxDia = diaConstraint->GetValue().Max() / 1000000.0;
204
205 double minDrill = holeConstraint->GetValue().Min() / 1000000.0;
206 double maxDrill = holeConstraint->GetValue().Max() / 1000000.0;
207
209
210 if( aRule->m_Condition )
211 {
212 wxString expr = aRule->m_Condition->GetExpression();
213
214 if( expr.Contains( wxS( "'Micro'" ) ) )
215 viaType = VIA_STYLE_TYPE::MICRO;
216 else if( expr.Contains( wxS( "'Through'" ) ) )
217 viaType = VIA_STYLE_TYPE::THROUGH;
218 else if( expr.Contains( wxS( "'Blind'" ) ) )
219 viaType = VIA_STYLE_TYPE::BLIND;
220 else if( expr.Contains( wxS( "'Buried'" ) ) )
221 viaType = VIA_STYLE_TYPE::BURIED;
222 }
223
224 auto data = std::make_shared<DRC_RE_VIA_STYLE_CONSTRAINT_DATA>( 0, 0, aRule->m_Name, minDia, maxDia,
225 minDrill, maxDrill, viaType );
226 data->SetConstraintCode( "via_style" );
227 return data;
228 }
229 return nullptr;
230 } );
231}
232
233
235{
236 auto it = sCodeMap.find( aConstraintType );
237 if( it != sCodeMap.end() )
238 return wxString::FromUTF8( it->second );
239
240 return wxString();
241}
242
243
244std::optional<DRC_RULE_EDITOR_CONSTRAINT_NAME> DRC_RULE_EDITOR_UTILS::GetConstraintTypeFromCode( const wxString& aCode )
245{
246 auto it = sCodeReverse.find( aCode );
247 if( it != sCodeReverse.end() )
248 return it->second;
249
250 return std::nullopt;
251}
252
253
258
259
261{
262 if( !aData )
263 return false;
264
265 auto type = GetConstraintTypeFromCode( aCode );
266 if( type )
267 {
268 aData->SetConstraintCode( GetConstraintCode( *type ) );
269 return true;
270 }
271
272 aData->SetConstraintCode( aCode );
273 return false;
274}
275
276
278{
279 switch( aConstraintType )
280 {
281 default: return false;
282 }
283}
284
285
287{
288 switch( aConstraintType )
289 {
295 case HOLE_SIZE:
310 return true;
311 default:
312 return false;
313 }
314}
315
316
317bool DRC_RULE_EDITOR_UTILS::ValidateNumericCtrl( wxTextCtrl* aTextCtrl, const wxString& aLabel, bool aCanBeZero,
318 int* aErrorCount, wxString* aValidationMessage )
319{
320 VALIDATOR_NUMERIC_CTRL validator( aCanBeZero );
321 aTextCtrl->SetValidator( validator );
322
323 if( !aTextCtrl->Validate() )
324 {
325 VALIDATOR_NUMERIC_CTRL* v = static_cast<VALIDATOR_NUMERIC_CTRL*>( aTextCtrl->GetValidator() );
326
327 switch( v->GetValidationState() )
328 {
330 {
331 ( *aErrorCount )++;
332 *aValidationMessage +=
334 wxString::Format( _( "%s should not be empty." ), aLabel ) );
335 return false;
336 }
338 {
339 ( *aErrorCount )++;
340 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
341 *aErrorCount, wxString::Format( _( "The value of %s must be a valid number." ), aLabel ) );
342 return false;
343 }
345 {
346 ( *aErrorCount )++;
347 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
348 *aErrorCount, wxString::Format( _( "The value of %s must be greater than 0." ), aLabel ) );
349 return false;
350 }
351 default: break;
352 }
353 }
354
355 return true;
356}
357
358
359bool DRC_RULE_EDITOR_UTILS::ValidateIntegerCtrl( wxTextCtrl* aTextCtrl, const wxString& aLabel, bool aCanBeZero,
360 int* aErrorCount, wxString* aValidationMessage )
361{
362 VALIDATOR_NUMERIC_CTRL validator( aCanBeZero, true );
363 aTextCtrl->SetValidator( validator );
364
365 if( !aTextCtrl->Validate() )
366 {
367 VALIDATOR_NUMERIC_CTRL* v = static_cast<VALIDATOR_NUMERIC_CTRL*>( aTextCtrl->GetValidator() );
368
369 switch( v->GetValidationState() )
370 {
372 {
373 ( *aErrorCount )++;
374 *aValidationMessage +=
376 wxString::Format( _( "%s should not be empty." ), aLabel ) );
377 return false;
378 }
380 {
381 ( *aErrorCount )++;
382 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
383 *aErrorCount, wxString::Format( _( "The value of %s must be a valid integer." ), aLabel ) );
384 return false;
385 }
387 {
388 ( *aErrorCount )++;
389 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
390 *aErrorCount, wxString::Format( _( "The value of %s must be greater than 0." ), aLabel ) );
391 return false;
392 }
393 default: break;
394 }
395 }
396
397 return true;
398}
399
400
401bool DRC_RULE_EDITOR_UTILS::ValidateComboCtrl( wxComboBox* aComboBox, const wxString& aLabel, int* aErrorCount,
402 wxString* aValidationMessage )
403{
404 VALIDATOR_COMBO_CTRL cmbCtrlValidator;
405 aComboBox->SetValidator( cmbCtrlValidator );
406
407 if( !aComboBox->Validate() )
408 {
409 VALIDATOR_COMBO_CTRL* v = static_cast<VALIDATOR_COMBO_CTRL*>( aComboBox->GetValidator() );
410
411 switch( v->GetValidationState() )
412 {
414 {
415 ( *aErrorCount )++;
416 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage( *aErrorCount,
417 wxString::Format( _( "Please choose %s." ), aLabel ) );
418 return false;
419 }
420 default: break;
421 }
422 }
423
424 return true;
425}
426
427
428bool DRC_RULE_EDITOR_UTILS::ValidateMinMaxCtrl( wxTextCtrl* aMinTextCtrl, wxTextCtrl* aMaxTextCtrl,
429 const wxString& aMinLabel, const wxString& aMaxLabel,
430 int* aErrorCount, wxString* aValidationMessage )
431{
432 aMinTextCtrl->SetName( "min" );
433 aMaxTextCtrl->SetName( "max" );
434
435 aMinTextCtrl->SetValidator( VALIDATE_MIN_MAX_CTRL( aMinTextCtrl, aMaxTextCtrl ) );
436
437 if( !aMinTextCtrl->Validate() )
438 {
439 VALIDATE_MIN_MAX_CTRL* v = static_cast<VALIDATE_MIN_MAX_CTRL*>( aMinTextCtrl->GetValidator() );
440
441 switch( v->GetValidationState() )
442 {
444 {
445 ( *aErrorCount )++;
446 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
447 *aErrorCount, wxString::Format( _( "%s value cannot be greater than %s value." ),
448 aMinLabel, aMaxLabel ) );
449 return false;
450 }
451 default: break;
452 }
453 }
454
455 aMinTextCtrl->SetName( "text" );
456 aMaxTextCtrl->SetName( "text" );
457
458 return true;
459}
460
461
462bool DRC_RULE_EDITOR_UTILS::ValidateMinPreferredMaxCtrl( wxTextCtrl* aMinTextCtrl, wxTextCtrl* aPreferredTextCtrl,
463 wxTextCtrl* aMaxTextCtrl, const wxString& aMinLabel,
464 const wxString& aPreferredLabel, const wxString& aMaxLabel,
465 int* aErrorCount, wxString* aValidationMessage )
466{
467 aMinTextCtrl->SetName( "min" );
468 aPreferredTextCtrl->SetName( "preferred" );
469 aMaxTextCtrl->SetName( "max" );
470
471 aMinTextCtrl->SetValidator( VALIDATE_MIN_PREFERRED_MAX_CTRL( aMinTextCtrl, aPreferredTextCtrl, aMaxTextCtrl ) );
472
473 if( !aMinTextCtrl->Validate() )
474 {
476 static_cast<VALIDATE_MIN_PREFERRED_MAX_CTRL*>( aMinTextCtrl->GetValidator() );
477
478 switch( v->GetValidationState() )
479 {
481 {
482 ( *aErrorCount )++;
483 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
484 *aErrorCount, wxString::Format( _( "%s value cannot be greater than %s value." ),
485 aMinLabel, aPreferredLabel ) );
486 return false;
487 }
489 {
490 ( *aErrorCount )++;
491 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
492 *aErrorCount, wxString::Format( _( "%s value cannot be greater than %s value." ),
493 aPreferredLabel, aMaxLabel ) );
494 return false;
495 }
497 {
498 ( *aErrorCount )++;
499 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
500 *aErrorCount, wxString::Format( _( "%s value cannot be greater than %s value." ),
501 aMinLabel, aMaxLabel ) );
502 return false;
503 }
504 default: break;
505 }
506 }
507
508 aMinTextCtrl->SetName( "text" );
509 aPreferredTextCtrl->SetName( "text" );
510 aMaxTextCtrl->SetName( "text" );
511
512 return true;
513}
514
515
516bool DRC_RULE_EDITOR_UTILS::ValidateCheckBoxCtrls( const std::vector<wxCheckBox*>& aCheckboxes, const wxString& aLabel,
517 int* aErrorCount, wxString* aValidationMessage )
518{
519 VALIDATE_CHECKBOX_LIST validator( aCheckboxes );
520
521 aCheckboxes[0]->SetValidator( validator );
522
523 if( !aCheckboxes[0]->Validate() )
524 {
525 VALIDATE_CHECKBOX_LIST* v = static_cast<VALIDATE_CHECKBOX_LIST*>( aCheckboxes[0]->GetValidator() );
526
527 switch( v->GetValidationState() )
528 {
530 {
531 ( *aErrorCount )++;
532 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
533 *aErrorCount, wxString::Format( _( "Please select at least one option from %s list." ), aLabel ));
534 return false;
535 }
536 default: break;
537 }
538 }
539
540 return true;
541}
542
543
544wxString DRC_RULE_EDITOR_UTILS::FormatErrorMessage( int aErrorCount, const wxString& aErrorMessage )
545{
546 return wxString::Format( wxS( "%d. %s\n" ), aErrorCount, aErrorMessage );
547}
548
549
550// ==================== Pure Validators (No GUI Dependencies) ====================
551
552bool DRC_RULE_EDITOR_UTILS::ValidateNumericValue( double aValue, bool aCanBeZero, const wxString& aLabel,
553 VALIDATION_RESULT* aResult )
554{
555 if( !aCanBeZero && aValue <= 0.0 )
556 {
557 aResult->AddError( wxString::Format( _( "The value of %s must be greater than 0." ), aLabel ) );
558 return false;
559 }
560
561 return true;
562}
563
564
565bool DRC_RULE_EDITOR_UTILS::ValidateNumericString( const wxString& aValueStr, bool aCanBeZero,
566 bool aIntegerOnly, const wxString& aLabel,
567 VALIDATION_RESULT* aResult )
568{
569 if( aValueStr.IsEmpty() )
570 {
571 aResult->AddError( wxString::Format( _( "%s should not be empty." ), aLabel ) );
572 return false;
573 }
574
575 try
576 {
577 if( aIntegerOnly )
578 {
579 std::string stdStr = aValueStr.ToStdString();
580 size_t pos;
581 long intVal = std::stol( stdStr, &pos );
582
583 if( pos != stdStr.length() )
584 {
585 aResult->AddError( wxString::Format( _( "The value of %s must be a valid integer." ), aLabel ) );
586 return false;
587 }
588
589 if( !aCanBeZero && intVal <= 0 )
590 {
591 aResult->AddError( wxString::Format( _( "The value of %s must be greater than 0." ), aLabel ) );
592 return false;
593 }
594 }
595 else
596 {
597 std::string stdStr = aValueStr.ToStdString();
598 size_t pos;
599 double floatVal = std::stod( stdStr, &pos );
600
601 if( pos != stdStr.length() )
602 {
603 aResult->AddError( wxString::Format( _( "The value of %s must be a valid number." ), aLabel ) );
604 return false;
605 }
606
607 if( !aCanBeZero && floatVal <= 0.0 )
608 {
609 aResult->AddError( wxString::Format( _( "The value of %s must be greater than 0." ), aLabel ) );
610 return false;
611 }
612 }
613 }
614 catch( const std::exception& )
615 {
616 if( aIntegerOnly )
617 aResult->AddError( wxString::Format( _( "The value of %s must be a valid integer." ), aLabel ) );
618 else
619 aResult->AddError( wxString::Format( _( "The value of %s must be a valid number." ), aLabel ) );
620
621 return false;
622 }
623
624 return true;
625}
626
627
628bool DRC_RULE_EDITOR_UTILS::ValidateMinMax( double aMin, double aMax, const wxString& aMinLabel,
629 const wxString& aMaxLabel, VALIDATION_RESULT* aResult )
630{
631 if( aMin > aMax )
632 {
633 aResult->AddError( wxString::Format( _( "%s value cannot be greater than %s value." ), aMinLabel, aMaxLabel ));
634 return false;
635 }
636
637 return true;
638}
639
640
641bool DRC_RULE_EDITOR_UTILS::ValidateMinPreferredMax( double aMin, double aPreferred, double aMax,
642 const wxString& aMinLabel,
643 const wxString& aPrefLabel,
644 const wxString& aMaxLabel,
645 VALIDATION_RESULT* aResult )
646{
647 bool valid = true;
648
649 if( aMin > aPreferred )
650 {
651 aResult->AddError( wxString::Format( _( "%s value cannot be greater than %s value." ), aMinLabel, aPrefLabel ));
652 valid = false;
653 }
654
655 if( aPreferred > aMax )
656 {
657 aResult->AddError( wxString::Format( _( "%s value cannot be greater than %s value." ), aPrefLabel, aMaxLabel ));
658 valid = false;
659 }
660
661 if( aMin > aMax )
662 {
663 aResult->AddError( wxString::Format( _( "%s value cannot be greater than %s value." ), aMinLabel, aMaxLabel ));
664 valid = false;
665 }
666
667 return valid;
668}
669
670
671bool DRC_RULE_EDITOR_UTILS::ValidateAtLeastOneSelected( const std::vector<bool>& aSelected,
672 const wxString& aLabel,
673 VALIDATION_RESULT* aResult )
674{
675 for( bool selected : aSelected )
676 {
677 if( selected )
678 return true;
679 }
680
681 aResult->AddError( wxString::Format( _( "Please select at least one option from %s list." ), aLabel ) );
682 return false;
683}
684
685
686bool DRC_RULE_EDITOR_UTILS::ValidateSelection( int aSelectionIndex, const wxString& aLabel,
687 VALIDATION_RESULT* aResult )
688{
689 if( aSelectionIndex < 0 )
690 {
691 aResult->AddError( wxString::Format( _( "Please choose %s." ), aLabel ) );
692 return false;
693 }
694
695 return true;
696}
697
698
699std::vector<std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>> DRC_RULE_EDITOR_UTILS::ParseRules( const wxString& aRules )
700{
702
703 std::vector<std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>> rules;
704 std::vector<std::shared_ptr<DRC_RULE>> parsedRules;
705
706 wxString rulesText = aRules;
707 if( !rulesText.Contains( "(version" ) )
708 rulesText.Prepend( "(version 2)\n" );
709
710 try
711 {
712 DRC_RULES_PARSER parser( rulesText, "Rule Editor Source" );
713 parser.Parse( parsedRules, nullptr );
714 }
715 catch( const IO_ERROR& )
716 {
717 }
718
719 for( const auto& rule : parsedRules )
720 {
721 std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA> data;
722
723 for( const auto& converter : GetRuleConverters() )
724 {
725 data = converter( rule );
726 if( data )
727 break;
728 }
729
730 if( !data )
731 {
732 auto customData = std::make_shared<DRC_RE_CUSTOM_RULE_CONSTRAINT_DATA>( 0, 0, rule->m_Name );
733 customData->SetRuleText( wxString::Format( "(rule \"%s\" ...)", rule->m_Name ) );
734 data = customData;
735 }
736
737 if( rule->m_Condition )
738 data->SetRuleCondition( rule->m_Condition->GetExpression() );
739
740 rules.push_back( data );
741 }
742
743 return rules;
744}
745
746bool DRC_RULE_EDITOR_UTILS::SaveRules( const wxString& aFilename,
747 const std::vector<std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>>& aRules,
748 const BOARD* aBoard )
749{
750 wxString content = wxT( "(version 2)\n" );
751
752 for( const auto& data : aRules )
753 {
754 if( !data )
755 continue;
756
758 ctx.ruleName = data->GetRuleName();
759 ctx.comment = data->GetComment();
760 ctx.conditionExpression = data->GetRuleCondition();
761 ctx.constraintCode = data->GetConstraintCode();
762
763 std::vector<PCB_LAYER_ID> layers = data->GetLayers();
764
765 if( !layers.empty() && aBoard )
766 {
767 wxString layerStr = "(layer";
768
769 for( PCB_LAYER_ID layer : layers )
770 layerStr += " \"" + aBoard->GetLayerName( layer ) + "\"";
771
772 layerStr += ")";
773 ctx.layerClause = layerStr;
774 }
775
776 content += data->GenerateRule( ctx ) + wxT( "\n" );
777 }
778
779 std::string utf8 = std::string( content.mb_str( wxConvUTF8 ) );
780 return KIPLATFORM::IO::AtomicWriteFile( aFilename, utf8.data(), utf8.size() );
781}
782
783
784// ==================== Layer Filtering ====================
785
787 DRC_RULE_EDITOR_CONSTRAINT_NAME aConstraintType )
788{
789 switch( aConstraintType )
790 {
791 // COPPER_ONLY: Constraints that only apply to copper layers
796 case VIA_STYLE:
800 case ROUTING_WIDTH:
804 case ABSOLUTE_LENGTH:
806
807 // SILKSCREEN_ONLY: Constraints that only apply to silkscreen layers
810
811 // SOLDERMASK_ONLY: Constraints that only apply to soldermask layers
815
816 // SOLDERPASTE_ONLY: Constraints that only apply to solderpaste layers
819
820 // TOP_BOTTOM_ANY: Constraints with simplified top/bottom/any selection
823 case VIAS_UNDER_SMD:
826
827 // GENERAL_ANY_LAYER: Constraints that can apply to any layer type
829 case HOLE_SIZE:
834
835 // NO_LAYER_SELECTOR: Constraints where layer selection doesn't apply
837 case PERMITTED_LAYERS:
838 case CUSTOM_RULE:
840
841 default:
843 }
844}
845
846
848 bool aIsTop )
849{
850 switch( aConstraintType )
851 {
853 return wxString::Format( wxS( "(layer \"%s\")" ),
854 aIsTop ? wxS( "F.CrtYd" ) : wxS( "B.CrtYd" ) );
855
857 // Generates a condition to match silk on one side with mask on the same side
858 return wxString::Format( wxS( "(condition \"A.Layer == '%s' && B.Layer == '%s'\")" ),
859 aIsTop ? wxS( "F.SilkS" ) : wxS( "B.SilkS" ),
860 aIsTop ? wxS( "F.Mask" ) : wxS( "B.Mask" ) );
861
862 case VIAS_UNDER_SMD:
864 return wxString::Format( wxS( "(layer \"%s\")" ), aIsTop ? wxS( "F.Cu" ) : wxS( "B.Cu" ) );
865
866 default:
867 return wxEmptyString;
868 }
869}
870
871
872std::shared_ptr<DRC_RE_NUMERIC_INPUT_CONSTRAINT_DATA>
874{
875 switch( aType )
876 {
877 case COPPER_TO_EDGE_CLEARANCE: return std::make_shared<DRC_RE_COPPER_TO_EDGE_CLEARANCE_CONSTRAINT_DATA>();
878 case COPPER_TO_HOLE_CLEARANCE: return std::make_shared<DRC_RE_COPPER_TO_HOLE_CLEARANCE_CONSTRAINT_DATA>();
879 case COURTYARD_CLEARANCE: return std::make_shared<DRC_RE_COURTYARD_CLEARANCE_CONSTRAINT_DATA>();
880 case PHYSICAL_CLEARANCE: return std::make_shared<DRC_RE_PHYSICAL_CLEARANCE_CONSTRAINT_DATA>();
881 case CREEPAGE_DISTANCE: return std::make_shared<DRC_RE_CREEPAGE_DISTANCE_CONSTRAINT_DATA>();
882 case HOLE_SIZE: return std::make_shared<DRC_RE_HOLE_SIZE_CONSTRAINT_DATA>();
883 case HOLE_TO_HOLE_DISTANCE: return std::make_shared<DRC_RE_HOLE_TO_HOLE_DISTANCE_CONSTRAINT_DATA>();
884 case MAXIMUM_VIA_COUNT: return std::make_shared<DRC_RE_MAXIMUM_VIA_COUNT_CONSTRAINT_DATA>();
885 case MINIMUM_ANNULAR_WIDTH: return std::make_shared<DRC_RE_MINIMUM_ANNULAR_WIDTH_CONSTRAINT_DATA>();
886 case MINIMUM_CLEARANCE: return std::make_shared<DRC_RE_MINIMUM_CLEARANCE_CONSTRAINT_DATA>();
887 case MINIMUM_CONNECTION_WIDTH: return std::make_shared<DRC_RE_MINIMUM_CONNECTION_WIDTH_CONSTRAINT_DATA>();
888 case MINIMUM_SOLDERMASK_SLIVER: return std::make_shared<DRC_RE_MINIMUM_SOLDERMASK_SLIVER_CONSTRAINT_DATA>();
889 case MINIMUM_THERMAL_RELIEF_SPOKE_COUNT: return std::make_shared<DRC_RE_MINIMUM_THERMAL_SPOKE_COUNT_CONSTRAINT_DATA>();
890 case MINIMUM_DRILL_SIZE: return std::make_shared<DRC_RE_MINIMUM_DRILL_SIZE_CONSTRAINT_DATA>();
891 case MINIMUM_VIA_DIAMETER: return std::make_shared<DRC_RE_MINIMUM_VIA_DIAMETER_CONSTRAINT_DATA>();
892 case SILK_TO_SILK_CLEARANCE: return std::make_shared<DRC_RE_SILK_TO_SILK_CLEARANCE_CONSTRAINT_DATA>();
893 case SILK_TO_SOLDERMASK_CLEARANCE: return std::make_shared<DRC_RE_SILK_TO_SOLDERMASK_CLEARANCE_CONSTRAINT_DATA>();
894 case SOLDERMASK_EXPANSION: return std::make_shared<DRC_RE_SOLDERMASK_EXPANSION_CONSTRAINT_DATA>();
895 case SOLDERPASTE_EXPANSION: return std::make_shared<DRC_RE_SOLDERPASTE_EXPANSION_CONSTRAINT_DATA>();
896 default: return std::make_shared<DRC_RE_NUMERIC_INPUT_CONSTRAINT_DATA>();
897 }
898}
899
900
901std::shared_ptr<DRC_RE_NUMERIC_INPUT_CONSTRAINT_DATA>
903 const DRC_RE_BASE_CONSTRAINT_DATA& aBase )
904{
905 switch( aType )
906 {
907 case COPPER_TO_EDGE_CLEARANCE: return std::make_shared<DRC_RE_COPPER_TO_EDGE_CLEARANCE_CONSTRAINT_DATA>( aBase );
908 case COPPER_TO_HOLE_CLEARANCE: return std::make_shared<DRC_RE_COPPER_TO_HOLE_CLEARANCE_CONSTRAINT_DATA>( aBase );
909 case COURTYARD_CLEARANCE: return std::make_shared<DRC_RE_COURTYARD_CLEARANCE_CONSTRAINT_DATA>( aBase );
910 case PHYSICAL_CLEARANCE: return std::make_shared<DRC_RE_PHYSICAL_CLEARANCE_CONSTRAINT_DATA>( aBase );
911 case CREEPAGE_DISTANCE: return std::make_shared<DRC_RE_CREEPAGE_DISTANCE_CONSTRAINT_DATA>( aBase );
912 case HOLE_SIZE: return std::make_shared<DRC_RE_HOLE_SIZE_CONSTRAINT_DATA>( aBase );
913 case HOLE_TO_HOLE_DISTANCE: return std::make_shared<DRC_RE_HOLE_TO_HOLE_DISTANCE_CONSTRAINT_DATA>( aBase );
914 case MAXIMUM_VIA_COUNT: return std::make_shared<DRC_RE_MAXIMUM_VIA_COUNT_CONSTRAINT_DATA>( aBase );
915 case MINIMUM_ANNULAR_WIDTH: return std::make_shared<DRC_RE_MINIMUM_ANNULAR_WIDTH_CONSTRAINT_DATA>( aBase );
916 case MINIMUM_CLEARANCE: return std::make_shared<DRC_RE_MINIMUM_CLEARANCE_CONSTRAINT_DATA>( aBase );
917 case MINIMUM_CONNECTION_WIDTH: return std::make_shared<DRC_RE_MINIMUM_CONNECTION_WIDTH_CONSTRAINT_DATA>( aBase );
918 case MINIMUM_SOLDERMASK_SLIVER: return std::make_shared<DRC_RE_MINIMUM_SOLDERMASK_SLIVER_CONSTRAINT_DATA>( aBase );
919 case MINIMUM_THERMAL_RELIEF_SPOKE_COUNT: return std::make_shared<DRC_RE_MINIMUM_THERMAL_SPOKE_COUNT_CONSTRAINT_DATA>( aBase );
920 case MINIMUM_DRILL_SIZE: return std::make_shared<DRC_RE_MINIMUM_DRILL_SIZE_CONSTRAINT_DATA>( aBase );
921 case MINIMUM_VIA_DIAMETER: return std::make_shared<DRC_RE_MINIMUM_VIA_DIAMETER_CONSTRAINT_DATA>( aBase );
922 case SILK_TO_SILK_CLEARANCE: return std::make_shared<DRC_RE_SILK_TO_SILK_CLEARANCE_CONSTRAINT_DATA>( aBase );
923 case SILK_TO_SOLDERMASK_CLEARANCE: return std::make_shared<DRC_RE_SILK_TO_SOLDERMASK_CLEARANCE_CONSTRAINT_DATA>( aBase );
924 case SOLDERMASK_EXPANSION: return std::make_shared<DRC_RE_SOLDERMASK_EXPANSION_CONSTRAINT_DATA>( aBase );
925 case SOLDERPASTE_EXPANSION: return std::make_shared<DRC_RE_SOLDERPASTE_EXPANSION_CONSTRAINT_DATA>( aBase );
926 default: return std::make_shared<DRC_RE_NUMERIC_INPUT_CONSTRAINT_DATA>( aBase );
927 }
928}
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:372
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:793
void SetConstraintCode(const wxString &aCode)
void Parse(std::vector< std::shared_ptr< DRC_RULE > > &aRules, REPORTER *aReporter)
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 ValidateNumericValue(double aValue, bool aCanBeZero, const wxString &aLabel, VALIDATION_RESULT *aResult)
Validates a numeric value.
static bool ValidateAtLeastOneSelected(const std::vector< bool > &aSelected, const wxString &aLabel, VALIDATION_RESULT *aResult)
Validates that at least one option is selected.
static bool ValidateSelection(int aSelectionIndex, const wxString &aLabel, VALIDATION_RESULT *aResult)
Validates that a selection has been made (index >= 0).
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 ValidateNumericCtrl(wxTextCtrl *aTextCtrl, const wxString &aLabel, bool aCanBeZero, int *aErrorCount, wxString *aValidationMessage)
Validates a numeric input control, checking if the value is valid, non-empty, and greater than zero.
static bool ValidateMinMax(double aMin, double aMax, const wxString &aMinLabel, const wxString &aMaxLabel, VALIDATION_RESULT *aResult)
Validates that min <= max.
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 ValidateMinPreferredMaxCtrl(wxTextCtrl *aMinTextCtrl, wxTextCtrl *aPreferredTextCtrl, wxTextCtrl *aMaxTextCtrl, const wxString &aMinLabel, const wxString &aPreferredLabel, const wxString &aMaxLabel, int *aErrorCount, wxString *aValidationMessage)
Validates the minimum, preferred, and maximum value controls, ensuring that:
static wxString FormatErrorMessage(int aErrorCount, const wxString &aErrorMessage)
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 ValidateComboCtrl(wxComboBox *aComboBox, const wxString &aLabel, int *aErrorCount, wxString *aValidationMessage)
Validates a combo box control, ensuring that a selection has been made.
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 wxString TranslateTopBottomLayer(DRC_RULE_EDITOR_CONSTRAINT_NAME aConstraintType, bool aIsTop)
Translate a top/bottom selection to the appropriate layer clause or condition.
static bool ValidateCheckBoxCtrls(const std::vector< wxCheckBox * > &aCheckboxes, const wxString &aLabel, int *aErrorCount, wxString *aValidationMessage)
Validates a list of checkboxes, ensuring that at least one option is selected.
static bool ValidateNumericString(const wxString &aValueStr, bool aCanBeZero, bool aIntegerOnly, const wxString &aLabel, VALIDATION_RESULT *aResult)
Validates that a string represents a valid numeric value.
static bool ValidateMinMaxCtrl(wxTextCtrl *aMinTextCtrl, wxTextCtrl *aMaxTextCtrl, const wxString &aMinLabel, const wxString &aMaxLabel, int *aErrorCount, wxString *aValidationMessage)
Validates the minimum and maximum value controls, ensuring that the minimum value is not greater than...
std::function< std::shared_ptr< DRC_RE_BASE_CONSTRAINT_DATA >(const std::shared_ptr< DRC_RULE > &)> RuleConverter
static std::shared_ptr< DRC_RE_NUMERIC_INPUT_CONSTRAINT_DATA > CreateNumericConstraintData(DRC_RULE_EDITOR_CONSTRAINT_NAME aType)
static DRC_LAYER_CATEGORY GetLayerCategoryForConstraint(DRC_RULE_EDITOR_CONSTRAINT_NAME aConstraintType)
Get the layer category for a constraint type.
static bool ValidateMinPreferredMax(double aMin, double aPreferred, double aMax, const wxString &aMinLabel, const wxString &aPrefLabel, const wxString &aMaxLabel, VALIDATION_RESULT *aResult)
Validates that min <= preferred <= max.
static bool ValidateIntegerCtrl(wxTextCtrl *aTextCtrl, const wxString &aLabel, bool aCanBeZero, int *aErrorCount, wxString *aValidationMessage)
Validates an integer input control, ensuring the value is a valid integer, non-empty,...
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:49
@ ANNULAR_WIDTH_CONSTRAINT
Definition drc_rule.h:63
@ BRIDGED_MASK_CONSTRAINT
Definition drc_rule.h:88
@ COURTYARD_CLEARANCE_CONSTRAINT
Definition drc_rule.h:57
@ VIA_DIAMETER_CONSTRAINT
Definition drc_rule.h:72
@ ZONE_CONNECTION_CONSTRAINT
Definition drc_rule.h:64
@ DIFF_PAIR_GAP_CONSTRAINT
Definition drc_rule.h:78
@ VIA_DANGLING_CONSTRAINT
Definition drc_rule.h:87
@ SOLDER_MASK_SLIVER_CONSTRAINT
Definition drc_rule.h:89
@ DISALLOW_CONSTRAINT
Definition drc_rule.h:71
@ TRACK_WIDTH_CONSTRAINT
Definition drc_rule.h:61
@ SILK_CLEARANCE_CONSTRAINT
Definition drc_rule.h:58
@ EDGE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:55
@ MIN_RESOLVED_SPOKES_CONSTRAINT
Definition drc_rule.h:67
@ TRACK_SEGMENT_LENGTH_CONSTRAINT
Definition drc_rule.h:62
@ TEXT_THICKNESS_CONSTRAINT
Definition drc_rule.h:60
@ LENGTH_CONSTRAINT
Definition drc_rule.h:73
@ VIA_COUNT_CONSTRAINT
Definition drc_rule.h:81
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:83
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:51
@ THERMAL_SPOKE_WIDTH_CONSTRAINT
Definition drc_rule.h:66
@ CONNECTION_WIDTH_CONSTRAINT
Definition drc_rule.h:85
@ THERMAL_RELIEF_GAP_CONSTRAINT
Definition drc_rule.h:65
@ MAX_UNCOUPLED_CONSTRAINT
Definition drc_rule.h:79
@ ASSERTION_CONSTRAINT
Definition drc_rule.h:84
@ SKEW_CONSTRAINT
Definition drc_rule.h:77
@ HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:53
@ SOLDER_PASTE_ABS_MARGIN_CONSTRAINT
Definition drc_rule.h:69
@ SOLDER_MASK_EXPANSION_CONSTRAINT
Definition drc_rule.h:68
@ TRACK_ANGLE_CONSTRAINT
Definition drc_rule.h:86
@ HOLE_SIZE_CONSTRAINT
Definition drc_rule.h:56
@ TEXT_HEIGHT_CONSTRAINT
Definition drc_rule.h:59
@ PHYSICAL_CLEARANCE_CONSTRAINT
Definition drc_rule.h:82
@ SOLDER_PASTE_REL_MARGIN_CONSTRAINT
Definition drc_rule.h:70
@ HOLE_TO_HOLE_CONSTRAINT
Definition drc_rule.h:54
DRC_RULE_EDITOR_CONSTRAINT_NAME
@ ALLOWED_ORIENTATION
@ SILK_TO_SILK_CLEARANCE
@ ROUTING_DIFF_PAIR
@ SOLDERPASTE_EXPANSION
@ SILK_TO_SOLDERMASK_CLEARANCE
@ COURTYARD_CLEARANCE
@ MINIMUM_CONNECTION_WIDTH
@ SOLDERMASK_EXPANSION
@ MAXIMUM_VIA_COUNT
@ MINIMUM_ANNULAR_WIDTH
@ PHYSICAL_CLEARANCE
@ CREEPAGE_DISTANCE
@ ABSOLUTE_LENGTH
@ MINIMUM_CLEARANCE
@ MINIMUM_THERMAL_RELIEF_SPOKE_COUNT
@ PERMITTED_LAYERS
@ MINIMUM_TEXT_HEIGHT_AND_THICKNESS
@ COPPER_TO_HOLE_CLEARANCE
@ HOLE_TO_HOLE_DISTANCE
@ ROUTING_WIDTH
@ MINIMUM_DRILL_SIZE
@ MATCHED_LENGTH_DIFF_PAIR
@ COPPER_TO_EDGE_CLEARANCE
@ MINIMUM_SOLDERMASK_SLIVER
@ MINIMUM_VIA_DIAMETER
DRC_LAYER_CATEGORY
Layer categories for filtering the layer selector dropdown.
@ NO_LAYER_SELECTOR
Hide layer selector entirely.
@ TOP_BOTTOM_ANY
Simplified top/bottom/any selector with custom translation.
@ SOLDERMASK_ONLY
F_Mask, B_Mask.
@ GENERAL_ANY_LAYER
All layers + inner/outer synthetic.
@ SOLDERPASTE_ONLY
F_Paste, B_Paste.
@ COPPER_ONLY
Copper layers + inner/outer synthetic.
@ SILKSCREEN_ONLY
F_SilkS, B_SilkS.
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()
#define _(s)
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
bool AtomicWriteFile(const wxString &aTargetPath, const void *aData, size_t aSize, wxString *aError=nullptr)
Writes aData to aTargetPath via a sibling temp file, fsyncs the data and directory,...
Result of a validation operation.
void AddError(const wxString &aError)