55 virtual bool Run()
override;
57 virtual const wxString
GetName()
const override {
return wxT(
"diff_pair_coupling" ); };
71 int64_t t_b = p.
TCoef( p.
B );
73 int64_t tproj_a = p.
TCoef( n_proj_p.
A );
74 int64_t tproj_b = p.
TCoef( n_proj_p.
B );
77 std::swap( t_b, t_a );
79 if( tproj_b < tproj_a )
80 std::swap( tproj_b, tproj_a );
89 std::vector<int64_t> tv( t, t + 4 );
90 std::sort( tv.begin(), tv.end() );
95 pClip.
A.
x = p.
A.
x +
rescale( (int64_t)dp.
x, tv[1], pLenSq );
96 pClip.
A.
y = p.
A.
y +
rescale( (int64_t)dp.
y, tv[1], pLenSq );
98 pClip.
B.
x = p.
A.
x +
rescale( (int64_t)dp.
x, tv[2], pLenSq );
99 pClip.
B.
y = p.
A.
y +
rescale( (int64_t)dp.
y, tv[2], pLenSq );
114 bool p_is_ccw = p.
IsCCW();
115 bool n_is_ccw = n.
IsCCW();
118 double radiusDiffRatio =
std::abs(p_radius - n_radius) / std::max(p_radius, n_radius);
119 double centerDistance = (p_center - n_center).EuclideanNorm();
121 if (radiusDiffRatio > 0.5 || centerDistance > std::max(p_radius, n_radius) * 0.5)
128 std::swap( p_start, p_end );
134 std::swap( n_start, n_end );
142 p_arc.
Rotate( p_start_angle, p_center );
143 n_arc.
Rotate( p_start_angle, n_center );
150 EDA_ANGLE clip_start_angle, clip_end_angle;
153 if( n_start_angle >= p_end_angle || n_end_angle <=
EDA_ANGLE(0) )
157 clip_start_angle = std::max(
EDA_ANGLE(0), n_start_angle );
158 clip_end_angle = std::min( p_end_angle, n_end_angle );
161 EDA_ANGLE clip_total_angle = clip_end_angle - clip_start_angle;
165 clip_start_angle += p_start_angle;
166 clip_end_angle += p_start_angle;
176 VECTOR2I p_clip_point, n_clip_point;
181 KiROUND( p_radius * clip_start_angle.
Sin() ) );
182 pClip =
SHAPE_ARC( p_center, p_clip_point, clip_total_angle );
188 pClip =
SHAPE_ARC( p_center, p_clip_point, -clip_total_angle );
194 KiROUND( n_radius * clip_start_angle.
Sin() ) );
195 nClip =
SHAPE_ARC( n_center, n_clip_point, clip_total_angle );
201 nClip =
SHAPE_ARC( n_center, n_clip_point, -clip_total_angle );
277 std::vector<DIFF_PAIR_COUPLED_SEGMENTS>
coupled;
286 auto isInTuningPattern =
289 if(
EDA_GROUP* parent = track->GetParentGroup() )
293 if( generator->GetGeneratorType() == wxS(
"tuning_pattern" ) )
303 if( !itemP || itemP->
Type() !=
PCB_TRACE_T || isInTuningPattern( itemP ) )
307 std::vector<std::optional<DIFF_PAIR_COUPLED_SEGMENTS>> coupled_vec;
311 if( !itemN || itemN->
Type() !=
PCB_TRACE_T || isInTuningPattern( itemN ) )
338 coupled_vec.push_back( cpair );
344 for(
const std::optional<DIFF_PAIR_COUPLED_SEGMENTS>& coupled : coupled_vec )
349 if( aItem == coupled->parentN || aItem == coupled->parentP )
357 if( bci->
HitTest( coupled->coupledN.A, 0 )
358 || bci->
HitTest( coupled->coupledN.B, 0 )
359 || bci->
HitTest( coupled->coupledP.A, 0 )
360 || bci->
HitTest( coupled->coupledP.B, 0 ) )
369 auto trackExitsPad = [&](
PCB_TRACK* track )
371 bool startIn =
pad->HitTest( track->GetStart(), 0 );
372 bool endIn =
pad->HitTest( track->GetEnd(), 0 );
374 return startIn ^ endIn;
377 if( trackExitsPad(
static_cast<PCB_TRACK*
>( coupled->parentP ) )
378 || trackExitsPad(
static_cast<PCB_TRACK*
>( coupled->parentN ) ) )
387 SHAPE_SEGMENT checkSeg( coupled->nearestN, coupled->nearestP );
388 DRC_RTREE* tree = coupled->parentP->GetBoard()->m_CopperItemRTreeCache.get();
394 aDp.
coupled.push_back( *coupled );
400 if( !itemP || itemP->
Type() !=
PCB_ARC_T || isInTuningPattern( itemP ) )
404 std::vector<std::optional<DIFF_PAIR_COUPLED_SEGMENTS>> coupled_vec;
408 if( !itemN || itemN->
Type() !=
PCB_ARC_T || isInTuningPattern( itemN ) )
437 coupled_vec.push_back( cpair );
442 for(
const std::optional<DIFF_PAIR_COUPLED_SEGMENTS>& coupled : coupled_vec )
447 if( aItem == coupled->parentN || aItem == coupled->parentP )
454 if( bci->
GetNetCode() == coupled->parentN->GetNetCode()
455 || bci->
GetNetCode() == coupled->parentP->GetNetCode() )
464 auto arcExitsPad = [&](
PCB_ARC* arc )
466 bool startIn =
pad->HitTest( arc->GetStart(), 0 );
467 bool endIn =
pad->HitTest( arc->GetEnd(), 0 );
469 return startIn ^ endIn;
472 if( arcExitsPad(
static_cast<PCB_ARC*
>( coupled->parentP ) )
473 || arcExitsPad(
static_cast<PCB_ARC*
>( coupled->parentN ) ) )
482 SHAPE_SEGMENT checkArcMid( coupled->coupledArcN.GetArcMid(), coupled->coupledArcP.GetArcMid() );
483 DRC_RTREE* tree = coupled->parentP->GetBoard()->m_CopperItemRTreeCache.get();
489 aDp.
coupled.push_back( *coupled );
503 std::map<DIFF_PAIR_KEY, DIFF_PAIR_ITEMS> dpRuleMatches;
505 auto evaluateDpConstraints =
529 wxString ruleName = parentRule ? parentRule->
m_Name : constraint.
GetName();
531 switch( constraintType )
550 dpRuleMatches[key].itemsN.insert( citem );
552 dpRuleMatches[key].itemsP.insert( citem );
567 for(
auto& [ key, itemSet ] : dpRuleMatches )
578 REPORT_AUX( wxString::Format( wxT(
"Rule '%s', DP: (+) %s - (-) %s" ),
579 key.gapRuleName, nameP, nameN ) );
583 itemSet.totalCoupled = 0;
584 itemSet.totalLengthN = 0;
585 itemSet.totalLengthP = 0;
589 std::set<BOARD_CONNECTED_ITEM*> allItems;
595 if( allItems.insert( item ).second)
596 itemSet.totalLengthN += track->GetLength();
604 if( allItems.insert( item ).second)
605 itemSet.totalLengthP += track->GetLength();
621 overlay->SetLineWidth( 100000 );
632 if( key.gapConstraint )
634 if( key.gapConstraint->HasMin()
635 && key.gapConstraint->Min() >= 0
641 if( key.gapConstraint->HasMax()
642 && key.gapConstraint->Max() >= 0
650 itemSet.totalCoupled += length;
653 int totalLen = std::max( itemSet.totalLengthN, itemSet.totalLengthP );
655 REPORT_AUX( wxString::Format( wxT(
" - coupled length: %s, total length: %s" ),
659 int totalUncoupled = totalLen - itemSet.totalCoupled;
660 bool uncoupledViolation =
false;
662 if( key.uncoupledConstraint && ( !itemSet.itemsP.empty() || !itemSet.itemsN.empty() ) )
666 if( val.
HasMax() && val.
Max() >= 0 && totalUncoupled > val.
Max() )
669 wxString msg =
formatMsg(
_(
"(%s maximum uncoupled length %s; actual %s)" ),
670 key.uncoupledRuleName,
674 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
677 auto p_it = itemSet.itemsP.begin();
678 auto n_it = itemSet.itemsN.begin();
680 if( p_it != itemSet.itemsP.end() )
683 drce->AddItem( *p_it );
687 if( n_it != itemSet.itemsN.end() )
690 drce->AddItem( *n_it );
694 while( p_it != itemSet.itemsP.end() )
695 drce->AddItem( *p_it++ );
697 while( n_it != itemSet.itemsN.end() )
698 drce->AddItem( *n_it++ );
700 uncoupledViolation =
true;
702 drce->SetViolatingRule( key.uncoupledRule );
708 if( key.gapConstraint && ( uncoupledViolation || !key.uncoupledConstraint ) )
737 msg =
formatMsg(
_(
"(%s minimum gap %s; actual %s)" ),
744 msg =
formatMsg(
_(
"(%s maximum gap %s; actual %s)" ),
750 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS(
" " ) + msg );
751 drcItem->SetViolatingRule( key.gapRule );
758 drcItem->AddItem( dp.
parentP );
764 drcItem->AddItem( dp.
parentN );
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
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...
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Information pertinent to a Pcbnew printed circuit board.
SEVERITY GetSeverity() const
const MINOPTMAX< int > & GetValue() const
DRC_RULE * GetParentRule() const
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.
Implement an R-tree for fast spatial and layer indexing of connectable items.
bool CheckColliding(SHAPE *aRefShape, PCB_LAYER_ID aTargetLayer, int aClearance=0, std::function< bool(BOARD_ITEM *)> aFilter=nullptr) const
int forEachGeometryItem(const std::vector< KICAD_T > &aTypes, const LSET &aLayers, const std::function< bool(BOARD_ITEM *)> &aFunc)
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer, const std::vector< PCB_SHAPE > &aShapes={})
wxString formatMsg(const wxString &aFormatString, const wxString &aSource, double aConstraint, double aActual, EDA_DATA_TYPE aDataType=EDA_DATA_TYPE::DISTANCE)
A set of EDA_ITEMs (i.e., without duplicates).
virtual VECTOR2I GetPosition() const
virtual const VECTOR2I GetFocusPosition() const
Similar to GetPosition() but allows items to return their visual center rather than their anchor.
KICAD_T Type() const
Returns the type of object.
LSET is a set of PCB_LAYER_IDs.
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Handle the data for a net.
const wxString & GetNetname() const
virtual double GetLength() const override
Return the length of the arc track.
const VECTOR2I & GetMid() const
virtual VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
const VECTOR2I & GetStart() const
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
const VECTOR2I & GetEnd() const
virtual int GetWidth() const
int Length() const
Return the length (this).
OPT_VECTOR2I Intersect(const SEG &aSeg, bool aIgnoreEndpoints=false, bool aLines=false) const
Compute intersection point of segment (this) with segment aSeg.
ecoord TCoef(const VECTOR2I &aP) const
ecoord SquaredLength() const
bool NearestPoints(const SEG &aSeg, VECTOR2I &aPtA, VECTOR2I &aPtB, int64_t &aDistSq) const
Compute closest points between this segment and aSeg.
VECTOR2I LineProject(const VECTOR2I &aP) const
Compute the perpendicular projection point of aP on a line passing through ends of the segment.
EDA_ANGLE GetEndAngle() const
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter) override
Rotate the arc by a given angle about a point.
EDA_ANGLE GetStartAngle() const
bool NearestPoints(const SHAPE_ARC &aArc, VECTOR2I &aPtA, VECTOR2I &aPtB, int64_t &aDistSq) const
Compute closest points between this arc and aArc.
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.
virtual ~DRC_TEST_PROVIDER_DIFF_PAIR_COUPLING()=default
DRC_TEST_PROVIDER_DIFF_PAIR_COUPLING()
virtual const wxString GetName() const override
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
@ DRCE_DIFF_PAIR_GAP_OUT_OF_RANGE
@ DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG
@ DIFF_PAIR_GAP_CONSTRAINT
@ MAX_UNCOUPLED_CONSTRAINT
static bool commonParallelProjection(SEG p, SEG n, SEG &pClip, SEG &nClip)
static void extractDiffPairCoupledItems(DIFF_PAIR_ITEMS &aDp)
PCB_LAYER_ID
A quick note on layer IDs:
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
std::shared_ptr< PNS_LOG_VIEWER_OVERLAY > overlay
DIFF_PAIR_COUPLED_SEGMENTS()
std::set< BOARD_CONNECTED_ITEM * > itemsN
std::vector< DIFF_PAIR_COUPLED_SEGMENTS > coupled
std::set< BOARD_CONNECTED_ITEM * > itemsP
wxString uncoupledRuleName
std::optional< MINOPTMAX< int > > uncoupledConstraint
std::optional< MINOPTMAX< int > > gapConstraint
bool operator<(const DIFF_PAIR_KEY &b) const
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_PAD_T
class PAD, a pad in a footprint
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
T rescale(T aNumerator, T aValue, T aDenominator)
Scale a number (value) by rational (numerator/denominator).
VECTOR2< int32_t > VECTOR2I