60 virtual bool Run()
override;
62 virtual const wxString
GetName()
const override {
return wxT(
"length" ); };
71 const std::vector<CONNECTION>& aMatchedConnections );
73 const std::vector<CONNECTION>& aMatchedConnections );
75 const std::vector<CONNECTION>& aMatchedConnections );
78 const std::vector<CONNECTION>& aMatchedConnections );
81 const std::map<wxString, CONNECTION>& aChainAgg );
103 const std::vector<CONNECTION>& aMatchedConnections )
107 bool minViolation =
false;
108 bool maxViolation =
false;
142 if( ( minViolation || maxViolation ) )
148 drcItem->SetErrorDetail(
formatMsg(
_(
"(%s min length %s; actual %s)" ),
156 else if( maxViolation )
158 drcItem->SetErrorDetail(
formatMsg(
_(
"(%s max length %s; actual %s)" ),
167 for(
auto offendingTrack : ent.items )
168 drcItem->AddItem( offendingTrack );
172 reportViolation( drcItem, ( *ent.items.begin() )->GetPosition(), ( *ent.items.begin() )->GetLayer() );
178 const std::vector<CONNECTION>& aMatchedConnections )
180 auto checkSkewsImpl = [
this, &aConstraint](
const std::vector<CONNECTION>& connections )
185 double maxLength = 0;
192 if( ent.total > maxLength )
194 maxLength = ent.total;
195 maxNetname = ent.netname;
203 if( ent.totalDelay > maxLength )
205 maxLength = ent.totalDelay;
206 maxNetname = ent.netname;
213 int skew = isTimeDomain ?
KiROUND( ent.totalDelay - maxLength )
214 :
KiROUND( ent.total - maxLength );
216 bool fail_min =
false;
217 bool fail_max =
false;
224 if( fail_min || fail_max )
229 double reportTotal = isTimeDomain ? ent.totalDelay : ent.total;
233 msg.Printf(
_(
"(%s min skew %s; actual %s; target net length %s (from %s); actual %s)" ),
243 msg.Printf(
_(
"(%s max skew %s; actual %s; target net length %s (from %s); actual %s)" ),
252 drcItem->SetErrorDetail( msg );
255 drcItem->SetItems( offendingTrack );
259 reportViolation( drcItem, ( *ent.items.begin() )->GetPosition(), ( *ent.items.begin() )->GetLayer() );
267 std::map<int, CONNECTION> netcodeMap;
270 netcodeMap[ent.netcode] = ent;
272 std::vector<std::vector<CONNECTION>> matchedDiffPairs;
274 for(
auto& [netcode, connection] : netcodeMap )
280 int matchedNetcode = matchedNet->
GetNetCode();
282 if( netcodeMap.count( matchedNetcode ) )
284 std::vector<CONNECTION> pair{ connection, netcodeMap[matchedNetcode] };
285 matchedDiffPairs.emplace_back( std::move( pair ) );
286 netcodeMap.erase( matchedNetcode );
292 for(
const std::vector<CONNECTION>& matchedDiffPair : matchedDiffPairs )
293 checkSkewsImpl( matchedDiffPair );
298 checkSkewsImpl( aMatchedConnections );
304 const std::vector<CONNECTION>& aMatchedConnections )
306 for(
const auto& ent : aMatchedConnections )
308 std::shared_ptr<DRC_ITEM> drcItem =
nullptr;
313 wxString msg = wxString::Format(
_(
"(%s max count %d; actual %d)" ),
318 drcItem->SetErrorMessage(
_(
"Too many vias on a connection" ) + wxS(
" " ) + msg );
323 wxString msg = wxString::Format(
_(
"(%s min count %d; actual %d)" ),
328 drcItem->SetErrorMessage(
_(
"Too few vias on a connection" ) + wxS(
" " ) + msg );
334 drcItem->SetItems( offendingTrack );
338 reportViolation( drcItem, ( *ent.items.begin() )->GetPosition(), ( *ent.items.begin() )->GetLayer() );
357 if( !aDelayReportMode )
359 if( !
reportPhase(
_(
"Gathering length-constrained connections..." ) ) )
364 std::map<DRC_RULE*, std::set<BOARD_CONNECTED_ITEM*> > itemSets;
366 std::shared_ptr<FROM_TO_CACHE> ftCache =
m_board->GetConnectivity()->GetFromToCache();
370 const size_t progressDelta = 100;
407 std::map< DRC_RULE*, std::vector<CONNECTION> > matches;
409 for(
const auto& [rule, ruleItems] : itemSets )
411 std::map<int, std::set<BOARD_CONNECTED_ITEM*> > netMap;
414 netMap[item->GetNetCode()].insert( item );
416 for(
const auto& [netCode, netItems] : netMap )
418 std::vector<LENGTH_DELAY_CALCULATION_ITEM> lengthItems;
419 lengthItems.reserve( netItems.size() );
422 ent.
items = netItems;
438 if( lengthItem.
Type() != LENGTH_DELAY_CALCULATION_ITEM::TYPE::UNKNOWN )
439 lengthItems.emplace_back( lengthItem );
443 .OptimiseVias =
true, .MergeTracks =
true, .OptimiseTracesInPads =
true, .InferViaInPad =
false
445 LENGTH_DELAY_STATS details = calc->CalculateLengthDetails( lengthItems, opts,
nullptr,
nullptr,
462 ent.
from = ftPath->fromName;
463 ent.
to = ftPath->toName;
467 ent.
from = ent.
to =
_(
"<unconstrained>" );
471 matches[rule].push_back( ent );
475 if( !aDelayReportMode )
477 if( !
reportPhase(
_(
"Checking length constraints..." ) ) )
481 count = matches.size();
483 for( std::pair<
DRC_RULE*
const, std::vector<CONNECTION> > it : matches )
486 auto& matchedConnections = it.second;
491 std::sort( matchedConnections.begin(), matchedConnections.end(),
494 return a.netname < b.netname;
499 REPORT_AUX( wxString::Format( wxT(
"Length-constrained traces for rule '%s':" ),
500 it.first->m_Name ) );
504 REPORT_AUX( wxString::Format( wxT(
" - net: %s, from: %s, to: %s, %d matching items, "
505 "total: %s (tracks: %s, vias: %s, pad-to-die: %s), "
509 static_cast<int>( ent.items.size() ),
526 std::map<wxString, CONNECTION> chainAgg;
527 std::optional<DRC_CONSTRAINT> stubConstraint =
529 std::optional<DRC_CONSTRAINT> returnPathConstraint =
532 const bool needsChainAgg =
533 ( netChainLengthConstraint
536 || ( returnPathConstraint
541 for(
const CONNECTION& conn : matchedConnections )
546 wxString chainName = conn.netinfo->GetNetChain();
548 if( chainName.IsEmpty() )
551 auto aggIt = chainAgg.find( chainName );
553 if( aggIt == chainAgg.end() )
557 chainAgg[chainName] = agg;
562 agg.
total += conn.total;
571 agg.
items.insert( conn.items.begin(), conn.items.end() );
576 if( netChainLengthConstraint && netChainLengthConstraint->GetSeverity() !=
RPT_SEVERITY_IGNORE )
578 std::vector<CONNECTION> chainConnections;
579 chainConnections.reserve( chainAgg.size() );
581 for(
auto& [chainName, agg] : chainAgg )
586 if( topo && topo->IsValid() )
591 constraintInput.
total = topo->TrunkLength();
592 constraintInput.
totalDelay = topo->TrunkDelay();
593 constraintInput.
totalRoute = topo->TrunkLength();
604 constraintInput.
total += bridging;
610 chainConnections.push_back( std::move( constraintInput ) );
613 checkLengths( *netChainLengthConstraint, chainConnections );
624 checkSkews( *skewConstraint, matchedConnections );
631 if( returnPathConstraint
633 && !returnPathConstraint->m_ReferenceLayer.IsEmpty() )
647std::shared_ptr<CHAIN_TOPOLOGY>
655 std::set<BOARD_CONNECTED_ITEM*> items;
659 if( t->GetNet() && t->GetNet()->GetNetChain() == aChain )
665 for(
PAD* p : fp->Pads() )
667 if( p->GetNet() && p->GetNet()->GetNetChain() == aChain )
672 auto topo = std::make_shared<CHAIN_TOPOLOGY>(
m_board, aChain, items );
680 const wxString& aRefNet )
682 auto key = std::make_pair( aRefLayer, aRefNet );
692 if( !zone || !zone->IsOnLayer( aRefLayer ) || zone->GetIsRuleArea() )
695 if( !aRefNet.IsEmpty() )
697 wxString zoneNet = zone->GetNetname();
713 else if( zone->Outline() )
720 return &
m_refUnionCache.emplace( key, std::move( refUnion ) ).first->second;
726 const std::vector<CONNECTION>& aMatchedConnections )
728 const bool isTimeDomain =
734 if( !range.HasMax() && !range.HasMin() )
737 auto outOfRange = [&](
double aMeasured )
739 return ( range.HasMax() && aMeasured > range.Max() )
740 || ( range.HasMin() && aMeasured < range.Min() );
746 std::set<wxString> chainNames;
748 for(
const CONNECTION& conn : aMatchedConnections )
750 if( conn.netinfo && !conn.netinfo->GetNetChain().IsEmpty() )
751 chainNames.insert( conn.netinfo->GetNetChain() );
754 std::set<wxString> handledByTopology;
756 for(
const wxString& chainName : chainNames )
760 if( !topoPtr || !topoPtr->IsValid() )
763 handledByTopology.insert( chainName );
767 const double measured = isTimeDomain ? stub.delay : stub.length;
769 if( !outOfRange( measured ) )
772 std::shared_ptr<DRC_ITEM> item =
774 item->SetErrorMessage( wxString::Format(
775 _(
"Stub length (%s) out of range for net chain '%s'." ),
778 item->SetViolatingRule( aRule );
790 for(
const CONNECTION& conn : aMatchedConnections )
797 if( handledByTopology.count( netInfo->
GetNetChain() ) )
809 const double measured = isTimeDomain ? conn.totalDelay
810 :
static_cast<double>( conn.total );
812 if( !outOfRange( measured ) )
815 std::shared_ptr<DRC_ITEM> item =
817 item->SetErrorMessage( wxString::Format(
818 _(
"Stub length (%s) out of range for net chain '%s' on net '%s'." ),
822 item->SetViolatingRule( aRule );
825 item->AddItem( connItem );
830 if( !conn.items.empty() )
832 pos = ( *conn.items.begin() )->GetPosition();
833 layer = ( *conn.items.begin() )->GetLayer();
843 const std::map<wxString, CONNECTION>& aChainAgg )
859 std::vector<BOARD_CONNECTED_ITEM*> items;
864 std::vector<FlaggedRegion>& aFlagged,
867 for(
int o = 0; o < aRegion.OutlineCount(); ++o )
870 fr.poly.AddOutline( aRegion.Outline( o ) );
872 for(
int h = 0; h < aRegion.HoleCount( o ); ++h )
873 fr.poly.AddHole( aRegion.Hole( o, h ) );
875 fr.items.push_back( aItem );
877 aFlagged.push_back( std::move( fr ) );
881 for(
const auto& [chainName, agg] : aChainAgg )
883 std::vector<FlaggedRegion> flagged;
901 flagItem( item, flagged, std::move( itemPoly ) );
916 flagItem( item, flagged, std::move( diff ) );
919 if( flagged.empty() )
926 std::vector<int> parent( flagged.size() );
927 std::iota( parent.begin(), parent.end(), 0 );
929 auto find = [&](
int x )
931 while( parent[x] != x )
933 parent[x] = parent[parent[x]];
940 for(
size_t i = 0; i < flagged.size(); ++i )
942 BOX2I bi = flagged[i].poly.BBox();
945 for(
size_t j = i + 1; j < flagged.size(); ++j )
947 BOX2I bj = flagged[j].poly.BBox();
967 int ri =
find(
static_cast<int>( i ) );
968 int rj =
find(
static_cast<int>( j ) );
975 std::map<int, std::vector<int>> groups;
977 for(
size_t i = 0; i < flagged.size(); ++i )
978 groups[
find(
static_cast<int>( i ) )].push_back(
static_cast<int>( i ) );
980 for(
const auto& [root, members] : groups )
983 std::vector<BOARD_CONNECTED_ITEM*> items;
984 std::set<BOARD_CONNECTED_ITEM*> seen;
987 for(
int idx : members )
993 if( seen.insert( it ).second )
994 items.push_back( it );
998 markerLayer = flagged[idx].layer;
1006 ? items.front()->GetPosition()
1009 std::shared_ptr<DRC_ITEM> drcItem =
1012 wxString msg = wxString::Format(
1013 _(
"Net chain '%s' has no copper return path on reference layer '%s'." ),
1014 chainName, refLayerName );
1016 if( !refNetPattern.IsEmpty() )
1017 msg += wxString::Format(
_(
" (net '%s')" ), refNetPattern );
1019 drcItem->SetErrorMessage( msg );
1020 drcItem->SetViolatingRule( aRule );
1023 drcItem->AddItem( it );
constexpr int ARC_HIGH_DEF
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
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.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const
Convert the item shape to a closed polygon.
Information pertinent to a Pcbnew printed circuit board.
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
constexpr Vec Centre() const
constexpr bool Intersects(const BOX2< Vec > &aRect) const
const MINOPTMAX< int > & GetValue() const
wxString m_ReferenceLayer
bool GetOption(OPTIONS option) const
DRC_RULE * GetParentRule() const
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
std::optional< DRC_CONSTRAINT > FindConstraint(DRC_CONSTRAINT_T aType)
bool runInternal(bool aDelayReportMode=false)
virtual const wxString GetName() const override
std::shared_ptr< CHAIN_TOPOLOGY > chainTopologyFor(const wxString &aChain)
void checkSkews(const DRC_CONSTRAINT &aConstraint, const std::vector< CONNECTION > &aMatchedConnections)
SHAPE_POLY_SET * zoneUnionFor(PCB_LAYER_ID aRefLayer, const wxString &aRefNet)
virtual ~DRC_TEST_PROVIDER_MATCHED_LENGTH()=default
void checkReturnPath(const DRC_CONSTRAINT &aConstraint, DRC_RULE *aRule, const std::map< wxString, CONNECTION > &aChainAgg)
void checkViaCounts(const DRC_CONSTRAINT &aConstraint, const std::vector< CONNECTION > &aMatchedConnections)
DRC_LENGTH_REPORT m_report
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
std::map< wxString, std::shared_ptr< CHAIN_TOPOLOGY > > m_chainTopoCache
DRC_TEST_PROVIDER_MATCHED_LENGTH()
DRC_LENGTH_REPORT::ENTRY CONNECTION
std::map< std::pair< PCB_LAYER_ID, wxString >, SHAPE_POLY_SET > m_refUnionCache
void checkStubLengths(const DRC_CONSTRAINT &aConstraint, DRC_RULE *aRule, const std::vector< CONNECTION > &aMatchedConnections)
void checkLengths(const DRC_CONSTRAINT &aConstraint, const std::vector< CONNECTION > &aMatchedConnections)
virtual bool reportPhase(const wxString &aStageName)
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 *){})
REPORTER * getLogReporter() const
wxString formatMsg(const wxString &aFormatString, const wxString &aSource, double aConstraint, double aActual, EDA_DATA_TYPE aDataType=EDA_DATA_TYPE::DISTANCE)
virtual bool reportProgress(size_t aCount, size_t aSize, size_t aDelta=1)
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
KICAD_T Type() const
Returns the type of object.
Lightweight class which holds a pad, via, or a routed trace outline.
TYPE Type() const
Gets the routing item type.
Class which calculates lengths (and associated routing statistics) in a BOARD context.
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 & GetNetChain() const
const wxString & GetNetname() const
PAD * GetTerminalPad(int aIndex) const
Represent a set of closed polygons.
void BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
void BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
int OutlineCount() const
Return the number of outlines in the set.
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
Handle a list of polygons defining a copper zone.
@ ROUND_ALL_CORNERS
All angles are rounded.
@ DRCE_NET_CHAIN_STUB_TOO_LONG
@ DRCE_NET_CHAIN_RETURN_PATH_BREAK
@ DRCE_LENGTH_OUT_OF_RANGE
@ DRCE_VIA_COUNT_OUT_OF_RANGE
@ NET_CHAIN_LENGTH_CONSTRAINT
@ NET_CHAIN_STUB_LENGTH_CONSTRAINT
@ NET_CHAIN_RETURN_PATH_CONSTRAINT
EDA_DATA_TYPE
The type of unit.
PCB_LAYER_ID
A quick note on layer IDs:
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
std::tuple< double, double > BoardChainBridging(const BOARD *aBoard, const wxString &aNetChain)
Compute both the chain bridging length and its associated propagation delay (in internal delay IU,...
bool WildCompareString(const wxString &pattern, const wxString &string_to_tst, bool case_sensitive)
Compare a string against wild card (* and ?) pattern using the usual rules.
BOARD_CONNECTED_ITEM * fromItem
BOARD_CONNECTED_ITEM * toItem
std::set< BOARD_CONNECTED_ITEM * > items
int64_t totalPadToDieDelay
Holds length measurement result details and statistics.
Struct to control which optimisations the length calculation code runs on the given path objects.
@ 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)
VECTOR2< int32_t > VECTOR2I