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 <board.h>
23#include <pcb_track.h>
24
25#include <drc/drc_engine.h>
26#include <drc/drc_item.h>
27#include <drc/drc_rule.h>
29#include <drc/drc_rtree.h>
30
32
35
36#include <view/view_overlay.h>
37
38/*
39 Differential pair gap/coupling test.
40 Errors generated:
41 - DRCE_DIFF_PAIR_GAP_OUT_OF_RANGE
42 - DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG
43 - DRCE_TOO_MANY_VIAS
44 Todo:
45 - arc support.
46 - improve recognition of coupled segments (now anything that's parallel is considered
47 coupled, causing DRC errors on meanders)
48*/
49
50namespace test {
51
53{
54public:
56 m_board( nullptr )
57 {
58 }
59
61 {
62 }
63
64 virtual bool Run() override;
65
66 virtual const wxString GetName() const override
67 {
68 return wxT( "diff_pair_coupling" );
69 };
70
71 virtual const wxString GetDescription() const override
72 {
73 return wxT( "Tests differential pair coupling" );
74 }
75
76private:
78};
79
80};
81
82
83static bool commonParallelProjection( SEG p, SEG n, SEG &pClip, SEG& nClip )
84{
85 SEG n_proj_p( p.LineProject( n.A ), p.LineProject( n.B ) );
86
87 int64_t t_a = 0;
88 int64_t t_b = p.TCoef( p.B );
89
90 int64_t tproj_a = p.TCoef( n_proj_p.A );
91 int64_t tproj_b = p.TCoef( n_proj_p.B );
92
93 if( t_b < t_a )
94 std::swap( t_b, t_a );
95
96 if( tproj_b < tproj_a )
97 std::swap( tproj_b, tproj_a );
98
99 if( t_b <= tproj_a )
100 return false;
101
102 if( t_a >= tproj_b )
103 return false;
104
105 int64_t t[4] = { 0, p.TCoef( p.B ), p.TCoef( n_proj_p.A ), p.TCoef( n_proj_p.B ) };
106 std::vector<int64_t> tv( t, t + 4 );
107 std::sort( tv.begin(), tv.end() ); // fixme: awful and disgusting way of finding 2 midpoints
108
109 int64_t pLenSq = p.SquaredLength();
110
111 VECTOR2I dp = p.B - p.A;
112 pClip.A.x = p.A.x + rescale( (int64_t)dp.x, tv[1], pLenSq );
113 pClip.A.y = p.A.y + rescale( (int64_t)dp.y, tv[1], pLenSq );
114
115 pClip.B.x = p.A.x + rescale( (int64_t)dp.x, tv[2], pLenSq );
116 pClip.B.y = p.A.y + rescale( (int64_t)dp.y, tv[2], pLenSq );
117
118 nClip.A = n.LineProject( pClip.A );
119 nClip.B = n.LineProject( pClip.B );
120
121 return true;
122}
123
124
125static bool commonParallelProjection( const PCB_ARC& p, const PCB_ARC& n, SHAPE_ARC &pClip, SHAPE_ARC& nClip )
126{
127 VECTOR2I p_center = p.GetCenter();
128 VECTOR2I n_center = n.GetCenter();
129 double p_radius = p.GetRadius();
130 double n_radius = n.GetRadius();
131
132 VECTOR2I p_start( p.GetStart() );
133 VECTOR2I p_end( p.GetEnd() );
134
135 if( !p.IsCCW() )
136 std::swap( p_start, p_end );
137
138 VECTOR2I n_start( n.GetStart() );
139 VECTOR2I n_end( n.GetEnd() );
140
141 if( !n.IsCCW() )
142 std::swap( n_start, n_end );
143
144 SHAPE_ARC p_arc( p_start, p.GetMid(), p_end, 0 );
145 SHAPE_ARC n_arc( n_start, n.GetMid(), n_end, 0 );
146
147 EDA_ANGLE p_start_angle = p_arc.GetStartAngle();
148
149 // Rotate the arcs to a common 0 starting angle
150 p_arc.Rotate( -p_start_angle, p_center );
151 n_arc.Rotate( -p_start_angle, n_center );
152
153 EDA_ANGLE p_end_angle = p_arc.GetEndAngle();
154 EDA_ANGLE n_start_angle = n_arc.GetStartAngle();
155 EDA_ANGLE n_end_angle = n_arc.GetEndAngle();
156
157
158 EDA_ANGLE clip_total_angle;
159 EDA_ANGLE clip_start_angle;
160
161 if( n_start_angle > p_end_angle )
162 {
163 // n is fully outside of p
164 if( n_end_angle > p_end_angle )
165 return false;
166
167 // n starts before angle 0 and ends in the middle of p
168 clip_total_angle = n_end_angle + p_start_angle;
169 clip_start_angle = p_start_angle;
170 }
171 else
172 {
173 clip_start_angle = n_start_angle + p_start_angle;
174
175 // n is fully inside of p
176 if( n_end_angle < p_end_angle )
177 clip_total_angle = n_end_angle - n_start_angle;
178 else // n starts after 0 and ends after p
179 clip_total_angle = p_end_angle - n_start_angle;
180 }
181
182 // One arc starts exactly where the other ends
183 if( clip_total_angle == ANGLE_0 )
184 return false;
185
186 VECTOR2I n_start_pt = n_center + VECTOR2I( KiROUND( n_radius ), 0 );
187 VECTOR2I p_start_pt = p_center + VECTOR2I( KiROUND( p_radius ), 0 );
188
189 RotatePoint( n_start_pt, n_center, clip_start_angle );
190 RotatePoint( p_start_pt, p_center, clip_start_angle );
191
192 pClip = SHAPE_ARC( p_center, p_start_pt, clip_total_angle );
193 nClip = SHAPE_ARC( n_center, n_start_pt, clip_total_angle );
194
195 return true;
196}
197
198
200{
201 bool operator<( const DIFF_PAIR_KEY& b ) const
202 {
203 if( netP < b.netP )
204 {
205 return true;
206 }
207 else if( netP > b.netP )
208 {
209 return false;
210 }
211 else // netP == b.netP
212 {
213 if( netN < b.netN )
214 return true;
215 else if( netN > b.netN )
216 return false;
217 else if( gapRuleName.IsEmpty() )
218 return gapRuleName < b.gapRuleName;
219 else
221 }
222 }
223
224 int netP, netN;
225 wxString gapRuleName;
227 std::optional<MINOPTMAX<int>> gapConstraint;
229 std::optional<MINOPTMAX<int>> uncoupledConstraint;
231};
232
234{
237 bool isArc;
246
248 isArc( false ),
249 parentN( nullptr ),
250 parentP( nullptr ),
251 computedGap( 0 ),
253 couplingFailMin( false ),
254 couplingFailMax( false )
255 {}
256};
257
258
260{
261 std::set<BOARD_CONNECTED_ITEM*> itemsP, itemsN;
262 std::vector<DIFF_PAIR_COUPLED_SEGMENTS> coupled;
266};
267
268
270{
271 for( BOARD_CONNECTED_ITEM* itemP : aDp.itemsP )
272 {
273 PCB_TRACK* sp = dyn_cast<PCB_TRACK*>( itemP );
274 std::optional<DIFF_PAIR_COUPLED_SEGMENTS> bestCoupled;
275 int bestGap = std::numeric_limits<int>::max();
276
277 if( !sp )
278 continue;
279
280 for ( BOARD_CONNECTED_ITEM* itemN : aDp.itemsN )
281 {
282 PCB_TRACK* sn = dyn_cast<PCB_TRACK*> ( itemN );
283
284 if( !sn )
285 continue;
286
287 if( ( sn->GetLayerSet() & sp->GetLayerSet() ).none() )
288 continue;
289
290 SEG ssp ( sp->GetStart(), sp->GetEnd() );
291 SEG ssn ( sn->GetStart(), sn->GetEnd() );
292
293 // Segments that are ~ 1 IU in length per side are approximately parallel (tolerance is 1 IU)
294 // with everything and their parallel projection is < 1 IU, leading to bad distance calculations
295 if( ssp.SquaredLength() > 2 && ssn.SquaredLength() > 2 && ssp.ApproxParallel(ssn) )
296 {
298 bool coupled = commonParallelProjection( ssp, ssn, cpair.coupledP, cpair.coupledN );
299
300 if( coupled )
301 {
302 cpair.parentP = sp;
303 cpair.parentN = sn;
304 cpair.layer = sp->GetLayer();
305 cpair.computedGap = (cpair.coupledP.A - cpair.coupledN.A).EuclideanNorm();
306 cpair.computedGap -= ( sp->GetWidth() + sn->GetWidth() ) / 2;
307
308 if( cpair.computedGap < bestGap )
309 {
310 bestGap = cpair.computedGap;
311 bestCoupled = cpair;
312 }
313 }
314
315 }
316 }
317
318 if( bestCoupled )
319 {
320 auto excludeSelf = [&]( BOARD_ITEM* aItem )
321 {
322 if( aItem == bestCoupled->parentN || aItem == bestCoupled->parentP )
323 return false;
324
325 if( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_VIA_T
326 || aItem->Type() == PCB_ARC_T )
327 {
328 BOARD_CONNECTED_ITEM* bci = static_cast<BOARD_CONNECTED_ITEM*>( aItem );
329
330 if( bci->GetNetCode() == bestCoupled->parentN->GetNetCode()
331 || bci->GetNetCode() == bestCoupled->parentP->GetNetCode() )
332 {
333 return false;
334 }
335 }
336
337 return true;
338 };
339
340 SHAPE_SEGMENT checkSegStart( bestCoupled->coupledP.A, bestCoupled->coupledN.A );
341 SHAPE_SEGMENT checkSegEnd( bestCoupled->coupledP.B, bestCoupled->coupledN.B );
342 DRC_RTREE* tree = bestCoupled->parentP->GetBoard()->m_CopperItemRTreeCache.get();
343
344 // check if there's anything in between the segments suspected to be coupled. If
345 // there's nothing, assume they are really coupled.
346
347 if( !tree->CheckColliding( &checkSegStart, sp->GetLayer(), 0, excludeSelf )
348 && !tree->CheckColliding( &checkSegEnd, sp->GetLayer(), 0, excludeSelf ) )
349 {
350 aDp.coupled.push_back( *bestCoupled );
351 }
352 }
353 }
354
355 for( BOARD_CONNECTED_ITEM* itemP : aDp.itemsP )
356 {
357 PCB_ARC* sp = dyn_cast<PCB_ARC*>( itemP );
358 std::optional<DIFF_PAIR_COUPLED_SEGMENTS> bestCoupled;
359 int bestGap = std::numeric_limits<int>::max();
360
361 if( !sp )
362 continue;
363
364 for ( BOARD_CONNECTED_ITEM* itemN : aDp.itemsN )
365 {
366 PCB_ARC* sn = dyn_cast<PCB_ARC*> ( itemN );
367
368 if( !sn )
369 continue;
370
371 if( ( sn->GetLayerSet() & sp->GetLayerSet() ).none() )
372 continue;
373
374 // Segments that are ~ 1 IU in length per side are approximately parallel (tolerance is 1 IU)
375 // with everything and their parallel projection is < 1 IU, leading to bad distance calculations
376 if( sp->GetLength() > 2 && sn->GetLength() > 2 && ( sp->GetCenter() - sn->GetCenter() ).SquaredEuclideanNorm() < 4 )
377 {
379 cpair.isArc = true;
380 bool coupled = commonParallelProjection( *sp, *sn, cpair.coupledArcP, cpair.coupledArcN );
381
382 if( coupled )
383 {
384 cpair.parentP = sp;
385 cpair.parentN = sn;
386 cpair.layer = sp->GetLayer();
388 - cpair.coupledArcN.GetRadius() ) );
389 cpair.computedGap -= ( sp->GetWidth() + sn->GetWidth() ) / 2;
390
391 if( cpair.computedGap < bestGap )
392 {
393 bestGap = cpair.computedGap;
394 bestCoupled = cpair;
395 }
396 }
397
398 }
399 }
400
401 if( bestCoupled )
402 {
403 auto excludeSelf =
404 [&] ( BOARD_ITEM *aItem )
405 {
406 if( aItem == bestCoupled->parentN || aItem == bestCoupled->parentP )
407 return false;
408
409 if( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_VIA_T || aItem->Type() == PCB_ARC_T )
410 {
411 BOARD_CONNECTED_ITEM* bci = static_cast<BOARD_CONNECTED_ITEM*>( aItem );
412
413 if( bci->GetNetCode() == bestCoupled->parentN->GetNetCode()
414 || bci->GetNetCode() == bestCoupled->parentP->GetNetCode() )
415 {
416 return false;
417 }
418 }
419
420 return true;
421 };
422
423 SHAPE_SEGMENT checkSegStart( bestCoupled->coupledP.A, bestCoupled->coupledN.A );
424 SHAPE_SEGMENT checkSegEnd( bestCoupled->coupledP.B, bestCoupled->coupledN.B );
425 DRC_RTREE* tree = bestCoupled->parentP->GetBoard()->m_CopperItemRTreeCache.get();
426
427 // check if there's anything in between the segments suspected to be coupled. If
428 // there's nothing, assume they are really coupled.
429
430 if( !tree->CheckColliding( &checkSegStart, sp->GetLayer(), 0, excludeSelf )
431 && !tree->CheckColliding( &checkSegEnd, sp->GetLayer(), 0, excludeSelf ) )
432 {
433 aDp.coupled.push_back( *bestCoupled );
434 }
435 }
436 }
437}
438
439
440
442{
444
446
447 std::map<DIFF_PAIR_KEY, DIFF_PAIR_ITEMS> dpRuleMatches;
448
449 auto evaluateDpConstraints =
450 [&]( BOARD_ITEM *item ) -> bool
451 {
452 DIFF_PAIR_KEY key;
453 BOARD_CONNECTED_ITEM* citem = static_cast<BOARD_CONNECTED_ITEM*>( item );
454 NETINFO_ITEM* refNet = citem->GetNet();
455
456 if( refNet && DRC_ENGINE::IsNetADiffPair( m_board, refNet, key.netP, key.netN ) )
457 {
458 drc_dbg( 10, wxT( "eval dp %p\n" ), item );
459
460 const DRC_CONSTRAINT_T constraintsToCheck[] = {
463 };
464
465 for( int i = 0; i < 2; i++ )
466 {
467 DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( constraintsToCheck[ i ],
468 item, nullptr,
469 item->GetLayer() );
470
471 if( constraint.IsNull() || constraint.GetSeverity() == RPT_SEVERITY_IGNORE )
472 continue;
473
474 drc_dbg( 10, wxT( "cns %d item %p\n" ), constraintsToCheck[i], item );
475
476 DRC_RULE* parentRule = constraint.GetParentRule();
477 wxString ruleName = parentRule ? parentRule->m_Name : constraint.GetName();
478
479 switch( constraintsToCheck[i] )
480 {
482 key.gapConstraint = constraint.GetValue();
483 key.gapRule = parentRule;
484 key.gapRuleName = ruleName;
485 break;
486
488 key.uncoupledConstraint = constraint.GetValue();
489 key.uncoupledRule = parentRule;
490 key.uncoupledRuleName = ruleName;
491 break;
492
493 default:
494 break;
495 }
496
497 if( refNet->GetNetCode() == key.netN )
498 dpRuleMatches[key].itemsN.insert( citem );
499 else
500 dpRuleMatches[key].itemsP.insert( citem );
501 }
502 }
503
504 return true;
505 };
506
507 m_board->GetConnectivity()->GetFromToCache()->Rebuild( m_board );
508
510 evaluateDpConstraints );
511
512 drc_dbg( 10, wxT( "dp rule matches %d\n" ), (int) dpRuleMatches.size() );
513
514 reportAux( wxT( "DPs evaluated:" ) );
515
516 for( auto& [ key, itemSet ] : dpRuleMatches )
517 {
518 NETINFO_ITEM *niP = m_board->GetNetInfo().GetNetItem( key.netP );
519 NETINFO_ITEM *niN = m_board->GetNetInfo().GetNetItem( key.netN );
520
521 assert( niP );
522 assert( niN );
523
524 wxString nameP = niP->GetNetname();
525 wxString nameN = niN->GetNetname();
526
527 reportAux( wxString::Format( wxT( "Rule '%s', DP: (+) %s - (-) %s" ),
528 key.gapRuleName, nameP, nameN ) );
529
531
532 itemSet.totalCoupled = 0;
533 itemSet.totalLengthN = 0;
534 itemSet.totalLengthP = 0;
535
536 drc_dbg(10, wxT( " coupled prims : %d\n" ), (int) itemSet.coupled.size() );
537
538 for( BOARD_CONNECTED_ITEM* item : itemSet.itemsN )
539 {
540 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
541 itemSet.totalLengthN += track->GetLength();
542 }
543
544 for( BOARD_CONNECTED_ITEM* item : itemSet.itemsP )
545 {
546 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
547 itemSet.totalLengthP += track->GetLength();
548 }
549
550 for( DIFF_PAIR_COUPLED_SEGMENTS& dp : itemSet.coupled )
551 {
552 int length = dp.coupledN.Length();
553
554 wxCHECK2( dp.parentN && dp.parentP, continue );
555
556 std::shared_ptr<KIGFX::VIEW_OVERLAY> overlay = m_drcEngine->GetDebugOverlay();
557
558 if( overlay )
559 {
560 overlay->SetIsFill(false);
561 overlay->SetIsStroke(true);
562 overlay->SetStrokeColor( RED );
563 overlay->SetLineWidth( 100000 );
564 overlay->Line( dp.coupledP );
565 overlay->SetStrokeColor( BLUE );
566 overlay->Line( dp.coupledN );
567 }
568
569 drc_dbg( 10, wxT( " len %d gap %d l %d\n" ),
570 length,
571 dp.computedGap,
572 dp.parentP->GetLayer() );
573
574 if( key.gapConstraint )
575 {
576 if( key.gapConstraint->HasMin()
577 && key.gapConstraint->Min() >= 0
578 && ( dp.computedGap < key.gapConstraint->Min() - epsilon ) )
579 {
580 dp.couplingFailMin = true;
581 }
582
583 if( key.gapConstraint->HasMax()
584 && key.gapConstraint->Max() >= 0
585 && ( dp.computedGap > key.gapConstraint->Max() + epsilon ) )
586 {
587 dp.couplingFailMax = true;
588 }
589 }
590
591 if( !dp.couplingFailMin && !dp.couplingFailMax )
592 itemSet.totalCoupled += length;
593 }
594
595 int totalLen = std::max( itemSet.totalLengthN, itemSet.totalLengthP );
596 reportAux( wxString::Format( wxT( " - coupled length: %s, total length: %s" ),
597 MessageTextFromValue( itemSet.totalCoupled ),
598 MessageTextFromValue( totalLen ) ) );
599
600 int totalUncoupled = totalLen - itemSet.totalCoupled;
601
602 bool uncoupledViolation = false;
603
604 if( key.uncoupledConstraint && ( !itemSet.itemsP.empty() || !itemSet.itemsN.empty() ) )
605 {
606 const MINOPTMAX<int>& val = *key.uncoupledConstraint;
607
608 if( val.HasMax() && val.Max() >= 0 && totalUncoupled > val.Max() )
609 {
611 wxString msg = formatMsg( _( "(%s maximum uncoupled length %s; actual %s)" ),
612 key.uncoupledRuleName,
613 val.Max(),
614 totalUncoupled );
615
616 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
617
618 BOARD_CONNECTED_ITEM* item = nullptr;
619 auto p_it = itemSet.itemsP.begin();
620 auto n_it = itemSet.itemsN.begin();
621
622 if( p_it != itemSet.itemsP.end() )
623 {
624 item = *p_it;
625 drce->AddItem( *p_it );
626 p_it++;
627 }
628
629 if( n_it != itemSet.itemsN.end() )
630 {
631 item = *n_it;
632 drce->AddItem( *n_it );
633 n_it++;
634 }
635
636 while( p_it != itemSet.itemsP.end() )
637 drce->AddItem( *p_it++ );
638
639 while( n_it != itemSet.itemsN.end() )
640 drce->AddItem( *n_it++ );
641
642 uncoupledViolation = true;
643
644 drce->SetViolatingRule( key.uncoupledRule );
645
646 reportViolation( drce, item->GetPosition(), item->GetLayer() );
647 }
648 }
649
650 if( key.gapConstraint && ( uncoupledViolation || !key.uncoupledConstraint ) )
651 {
652 for( DIFF_PAIR_COUPLED_SEGMENTS& dp : itemSet.coupled )
653 {
654 wxCHECK2( dp.parentP && dp.parentN, continue );
655
656 if( ( dp.couplingFailMin || dp.couplingFailMax ) )
657 {
658 // We have a candidate violation, now we need to re-query for a constraint
659 // given the actual items, because there may be a location-based rule in play.
661 dp.parentP, dp.parentN,
662 dp.parentP->GetLayer() );
663 MINOPTMAX<int> val = constraint.GetValue();
664
665 if( !val.HasMin() || val.Min() < 0 || dp.computedGap >= val.Min() )
666 dp.couplingFailMin = false;
667
668 if( !val.HasMax() || val.Max() < 0 || dp.computedGap <= val.Max() )
669 dp.couplingFailMax = false;
670
671 if( !dp.couplingFailMin && !dp.couplingFailMax )
672 continue;
673
675 wxString msg;
676
677 if( dp.couplingFailMin )
678 {
679 msg = formatMsg( _( "(%s minimum gap %s; actual %s)" ),
680 key.gapRuleName,
681 val.Min(),
682 dp.computedGap );
683 }
684 else if( dp.couplingFailMax )
685 {
686 msg = formatMsg( _( "(%s maximum gap %s; actual %s)" ),
687 key.gapRuleName,
688 val.Max(),
689 dp.computedGap );
690 }
691
692 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
693
694 BOARD_CONNECTED_ITEM* item = nullptr;
695
696 if( dp.parentP )
697 {
698 item = dp.parentP;
699 drcItem->AddItem( dp.parentP );
700 }
701
702 if( dp.parentN )
703 {
704 item = dp.parentN;
705 drcItem->AddItem( dp.parentN );
706 }
707
708 drcItem->SetViolatingRule( key.gapRule );
709
710 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
711 }
712 }
713 }
714 }
715
717
718 return true;
719}
720
721
722namespace detail
723{
725}
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:77
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:231
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:236
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:282
const NETINFO_LIST & GetNetInfo() const
Definition: board.h:853
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:794
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:460
wxString GetName() const
Definition: drc_rule.h:149
SEVERITY GetSeverity() const
Definition: drc_rule.h:162
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:141
DRC_RULE * GetParentRule() const
Definition: drc_rule.h:145
bool IsNull() const
Definition: drc_rule.h:136
BOARD * GetBoard() const
Definition: drc_engine.h:89
std::shared_ptr< KIGFX::VIEW_OVERLAY > GetDebugOverlay() const
Definition: drc_engine.h:105
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:652
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:338
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:176
wxString m_Name
Definition: drc_rule.h:112
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:242
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:863
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:714
virtual double GetLength() const override
Return the length of the arc track.
Definition: pcb_track.h:327
double GetRadius() const
Definition: pcb_track.cpp:1505
const VECTOR2I & GetMid() const
Definition: pcb_track.h:293
virtual VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_track.h:300
int GetWidth() const
Definition: pcb_track.h:108
const VECTOR2I & GetStart() const
Definition: pcb_track.h:114
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:111
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:326
bool ApproxParallel(const SEG &aSeg, int aDistanceThreshold=1) const
Definition: seg.cpp:402
ecoord TCoef(const VECTOR2I &aP) const
Definition: seg.h:388
ecoord SquaredLength() const
Definition: seg.h:331
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:312
EDA_ANGLE GetEndAngle() const
Definition: shape_arc.cpp:497
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter) override
Rotate the arc by a given angle about a point.
Definition: shape_arc.cpp:617
double GetRadius() const
Definition: shape_arc.cpp:536
EDA_ANGLE GetStartAngle() const
Definition: shape_arc.cpp:489
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:58
@ DRCE_DIFF_PAIR_GAP_OUT_OF_RANGE
Definition: drc_item.h:100
@ DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG
Definition: drc_item.h:101
DRC_CONSTRAINT_T
Definition: drc_rule.h:45
@ DIFF_PAIR_GAP_CONSTRAINT
Definition: drc_rule.h:66
@ MAX_UNCOUPLED_CONSTRAINT
Definition: drc_rule.h:67
static bool commonParallelProjection(SEG p, SEG n, SEG &pClip, SEG &nClip)
static void extractDiffPairCoupledItems(DIFF_PAIR_ITEMS &aDp)
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:401
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:228
@ 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
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:118
T rescale(T aNumerator, T aValue, T aDenominator)
Scale a number (value) by rational (numerator/denominator).
Definition: util.h:162
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:638