KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_re_rule_loader.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
24#include "drc_re_rule_loader.h"
25
26#include <reporter.h>
28#include <drc/drc_rule_parser.h>
30#include <wx/ffile.h>
31
40
41
45
46
47double DRC_RULE_LOADER::toMM( int aValue )
48{
49 return aValue / 1000000.0;
50}
51
52
54{
55 for( const DRC_CONSTRAINT& constraint : aRule.m_Constraints )
56 {
57 if( constraint.m_Type == aType )
58 return &constraint;
59 }
60
61 return nullptr;
62}
63
64
65std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>
67 const DRC_RULE& aRule,
68 const std::set<DRC_CONSTRAINT_T>& aClaimedConstraints )
69{
70 switch( aPanel )
71 {
72 case VIA_STYLE:
73 {
74 auto data = std::make_shared<DRC_RE_VIA_STYLE_CONSTRAINT_DATA>();
75 data->SetRuleName( aRule.m_Name );
76 data->SetConstraintCode( "via_style" );
77
79 const DRC_CONSTRAINT* holeSize = findConstraint( aRule, HOLE_SIZE_CONSTRAINT );
80
81 if( viaDia )
82 {
83 data->SetMinViaDiameter( toMM( viaDia->GetValue().Min() ) );
84 data->SetPreferredViaDiameter( toMM( viaDia->GetValue().Opt() ) );
85 data->SetMaxViaDiameter( toMM( viaDia->GetValue().Max() ) );
86 }
87
88 if( holeSize )
89 {
90 data->SetMinViaHoleSize( toMM( holeSize->GetValue().Min() ) );
91 data->SetPreferredViaHoleSize( toMM( holeSize->GetValue().Opt() ) );
92 data->SetMaxViaHoleSize( toMM( holeSize->GetValue().Max() ) );
93 }
94
95 return data;
96 }
97
99 {
100 auto data = std::make_shared<DRC_RE_ROUTING_DIFF_PAIR_CONSTRAINT_DATA>();
101 data->SetRuleName( aRule.m_Name );
102 data->SetConstraintCode( "diff_pair_gap" );
103
104 const DRC_CONSTRAINT* trackWidth = findConstraint( aRule, TRACK_WIDTH_CONSTRAINT );
105 const DRC_CONSTRAINT* diffGap = findConstraint( aRule, DIFF_PAIR_GAP_CONSTRAINT );
106 const DRC_CONSTRAINT* uncoupled = findConstraint( aRule, MAX_UNCOUPLED_CONSTRAINT );
107
108 if( trackWidth )
109 {
110 data->SetMinWidth( toMM( trackWidth->GetValue().Min() ) );
111 data->SetPreferredWidth( toMM( trackWidth->GetValue().Opt() ) );
112 data->SetMaxWidth( toMM( trackWidth->GetValue().Max() ) );
113 }
114
115 if( diffGap )
116 {
117 data->SetMinGap( toMM( diffGap->GetValue().Min() ) );
118 data->SetPreferredGap( toMM( diffGap->GetValue().Opt() ) );
119 data->SetMaxGap( toMM( diffGap->GetValue().Max() ) );
120 }
121
122 if( uncoupled )
123 {
124 data->SetMaxUncoupledLength( toMM( uncoupled->GetValue().Max() ) );
125 }
126
127 return data;
128 }
129
131 {
132 auto data = std::make_shared<DRC_RE_MINIMUM_TEXT_HEIGHT_THICKNESS_CONSTRAINT_DATA>();
133 data->SetRuleName( aRule.m_Name );
134 data->SetConstraintCode( "text_height" );
135
136 const DRC_CONSTRAINT* textHeight = findConstraint( aRule, TEXT_HEIGHT_CONSTRAINT );
137 const DRC_CONSTRAINT* textThickness = findConstraint( aRule, TEXT_THICKNESS_CONSTRAINT );
138
139 if( textHeight )
140 data->SetMinTextHeight( toMM( textHeight->GetValue().Min() ) );
141
142 if( textThickness )
143 data->SetMinTextThickness( toMM( textThickness->GetValue().Min() ) );
144
145 return data;
146 }
147
148 case ROUTING_WIDTH:
149 {
150 auto data = std::make_shared<DRC_RE_ROUTING_WIDTH_CONSTRAINT_DATA>();
151 data->SetRuleName( aRule.m_Name );
152 data->SetConstraintCode( "track_width" );
153
154 const DRC_CONSTRAINT* trackWidth = findConstraint( aRule, TRACK_WIDTH_CONSTRAINT );
155
156 if( trackWidth )
157 {
158 data->SetMinRoutingWidth( toMM( trackWidth->GetValue().Min() ) );
159 data->SetPreferredRoutingWidth( toMM( trackWidth->GetValue().Opt() ) );
160 data->SetMaxRoutingWidth( toMM( trackWidth->GetValue().Max() ) );
161 }
162
163 return data;
164 }
165
166 case ABSOLUTE_LENGTH:
167 {
168 auto data = std::make_shared<DRC_RE_ABSOLUTE_LENGTH_TWO_CONSTRAINT_DATA>();
169 data->SetRuleName( aRule.m_Name );
170 data->SetConstraintCode( "length" );
171
172 const DRC_CONSTRAINT* length = findConstraint( aRule, LENGTH_CONSTRAINT );
173
174 if( length )
175 {
176 data->SetMinimumLength( toMM( length->GetValue().Min() ) );
177 data->SetOptimumLength( toMM( length->GetValue().Opt() ) );
178 data->SetMaximumLength( toMM( length->GetValue().Max() ) );
179 }
180
181 return data;
182 }
183
184 case CUSTOM_RULE:
185 {
186 auto data = std::make_shared<DRC_RE_CUSTOM_RULE_CONSTRAINT_DATA>();
187 data->SetRuleName( aRule.m_Name );
188 return data;
189 }
190
191 default:
192 {
193 // For numeric input types, create a generic numeric constraint data
195 {
196 auto data = std::make_shared<DRC_RE_NUMERIC_INPUT_CONSTRAINT_DATA>();
197 data->SetRuleName( aRule.m_Name );
198
199 wxString code = DRC_RULE_EDITOR_UTILS::GetConstraintCode( aPanel );
200 data->SetConstraintCode( code );
201
202 // Find the first matching constraint from the claimed set
203 for( DRC_CONSTRAINT_T type : aClaimedConstraints )
204 {
205 const DRC_CONSTRAINT* constraint = findConstraint( aRule, type );
206
207 if( constraint )
208 {
209 // Use Min for most constraints, Max for via_count
210 if( type == VIA_COUNT_CONSTRAINT )
211 data->SetNumericInputValue( toMM( constraint->GetValue().Max() ) );
212 else
213 data->SetNumericInputValue( toMM( constraint->GetValue().Min() ) );
214
215 break;
216 }
217 }
218
219 return data;
220 }
221
222 // Fallback to custom rule
223 auto data = std::make_shared<DRC_RE_CUSTOM_RULE_CONSTRAINT_DATA>();
224 data->SetRuleName( aRule.m_Name );
225 return data;
226 }
227 }
228}
229
230
231std::vector<DRC_RE_LOADED_PANEL_ENTRY> DRC_RULE_LOADER::LoadRule( const DRC_RULE& aRule,
232 const wxString& aOriginalText )
233{
234 std::vector<DRC_RE_LOADED_PANEL_ENTRY> entries;
235
236 // Get condition expression if present
237 wxString condition;
238
239 if( aRule.m_Condition )
240 condition = aRule.m_Condition->GetExpression();
241
242 // Match the rule to panels
243 std::vector<DRC_PANEL_MATCH> matches = m_matcher.MatchRule( aRule );
244
245 for( const DRC_PANEL_MATCH& match : matches )
246 {
247 auto constraintData = createConstraintData( match.panelType, aRule, match.claimedConstraints );
248
249 if( constraintData )
250 {
251 constraintData->SetRuleCondition( condition );
252
253 DRC_RE_LOADED_PANEL_ENTRY entry( match.panelType, constraintData, aRule.m_Name,
254 condition, aRule.m_Severity, aRule.m_LayerCondition );
255
256 // Store original text only for the first entry to avoid duplication issues
257 if( entries.empty() )
258 entry.originalRuleText = aOriginalText;
259
260 entries.push_back( std::move( entry ) );
261 }
262 }
263
264 // If no matches, create a custom rule entry
265 if( entries.empty() )
266 {
267 auto customData = std::make_shared<DRC_RE_CUSTOM_RULE_CONSTRAINT_DATA>();
268 customData->SetRuleName( aRule.m_Name );
269 customData->SetRuleCondition( condition );
270 customData->SetRuleText( aOriginalText );
271
272 DRC_RE_LOADED_PANEL_ENTRY entry( CUSTOM_RULE, customData, aRule.m_Name, condition,
273 aRule.m_Severity, aRule.m_LayerCondition );
274 entry.originalRuleText = aOriginalText;
275 entries.push_back( std::move( entry ) );
276 }
277
278 return entries;
279}
280
281
282std::vector<DRC_RE_LOADED_PANEL_ENTRY> DRC_RULE_LOADER::LoadFromString( const wxString& aRulesText )
283{
284 std::vector<DRC_RE_LOADED_PANEL_ENTRY> allEntries;
285 std::vector<std::shared_ptr<DRC_RULE>> parsedRules;
286
287 wxString rulesText = aRulesText;
288
289 if( !rulesText.Contains( "(version" ) )
290 rulesText.Prepend( "(version 1)\n" );
291
292 try
293 {
294 DRC_RULES_PARSER parser( rulesText, "Rule Loader" );
295 parser.Parse( parsedRules, nullptr );
296 }
297 catch( const IO_ERROR& )
298 {
299 return allEntries;
300 }
301
302 for( const auto& rule : parsedRules )
303 {
304 // Generate original text representation for round-trip
305 wxString originalText = wxString::Format( "(rule \"%s\" ...)", rule->m_Name );
306
307 std::vector<DRC_RE_LOADED_PANEL_ENTRY> ruleEntries = LoadRule( *rule, originalText );
308
309 for( auto& entry : ruleEntries )
310 allEntries.push_back( std::move( entry ) );
311 }
312
313 return allEntries;
314}
315
316
317std::vector<DRC_RE_LOADED_PANEL_ENTRY> DRC_RULE_LOADER::LoadFile( const wxString& aPath )
318{
319 std::vector<DRC_RE_LOADED_PANEL_ENTRY> allEntries;
320
321 wxFFile file( aPath, "r" );
322
323 if( !file.IsOpened() )
324 return allEntries;
325
326 wxString content;
327 file.ReadAll( &content );
328 file.Close();
329
330 return LoadFromString( content );
331}
const MINOPTMAX< int > & GetValue() const
Definition drc_rule.h:186
DRC_CONSTRAINT_T m_Type
Definition drc_rule.h:227
void Parse(std::vector< std::shared_ptr< DRC_RULE > > &aRules, REPORTER *aReporter)
wxString GetExpression() const
static bool IsNumericInputType(const DRC_RULE_EDITOR_CONSTRAINT_NAME &aConstraintType)
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.
double toMM(int aValue)
Convert internal units (nanometers) to millimeters.
DRC_PANEL_MATCHER m_matcher
std::vector< DRC_RE_LOADED_PANEL_ENTRY > LoadRule(const DRC_RULE &aRule, const wxString &aOriginalText)
Load a single DRC_RULE and convert it to panel entries.
std::vector< DRC_RE_LOADED_PANEL_ENTRY > LoadFromString(const wxString &aRulesText)
Load rules from a text string.
const DRC_CONSTRAINT * findConstraint(const DRC_RULE &aRule, DRC_CONSTRAINT_T aType)
Find a constraint of a specific type in a rule.
std::vector< DRC_RE_LOADED_PANEL_ENTRY > LoadFile(const wxString &aPath)
Load all rules from a .kicad_dru file.
std::shared_ptr< DRC_RE_BASE_CONSTRAINT_DATA > createConstraintData(DRC_RULE_EDITOR_CONSTRAINT_NAME aPanel, const DRC_RULE &aRule, const std::set< DRC_CONSTRAINT_T > &aClaimedConstraints)
Create the appropriate constraint data object for a panel type.
SEVERITY m_Severity
Definition drc_rule.h:148
DRC_RULE_CONDITION * m_Condition
Definition drc_rule.h:146
LSET m_LayerCondition
Definition drc_rule.h:145
std::vector< DRC_CONSTRAINT > m_Constraints
Definition drc_rule.h:147
wxString m_Name
Definition drc_rule.h:143
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
T Min() const
Definition minoptmax.h:33
T Max() const
Definition minoptmax.h:34
T Opt() const
Definition minoptmax.h:35
DRC_CONSTRAINT_T
Definition drc_rule.h:47
@ VIA_DIAMETER_CONSTRAINT
Definition drc_rule.h:70
@ DIFF_PAIR_GAP_CONSTRAINT
Definition drc_rule.h:73
@ TRACK_WIDTH_CONSTRAINT
Definition drc_rule.h:59
@ TEXT_THICKNESS_CONSTRAINT
Definition drc_rule.h:58
@ LENGTH_CONSTRAINT
Definition drc_rule.h:71
@ VIA_COUNT_CONSTRAINT
Definition drc_rule.h:76
@ MAX_UNCOUPLED_CONSTRAINT
Definition drc_rule.h:74
@ HOLE_SIZE_CONSTRAINT
Definition drc_rule.h:54
@ TEXT_HEIGHT_CONSTRAINT
Definition drc_rule.h:57
DRC_RULE_EDITOR_CONSTRAINT_NAME
@ ROUTING_DIFF_PAIR
@ ABSOLUTE_LENGTH
@ MINIMUM_TEXT_HEIGHT_AND_THICKNESS
Result of matching a panel to constraints.
Represents a rule loaded from a .kicad_dru file and mapped to a panel.
wxString originalRuleText