36 const std::shared_ptr<SHAPE_POLY_SET>& aPadShape,
40 int64_t bestDistSq = std::numeric_limits<int64_t>::max();
42 for(
int i = 0; i < aPadShape->OutlineCount(); i++ )
49 std::vector<VECTOR2I> intersections;
54 for(
const VECTOR2I& pt : intersections )
59 int64_t distSq = ( pt - aInsidePoint ).SquaredEuclideanNorm();
61 if( distSq < bestDistSq )
80 const int start = aForward ? 0 : aLine.
PointCount() - 1;
81 const int delta = aForward ? 1 : -1;
86 int firstOutside = -1;
88 bool hasIntersection =
false;
90 for(
int vertex = start +
delta; aForward ? vertex < aLine.
PointCount() : vertex >= 0; vertex +=
delta )
92 if( !shape->Contains( aLine.
GetPoint( vertex ) ) )
94 firstOutside = vertex;
95 int prevVertex = vertex -
delta;
98 ssize_t arcIdx = aLine.
ArcIndex( prevVertex );
100 if( arcIdx >= 0 && aLine.
ArcIndex( vertex ) == arcIdx )
107 if( !hasIntersection )
112 if( shape->Collide( seg, 0,
nullptr, &loc ) )
114 intersectionPt = loc;
115 hasIntersection =
true;
123 if( firstOutside < 0 )
133 if( hasIntersection )
134 newChain.
Append( intersectionPt );
135 newChain.
Append( aLine.
Slice( firstOutside, -1 ) );
141 if( hasIntersection )
142 newChain.
Append( intersectionPt );
152 const PAD* aStartPad,
const PAD* aEndPad,
156 const bool doTrace = wxLog::IsAllowedTraceMask( wxT(
"PNS_TUNE" ) );
160 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"" ) );
161 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"========== CalculateLengthDetails START ==========" ) );
162 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"CalculateLengthDetails: input has %zu items" ), aItems.size() );
163 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"CalculateLengthDetails: optimisations - OptimiseViaLayers=%d, MergeTracks=%d, OptimiseTracesInPads=%d, InferViaInPad=%d" ),
168 int initialPads = 0, initialVias = 0, initialLines = 0, initialUnknown = 0;
172 switch( item.Type() )
174 case LENGTH_DELAY_CALCULATION_ITEM::TYPE::PAD: initialPads++;
break;
175 case LENGTH_DELAY_CALCULATION_ITEM::TYPE::VIA: initialVias++;
break;
176 case LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE: initialLines++;
break;
177 default: initialUnknown++;
break;
181 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"CalculateLengthDetails: initial items - PADs=%d, VIAs=%d, LINEs=%d, UNKNOWN=%d" ),
182 initialPads, initialVias, initialLines, initialUnknown );
189 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"CalculateLengthDetails: performing optimisations..." ) );
191 std::vector<LENGTH_DELAY_CALCULATION_ITEM*> pads;
192 std::vector<LENGTH_DELAY_CALCULATION_ITEM*> lines;
193 std::vector<LENGTH_DELAY_CALCULATION_ITEM*> vias;
196 std::map<VECTOR2I, std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>> linesPositionMap;
199 std::map<VECTOR2I, std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>> padsPositionMap;
203 if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::PAD )
205 pads.emplace_back( &item );
206 padsPositionMap[item.GetPad()->GetPosition()].insert( &item );
208 else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::VIA )
210 vias.emplace_back( &item );
212 else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE )
214 lines.emplace_back( &item );
215 linesPositionMap[item.GetLine().CPoint( 0 )].insert( &item );
216 linesPositionMap[item.GetLine().CLastPoint()].insert( &item );
223 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"CalculateLengthDetails: optimising via layers (%zu vias)" ), vias.size() );
231 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"CalculateLengthDetails: merging tracks (%zu lines)" ), lines.size() );
239 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"CalculateLengthDetails: optimising traces in pads" ) );
251 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"CalculateLengthDetails: creating layer detail maps" ) );
253 details.
LayerLengths = std::make_unique<std::map<PCB_LAYER_ID, int64_t>>();
256 details.
LayerDelays = std::make_unique<std::map<PCB_LAYER_ID, int64_t>>();
259 const bool useHeight =
m_board->GetDesignSettings().m_UseHeightForLengthCalcs;
262 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"CalculateLengthDetails: useHeight=%d" ), useHeight );
270 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"CalculateLengthDetails: inferring vias in pads" ) );
277 int processedPads = 0, processedVias = 0, processedLines = 0;
278 int mergedRetired = 0, unknownType = 0;
281 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"CalculateLengthDetails: processing %zu items..." ), aItems.size() );
287 || item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::UNKNOWN )
297 if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE )
299 const int64_t length = item.GetLine().Length();
305 ( *details.
LayerLengths )[item.GetStartLayer()] += length;
307 else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::VIA && useHeight )
309 const auto [layerStart, layerEnd] = item.GetLayers();
316 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"CalculateLengthDetails: via from layer %d to %d, height=%lld" ),
317 layerStart, layerEnd, viaHeight );
319 else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::PAD )
321 int64_t padToDie = item.GetPad()->GetPadToDieLength();
326 if( doTrace && padToDie > 0 )
327 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"CalculateLengthDetails: pad with pad-to-die length=%lld" ), padToDie );
333 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"CalculateLengthDetails: processed items - PADs=%d, VIAs=%d, LINEs=%d" ),
334 processedPads, processedVias, processedLines );
335 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"CalculateLengthDetails: skipped items - merged/retired=%d, unknown=%d" ),
336 mergedRetired, unknownType );
343 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"CalculateLengthDetails: calculating time domain statistics" ) );
347 ctx.
NetClass = aItems.front().GetEffectiveNetClass();
351 wxASSERT( itemDelays.size() == aItems.size() );
353 for(
size_t i = 0; i < aItems.size(); ++i )
357 if( item.
Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE )
364 else if( item.
Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::VIA && useHeight )
368 else if( item.
Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::PAD )
375 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"CalculateLengthDetails: total delays - Track=%lld, Via=%lld, PadToDie=%lld" ),
381 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"CalculateLengthDetails: RESULTS:" ) );
382 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
" Track length: %lld" ), details.
TrackLength );
383 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
" Via length: %d (from %d vias)" ), details.
ViaLength, details.
NumVias );
384 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
" Pad-to-die length: %d (from %d pads)" ), details.
PadToDieLength, details.
NumPads );
385 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
" TOTAL LENGTH: %lld" ), details.
TotalLength() );
386 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"========== CalculateLengthDetails END ==========" ) );
387 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"" ) );
397 if( aPad && aItem.
Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE )
402 if( !padLayers.
Contains( startBottomLayer ) )
416 const PAD* aEndPad )
const
424 const PAD* aEndPad )
const
434 if( !
m_board || !
m_board->GetDesignSettings().m_UseHeightForLengthCalcs )
437 if(
m_board->GetDesignSettings().m_HasStackup )
452 std::vector<LENGTH_DELAY_CALCULATION_ITEM*>& aLines,
453 std::map<
VECTOR2I, std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>>& aLinesPositionMap )
456 std::vector<LENGTH_DELAY_CALCULATION_ITEM*> pads;
460 aLinesPositionMap[line->GetLine().CPoint( 0 )].erase( line );
461 aLinesPositionMap[line->GetLine().CLastPoint()].erase( line );
465 auto tryMerge = [&removeFromPositionMap, &aLinesPositionMap](
const MERGE_POINT aMergePoint,
470 const auto startItr = aLinesPositionMap.find( aMergePos );
472 if( startItr == aLinesPositionMap.end() )
475 std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>& startItems = startItr->second;
477 if( startItems.size() != 1 )
487 if( aPrimaryItem->GetStartLayer() != lineToMerge->
GetStartLayer() )
493 removeFromPositionMap( lineToMerge );
505 removeFromPositionMap( primaryItem );
511 bool mergeComplete =
false;
513 while( !mergeComplete )
515 bool startMerged =
false;
516 bool endMerged =
false;
524 mergeComplete = !startMerged && !endMerged;
537 for(
auto itr = aSecondary.
CPoints().begin() + 1; itr != aSecondary.
CPoints().end(); ++itr )
538 aPrimary.
Insert( 0, *itr );
544 for(
auto itr = aSecondary.
CPoints().rbegin() + 1; itr != aSecondary.
CPoints().rend(); ++itr )
545 aPrimary.
Insert( 0, *itr );
552 for(
auto itr = aSecondary.
CPoints().begin() + 1; itr != aSecondary.
CPoints().end(); ++itr )
559 for(
auto itr = aSecondary.
CPoints().rbegin() + 1; itr != aSecondary.
CPoints().rend(); ++itr )
567 const std::vector<LENGTH_DELAY_CALCULATION_ITEM*>& aLines )
571 const PAD*
pad = padItem->GetPad();
579 const PCB_LAYER_ID pcbLayer = lineItem->GetStartLayer();
589 const std::vector<LENGTH_DELAY_CALCULATION_ITEM*>& aVias, std::vector<LENGTH_DELAY_CALCULATION_ITEM*>& aLines,
590 std::map<
VECTOR2I, std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>>& aLinesPositionMap,
591 const std::map<
VECTOR2I, std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>>& aPadsPositionMap )
595 auto lineItr = aLinesPositionMap.find(
via->GetVia()->GetPosition() );
597 if( lineItr == aLinesPositionMap.end() )
600 std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>& connectedLines = lineItr->second;
602 if( connectedLines.empty() )
605 via->SetLayers(
via->GetVia()->GetLayer(),
via->GetVia()->GetLayer() );
607 else if( connectedLines.size() == 1 )
610 bool isViaInPad =
false;
611 const PCB_LAYER_ID lineLayer = ( *connectedLines.begin() )->GetStartLayer();
613 auto padItr = aPadsPositionMap.find(
via->GetVia()->GetPosition() );
615 if( padItr != aPadsPositionMap.end() )
618 const std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>& pads = padItr->second;
620 if( pads.size() == 1 )
636 via->SetLayers( lineLayer, lineLayer );
646 layers.
set( lineItem->GetStartLayer() );
662 via->SetLayers( firstLayer, firstLayer );
664 via->SetLayers( firstLayer, lastLayer );
682 if( shape->Contains( aLine.
CPoint( 0 ) ) )
684 else if( shape->Contains( aLine.
CLastPoint() ) )
723 std::vector<VECTOR2I> points{ track->GetStart(), track->GetEnd() };
734 else if(
const PAD*
pad =
dynamic_cast<const PAD*
>( aBoardItem ) )
739 const LSET& layers =
pad->Padstack().LayerSet();
751 item.
SetLayers( firstLayer, secondLayer );
762 std::unique_ptr<TUNING_PROFILE_PARAMETERS_IFACE>&& aProvider )
BASE_SET & set(size_t pos)
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual NETCLASS * GetEffectiveNetClass() const
Return the NETCLASS for this item.
Manage layers needed to make a physical board.
void BuildDefaultStackupList(const BOARD_DESIGN_SETTINGS *aSettings, int aActiveCopperLayersCount=0)
Create a default stackup, according to the current BOARD_DESIGN_SETTINGS settings.
int GetLayerDistance(PCB_LAYER_ID aFirstLayer, PCB_LAYER_ID aSecondLayer) const
Calculate the distance (height) between the two given copper layers.
Lightweight class which holds a pad, via, or a routed trace outline.
void SetLine(const SHAPE_LINE_CHAIN &aLine)
Sets the source SHAPE_LINE_CHAIN of this item.
void SetVia(const PCB_VIA *aVia)
Sets the VIA associated with this item.
TYPE Type() const
Gets the routing item type.
void SetPad(const PAD *aPad)
Sets the parent PAD associated with this item.
void SetMergeStatus(const MERGE_STATUS aStatus)
Sets the MERGE_STATUS of this item.
SHAPE_LINE_CHAIN & GetLine() const
Gets the SHAPE_LINE_CHAIN associated with this item.
const PAD * GetPad() const
Gets the parent PAD associated with this item.
PCB_LAYER_ID GetStartLayer() const
Gets the start board layer for the proxied item.
void SetEffectiveNetClass(const NETCLASS *aNetClass)
Sets the effective net class for the item.
void CalculateViaLayers(const BOARD *aBoard)
Calculates active via payers for a proxied VIA object.
void SetLayers(const PCB_LAYER_ID aStart, const PCB_LAYER_ID aEnd=PCB_LAYER_ID::UNDEFINED_LAYER)
Sets the first and last layers associated with this item.
std::unique_ptr< TUNING_PROFILE_PARAMETERS_IFACE > m_tuningProfileParameters
The active provider of tuning profile parameters.
int64_t CalculateLengthForDelay(int64_t aDesiredDelay, const TUNING_PROFILE_GEOMETRY_CONTEXT &aCtx) const
Calculates the length of track required for the given delay in a specific geometry context.
int64_t CalculatePropagationDelayForShapeLineChain(const SHAPE_LINE_CHAIN &aShape, const TUNING_PROFILE_GEOMETRY_CONTEXT &aCtx) const
Gets the propagation delay for the given shape line chain.
static void clipLineToPad(SHAPE_LINE_CHAIN &aLine, const PAD *aPad, PCB_LAYER_ID aLayer, bool aForward=true)
Clips the given line to the minimal direct electrical length within the pad.
MERGE_POINT
Enum to describe whether track merging is attempted from the start or end of a track segment.
void inferViaInPad(const PAD *aPad, const LENGTH_DELAY_CALCULATION_ITEM &aItem, LENGTH_DELAY_STATS &aDetails) const
Infers if there is a via in the given pad.
static void optimiseTracesInPads(const std::vector< LENGTH_DELAY_CALCULATION_ITEM * > &aPads, const std::vector< LENGTH_DELAY_CALCULATION_ITEM * > &aLines)
Optimises the given set of items to minimise the electrical path length.
static void mergeLines(std::vector< LENGTH_DELAY_CALCULATION_ITEM * > &aLines, std::map< VECTOR2I, std::unordered_set< LENGTH_DELAY_CALCULATION_ITEM * > > &aLinesPositionMap)
Merges any lines (traces) that are contiguous, on one layer, and with no junctions.
int64_t CalculateDelay(std::vector< LENGTH_DELAY_CALCULATION_ITEM > &aItems, PATH_OPTIMISATIONS aOptimisations, const PAD *aStartPad=nullptr, const PAD *aEndPad=nullptr) const
Calculates the electrical propagation delay of the given items.
int64_t CalculateLength(std::vector< LENGTH_DELAY_CALCULATION_ITEM > &aItems, PATH_OPTIMISATIONS aOptimisations, const PAD *aStartPad=nullptr, const PAD *aEndPad=nullptr) const
Calculates the electrical length of the given items.
int StackupHeight(PCB_LAYER_ID aFirstLayer, PCB_LAYER_ID aSecondLayer) const
Returns the stackup distance between the two given layers.
void SynchronizeTuningProfileProperties() const
Ensure time domain properties provider is synced with board / project settings if required.
BOARD * m_board
The parent board for all items.
LENGTH_DELAY_CALCULATION_ITEM GetLengthCalculationItem(const BOARD_CONNECTED_ITEM *aBoardItem) const
Return a LENGTH_CALCULATION_ITEM constructed from the given BOARD_CONNECTED_ITEM.
static void optimiseViaLayers(const std::vector< LENGTH_DELAY_CALCULATION_ITEM * > &aVias, std::vector< LENGTH_DELAY_CALCULATION_ITEM * > &aLines, std::map< VECTOR2I, std::unordered_set< LENGTH_DELAY_CALCULATION_ITEM * > > &aLinesPositionMap, const std::map< VECTOR2I, std::unordered_set< LENGTH_DELAY_CALCULATION_ITEM * > > &aPadsPositionMap)
Optimises the via layers.
void SetTuningProfileParametersProvider(std::unique_ptr< TUNING_PROFILE_PARAMETERS_IFACE > &&aProvider)
Sets the provider for tuning profile parameter resolution.
static void mergeShapeLineChains(SHAPE_LINE_CHAIN &aPrimary, const SHAPE_LINE_CHAIN &aSecondary, MERGE_POINT aMergePoint)
Merges two SHAPE_LINE_CHAINs where there is a shared endpoing.
static bool findArcPadIntersection(const SHAPE_ARC &aArc, const std::shared_ptr< SHAPE_POLY_SET > &aPadShape, const VECTOR2I &aInsidePoint, VECTOR2I &aIntersection)
Finds the intersection point between an arc and a pad shape.
LENGTH_DELAY_STATS CalculateLengthDetails(std::vector< LENGTH_DELAY_CALCULATION_ITEM > &aItems, PATH_OPTIMISATIONS aOptimisations, const PAD *aStartPad=nullptr, const PAD *aEndPad=nullptr, LENGTH_DELAY_LAYER_OPT aLayerOpt=LENGTH_DELAY_LAYER_OPT::NO_LAYER_DETAIL, LENGTH_DELAY_DOMAIN_OPT aDomain=LENGTH_DELAY_DOMAIN_OPT::NO_DELAY_DETAIL) const
Calculates the electrical length of the given items.
static void OptimiseTraceInPad(SHAPE_LINE_CHAIN &aLine, const PAD *aPad, PCB_LAYER_ID aPcbLayer)
Optimises the given trace / line to minimise the electrical path length within the given pad.
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
LSET is a set of PCB_LAYER_IDs.
copper_layers_iterator copper_layers_end() const
LSEQ CuStack() const
Return a sequence of copper layers in starting from the front/top and extending to the back/bottom.
copper_layers_iterator copper_layers_begin() const
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
const LSET & LayerSet() const
bool FlashLayer(int aLayer, bool aOnlyCheckIfPermitted=false) const
Check to see whether the pad should be flashed on the specific layer.
VECTOR2I GetPosition() const override
const PADSTACK & Padstack() const
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
const VECTOR2I & GetMid() const
const VECTOR2I & GetStart() const
const VECTOR2I & GetEnd() const
virtual int GetWidth() const
bool Contains(const SEG &aSeg) const
int IntersectLine(const SEG &aSeg, std::vector< VECTOR2I > *aIpsBuffer) const
Find intersection points between this arc and aSeg, treating aSeg as an infinite line.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const SHAPE_ARC & Arc(size_t aArc) const
virtual const VECTOR2I GetPoint(int aIndex) const override
int PointCount() const
Return the number of points (vertices) in this line chain.
ssize_t ArcIndex(size_t aSegment) const
Return the arc index for the given segment index.
const std::vector< SHAPE_ARC > & CArcs() const
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
const SHAPE_LINE_CHAIN Slice(int aStartIndex, int aEndIndex) const
Return a subset of this line chain containing the [start_index, end_index] range of points.
int SegmentCount() const
Return the number of segments in this line chain.
const VECTOR2I & CLastPoint() const
Return the last point in the line chain.
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
void Insert(size_t aVertex, const VECTOR2I &aP)
const std::vector< VECTOR2I > & CPoints() const
a few functions useful in geometry calculations.
PCB_LAYER_ID
A quick note on layer IDs:
LENGTH_DELAY_DOMAIN_OPT
Enum which controls the calculation domain of the length / delay calculation methods.
LENGTH_DELAY_LAYER_OPT
Enum which controls the level of detail returned by the length / delay calculation methods.
Holds length measurement result details and statistics.
std::unique_ptr< std::map< PCB_LAYER_ID, int64_t > > LayerDelays
int64_t TotalLength() const
Calculates the total electrical length for this set of statistics.
std::unique_ptr< std::map< PCB_LAYER_ID, int64_t > > LayerLengths
int64_t TotalDelay() const
Calculates the total electrical propagation delay for this set of statistics.
Struct to control which optimisations the length calculation code runs on the given path objects.
bool InferViaInPad
Determines if there is a via-in-pad present on the board but not in the item set.
bool OptimiseViaLayers
Optimise via layers for height calculations, ensuring only the distance between routed segments is co...
bool MergeTracks
Merges all contiguous (end-to-end, same layer) tracks.
bool OptimiseTracesInPads
Optimises the electrical length of tracks within pads.
A data structure to contain basic geometry data which can affect signal propagation calculations.
const NETCLASS * NetClass
The net class this track belongs to.
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ 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