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;
180 p_clip_point = p_center +
KiROUND( p_radius * clip_start_angle.
Cos(), p_radius * clip_start_angle.
Sin() );
181 pClip =
SHAPE_ARC( p_center, p_clip_point, clip_total_angle );
185 p_clip_point = p_center +
KiROUND( p_radius * clip_end_angle.
Cos(), p_radius * clip_end_angle.
Sin() );
186 pClip =
SHAPE_ARC( p_center, p_clip_point, -clip_total_angle );
191 n_clip_point = n_center +
KiROUND( n_radius * clip_start_angle.
Cos(), n_radius * clip_start_angle.
Sin() );
192 nClip =
SHAPE_ARC( n_center, n_clip_point, clip_total_angle );
196 n_clip_point = n_center +
KiROUND( n_radius * clip_end_angle.
Cos(), n_radius * clip_end_angle.
Sin() );
197 nClip =
SHAPE_ARC( n_center, n_clip_point, -clip_total_angle );
273 std::vector<DIFF_PAIR_COUPLED_SEGMENTS>
coupled;
286 if( generator->GetGeneratorType() == wxS(
"tuning_pattern" ) )
303 std::vector<std::optional<DIFF_PAIR_COUPLED_SEGMENTS>> coupled_vec;
334 coupled_vec.push_back( cpair );
340 for(
const std::optional<DIFF_PAIR_COUPLED_SEGMENTS>& coupled : coupled_vec )
345 if( aItem == coupled->parentN || aItem == coupled->parentP )
353 if( bci->
HitTest( coupled->coupledN.A, 0 )
354 || bci->
HitTest( coupled->coupledN.B, 0 )
355 || bci->
HitTest( coupled->coupledP.A, 0 )
356 || bci->
HitTest( coupled->coupledP.B, 0 ) )
365 auto trackExitsPad = [&](
PCB_TRACK* track )
367 bool startIn =
pad->HitTest( track->GetStart(), 0 );
368 bool endIn =
pad->HitTest( track->GetEnd(), 0 );
370 return startIn ^ endIn;
373 if( trackExitsPad(
static_cast<PCB_TRACK*
>( coupled->parentP ) )
374 || trackExitsPad(
static_cast<PCB_TRACK*
>( coupled->parentN ) ) )
383 SHAPE_SEGMENT checkSeg( coupled->nearestN, coupled->nearestP );
384 DRC_RTREE* tree = coupled->parentP->GetBoard()->m_CopperItemRTreeCache.get();
390 aDp.
coupled.push_back( *coupled );
400 std::vector<std::optional<DIFF_PAIR_COUPLED_SEGMENTS>> coupled_vec;
433 coupled_vec.push_back( cpair );
438 for(
const std::optional<DIFF_PAIR_COUPLED_SEGMENTS>& coupled : coupled_vec )
443 if( aItem == coupled->parentN || aItem == coupled->parentP )
450 if( bci->
GetNetCode() == coupled->parentN->GetNetCode()
451 || bci->
GetNetCode() == coupled->parentP->GetNetCode() )
460 auto arcExitsPad = [&](
PCB_ARC* arc )
462 bool startIn =
pad->HitTest( arc->GetStart(), 0 );
463 bool endIn =
pad->HitTest( arc->GetEnd(), 0 );
465 return startIn ^ endIn;
468 if( arcExitsPad(
static_cast<PCB_ARC*
>( coupled->parentP ) )
469 || arcExitsPad(
static_cast<PCB_ARC*
>( coupled->parentN ) ) )
478 SHAPE_SEGMENT checkArcMid( coupled->coupledArcN.GetArcMid(), coupled->coupledArcP.GetArcMid() );
479 DRC_RTREE* tree = coupled->parentP->GetBoard()->m_CopperItemRTreeCache.get();
485 aDp.
coupled.push_back( *coupled );
498 std::map<DIFF_PAIR_KEY, DIFF_PAIR_ITEMS> dpRuleMatches;
500 auto evaluateDpConstraints =
524 wxString ruleName = parentRule ? parentRule->
m_Name : constraint.
GetName();
526 switch( constraintType )
545 dpRuleMatches[key].itemsN.insert( citem );
547 dpRuleMatches[key].itemsP.insert( citem );
562 for(
auto& [ key, itemSet ] : dpRuleMatches )
573 REPORT_AUX( wxString::Format( wxT(
"Rule '%s', DP: (+) %s - (-) %s" ),
574 key.gapRuleName, nameP, nameN ) );
578 itemSet.totalCoupled = 0;
579 itemSet.totalLengthN = 0;
580 itemSet.totalLengthP = 0;
584 std::set<BOARD_CONNECTED_ITEM*> allItems;
593 if( allItems.insert( item ).second)
594 itemSet.totalLengthN += track->GetLength();
605 if( allItems.insert( item ).second)
606 itemSet.totalLengthP += track->GetLength();
622 overlay->SetLineWidth( 100000 );
633 if( key.gapConstraint )
635 if( key.gapConstraint->HasMin()
636 && key.gapConstraint->Min() >= 0
642 if( key.gapConstraint->HasMax()
643 && key.gapConstraint->Max() >= 0
651 itemSet.totalCoupled += length;
654 int totalLen = std::max( itemSet.totalLengthN, itemSet.totalLengthP );
656 REPORT_AUX( wxString::Format( wxT(
" - coupled length: %s, total length: %s" ),
660 int totalUncoupled = totalLen - itemSet.totalCoupled;
661 bool uncoupledViolation =
false;
663 if( key.uncoupledConstraint && ( !itemSet.itemsP.empty() || !itemSet.itemsN.empty() ) )
667 if( val.
HasMax() && val.
Max() >= 0 && totalUncoupled > val.
Max() )
670 drce->SetErrorDetail(
formatMsg(
_(
"(%s maximum uncoupled length %s; actual %s)" ),
671 key.uncoupledRuleName,
676 auto p_it = itemSet.itemsP.begin();
677 auto n_it = itemSet.itemsN.begin();
679 if( p_it != itemSet.itemsP.end() )
682 drce->AddItem( *p_it );
686 if( n_it != itemSet.itemsN.end() )
689 drce->AddItem( *n_it );
693 while( p_it != itemSet.itemsP.end() )
694 drce->AddItem( *p_it++ );
696 while( n_it != itemSet.itemsN.end() )
697 drce->AddItem( *n_it++ );
699 uncoupledViolation =
true;
701 drce->SetViolatingRule( key.uncoupledRule );
707 if( key.gapConstraint && ( uncoupledViolation || !key.uncoupledConstraint ) )
735 drcItem->SetErrorDetail(
formatMsg(
_(
"(%s minimum gap %s; actual %s)" ),
742 drcItem->SetErrorDetail(
formatMsg(
_(
"(%s maximum gap %s; actual %s)" ),
748 drcItem->SetViolatingRule( key.gapRule );
755 drcItem->AddItem( dp.
parentP );
761 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,...
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
NETINFO_ITEM * GetNet() const
Return NETINFO_ITEM object for a given item.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
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, const 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)
void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer, const std::function< void(PCB_MARKER *)> &aPathGenerator=[](PCB_MARKER *){})
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.
virtual EDA_GROUP * GetParentGroup() const
KICAD_T Type() const
Returns the type of object.
LSET is a set of PCB_LAYER_IDs.
static const 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.
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
const VECTOR2I & GetMid() const
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).
@ DIFF_PAIR_GAP_CONSTRAINT
@ MAX_UNCOUPLED_CONSTRAINT
@ DRCE_DP_UNCOUPLED_LENGTH_TOO_LONG
@ DRCE_DP_GAP_OUT_OF_RANGE
static bool commonParallelProjection(SEG p, SEG n, SEG &pClip, SEG &nClip)
static void extractDiffPairCoupledItems(DIFF_PAIR_ITEMS &aDp)
static bool isInTuningPattern(BOARD_ITEM *aItem)
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