KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_test_provider_diff_pair_coupling.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) 2004-2023 KiCad Developers.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20
21#include <advanced_config.h>
22#include <board.h>
24#include <pcb_track.h>
25
26#include <drc/drc_engine.h>
27#include <drc/drc_item.h>
28#include <drc/drc_rule.h>
30#include <drc/drc_rtree.h>
31
33
36
37#include <view/view_overlay.h>
38
39/*
40 Differential pair gap/coupling test.
41 Errors generated:
42 - DRCE_DIFF_PAIR_GAP_OUT_OF_RANGE
43 - DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG
44 - DRCE_TOO_MANY_VIAS
45 Todo:
46 - arc support.
47 - improve recognition of coupled segments (now anything that's parallel is considered
48 coupled, causing DRC errors on meanders)
49*/
50
51namespace test {
52
54{
55public:
57 m_board( nullptr )
58 {
59 }
60
62 {
63 }
64
65 virtual bool Run() override;
66
67 virtual const wxString GetName() const override
68 {
69 return wxT( "diff_pair_coupling" );
70 };
71
72 virtual const wxString GetDescription() const override
73 {
74 return wxT( "Tests differential pair coupling" );
75 }
76
77private:
79};
80
81};
82
83
84static bool commonParallelProjection( SEG p, SEG n, SEG &pClip, SEG& nClip )
85{
86 SEG n_proj_p( p.LineProject( n.A ), p.LineProject( n.B ) );
87
88 int64_t t_a = 0;
89 int64_t t_b = p.TCoef( p.B );
90
91 int64_t tproj_a = p.TCoef( n_proj_p.A );
92 int64_t tproj_b = p.TCoef( n_proj_p.B );
93
94 if( t_b < t_a )
95 std::swap( t_b, t_a );
96
97 if( tproj_b < tproj_a )
98 std::swap( tproj_b, tproj_a );
99
100 if( t_b <= tproj_a )
101 return false;
102
103 if( t_a >= tproj_b )
104 return false;
105
106 int64_t t[4] = { 0, p.TCoef( p.B ), p.TCoef( n_proj_p.A ), p.TCoef( n_proj_p.B ) };
107 std::vector<int64_t> tv( t, t + 4 );
108 std::sort( tv.begin(), tv.end() ); // fixme: awful and disgusting way of finding 2 midpoints
109
110 int64_t pLenSq = p.SquaredLength();
111
112 VECTOR2I dp = p.B - p.A;
113 pClip.A.x = p.A.x + rescale( (int64_t)dp.x, tv[1], pLenSq );
114 pClip.A.y = p.A.y + rescale( (int64_t)dp.y, tv[1], pLenSq );
115
116 pClip.B.x = p.A.x + rescale( (int64_t)dp.x, tv[2], pLenSq );
117 pClip.B.y = p.A.y + rescale( (int64_t)dp.y, tv[2], pLenSq );
118
119 nClip.A = n.LineProject( pClip.A );
120 nClip.B = n.LineProject( pClip.B );
121
122 return true;
123}
124
125
126static bool commonParallelProjection( const PCB_ARC& p, const PCB_ARC& n, SHAPE_ARC &pClip, SHAPE_ARC& nClip )
127{
128 VECTOR2I p_center = p.GetCenter();
129 VECTOR2I n_center = n.GetCenter();
130 double p_radius = p.GetRadius();
131 double n_radius = n.GetRadius();
132
133 VECTOR2I p_start( p.GetStart() );
134 VECTOR2I p_end( p.GetEnd() );
135
136 if( !p.IsCCW() )
137 std::swap( p_start, p_end );
138
139 VECTOR2I n_start( n.GetStart() );
140 VECTOR2I n_end( n.GetEnd() );
141
142 if( !n.IsCCW() )
143 std::swap( n_start, n_end );
144
145 SHAPE_ARC p_arc( p_start, p.GetMid(), p_end, 0 );
146 SHAPE_ARC n_arc( n_start, n.GetMid(), n_end, 0 );
147
148 EDA_ANGLE p_start_angle = p_arc.GetStartAngle();
149
150 // Rotate the arcs to a common 0 starting angle
151 p_arc.Rotate( -p_start_angle, p_center );
152 n_arc.Rotate( -p_start_angle, n_center );
153
154 EDA_ANGLE p_end_angle = p_arc.GetEndAngle();
155 EDA_ANGLE n_start_angle = n_arc.GetStartAngle();
156 EDA_ANGLE n_end_angle = n_arc.GetEndAngle();
157
158
159 EDA_ANGLE clip_total_angle;
160 EDA_ANGLE clip_start_angle;
161
162 if( n_start_angle > p_end_angle )
163 {
164 // n is fully outside of p
165 if( n_end_angle > p_end_angle )
166 return false;
167
168 // n starts before angle 0 and ends in the middle of p
169 clip_total_angle = n_end_angle + p_start_angle;
170 clip_start_angle = p_start_angle;
171 }
172 else
173 {
174 clip_start_angle = n_start_angle + p_start_angle;
175
176 // n is fully inside of p
177 if( n_end_angle < p_end_angle )
178 clip_total_angle = n_end_angle - n_start_angle;
179 else // n starts after 0 and ends after p
180 clip_total_angle = p_end_angle - n_start_angle;
181 }
182
183 // One arc starts approximately where the other ends
184 if( clip_total_angle <= EDA_ANGLE( ADVANCED_CFG::GetCfg().m_MinParallelAngle ) )
185 return false;
186
187 VECTOR2I n_start_pt = n_center + VECTOR2I( KiROUND( n_radius ), 0 );
188 VECTOR2I p_start_pt = p_center + VECTOR2I( KiROUND( p_radius ), 0 );
189
190 RotatePoint( n_start_pt, n_center, clip_start_angle );
191 RotatePoint( p_start_pt, p_center, clip_start_angle );
192
193 pClip = SHAPE_ARC( p_center, p_start_pt, clip_total_angle );
194 nClip = SHAPE_ARC( n_center, n_start_pt, clip_total_angle );
195
196 return true;
197}
198
199
201{
202 bool operator<( const DIFF_PAIR_KEY& b ) const
203 {
204 if( netP < b.netP )
205 {
206 return true;
207 }
208 else if( netP > b.netP )
209 {
210 return false;
211 }
212 else // netP == b.netP
213 {
214 if( netN < b.netN )
215 return true;
216 else if( netN > b.netN )
217 return false;
218 else if( gapRuleName.IsEmpty() )
219 return gapRuleName < b.gapRuleName;
220 else
222 }
223 }
224
225 int netP, netN;
226 wxString gapRuleName;
228 std::optional<MINOPTMAX<int>> gapConstraint;
230 std::optional<MINOPTMAX<int>> uncoupledConstraint;
232};
233
235{
238 bool isArc;
247
249 isArc( false ),
250 parentN( nullptr ),
251 parentP( nullptr ),
252 computedGap( 0 ),
254 couplingFailMin( false ),
255 couplingFailMax( false )
256 {}
257};
258
259
261{
262 std::set<BOARD_CONNECTED_ITEM*> itemsP, itemsN;
263 std::vector<DIFF_PAIR_COUPLED_SEGMENTS> coupled;
267};
268
269
271{
272 for( BOARD_CONNECTED_ITEM* itemP : aDp.itemsP )
273 {
274 PCB_TRACK* sp = dyn_cast<PCB_TRACK*>( itemP );
275 std::optional<DIFF_PAIR_COUPLED_SEGMENTS> bestCoupled;
276 int bestGap = std::numeric_limits<int>::max();
277
278 if( !sp )
279 continue;
280
281 for ( BOARD_CONNECTED_ITEM* itemN : aDp.itemsN )
282 {
283 PCB_TRACK* sn = dyn_cast<PCB_TRACK*> ( itemN );
284
285 if( !sn )
286 continue;
287
288 if( ( sn->GetLayerSet() & sp->GetLayerSet() ).none() )
289 continue;
290
291 SEG ssp ( sp->GetStart(), sp->GetEnd() );
292 SEG ssn ( sn->GetStart(), sn->GetEnd() );
293
294 // Segments that are ~ 1 IU in length per side are approximately parallel (tolerance is 1 IU)
295 // with everything and their parallel projection is < 1 IU, leading to bad distance calculations
296 if( ssp.SquaredLength() > 2 && ssn.SquaredLength() > 2 && ssp.ApproxParallel(ssn) )
297 {
299 bool coupled = commonParallelProjection( ssp, ssn, cpair.coupledP, cpair.coupledN );
300
301 if( coupled )
302 {
303 cpair.parentP = sp;
304 cpair.parentN = sn;
305 cpair.layer = sp->GetLayer();
306 cpair.computedGap = (cpair.coupledP.A - cpair.coupledN.A).EuclideanNorm();
307 cpair.computedGap -= ( sp->GetWidth() + sn->GetWidth() ) / 2;
308
309 if( cpair.computedGap < bestGap )
310 {
311 bestGap = cpair.computedGap;
312 bestCoupled = cpair;
313 }
314 }
315
316 }
317 }
318
319 if( bestCoupled )
320 {
321 auto excludeSelf = [&]( BOARD_ITEM* aItem )
322 {
323 if( aItem == bestCoupled->parentN || aItem == bestCoupled->parentP )
324 return false;
325
326 if( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_VIA_T
327 || aItem->Type() == PCB_ARC_T )
328 {
329 BOARD_CONNECTED_ITEM* bci = static_cast<BOARD_CONNECTED_ITEM*>( aItem );
330
331 if( bci->GetNetCode() == bestCoupled->parentN->GetNetCode()
332 || bci->GetNetCode() == bestCoupled->parentP->GetNetCode() )
333 {
334 return false;
335 }
336 }
337
338 return true;
339 };
340
341 SHAPE_SEGMENT checkSegStart( bestCoupled->coupledP.A, bestCoupled->coupledN.A );
342 SHAPE_SEGMENT checkSegEnd( bestCoupled->coupledP.B, bestCoupled->coupledN.B );
343 DRC_RTREE* tree = bestCoupled->parentP->GetBoard()->m_CopperItemRTreeCache.get();
344
345 // check if there's anything in between the segments suspected to be coupled. If
346 // there's nothing, assume they are really coupled.
347
348 if( !tree->CheckColliding( &checkSegStart, sp->GetLayer(), 0, excludeSelf )
349 && !tree->CheckColliding( &checkSegEnd, sp->GetLayer(), 0, excludeSelf ) )
350 {
351 aDp.coupled.push_back( *bestCoupled );
352 }
353 }
354 }
355
356 for( BOARD_CONNECTED_ITEM* itemP : aDp.itemsP )
357 {
358 PCB_ARC* sp = dyn_cast<PCB_ARC*>( itemP );
359 std::optional<DIFF_PAIR_COUPLED_SEGMENTS> bestCoupled;
360 int bestGap = std::numeric_limits<int>::max();
361
362 if( !sp )
363 continue;
364
365 for ( BOARD_CONNECTED_ITEM* itemN : aDp.itemsN )
366 {
367 PCB_ARC* sn = dyn_cast<PCB_ARC*> ( itemN );
368
369 if( !sn )
370 continue;
371
372 if( ( sn->GetLayerSet() & sp->GetLayerSet() ).none() )
373 continue;
374
375 // Segments that are ~ 1 IU in length per side are approximately parallel (tolerance is 1 IU)
376 // with everything and their parallel projection is < 1 IU, leading to bad distance calculations
377 if( sp->GetLength() > 2 && sn->GetLength() > 2 && ( sp->GetCenter() - sn->GetCenter() ).SquaredEuclideanNorm() < 4 )
378 {
380 cpair.isArc = true;
381 bool coupled = commonParallelProjection( *sp, *sn, cpair.coupledArcP, cpair.coupledArcN );
382
383 if( coupled )
384 {
385 cpair.parentP = sp;
386 cpair.parentN = sn;
387 cpair.layer = sp->GetLayer();
389 - cpair.coupledArcN.GetRadius() ) );
390 cpair.computedGap -= ( sp->GetWidth() + sn->GetWidth() ) / 2;
391
392 if( cpair.computedGap < bestGap )
393 {
394 bestGap = cpair.computedGap;
395 bestCoupled = cpair;
396 }
397 }
398
399 }
400 }
401
402 if( bestCoupled )
403 {
404 auto excludeSelf =
405 [&] ( BOARD_ITEM *aItem )
406 {
407 if( aItem == bestCoupled->parentN || aItem == bestCoupled->parentP )
408 return false;
409
410 if( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_VIA_T || aItem->Type() == PCB_ARC_T )
411 {
412 BOARD_CONNECTED_ITEM* bci = static_cast<BOARD_CONNECTED_ITEM*>( aItem );
413
414 if( bci->GetNetCode() == bestCoupled->parentN->GetNetCode()
415 || bci->GetNetCode() == bestCoupled->parentP->GetNetCode() )
416 {
417 return false;
418 }
419 }
420
421 return true;
422 };
423
424 SHAPE_SEGMENT checkSegStart( bestCoupled->coupledP.A, bestCoupled->coupledN.A );
425 SHAPE_SEGMENT checkSegEnd( bestCoupled->coupledP.B, bestCoupled->coupledN.B );
426 DRC_RTREE* tree = bestCoupled->parentP->GetBoard()->m_CopperItemRTreeCache.get();
427
428 // check if there's anything in between the segments suspected to be coupled. If
429 // there's nothing, assume they are really coupled.
430
431 if( !tree->CheckColliding( &checkSegStart, sp->GetLayer(), 0, excludeSelf )
432 && !tree->CheckColliding( &checkSegEnd, sp->GetLayer(), 0, excludeSelf ) )
433 {
434 aDp.coupled.push_back( *bestCoupled );
435 }
436 }
437 }
438}
439
440
441
443{
445
447
448 std::map<DIFF_PAIR_KEY, DIFF_PAIR_ITEMS> dpRuleMatches;
449
450 auto evaluateDpConstraints =
451 [&]( BOARD_ITEM *item ) -> bool
452 {
453 DIFF_PAIR_KEY key;
454 BOARD_CONNECTED_ITEM* citem = static_cast<BOARD_CONNECTED_ITEM*>( item );
455 NETINFO_ITEM* refNet = citem->GetNet();
456
457 if( refNet && DRC_ENGINE::IsNetADiffPair( m_board, refNet, key.netP, key.netN ) )
458 {
459 drc_dbg( 10, wxT( "eval dp %p\n" ), item );
460
461 const DRC_CONSTRAINT_T constraintsToCheck[] = {
464 };
465
466 for( int i = 0; i < 2; i++ )
467 {
468 DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( constraintsToCheck[ i ],
469 item, nullptr,
470 item->GetLayer() );
471
472 if( constraint.IsNull() || constraint.GetSeverity() == RPT_SEVERITY_IGNORE )
473 continue;
474
475 drc_dbg( 10, wxT( "cns %d item %p\n" ), constraintsToCheck[i], item );
476
477 DRC_RULE* parentRule = constraint.GetParentRule();
478 wxString ruleName = parentRule ? parentRule->m_Name : constraint.GetName();
479
480 switch( constraintsToCheck[i] )
481 {
483 key.gapConstraint = constraint.GetValue();
484 key.gapRule = parentRule;
485 key.gapRuleName = ruleName;
486 break;
487
489 key.uncoupledConstraint = constraint.GetValue();
490 key.uncoupledRule = parentRule;
491 key.uncoupledRuleName = ruleName;
492 break;
493
494 default:
495 break;
496 }
497
498 if( refNet->GetNetCode() == key.netN )
499 dpRuleMatches[key].itemsN.insert( citem );
500 else
501 dpRuleMatches[key].itemsP.insert( citem );
502 }
503 }
504
505 return true;
506 };
507
508 m_board->GetConnectivity()->GetFromToCache()->Rebuild( m_board );
509
511 evaluateDpConstraints );
512
513 drc_dbg( 10, wxT( "dp rule matches %d\n" ), (int) dpRuleMatches.size() );
514
515 reportAux( wxT( "DPs evaluated:" ) );
516
517 for( auto& [ key, itemSet ] : dpRuleMatches )
518 {
519 NETINFO_ITEM *niP = m_board->GetNetInfo().GetNetItem( key.netP );
520 NETINFO_ITEM *niN = m_board->GetNetInfo().GetNetItem( key.netN );
521
522 assert( niP );
523 assert( niN );
524
525 wxString nameP = niP->GetNetname();
526 wxString nameN = niN->GetNetname();
527
528 reportAux( wxString::Format( wxT( "Rule '%s', DP: (+) %s - (-) %s" ),
529 key.gapRuleName, nameP, nameN ) );
530
532
533 itemSet.totalCoupled = 0;
534 itemSet.totalLengthN = 0;
535 itemSet.totalLengthP = 0;
536
537 drc_dbg(10, wxT( " coupled prims : %d\n" ), (int) itemSet.coupled.size() );
538
539 for( BOARD_CONNECTED_ITEM* item : itemSet.itemsN )
540 {
541 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
542 itemSet.totalLengthN += track->GetLength();
543 }
544
545 for( BOARD_CONNECTED_ITEM* item : itemSet.itemsP )
546 {
547 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
548 itemSet.totalLengthP += track->GetLength();
549 }
550
551 for( DIFF_PAIR_COUPLED_SEGMENTS& dp : itemSet.coupled )
552 {
553 int length = dp.coupledN.Length();
554
555 wxCHECK2( dp.parentN && dp.parentP, continue );
556
557 std::shared_ptr<KIGFX::VIEW_OVERLAY> overlay = m_drcEngine->GetDebugOverlay();
558
559 if( overlay )
560 {
561 overlay->SetIsFill(false);
562 overlay->SetIsStroke(true);
563 overlay->SetStrokeColor( RED );
564 overlay->SetLineWidth( 100000 );
565 overlay->Line( dp.coupledP );
566 overlay->SetStrokeColor( BLUE );
567 overlay->Line( dp.coupledN );
568 }
569
570 drc_dbg( 10, wxT( " len %d gap %d l %d\n" ),
571 length,
572 dp.computedGap,
573 dp.parentP->GetLayer() );
574
575 if( key.gapConstraint )
576 {
577 if( key.gapConstraint->HasMin()
578 && key.gapConstraint->Min() >= 0
579 && ( dp.computedGap < key.gapConstraint->Min() - epsilon ) )
580 {
581 dp.couplingFailMin = true;
582 }
583
584 if( key.gapConstraint->HasMax()
585 && key.gapConstraint->Max() >= 0
586 && ( dp.computedGap > key.gapConstraint->Max() + epsilon ) )
587 {
588 dp.couplingFailMax = true;
589 }
590 }
591
592 if( !dp.couplingFailMin && !dp.couplingFailMax )
593 itemSet.totalCoupled += length;
594 }
595
596 int totalLen = std::max( itemSet.totalLengthN, itemSet.totalLengthP );
597 reportAux( wxString::Format( wxT( " - coupled length: %s, total length: %s" ),
598 MessageTextFromValue( itemSet.totalCoupled ),
599 MessageTextFromValue( totalLen ) ) );
600
601 int totalUncoupled = totalLen - itemSet.totalCoupled;
602
603 bool uncoupledViolation = false;
604
605 if( key.uncoupledConstraint && ( !itemSet.itemsP.empty() || !itemSet.itemsN.empty() ) )
606 {
607 const MINOPTMAX<int>& val = *key.uncoupledConstraint;
608
609 if( val.HasMax() && val.Max() >= 0 && totalUncoupled > val.Max() )
610 {
612 wxString msg = formatMsg( _( "(%s maximum uncoupled length %s; actual %s)" ),
613 key.uncoupledRuleName,
614 val.Max(),
615 totalUncoupled );
616
617 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
618
619 BOARD_CONNECTED_ITEM* item = nullptr;
620 auto p_it = itemSet.itemsP.begin();
621 auto n_it = itemSet.itemsN.begin();
622
623 if( p_it != itemSet.itemsP.end() )
624 {
625 item = *p_it;
626 drce->AddItem( *p_it );
627 p_it++;
628 }
629
630 if( n_it != itemSet.itemsN.end() )
631 {
632 item = *n_it;
633 drce->AddItem( *n_it );
634 n_it++;
635 }
636
637 while( p_it != itemSet.itemsP.end() )
638 drce->AddItem( *p_it++ );
639
640 while( n_it != itemSet.itemsN.end() )
641 drce->AddItem( *n_it++ );
642
643 uncoupledViolation = true;
644
645 drce->SetViolatingRule( key.uncoupledRule );
646
647 reportViolation( drce, item->GetPosition(), item->GetLayer() );
648 }
649 }
650
651 if( key.gapConstraint && ( uncoupledViolation || !key.uncoupledConstraint ) )
652 {
653 for( DIFF_PAIR_COUPLED_SEGMENTS& dp : itemSet.coupled )
654 {
655 wxCHECK2( dp.parentP && dp.parentN, continue );
656
657 if( ( dp.couplingFailMin || dp.couplingFailMax ) )
658 {
659 // We have a candidate violation, now we need to re-query for a constraint
660 // given the actual items, because there may be a location-based rule in play.
662 dp.parentP, dp.parentN,
663 dp.parentP->GetLayer() );
664 MINOPTMAX<int> val = constraint.GetValue();
665
666 if( !val.HasMin() || val.Min() < 0 || dp.computedGap >= val.Min() )
667 dp.couplingFailMin = false;
668
669 if( !val.HasMax() || val.Max() < 0 || dp.computedGap <= val.Max() )
670 dp.couplingFailMax = false;
671
672 if( !dp.couplingFailMin && !dp.couplingFailMax )
673 continue;
674
676 wxString msg;
677
678 if( dp.couplingFailMin )
679 {
680 msg = formatMsg( _( "(%s minimum gap %s; actual %s)" ),
681 key.gapRuleName,
682 val.Min(),
683 dp.computedGap );
684 }
685 else if( dp.couplingFailMax )
686 {
687 msg = formatMsg( _( "(%s maximum gap %s; actual %s)" ),
688 key.gapRuleName,
689 val.Max(),
690 dp.computedGap );
691 }
692
693 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
694
695 BOARD_CONNECTED_ITEM* item = nullptr;
696
697 if( dp.parentP )
698 {
699 item = dp.parentP;
700 drcItem->AddItem( dp.parentP );
701 }
702
703 if( dp.parentN )
704 {
705 item = dp.parentN;
706 drcItem->AddItem( dp.parentN );
707 }
708
709 drcItem->SetViolatingRule( key.gapRule );
710
711 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
712 }
713 }
714 }
715 }
716
718
719 return true;
720}
721
722
723namespace detail
724{
726}
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:237
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:290
const NETINFO_LIST & GetNetInfo() const
Definition: board.h:871
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:895
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:475
wxString GetName() const
Definition: drc_rule.h:160
SEVERITY GetSeverity() const
Definition: drc_rule.h:173
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:152
DRC_RULE * GetParentRule() const
Definition: drc_rule.h:156
bool IsNull() const
Definition: drc_rule.h:147
BOARD * GetBoard() const
Definition: drc_engine.h:99
std::shared_ptr< KIGFX::VIEW_OVERLAY > GetDebugOverlay() const
Definition: drc_engine.h:115
DRC_CONSTRAINT EvalRules(DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
Definition: drc_engine.cpp:679
static bool IsNetADiffPair(BOARD *aBoard, NETINFO_ITEM *aNet, int &aNetP, int &aNetN)
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition: drc_item.cpp:372
Implement an R-tree for fast spatial and layer indexing of connectable items.
Definition: drc_rtree.h:48
bool CheckColliding(SHAPE *aRefShape, PCB_LAYER_ID aTargetLayer, int aClearance=0, std::function< bool(BOARD_ITEM *)> aFilter=nullptr) const
Definition: drc_rtree.h:178
wxString m_Name
Definition: drc_rule.h:117
Represent a DRC "provider" which runs some DRC functions over a BOARD and spits out DRC_ITEM and posi...
wxString formatMsg(const wxString &aFormatString, const wxString &aSource, double aConstraint, double aActual)
int forEachGeometryItem(const std::vector< KICAD_T > &aTypes, LSET aLayers, const std::function< bool(BOARD_ITEM *)> &aFunc)
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer)
DRC_ENGINE * m_drcEngine
void reportAux(const wxString &aMsg)
virtual void reportRuleStatistics()
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:243
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:676
T Min() const
Definition: minoptmax.h:33
bool HasMax() const
Definition: minoptmax.h:38
bool HasMin() const
Definition: minoptmax.h:37
T Max() const
Definition: minoptmax.h:34
Handle the data for a net.
Definition: netinfo.h:56
const wxString & GetNetname() const
Definition: netinfo.h:114
int GetNetCode() const
Definition: netinfo.h:108
NETINFO_ITEM * GetNetItem(int aNetCode) const
bool IsCCW() const
Definition: pcb_track.cpp:802
virtual double GetLength() const override
Return the length of the arc track.
Definition: pcb_track.h:339
double GetRadius() const
Definition: pcb_track.cpp:1855
const VECTOR2I & GetMid() const
Definition: pcb_track.h:305
virtual VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_track.h:312
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pcb_track.cpp:1046
const VECTOR2I & GetStart() const
Definition: pcb_track.h:122
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:119
virtual int GetWidth() const
Definition: pcb_track.h:116
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I B
Definition: seg.h:50
int Length() const
Return the length (this).
Definition: seg.h:333
bool ApproxParallel(const SEG &aSeg, int aDistanceThreshold=1) const
Definition: seg.cpp:489
ecoord TCoef(const VECTOR2I &aP) const
Definition: seg.h:395
ecoord SquaredLength() const
Definition: seg.h:338
VECTOR2I LineProject(const VECTOR2I &aP) const
Compute the perpendicular projection point of aP on a line passing through ends of the segment.
Definition: seg.cpp:371
EDA_ANGLE GetEndAngle() const
Definition: shape_arc.cpp:515
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter) override
Rotate the arc by a given angle about a point.
Definition: shape_arc.cpp:635
double GetRadius() const
Definition: shape_arc.cpp:554
EDA_ANGLE GetStartAngle() const
Definition: shape_arc.cpp:507
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
@ BLUE
Definition: color4d.h:56
@ RED
Definition: color4d.h:59
#define drc_dbg(level, fmt,...)
Definition: drc_engine.h:61
@ DRCE_DIFF_PAIR_GAP_OUT_OF_RANGE
Definition: drc_item.h:106
@ DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG
Definition: drc_item.h:107
DRC_CONSTRAINT_T
Definition: drc_rule.h:47
@ DIFF_PAIR_GAP_CONSTRAINT
Definition: drc_rule.h:70
@ MAX_UNCOUPLED_CONSTRAINT
Definition: drc_rule.h:71
static bool commonParallelProjection(SEG p, SEG n, SEG &pClip, SEG &nClip)
static void extractDiffPairCoupledItems(DIFF_PAIR_ITEMS &aDp)
#define _(s)
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:390
std::shared_ptr< PNS_LOG_VIEWER_OVERLAY > overlay
Definition: playground.cpp:46
@ RPT_SEVERITY_IGNORE
const double epsilon
std::vector< FAB_LAYER_COLOR > dummy
std::set< BOARD_CONNECTED_ITEM * > itemsN
std::vector< DIFF_PAIR_COUPLED_SEGMENTS > coupled
std::set< BOARD_CONNECTED_ITEM * > itemsP
std::optional< MINOPTMAX< int > > uncoupledConstraint
std::optional< MINOPTMAX< int > > gapConstraint
bool operator<(const DIFF_PAIR_KEY &b) const
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:229
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
T rescale(T aNumerator, T aValue, T aDenominator)
Scale a number (value) by rational (numerator/denominator).
Definition: util.h:153
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:691