KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_re_panel_matcher.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
21
22#include <algorithm>
24
53
58
59
61{
62 // Priority 100: ROUTING_DIFF_PAIR claims track_width + diff_pair_gap + diff_pair_uncoupled
63 // This must be checked before ROUTING_WIDTH which also wants track_width
64 m_claims.emplace_back( ROUTING_DIFF_PAIR,
65 std::set<DRC_CONSTRAINT_T>{ TRACK_WIDTH_CONSTRAINT, DIFF_PAIR_GAP_CONSTRAINT },
66 std::set<DRC_CONSTRAINT_T>{ MAX_UNCOUPLED_CONSTRAINT, SKEW_CONSTRAINT }, 100 );
67
68 // Priority 90: VIA_STYLE claims via_diameter + hole_size
69 m_claims.emplace_back(
71 std::set<DRC_CONSTRAINT_T>{ VIA_DIAMETER_CONSTRAINT, HOLE_SIZE_CONSTRAINT },
72 std::set<DRC_CONSTRAINT_T>{},
73 90 );
74
75 // Priority 80: MINIMUM_TEXT_HEIGHT_THICKNESS claims text_height + text_thickness
76 m_claims.emplace_back(
78 std::set<DRC_CONSTRAINT_T>{ TEXT_HEIGHT_CONSTRAINT, TEXT_THICKNESS_CONSTRAINT },
79 std::set<DRC_CONSTRAINT_T>{},
80 80 );
81
82 // Priority 70: ROUTING_WIDTH claims track_width (single constraint, min/opt/max values)
83 m_claims.emplace_back(
85 std::set<DRC_CONSTRAINT_T>{ TRACK_WIDTH_CONSTRAINT },
86 std::set<DRC_CONSTRAINT_T>{},
87 70 );
88
89 // Priority 60: ABSOLUTE_LENGTH claims length (single constraint, min/opt/max values)
90 m_claims.emplace_back(
92 std::set<DRC_CONSTRAINT_T>{ LENGTH_CONSTRAINT },
93 std::set<DRC_CONSTRAINT_T>{},
94 60 );
95
96 // Priority 50: PERMITTED_LAYERS claims assertion for layer-based rules
97 m_claims.emplace_back(
99 std::set<DRC_CONSTRAINT_T>{ ASSERTION_CONSTRAINT },
100 std::set<DRC_CONSTRAINT_T>{},
101 50 );
102
103 // Priority 40: ALLOWED_ORIENTATION claims assertion for orientation-based rules
104 // Note that both PERMITTED_LAYERS and ALLOWED_ORIENTATION claim ASSERTION_CONSTRAINT.
105 // The UI must differentiate based on assertion content.
106 m_claims.emplace_back(
108 std::set<DRC_CONSTRAINT_T>{ ASSERTION_CONSTRAINT },
109 std::set<DRC_CONSTRAINT_T>{},
110 40 );
111
112 // Priority 30: Generic single-constraint panels
113
114 // Clearance constraints
115 m_claims.emplace_back(
117 std::set<DRC_CONSTRAINT_T>{ CLEARANCE_CONSTRAINT },
118 std::set<DRC_CONSTRAINT_T>{},
119 30 );
120
121 m_claims.emplace_back(
123 std::set<DRC_CONSTRAINT_T>{ EDGE_CLEARANCE_CONSTRAINT },
124 std::set<DRC_CONSTRAINT_T>{},
125 30 );
126
127 m_claims.emplace_back(
129 std::set<DRC_CONSTRAINT_T>{ HOLE_CLEARANCE_CONSTRAINT },
130 std::set<DRC_CONSTRAINT_T>{},
131 30 );
132
133 m_claims.emplace_back(
135 std::set<DRC_CONSTRAINT_T>{ HOLE_TO_HOLE_CONSTRAINT },
136 std::set<DRC_CONSTRAINT_T>{},
137 30 );
138
139 m_claims.emplace_back(
141 std::set<DRC_CONSTRAINT_T>{ COURTYARD_CLEARANCE_CONSTRAINT },
142 std::set<DRC_CONSTRAINT_T>{},
143 30 );
144
145 m_claims.emplace_back(
147 std::set<DRC_CONSTRAINT_T>{ SOLDER_MASK_SLIVER_CONSTRAINT },
148 std::set<DRC_CONSTRAINT_T>{},
149 30 );
150
151 m_claims.emplace_back(
153 std::set<DRC_CONSTRAINT_T>{ PHYSICAL_CLEARANCE_CONSTRAINT },
154 std::set<DRC_CONSTRAINT_T>{},
155 30 );
156
157 m_claims.emplace_back(
159 std::set<DRC_CONSTRAINT_T>{ SILK_CLEARANCE_CONSTRAINT },
160 std::set<DRC_CONSTRAINT_T>{},
161 30 );
162
163 m_claims.emplace_back(
165 std::set<DRC_CONSTRAINT_T>{ CREEPAGE_CONSTRAINT },
166 std::set<DRC_CONSTRAINT_T>{},
167 30 );
168
169 // Size constraints
170 m_claims.emplace_back(
171 HOLE_SIZE,
172 std::set<DRC_CONSTRAINT_T>{ HOLE_SIZE_CONSTRAINT },
173 std::set<DRC_CONSTRAINT_T>{},
174 20 );
175
176 m_claims.emplace_back(
178 std::set<DRC_CONSTRAINT_T>{ VIA_DIAMETER_CONSTRAINT },
179 std::set<DRC_CONSTRAINT_T>{},
180 20 );
181
182 m_claims.emplace_back(
184 std::set<DRC_CONSTRAINT_T>{ ANNULAR_WIDTH_CONSTRAINT },
185 std::set<DRC_CONSTRAINT_T>{},
186 20 );
187
188 m_claims.emplace_back(
190 std::set<DRC_CONSTRAINT_T>{ CONNECTION_WIDTH_CONSTRAINT },
191 std::set<DRC_CONSTRAINT_T>{},
192 20 );
193
194 // Via count
195 m_claims.emplace_back(
197 std::set<DRC_CONSTRAINT_T>{ VIA_COUNT_CONSTRAINT },
198 std::set<DRC_CONSTRAINT_T>{},
199 20 );
200
201 // Solder mask/paste
202 m_claims.emplace_back(
204 std::set<DRC_CONSTRAINT_T>{ SOLDER_MASK_EXPANSION_CONSTRAINT },
205 std::set<DRC_CONSTRAINT_T>{},
206 20 );
207
208 m_claims.emplace_back(
210 std::set<DRC_CONSTRAINT_T>{ SOLDER_PASTE_ABS_MARGIN_CONSTRAINT },
211 std::set<DRC_CONSTRAINT_T>{},
212 20 );
213
214 // Thermal relief
215 m_claims.emplace_back(
217 std::set<DRC_CONSTRAINT_T>{ MIN_RESOLVED_SPOKES_CONSTRAINT },
218 std::set<DRC_CONSTRAINT_T>{},
219 20 );
220
221 // Microvia stack limits
222 m_claims.emplace_back( MICROVIA_STACK_DEPTH, std::set<DRC_CONSTRAINT_T>{ MICROVIA_STACK_DEPTH_CONSTRAINT },
223 std::set<DRC_CONSTRAINT_T>{}, 20 );
224
225 m_claims.emplace_back( MICROVIA_ASPECT_RATIO, std::set<DRC_CONSTRAINT_T>{ MICROVIA_ASPECT_RATIO_CONSTRAINT },
226 std::set<DRC_CONSTRAINT_T>{}, 20 );
227
228 // Diff pair length matching requires both length and skew.
229 // Without this, LENGTH_CONSTRAINT alone would match here at priority 65
230 // instead of falling through to ABSOLUTE_LENGTH at priority 60.
231 m_claims.emplace_back(
233 std::set<DRC_CONSTRAINT_T>{ LENGTH_CONSTRAINT, SKEW_CONSTRAINT },
234 std::set<DRC_CONSTRAINT_T>{ },
235 65 );
236
237 // Skew-only (when not combined with length) still goes to matched length diff pair
238 m_claims.emplace_back(
240 std::set<DRC_CONSTRAINT_T>{ SKEW_CONSTRAINT },
241 std::set<DRC_CONSTRAINT_T>{},
242 55 );
243
244 // Diff pair gap only (when not combined with track_width)
245 m_claims.emplace_back(
247 std::set<DRC_CONSTRAINT_T>{ DIFF_PAIR_GAP_CONSTRAINT },
248 std::set<DRC_CONSTRAINT_T>{ MAX_UNCOUPLED_CONSTRAINT },
249 15 );
250
251 // Diff pair uncoupled only (when not combined with track_width or gap)
252 m_claims.emplace_back(
254 std::set<DRC_CONSTRAINT_T>{ MAX_UNCOUPLED_CONSTRAINT },
255 std::set<DRC_CONSTRAINT_T>{},
256 10 );
257
258 // Priority 5: Bool constraints
259 m_claims.emplace_back(
261 std::set<DRC_CONSTRAINT_T>{ DISALLOW_CONSTRAINT },
262 std::set<DRC_CONSTRAINT_T>{},
263 5 );
264
265 // Sort claims by priority descending
266 std::sort( m_claims.begin(), m_claims.end(),
267 []( const DRC_PANEL_CLAIM& a, const DRC_PANEL_CLAIM& b )
268 {
269 return a.priority > b.priority;
270 } );
271}
272
273
275 const std::set<DRC_CONSTRAINT_T>& aConstraints,
276 std::set<DRC_CONSTRAINT_T>* aClaimedOut )
277{
278 // Check that all required constraints are present
279 for( DRC_CONSTRAINT_T required : aClaim.requiredConstraints )
280 {
281 if( aConstraints.find( required ) == aConstraints.end() )
282 return false;
283 }
284
285 // Build the set of claimed constraints (required + any optional that are present)
286 std::set<DRC_CONSTRAINT_T> claimed = aClaim.requiredConstraints;
287
288 for( DRC_CONSTRAINT_T optional : aClaim.optionalConstraints )
289 {
290 if( aConstraints.find( optional ) != aConstraints.end() )
291 claimed.insert( optional );
292 }
293
294 if( claimed.empty() )
295 return false;
296
297 if( aClaimedOut )
298 *aClaimedOut = claimed;
299
300 return true;
301}
302
303
304std::vector<DRC_PANEL_MATCH> DRC_PANEL_MATCHER::MatchRule( const DRC_RULE& aRule )
305{
306 std::vector<DRC_PANEL_MATCH> matches;
307
308 // Extract all constraint types from the rule
309 std::set<DRC_CONSTRAINT_T> remaining;
310
311 for( const DRC_CONSTRAINT& constraint : aRule.m_Constraints )
312 {
313 if( constraint.m_Type != NULL_CONSTRAINT )
314 remaining.insert( constraint.m_Type );
315 }
316
317 if( remaining.empty() )
318 return matches;
319
320 // Iterate through claims by priority (already sorted in initClaims)
321 for( const DRC_PANEL_CLAIM& claim : m_claims )
322 {
323 if( remaining.empty() )
324 break;
325
326 std::set<DRC_CONSTRAINT_T> claimed;
327
328 if( matchesClaim( claim, remaining, &claimed ) )
329 {
330 // VIAS_UNDER_SMD requires Pad_Type == 'SMD' in the condition
331 if( claim.panelType == VIAS_UNDER_SMD )
332 {
333 if( !aRule.m_Condition || !aRule.m_Condition->GetExpression().Contains( wxS( "Pad_Type == 'SMD'" ) ) )
334 continue;
335 }
336
337 matches.emplace_back( claim.panelType, claimed );
338
339 // Remove claimed constraints from remaining set
340 for( DRC_CONSTRAINT_T type : claimed )
341 remaining.erase( type );
342 }
343 }
344
345 // Any remaining constraints go to CUSTOM_RULE panel
346 if( !remaining.empty() )
347 matches.emplace_back( CUSTOM_RULE, remaining );
348
349 return matches;
350}
351
352
354 const std::set<DRC_CONSTRAINT_T>& aConstraints )
355{
356 for( const DRC_PANEL_CLAIM& claim : m_claims )
357 {
358 if( claim.panelType == aPanel )
359 {
360 // Check if all constraints can be handled by this panel
361 std::set<DRC_CONSTRAINT_T> allHandled = claim.requiredConstraints;
362 allHandled.insert( claim.optionalConstraints.begin(), claim.optionalConstraints.end() );
363
364 for( DRC_CONSTRAINT_T type : aConstraints )
365 {
366 if( allHandled.find( type ) == allHandled.end() )
367 return false;
368 }
369
370 return true;
371 }
372 }
373
374 // CUSTOM_RULE can load anything
375 return aPanel == CUSTOM_RULE;
376}
377
378
380{
381 std::set<DRC_CONSTRAINT_T> singleConstraint{ aConstraintType };
382
383 for( const DRC_PANEL_CLAIM& claim : m_claims )
384 {
385 // Only match claims with exactly one required constraint and no optional
386 if( claim.requiredConstraints.size() == 1 &&
387 claim.optionalConstraints.empty() &&
388 claim.requiredConstraints.count( aConstraintType ) > 0 )
389 {
390 return claim.panelType;
391 }
392 }
393
394 return CUSTOM_RULE;
395}
DRC_CONSTRAINT_T m_Type
Definition drc_rule.h:243
DRC_RULE_EDITOR_CONSTRAINT_NAME GetPanelForConstraint(DRC_CONSTRAINT_T aConstraintType)
Get the panel type for a single constraint.
bool CanPanelLoad(DRC_RULE_EDITOR_CONSTRAINT_NAME aPanel, const std::set< DRC_CONSTRAINT_T > &aConstraints)
Check if a specific panel type can load a set of constraints.
std::vector< DRC_PANEL_MATCH > MatchRule(const DRC_RULE &aRule)
Match a DRC rule to one or more panel types.
bool matchesClaim(const DRC_PANEL_CLAIM &aClaim, const std::set< DRC_CONSTRAINT_T > &aConstraints, std::set< DRC_CONSTRAINT_T > *aClaimedOut)
std::vector< DRC_PANEL_CLAIM > m_claims
DRC_PANEL_MATCHER()
Panel Claim Priority System.
wxString GetExpression() const
DRC_RULE_CONDITION * m_Condition
Definition drc_rule.h:158
std::vector< DRC_CONSTRAINT > m_Constraints
Definition drc_rule.h:159
DRC_CONSTRAINT_T
Definition drc_rule.h:49
@ ANNULAR_WIDTH_CONSTRAINT
Definition drc_rule.h:63
@ COURTYARD_CLEARANCE_CONSTRAINT
Definition drc_rule.h:57
@ VIA_DIAMETER_CONSTRAINT
Definition drc_rule.h:72
@ DIFF_PAIR_GAP_CONSTRAINT
Definition drc_rule.h:78
@ 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
@ TEXT_THICKNESS_CONSTRAINT
Definition drc_rule.h:60
@ LENGTH_CONSTRAINT
Definition drc_rule.h:73
@ VIA_COUNT_CONSTRAINT
Definition drc_rule.h:81
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:51
@ MICROVIA_ASPECT_RATIO_CONSTRAINT
Definition drc_rule.h:91
@ NULL_CONSTRAINT
Definition drc_rule.h:50
@ CONNECTION_WIDTH_CONSTRAINT
Definition drc_rule.h:85
@ MAX_UNCOUPLED_CONSTRAINT
Definition drc_rule.h:79
@ ASSERTION_CONSTRAINT
Definition drc_rule.h:84
@ SKEW_CONSTRAINT
Definition drc_rule.h:77
@ MICROVIA_STACK_DEPTH_CONSTRAINT
Definition drc_rule.h:90
@ 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
@ HOLE_SIZE_CONSTRAINT
Definition drc_rule.h:56
@ TEXT_HEIGHT_CONSTRAINT
Definition drc_rule.h:59
@ CREEPAGE_CONSTRAINT
Definition drc_rule.h:52
@ PHYSICAL_CLEARANCE_CONSTRAINT
Definition drc_rule.h:82
@ 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
@ 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
@ MICROVIA_STACK_DEPTH
@ MINIMUM_TEXT_HEIGHT_AND_THICKNESS
@ COPPER_TO_HOLE_CLEARANCE
@ HOLE_TO_HOLE_DISTANCE
@ ROUTING_WIDTH
@ MATCHED_LENGTH_DIFF_PAIR
@ COPPER_TO_EDGE_CLEARANCE
@ MICROVIA_ASPECT_RATIO
@ MINIMUM_SOLDERMASK_SLIVER
@ MINIMUM_VIA_DIAMETER
Defines which constraint types a panel can claim.
std::set< DRC_CONSTRAINT_T > optionalConstraints
std::set< DRC_CONSTRAINT_T > requiredConstraints