KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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 The 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 if( std::abs( pClip.GetP0().x - pClip.GetArcMid().x ) < 10
197 || std::abs( nClip.GetP0().x - nClip.GetArcMid().x ) < 10 )
198 return false;
199
200 return true;
201}
202
203
205{
206 bool operator<( const DIFF_PAIR_KEY& b ) const
207 {
208 if( netP < b.netP )
209 {
210 return true;
211 }
212 else if( netP > b.netP )
213 {
214 return false;
215 }
216 else // netP == b.netP
217 {
218 if( netN < b.netN )
219 return true;
220 else if( netN > b.netN )
221 return false;
222 else if( gapRuleName.IsEmpty() )
223 return gapRuleName < b.gapRuleName;
224 else
226 }
227 }
228
229 int netP, netN;
230 wxString gapRuleName;
232 std::optional<MINOPTMAX<int>> gapConstraint;
234 std::optional<MINOPTMAX<int>> uncoupledConstraint;
236};
237
239{
242 bool isArc;
247 int64_t computedGap;
253
255 isArc( false ),
256 parentN( nullptr ),
257 parentP( nullptr ),
258 computedGap( 0 ),
260 couplingFailMin( false ),
261 couplingFailMax( false )
262 {}
263};
264
265
267{
268 std::set<BOARD_CONNECTED_ITEM*> itemsP, itemsN;
269 std::vector<DIFF_PAIR_COUPLED_SEGMENTS> coupled;
273};
274
275
277{
278 for( BOARD_CONNECTED_ITEM* itemP : aDp.itemsP )
279 {
280 PCB_TRACK* sp = dyn_cast<PCB_TRACK*>( itemP );
281 std::vector<std::optional<DIFF_PAIR_COUPLED_SEGMENTS>> coupled_vec;
282
283 if( !sp )
284 continue;
285
286 for ( BOARD_CONNECTED_ITEM* itemN : aDp.itemsN )
287 {
288 PCB_TRACK* sn = dyn_cast<PCB_TRACK*> ( itemN );
289
290 if( !sn )
291 continue;
292
293 if( ( sn->GetLayerSet() & sp->GetLayerSet() ).none() )
294 continue;
295
296 SEG ssp ( sp->GetStart(), sp->GetEnd() );
297 SEG ssn ( sn->GetStart(), sn->GetEnd() );
298
299 // Segments that are ~ 1 IU in length per side are approximately parallel (tolerance is 1 IU)
300 // with everything and their parallel projection is < 1 IU, leading to bad distance calculations
301 if( ssp.SquaredLength() > 2 && ssn.SquaredLength() > 2 && !ssp.Intersect( ssn, false, true ) )
302 {
304 bool coupled = commonParallelProjection( ssp, ssn, cpair.coupledP, cpair.coupledN );
305
306 if( coupled )
307 {
308 cpair.parentP = sp;
309 cpair.parentN = sn;
310 cpair.layer = sp->GetLayer();
311 cpair.coupledP.NearestPoints( cpair.coupledN, cpair.nearestP, cpair.nearestN,
312 cpair.computedGap );
313 cpair.computedGap = std::sqrt( cpair.computedGap ); // NearestPoints returns squared distance
314 cpair.computedGap -= ( sp->GetWidth() + sn->GetWidth() ) / 2;
315 coupled_vec.push_back( cpair );
316 }
317
318 }
319 }
320
321 for( auto coupled : coupled_vec )
322 {
323 auto excludeSelf = [&]( BOARD_ITEM* aItem )
324 {
325 if( aItem == coupled->parentN || aItem == coupled->parentP )
326 return false;
327
328 if( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_VIA_T
329 || aItem->Type() == PCB_ARC_T )
330 {
331 PCB_TRACK* bci = static_cast<PCB_TRACK*>( aItem );
332
333 // Directly connected items don't count
334 if( bci->HitTest( coupled->coupledN.A, 0 )
335 || bci->HitTest( coupled->coupledN.B, 0 )
336 || bci->HitTest( coupled->coupledP.A, 0 )
337 || bci->HitTest( coupled->coupledP.B, 0 ) )
338 {
339 return false;
340 }
341 }
342
343 return true;
344 };
345
346 SHAPE_SEGMENT checkSeg( coupled->nearestN, coupled->nearestP );
347 DRC_RTREE* tree = coupled->parentP->GetBoard()->m_CopperItemRTreeCache.get();
348
349 // check if there's anything in between the segments suspected to be coupled. If
350 // there's nothing, assume they are really coupled.
351
352 if( !tree->CheckColliding( &checkSeg, sp->GetLayer(), 0, excludeSelf ) )
353 aDp.coupled.push_back( *coupled );
354 }
355 }
356
357 for( BOARD_CONNECTED_ITEM* itemP : aDp.itemsP )
358 {
359 PCB_ARC* sp = dyn_cast<PCB_ARC*>( itemP );
360 std::vector<std::optional<DIFF_PAIR_COUPLED_SEGMENTS>> coupled_vec;
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 int64_t sqWidth = static_cast<int64_t>( sp->GetWidth() ) * sp->GetWidth();
378
379 if( sp->GetLength() > 2 && sn->GetLength() > 2 && sp->GetCenter().SquaredDistance( sn->GetCenter() ) < sqWidth )
380 {
382 cpair.isArc = true;
383 bool coupled = commonParallelProjection( *sp, *sn, cpair.coupledArcP, cpair.coupledArcN );
384
385 if( coupled )
386 {
387 cpair.parentP = sp;
388 cpair.parentN = sn;
389 cpair.layer = sp->GetLayer();
390 cpair.coupledArcP.NearestPoints( cpair.coupledArcN, cpair.nearestP, cpair.nearestN,
391 cpair.computedGap );
392 cpair.computedGap = std::sqrt( cpair.computedGap ); // NearestPoints returns squared distance
393 cpair.computedGap -= ( sp->GetWidth() + sn->GetWidth() ) / 2;
394 coupled_vec.push_back( cpair );
395 }
396 }
397 }
398
399 for( auto coupled : coupled_vec )
400 {
401 auto excludeSelf =
402 [&] ( BOARD_ITEM *aItem )
403 {
404 if( aItem == coupled->parentN || aItem == coupled->parentP )
405 return false;
406
407 if( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_VIA_T || aItem->Type() == PCB_ARC_T )
408 {
409 BOARD_CONNECTED_ITEM* bci = static_cast<BOARD_CONNECTED_ITEM*>( aItem );
410
411 if( bci->GetNetCode() == coupled->parentN->GetNetCode()
412 || bci->GetNetCode() == coupled->parentP->GetNetCode() )
413 {
414 return false;
415 }
416 }
417
418 return true;
419 };
420
421 SHAPE_SEGMENT checkArcMid( coupled->coupledArcN.GetArcMid(), coupled->coupledArcP.GetArcMid() );
422 DRC_RTREE* tree = coupled->parentP->GetBoard()->m_CopperItemRTreeCache.get();
423
424 // check if there's anything in between the segments suspected to be coupled. If
425 // there's nothing, assume they are really coupled.
426
427 if( !tree->CheckColliding( &checkArcMid, sp->GetLayer(), 0, excludeSelf ) )
428 aDp.coupled.push_back( *coupled );
429 }
430 }
431}
432
433
434
436{
438
440
441 std::map<DIFF_PAIR_KEY, DIFF_PAIR_ITEMS> dpRuleMatches;
442
443 auto evaluateDpConstraints =
444 [&]( BOARD_ITEM *item ) -> bool
445 {
446 DIFF_PAIR_KEY key;
447 BOARD_CONNECTED_ITEM* citem = static_cast<BOARD_CONNECTED_ITEM*>( item );
448 NETINFO_ITEM* refNet = citem->GetNet();
449
450 if( refNet && DRC_ENGINE::IsNetADiffPair( m_board, refNet, key.netP, key.netN ) )
451 {
452 drc_dbg( 10, wxT( "eval dp %p\n" ), item );
453
454 for( DRC_CONSTRAINT_T constraintType : { DIFF_PAIR_GAP_CONSTRAINT,
456 {
457 DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( constraintType,
458 item, nullptr,
459 item->GetLayer() );
460
461 if( constraint.IsNull() || constraint.GetSeverity() == RPT_SEVERITY_IGNORE )
462 continue;
463
464 drc_dbg( 10, wxT( "cns %d item %p\n" ), (int) constraintType, item );
465
466 DRC_RULE* parentRule = constraint.GetParentRule();
467 wxString ruleName = parentRule ? parentRule->m_Name : constraint.GetName();
468
469 switch( constraintType )
470 {
472 key.gapConstraint = constraint.GetValue();
473 key.gapRule = parentRule;
474 key.gapRuleName = ruleName;
475 break;
476
478 key.uncoupledConstraint = constraint.GetValue();
479 key.uncoupledRule = parentRule;
480 key.uncoupledRuleName = ruleName;
481 break;
482
483 default:
484 break;
485 }
486
487 if( refNet->GetNetCode() == key.netN )
488 dpRuleMatches[key].itemsN.insert( citem );
489 else
490 dpRuleMatches[key].itemsP.insert( citem );
491 }
492 }
493
494 return true;
495 };
496
497 m_board->GetConnectivity()->GetFromToCache()->Rebuild( m_board );
498
500 evaluateDpConstraints );
501
502 drc_dbg( 10, wxT( "dp rule matches %d\n" ), (int) dpRuleMatches.size() );
503
504 reportAux( wxT( "DPs evaluated:" ) );
505
506 for( auto& [ key, itemSet ] : dpRuleMatches )
507 {
508 NETINFO_ITEM *niP = m_board->GetNetInfo().GetNetItem( key.netP );
509 NETINFO_ITEM *niN = m_board->GetNetInfo().GetNetItem( key.netN );
510
511 assert( niP );
512 assert( niN );
513
514 wxString nameP = niP->GetNetname();
515 wxString nameN = niN->GetNetname();
516
517 reportAux( wxString::Format( wxT( "Rule '%s', DP: (+) %s - (-) %s" ),
518 key.gapRuleName, nameP, nameN ) );
519
521
522 itemSet.totalCoupled = 0;
523 itemSet.totalLengthN = 0;
524 itemSet.totalLengthP = 0;
525
526 drc_dbg(10, wxT( " coupled prims : %d\n" ), (int) itemSet.coupled.size() );
527
528 std::set<BOARD_CONNECTED_ITEM*> allItems;
529
530 for( BOARD_CONNECTED_ITEM* item : itemSet.itemsN )
531 {
532 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
533 {
534 if( allItems.insert( item ).second)
535 itemSet.totalLengthN += track->GetLength();
536 }
537 }
538
539 for( BOARD_CONNECTED_ITEM* item : itemSet.itemsP )
540 {
541 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
542 {
543 if( allItems.insert( item ).second)
544 itemSet.totalLengthP += track->GetLength();
545 }
546 }
547
548 for( DIFF_PAIR_COUPLED_SEGMENTS& dp : itemSet.coupled )
549 {
550 int length = dp.isArc ? dp.coupledArcN.GetLength() : dp.coupledN.Length();
551 wxCHECK2( dp.parentN && dp.parentP, continue );
552
553 std::shared_ptr<KIGFX::VIEW_OVERLAY> overlay = m_drcEngine->GetDebugOverlay();
554
555 if( overlay )
556 {
557 overlay->SetIsFill(false);
558 overlay->SetIsStroke(true);
559 overlay->SetStrokeColor( RED );
560 overlay->SetLineWidth( 100000 );
561 overlay->Line( dp.coupledP );
562 overlay->SetStrokeColor( BLUE );
563 overlay->Line( dp.coupledN );
564 }
565
566 drc_dbg( 10, wxT( " len %d gap %ld l %d\n" ),
567 length,
568 (long int) dp.computedGap,
569 (int) dp.parentP->GetLayer() );
570
571 if( key.gapConstraint )
572 {
573 if( key.gapConstraint->HasMin()
574 && key.gapConstraint->Min() >= 0
575 && ( dp.computedGap < key.gapConstraint->Min() - epsilon ) )
576 {
577 dp.couplingFailMin = true;
578 }
579
580 if( key.gapConstraint->HasMax()
581 && key.gapConstraint->Max() >= 0
582 && ( dp.computedGap > key.gapConstraint->Max() + epsilon ) )
583 {
584 dp.couplingFailMax = true;
585 }
586 }
587
588 if( !dp.couplingFailMin && !dp.couplingFailMax )
589 itemSet.totalCoupled += length;
590 }
591
592 int totalLen = std::max( itemSet.totalLengthN, itemSet.totalLengthP );
593 reportAux( wxString::Format( wxT( " - coupled length: %s, total length: %s" ),
594 MessageTextFromValue( itemSet.totalCoupled ),
595 MessageTextFromValue( totalLen ) ) );
596
597 int totalUncoupled = totalLen - itemSet.totalCoupled;
598 bool uncoupledViolation = false;
599
600 if( key.uncoupledConstraint && ( !itemSet.itemsP.empty() || !itemSet.itemsN.empty() ) )
601 {
602 const MINOPTMAX<int>& val = *key.uncoupledConstraint;
603
604 if( val.HasMax() && val.Max() >= 0 && totalUncoupled > val.Max() )
605 {
607 wxString msg = formatMsg( _( "(%s maximum uncoupled length %s; actual %s)" ),
608 key.uncoupledRuleName,
609 val.Max(),
610 totalUncoupled );
611
612 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
613
614 BOARD_CONNECTED_ITEM* item = nullptr;
615 auto p_it = itemSet.itemsP.begin();
616 auto n_it = itemSet.itemsN.begin();
617
618 if( p_it != itemSet.itemsP.end() )
619 {
620 item = *p_it;
621 drce->AddItem( *p_it );
622 p_it++;
623 }
624
625 if( n_it != itemSet.itemsN.end() )
626 {
627 item = *n_it;
628 drce->AddItem( *n_it );
629 n_it++;
630 }
631
632 while( p_it != itemSet.itemsP.end() )
633 drce->AddItem( *p_it++ );
634
635 while( n_it != itemSet.itemsN.end() )
636 drce->AddItem( *n_it++ );
637
638 uncoupledViolation = true;
639
640 drce->SetViolatingRule( key.uncoupledRule );
641
642 reportViolation( drce, item->GetPosition(), item->GetLayer() );
643 }
644 }
645
646 if( key.gapConstraint && ( uncoupledViolation || !key.uncoupledConstraint ) )
647 {
648 for( DIFF_PAIR_COUPLED_SEGMENTS& dp : itemSet.coupled )
649 {
650 wxCHECK2( dp.parentP && dp.parentN, continue );
651
652 if( ( dp.couplingFailMin || dp.couplingFailMax ) )
653 {
654 // We have a candidate violation, now we need to re-query for a constraint
655 // given the actual items, because there may be a location-based rule in play.
657 dp.parentP, dp.parentN,
658 dp.parentP->GetLayer() );
659 MINOPTMAX<int> val = constraint.GetValue();
660
661 if( !val.HasMin() || val.Min() < 0 || dp.computedGap >= val.Min() )
662 dp.couplingFailMin = false;
663
664 if( !val.HasMax() || val.Max() < 0 || dp.computedGap <= val.Max() )
665 dp.couplingFailMax = false;
666
667 if( !dp.couplingFailMin && !dp.couplingFailMax )
668 continue;
669
671 wxString msg;
672
673 if( dp.couplingFailMin )
674 {
675 msg = formatMsg( _( "(%s minimum gap %s; actual %s)" ),
676 key.gapRuleName,
677 val.Min(),
678 dp.computedGap );
679 }
680 else if( dp.couplingFailMax )
681 {
682 msg = formatMsg( _( "(%s maximum gap %s; actual %s)" ),
683 key.gapRuleName,
684 val.Max(),
685 dp.computedGap );
686 }
687
688 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
689
690 BOARD_CONNECTED_ITEM* item = nullptr;
691
692 if( dp.parentP )
693 {
694 item = dp.parentP;
695 drcItem->AddItem( dp.parentP );
696 }
697
698 if( dp.parentN )
699 {
700 item = dp.parentN;
701 drcItem->AddItem( dp.parentN );
702 }
703
704 drcItem->SetViolatingRule( key.gapRule );
705
706 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
707 }
708 }
709 }
710 }
711
713
714 return true;
715}
716
717
718namespace detail
719{
721}
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.
int GetDRCEpsilon() const
Return an epsilon which accounts for rounding errors, etc.
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:239
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:295
const NETINFO_LIST & GetNetInfo() const
Definition: board.h:888
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:948
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:489
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:96
std::shared_ptr< KIGFX::VIEW_OVERLAY > GetDebugOverlay() const
Definition: drc_engine.h:112
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:690
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:392
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:175
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_CUSTOM_MARKER_HANDLER *aCustomHandler=nullptr)
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:564
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:1875
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
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
Definition: pcb_track.cpp:1710
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
OPT_VECTOR2I Intersect(const SEG &aSeg, bool aIgnoreEndpoints=false, bool aLines=false) const
Compute intersection point of segment (this) with segment aSeg.
Definition: seg.cpp:254
ecoord TCoef(const VECTOR2I &aP) const
Definition: seg.h:395
ecoord SquaredLength() const
Definition: seg.h:338
bool NearestPoints(const SEG &aSeg, VECTOR2I &aPtA, VECTOR2I &aPtB, int64_t &aDistSq) const
Compute closest points between this segment and aSeg.
Definition: seg.cpp:150
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
const VECTOR2I & GetArcMid() const
Definition: shape_arc.h:118
EDA_ANGLE GetEndAngle() const
Definition: shape_arc.cpp:841
double GetLength() const
Definition: shape_arc.cpp:855
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter) override
Rotate the arc by a given angle about a point.
Definition: shape_arc.cpp:961
EDA_ANGLE GetStartAngle() const
Definition: shape_arc.cpp:833
bool NearestPoints(const SHAPE_ARC &aArc, VECTOR2I &aPtA, VECTOR2I &aPtB, int64_t &aDistSq) const
Compute closest points between this arc and aArc.
Definition: shape_arc.cpp:629
const VECTOR2I & GetP0() const
Definition: shape_arc.h:116
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
constexpr extended_type SquaredDistance(const VECTOR2< T > &aVector) const
Compute the squared distance between two vectors.
Definition: vector2d.h:569
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:695