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 // Diff pair length matching requires both length and skew.
222 // Without this, LENGTH_CONSTRAINT alone would match here at priority 65
223 // instead of falling through to ABSOLUTE_LENGTH at priority 60.
224 m_claims.emplace_back(
226 std::set<DRC_CONSTRAINT_T>{ LENGTH_CONSTRAINT, SKEW_CONSTRAINT },
227 std::set<DRC_CONSTRAINT_T>{ },
228 65 );
229
230 // Skew-only (when not combined with length) still goes to matched length diff pair
231 m_claims.emplace_back(
233 std::set<DRC_CONSTRAINT_T>{ SKEW_CONSTRAINT },
234 std::set<DRC_CONSTRAINT_T>{},
235 55 );
236
237 // Diff pair gap only (when not combined with track_width)
238 m_claims.emplace_back(
240 std::set<DRC_CONSTRAINT_T>{ DIFF_PAIR_GAP_CONSTRAINT },
241 std::set<DRC_CONSTRAINT_T>{ MAX_UNCOUPLED_CONSTRAINT },
242 15 );
243
244 // Diff pair uncoupled only (when not combined with track_width or gap)
245 m_claims.emplace_back(
247 std::set<DRC_CONSTRAINT_T>{ MAX_UNCOUPLED_CONSTRAINT },
248 std::set<DRC_CONSTRAINT_T>{},
249 10 );
250
251 // Priority 5: Bool constraints
252 m_claims.emplace_back(
254 std::set<DRC_CONSTRAINT_T>{ DISALLOW_CONSTRAINT },
255 std::set<DRC_CONSTRAINT_T>{},
256 5 );
257
258 // Sort claims by priority descending
259 std::sort( m_claims.begin(), m_claims.end(),
260 []( const DRC_PANEL_CLAIM& a, const DRC_PANEL_CLAIM& b )
261 {
262 return a.priority > b.priority;
263 } );
264}
265
266
268 const std::set<DRC_CONSTRAINT_T>& aConstraints,
269 std::set<DRC_CONSTRAINT_T>* aClaimedOut )
270{
271 // Check that all required constraints are present
272 for( DRC_CONSTRAINT_T required : aClaim.requiredConstraints )
273 {
274 if( aConstraints.find( required ) == aConstraints.end() )
275 return false;
276 }
277
278 // Build the set of claimed constraints (required + any optional that are present)
279 std::set<DRC_CONSTRAINT_T> claimed = aClaim.requiredConstraints;
280
281 for( DRC_CONSTRAINT_T optional : aClaim.optionalConstraints )
282 {
283 if( aConstraints.find( optional ) != aConstraints.end() )
284 claimed.insert( optional );
285 }
286
287 if( claimed.empty() )
288 return false;
289
290 if( aClaimedOut )
291 *aClaimedOut = claimed;
292
293 return true;
294}
295
296
297std::vector<DRC_PANEL_MATCH> DRC_PANEL_MATCHER::MatchRule( const DRC_RULE& aRule )
298{
299 std::vector<DRC_PANEL_MATCH> matches;
300
301 // Extract all constraint types from the rule
302 std::set<DRC_CONSTRAINT_T> remaining;
303
304 for( const DRC_CONSTRAINT& constraint : aRule.m_Constraints )
305 {
306 if( constraint.m_Type != NULL_CONSTRAINT )
307 remaining.insert( constraint.m_Type );
308 }
309
310 if( remaining.empty() )
311 return matches;
312
313 // Iterate through claims by priority (already sorted in initClaims)
314 for( const DRC_PANEL_CLAIM& claim : m_claims )
315 {
316 if( remaining.empty() )
317 break;
318
319 std::set<DRC_CONSTRAINT_T> claimed;
320
321 if( matchesClaim( claim, remaining, &claimed ) )
322 {
323 // VIAS_UNDER_SMD requires Pad_Type == 'SMD' in the condition
324 if( claim.panelType == VIAS_UNDER_SMD )
325 {
326 if( !aRule.m_Condition || !aRule.m_Condition->GetExpression().Contains( wxS( "Pad_Type == 'SMD'" ) ) )
327 continue;
328 }
329
330 matches.emplace_back( claim.panelType, claimed );
331
332 // Remove claimed constraints from remaining set
333 for( DRC_CONSTRAINT_T type : claimed )
334 remaining.erase( type );
335 }
336 }
337
338 // Any remaining constraints go to CUSTOM_RULE panel
339 if( !remaining.empty() )
340 matches.emplace_back( CUSTOM_RULE, remaining );
341
342 return matches;
343}
344
345
347 const std::set<DRC_CONSTRAINT_T>& aConstraints )
348{
349 for( const DRC_PANEL_CLAIM& claim : m_claims )
350 {
351 if( claim.panelType == aPanel )
352 {
353 // Check if all constraints can be handled by this panel
354 std::set<DRC_CONSTRAINT_T> allHandled = claim.requiredConstraints;
355 allHandled.insert( claim.optionalConstraints.begin(), claim.optionalConstraints.end() );
356
357 for( DRC_CONSTRAINT_T type : aConstraints )
358 {
359 if( allHandled.find( type ) == allHandled.end() )
360 return false;
361 }
362
363 return true;
364 }
365 }
366
367 // CUSTOM_RULE can load anything
368 return aPanel == CUSTOM_RULE;
369}
370
371
373{
374 std::set<DRC_CONSTRAINT_T> singleConstraint{ aConstraintType };
375
376 for( const DRC_PANEL_CLAIM& claim : m_claims )
377 {
378 // Only match claims with exactly one required constraint and no optional
379 if( claim.requiredConstraints.size() == 1 &&
380 claim.optionalConstraints.empty() &&
381 claim.requiredConstraints.count( aConstraintType ) > 0 )
382 {
383 return claim.panelType;
384 }
385 }
386
387 return CUSTOM_RULE;
388}
DRC_CONSTRAINT_T m_Type
Definition drc_rule.h:239
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:156
std::vector< DRC_CONSTRAINT > m_Constraints
Definition drc_rule.h:157
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
@ 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
@ 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
@ MINIMUM_TEXT_HEIGHT_AND_THICKNESS
@ COPPER_TO_HOLE_CLEARANCE
@ HOLE_TO_HOLE_DISTANCE
@ ROUTING_WIDTH
@ MATCHED_LENGTH_DIFF_PAIR
@ COPPER_TO_EDGE_CLEARANCE
@ 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