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, 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
26#include <algorithm>
27
28
57
62
63
65{
66 // Priority 100: ROUTING_DIFF_PAIR claims track_width + diff_pair_gap + diff_pair_uncoupled
67 // This must be checked before ROUTING_WIDTH which also wants track_width
68 m_claims.emplace_back( ROUTING_DIFF_PAIR,
69 std::set<DRC_CONSTRAINT_T>{ TRACK_WIDTH_CONSTRAINT, DIFF_PAIR_GAP_CONSTRAINT },
70 std::set<DRC_CONSTRAINT_T>{ MAX_UNCOUPLED_CONSTRAINT, SKEW_CONSTRAINT }, 100 );
71
72 // Priority 90: VIA_STYLE claims via_diameter + hole_size
73 m_claims.emplace_back(
75 std::set<DRC_CONSTRAINT_T>{ VIA_DIAMETER_CONSTRAINT, HOLE_SIZE_CONSTRAINT },
76 std::set<DRC_CONSTRAINT_T>{},
77 90 );
78
79 // Priority 80: MINIMUM_TEXT_HEIGHT_THICKNESS claims text_height + text_thickness
80 m_claims.emplace_back(
82 std::set<DRC_CONSTRAINT_T>{ TEXT_HEIGHT_CONSTRAINT, TEXT_THICKNESS_CONSTRAINT },
83 std::set<DRC_CONSTRAINT_T>{},
84 80 );
85
86 // Priority 70: ROUTING_WIDTH claims track_width (single constraint, min/opt/max values)
87 m_claims.emplace_back(
89 std::set<DRC_CONSTRAINT_T>{ TRACK_WIDTH_CONSTRAINT },
90 std::set<DRC_CONSTRAINT_T>{},
91 70 );
92
93 // Priority 60: ABSOLUTE_LENGTH claims length (single constraint, min/opt/max values)
94 m_claims.emplace_back(
96 std::set<DRC_CONSTRAINT_T>{ LENGTH_CONSTRAINT },
97 std::set<DRC_CONSTRAINT_T>{},
98 60 );
99
100 // Priority 50: PERMITTED_LAYERS claims assertion for layer-based rules
101 m_claims.emplace_back(
103 std::set<DRC_CONSTRAINT_T>{ ASSERTION_CONSTRAINT },
104 std::set<DRC_CONSTRAINT_T>{},
105 50 );
106
107 // Priority 40: ALLOWED_ORIENTATION claims assertion for orientation-based rules
108 // Note that both PERMITTED_LAYERS and ALLOWED_ORIENTATION claim ASSERTION_CONSTRAINT.
109 // The UI must differentiate based on assertion content.
110 m_claims.emplace_back(
112 std::set<DRC_CONSTRAINT_T>{ ASSERTION_CONSTRAINT },
113 std::set<DRC_CONSTRAINT_T>{},
114 40 );
115
116 // Priority 30: Generic single-constraint panels
117
118 // Clearance constraints
119 m_claims.emplace_back(
121 std::set<DRC_CONSTRAINT_T>{ CLEARANCE_CONSTRAINT },
122 std::set<DRC_CONSTRAINT_T>{},
123 30 );
124
125 m_claims.emplace_back(
127 std::set<DRC_CONSTRAINT_T>{ EDGE_CLEARANCE_CONSTRAINT },
128 std::set<DRC_CONSTRAINT_T>{},
129 30 );
130
131 m_claims.emplace_back(
133 std::set<DRC_CONSTRAINT_T>{ HOLE_CLEARANCE_CONSTRAINT },
134 std::set<DRC_CONSTRAINT_T>{},
135 30 );
136
137 m_claims.emplace_back(
139 std::set<DRC_CONSTRAINT_T>{ HOLE_TO_HOLE_CONSTRAINT },
140 std::set<DRC_CONSTRAINT_T>{},
141 30 );
142
143 m_claims.emplace_back(
145 std::set<DRC_CONSTRAINT_T>{ COURTYARD_CLEARANCE_CONSTRAINT },
146 std::set<DRC_CONSTRAINT_T>{},
147 30 );
148
149 m_claims.emplace_back(
151 std::set<DRC_CONSTRAINT_T>{ PHYSICAL_CLEARANCE_CONSTRAINT },
152 std::set<DRC_CONSTRAINT_T>{},
153 30 );
154
155 m_claims.emplace_back(
157 std::set<DRC_CONSTRAINT_T>{ SILK_CLEARANCE_CONSTRAINT },
158 std::set<DRC_CONSTRAINT_T>{},
159 30 );
160
161 m_claims.emplace_back(
163 std::set<DRC_CONSTRAINT_T>{ CREEPAGE_CONSTRAINT },
164 std::set<DRC_CONSTRAINT_T>{},
165 30 );
166
167 // Size constraints
168 m_claims.emplace_back(
169 HOLE_SIZE,
170 std::set<DRC_CONSTRAINT_T>{ HOLE_SIZE_CONSTRAINT },
171 std::set<DRC_CONSTRAINT_T>{},
172 20 );
173
174 m_claims.emplace_back(
176 std::set<DRC_CONSTRAINT_T>{ VIA_DIAMETER_CONSTRAINT },
177 std::set<DRC_CONSTRAINT_T>{},
178 20 );
179
180 m_claims.emplace_back(
182 std::set<DRC_CONSTRAINT_T>{ ANNULAR_WIDTH_CONSTRAINT },
183 std::set<DRC_CONSTRAINT_T>{},
184 20 );
185
186 m_claims.emplace_back(
188 std::set<DRC_CONSTRAINT_T>{ CONNECTION_WIDTH_CONSTRAINT },
189 std::set<DRC_CONSTRAINT_T>{},
190 20 );
191
192 // Via count
193 m_claims.emplace_back(
195 std::set<DRC_CONSTRAINT_T>{ VIA_COUNT_CONSTRAINT },
196 std::set<DRC_CONSTRAINT_T>{},
197 20 );
198
199 // Solder mask/paste
200 m_claims.emplace_back(
202 std::set<DRC_CONSTRAINT_T>{ SOLDER_MASK_EXPANSION_CONSTRAINT },
203 std::set<DRC_CONSTRAINT_T>{},
204 20 );
205
206 m_claims.emplace_back(
208 std::set<DRC_CONSTRAINT_T>{ SOLDER_PASTE_ABS_MARGIN_CONSTRAINT },
209 std::set<DRC_CONSTRAINT_T>{},
210 20 );
211
212 // Thermal relief
213 m_claims.emplace_back(
215 std::set<DRC_CONSTRAINT_T>{ MIN_RESOLVED_SPOKES_CONSTRAINT },
216 std::set<DRC_CONSTRAINT_T>{},
217 20 );
218
219 // Diff pair length matching requires both length and skew.
220 // Without this, LENGTH_CONSTRAINT alone would match here at priority 65
221 // instead of falling through to ABSOLUTE_LENGTH at priority 60.
222 m_claims.emplace_back(
224 std::set<DRC_CONSTRAINT_T>{ LENGTH_CONSTRAINT, SKEW_CONSTRAINT },
225 std::set<DRC_CONSTRAINT_T>{},
226 65 );
227
228 // Diff pair gap only (when not combined with track_width)
229 m_claims.emplace_back(
231 std::set<DRC_CONSTRAINT_T>{ DIFF_PAIR_GAP_CONSTRAINT },
232 std::set<DRC_CONSTRAINT_T>{ MAX_UNCOUPLED_CONSTRAINT },
233 15 );
234
235 // Priority 5: Bool constraints
236 m_claims.emplace_back(
238 std::set<DRC_CONSTRAINT_T>{ DISALLOW_CONSTRAINT },
239 std::set<DRC_CONSTRAINT_T>{},
240 5 );
241
242 // Sort claims by priority descending
243 std::sort( m_claims.begin(), m_claims.end(),
244 []( const DRC_PANEL_CLAIM& a, const DRC_PANEL_CLAIM& b )
245 {
246 return a.priority > b.priority;
247 } );
248}
249
250
252 const std::set<DRC_CONSTRAINT_T>& aConstraints,
253 std::set<DRC_CONSTRAINT_T>* aClaimedOut )
254{
255 // Check that all required constraints are present
256 for( DRC_CONSTRAINT_T required : aClaim.requiredConstraints )
257 {
258 if( aConstraints.find( required ) == aConstraints.end() )
259 return false;
260 }
261
262 // Build the set of claimed constraints (required + any optional that are present)
263 std::set<DRC_CONSTRAINT_T> claimed = aClaim.requiredConstraints;
264
265 for( DRC_CONSTRAINT_T optional : aClaim.optionalConstraints )
266 {
267 if( aConstraints.find( optional ) != aConstraints.end() )
268 claimed.insert( optional );
269 }
270
271 if( aClaimedOut )
272 *aClaimedOut = claimed;
273
274 return true;
275}
276
277
278std::vector<DRC_PANEL_MATCH> DRC_PANEL_MATCHER::MatchRule( const DRC_RULE& aRule )
279{
280 std::vector<DRC_PANEL_MATCH> matches;
281
282 // Extract all constraint types from the rule
283 std::set<DRC_CONSTRAINT_T> remaining;
284
285 for( const DRC_CONSTRAINT& constraint : aRule.m_Constraints )
286 {
287 if( constraint.m_Type != NULL_CONSTRAINT )
288 remaining.insert( constraint.m_Type );
289 }
290
291 if( remaining.empty() )
292 return matches;
293
294 // Iterate through claims by priority (already sorted in initClaims)
295 for( const DRC_PANEL_CLAIM& claim : m_claims )
296 {
297 if( remaining.empty() )
298 break;
299
300 std::set<DRC_CONSTRAINT_T> claimed;
301
302 if( matchesClaim( claim, remaining, &claimed ) )
303 {
304 matches.emplace_back( claim.panelType, claimed );
305
306 // Remove claimed constraints from remaining set
307 for( DRC_CONSTRAINT_T type : claimed )
308 remaining.erase( type );
309 }
310 }
311
312 // Any remaining constraints go to CUSTOM_RULE panel
313 if( !remaining.empty() )
314 matches.emplace_back( CUSTOM_RULE, remaining );
315
316 return matches;
317}
318
319
321 const std::set<DRC_CONSTRAINT_T>& aConstraints )
322{
323 for( const DRC_PANEL_CLAIM& claim : m_claims )
324 {
325 if( claim.panelType == aPanel )
326 {
327 // Check if all constraints can be handled by this panel
328 std::set<DRC_CONSTRAINT_T> allHandled = claim.requiredConstraints;
329 allHandled.insert( claim.optionalConstraints.begin(), claim.optionalConstraints.end() );
330
331 for( DRC_CONSTRAINT_T type : aConstraints )
332 {
333 if( allHandled.find( type ) == allHandled.end() )
334 return false;
335 }
336
337 return true;
338 }
339 }
340
341 // CUSTOM_RULE can load anything
342 return aPanel == CUSTOM_RULE;
343}
344
345
347{
348 std::set<DRC_CONSTRAINT_T> singleConstraint{ aConstraintType };
349
350 for( const DRC_PANEL_CLAIM& claim : m_claims )
351 {
352 // Only match claims with exactly one required constraint and no optional
353 if( claim.requiredConstraints.size() == 1 &&
354 claim.optionalConstraints.empty() &&
355 claim.requiredConstraints.count( aConstraintType ) > 0 )
356 {
357 return claim.panelType;
358 }
359 }
360
361 return CUSTOM_RULE;
362}
DRC_CONSTRAINT_T m_Type
Definition drc_rule.h:228
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.
std::vector< DRC_CONSTRAINT > m_Constraints
Definition drc_rule.h:148
DRC_CONSTRAINT_T
Definition drc_rule.h:47
@ ANNULAR_WIDTH_CONSTRAINT
Definition drc_rule.h:61
@ COURTYARD_CLEARANCE_CONSTRAINT
Definition drc_rule.h:55
@ VIA_DIAMETER_CONSTRAINT
Definition drc_rule.h:70
@ DIFF_PAIR_GAP_CONSTRAINT
Definition drc_rule.h:73
@ 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
@ TEXT_THICKNESS_CONSTRAINT
Definition drc_rule.h:58
@ LENGTH_CONSTRAINT
Definition drc_rule.h:71
@ VIA_COUNT_CONSTRAINT
Definition drc_rule.h:76
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:49
@ NULL_CONSTRAINT
Definition drc_rule.h:48
@ CONNECTION_WIDTH_CONSTRAINT
Definition drc_rule.h:80
@ 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
@ HOLE_SIZE_CONSTRAINT
Definition drc_rule.h:54
@ TEXT_HEIGHT_CONSTRAINT
Definition drc_rule.h:57
@ CREEPAGE_CONSTRAINT
Definition drc_rule.h:50
@ PHYSICAL_CLEARANCE_CONSTRAINT
Definition drc_rule.h:77
@ HOLE_TO_HOLE_CONSTRAINT
Definition drc_rule.h:52
DRC_RULE_EDITOR_CONSTRAINT_NAME
@ ALLOWED_ORIENTATION
@ SILK_TO_SILK_CLEARANCE
@ ROUTING_DIFF_PAIR
@ HOLE_TO_HOLE_CLEARANCE
@ 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
@ MATCHED_LENGTH_DIFF_PAIR
@ COPPER_TO_EDGE_CLEARANCE
@ MINIMUM_VIA_DIAMETER
Defines which constraint types a panel can claim.
std::set< DRC_CONSTRAINT_T > optionalConstraints
std::set< DRC_CONSTRAINT_T > requiredConstraints