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(
70 std::set<DRC_CONSTRAINT_T>{ TRACK_WIDTH_CONSTRAINT, DIFF_PAIR_GAP_CONSTRAINT },
71 std::set<DRC_CONSTRAINT_T>{ MAX_UNCOUPLED_CONSTRAINT },
72 100 );
73
74 // Priority 90: VIA_STYLE claims via_diameter + hole_size
75 m_claims.emplace_back(
77 std::set<DRC_CONSTRAINT_T>{ VIA_DIAMETER_CONSTRAINT, HOLE_SIZE_CONSTRAINT },
78 std::set<DRC_CONSTRAINT_T>{},
79 90 );
80
81 // Priority 80: MINIMUM_TEXT_HEIGHT_THICKNESS claims text_height + text_thickness
82 m_claims.emplace_back(
84 std::set<DRC_CONSTRAINT_T>{ TEXT_HEIGHT_CONSTRAINT, TEXT_THICKNESS_CONSTRAINT },
85 std::set<DRC_CONSTRAINT_T>{},
86 80 );
87
88 // Priority 70: ROUTING_WIDTH claims track_width (single constraint, min/opt/max values)
89 m_claims.emplace_back(
91 std::set<DRC_CONSTRAINT_T>{ TRACK_WIDTH_CONSTRAINT },
92 std::set<DRC_CONSTRAINT_T>{},
93 70 );
94
95 // Priority 60: ABSOLUTE_LENGTH claims length (single constraint, min/opt/max values)
96 m_claims.emplace_back(
98 std::set<DRC_CONSTRAINT_T>{ LENGTH_CONSTRAINT },
99 std::set<DRC_CONSTRAINT_T>{},
100 60 );
101
102 // Priority 50: PERMITTED_LAYERS claims assertion for layer-based rules
103 m_claims.emplace_back(
105 std::set<DRC_CONSTRAINT_T>{ ASSERTION_CONSTRAINT },
106 std::set<DRC_CONSTRAINT_T>{},
107 50 );
108
109 // Priority 40: ALLOWED_ORIENTATION claims assertion for orientation-based rules
110 // Note that both PERMITTED_LAYERS and ALLOWED_ORIENTATION claim ASSERTION_CONSTRAINT.
111 // The UI must differentiate based on assertion content.
112 m_claims.emplace_back(
114 std::set<DRC_CONSTRAINT_T>{ ASSERTION_CONSTRAINT },
115 std::set<DRC_CONSTRAINT_T>{},
116 40 );
117
118 // Priority 30: Generic single-constraint panels
119
120 // Clearance constraints
121 m_claims.emplace_back(
123 std::set<DRC_CONSTRAINT_T>{ CLEARANCE_CONSTRAINT },
124 std::set<DRC_CONSTRAINT_T>{},
125 30 );
126
127 m_claims.emplace_back(
129 std::set<DRC_CONSTRAINT_T>{ EDGE_CLEARANCE_CONSTRAINT },
130 std::set<DRC_CONSTRAINT_T>{},
131 30 );
132
133 m_claims.emplace_back(
135 std::set<DRC_CONSTRAINT_T>{ HOLE_CLEARANCE_CONSTRAINT },
136 std::set<DRC_CONSTRAINT_T>{},
137 30 );
138
139 m_claims.emplace_back(
141 std::set<DRC_CONSTRAINT_T>{ HOLE_TO_HOLE_CONSTRAINT },
142 std::set<DRC_CONSTRAINT_T>{},
143 30 );
144
145 m_claims.emplace_back(
147 std::set<DRC_CONSTRAINT_T>{ COURTYARD_CLEARANCE_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 // Skew constraints
222 m_claims.emplace_back(
224 std::set<DRC_CONSTRAINT_T>{ SKEW_CONSTRAINT },
225 std::set<DRC_CONSTRAINT_T>{},
226 20 );
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:227
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:147
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