53 LINE l =
m_world->AssembleLine( root,
nullptr,
false,
false,
false );
73 std::deque<const JOINT*> searchQueue;
76 searchQueue.push_back( aStart );
77 processed.insert( aStart );
79 while( !searchQueue.empty() )
81 const JOINT* current = searchQueue.front();
82 searchQueue.pop_front();
88 const JOINT* a =
m_world->FindJoint( item->Anchor( 0 ), item );;
89 const JOINT* b =
m_world->FindJoint( item->Anchor( 1 ), item );;
90 const JOINT*
next = ( *a == *current ) ? b : a;
92 if( processed.find(
next ) == processed.end() )
94 processed.insert(
next );
95 searchQueue.push_back(
next );
108 LINE track( *aTrack );
114 std::unique_ptr<NODE> tmpNode(
m_world->Branch() );
117 tmpNode->Add( track );
121 if( !jt ||
m_world->GetRuleResolver()->NetCode( jt->
Net() ) <= 0 )
170 std::set<ITEM*> disconnected;
172 m_world->AllItemsInNet( aStart->
Net(), disconnected );
176 for(
ITEM* link : jt->LinkList() )
178 if( disconnected.find( link ) != disconnected.end() )
179 disconnected.erase( link );
183 int best_dist = INT_MAX;
184 ITEM* best =
nullptr;
186 for(
ITEM* item : disconnected )
188 if( item->OfKind( aKindMask ) )
190 for(
int i = 0; i < item->AnchorCount(); i++ )
193 int d = ( p - aStart->
Pos() ).EuclideanNorm();
212 std::set<ITEM*>& aVisited,
213 bool aFollowLockedSegments )
215 using clock = std::chrono::steady_clock;
218 best.
m_end = aStartJoint;
221 auto startTime = clock::now();
231 std::set<const JOINT*> visitedJoints;
235 std::stack<STATE> stateStack;
239 initial.joint = aStartJoint;
240 initial.prev = aPrev;
241 initial.pathLength = 0;
242 initial.visitedJoints.insert( aStartJoint );
243 initial.via =
nullptr;
245 stateStack.push( std::move( initial ) );
247 while( !stateStack.empty() )
250 auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
251 clock::now() - startTime ).count();
253 if( elapsed > timeoutMs )
255 wxLogTrace( wxT(
"PNS_TUNE" ),
256 wxT(
"followBranch: timeout after %lld ms, returning best path found" ),
261 STATE current = std::move( stateStack.top() );
264 const JOINT* joint = current.joint;
270 for(
ITEM* link : links )
272 if( link->OfKind(
ITEM::VIA_T ) && !aVisited.contains( link ) )
280 bool foundBranch =
false;
282 for(
ITEM* link : links )
287 if( link == current.prev )
290 if( aVisited.contains( link ) )
294 false, aFollowLockedSegments );
302 if( current.visitedJoints.count( nextJoint ) )
309 nextState.joint = nextJoint;
310 nextState.prev = l.
Links().back();
311 nextState.pathItems = current.pathItems;
312 nextState.pathLength = current.pathLength + l.
CLine().
Length();
313 nextState.visitedJoints = current.visitedJoints;
314 nextState.visitedJoints.insert( nextJoint );
319 nextState.pathItems.Add(
via );
321 nextState.pathItems.Add( l );
323 stateStack.push( std::move( nextState ) );
329 if( current.pathLength > best.
m_length )
333 best.
m_items = current.pathItems;
338 wxLogTrace( wxT(
"PNS_TUNE" ),
339 wxT(
"followBranch: completed with best path length=%d, %d items" ),
347 const JOINT** aTerminalJointB,
348 bool aFollowLockedSegments )
352 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"=== followTrivialPath START ===" ) );
353 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"followTrivialPath: initial line has %d segments, %zu links" ),
355 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"followTrivialPath: line endpoints: (%d,%d) to (%d,%d)" ),
362 std::set<ITEM*> visited;
365 visited.insert( link );
370 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"followTrivialPath: LEFT branch starting from joint at (%d,%d)" ),
373 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"followTrivialPath: LEFT branch result: length=%d, %d items" ),
374 left.m_length,
left.m_items.Size() );
376 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"followTrivialPath: RIGHT branch starting from joint at (%d,%d)" ),
379 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"followTrivialPath: RIGHT branch result: length=%d, %d items" ),
382 if( aTerminalJointA )
383 *aTerminalJointA =
left.m_end;
385 if( aTerminalJointB )
386 *aTerminalJointB =
right.m_end;
389 int leftSegCount = 0;
390 int rightSegCount = 0;
391 int initialSegCount = 0;
400 path.Prepend( item );
403 LINE* l =
dynamic_cast<LINE*
>( item );
417 LINE* l =
dynamic_cast<LINE*
>( item );
428 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"" ) );
429 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"=== followTrivialPath SUMMARY ===" ) );
430 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"Starting segment count: %d" ), initialSegCount );
431 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"Left branch: %d segments, length=%d" ), leftSegCount,
left.m_length );
432 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"Initial line: %d segments, length=%lld" ), initialSegCount, aLine2->
CLine().
Length() );
433 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"Right branch: %d segments, length=%d" ), rightSegCount,
right.m_length );
434 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"Total segments in path: %d" ), leftSegCount + initialSegCount + rightSegCount );
435 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"Total path length: %d" ), totalLength );
436 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"Total items in result: %d" ),
path.Size() );
437 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"=== followTrivialPath END ===" ) );
438 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"" ) );
445 std::pair<const JOINT*, const JOINT*>* aTerminalJoints,
446 bool aFollowLockedSegments )
448 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"*** AssembleTrivialPath: START ***" ) );
449 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"AssembleTrivialPath: aStart=%p, kind=%s" ),
450 aStart, aStart->
KindStr().c_str() );
457 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"AssembleTrivialPath: starting from VIA" ) );
463 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"AssembleTrivialPath: VIA is fanout, returning empty" ) );
469 for(
ITEM* item : links )
474 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"AssembleTrivialPath: found segment/arc from VIA" ) );
482 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"AssembleTrivialPath: starting from SEGMENT/ARC" ) );
487 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"AssembleTrivialPath: no segment found, returning empty" ) );
493 LINE l =
m_world->AssembleLine( seg,
nullptr,
false, aFollowLockedSegments );
495 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"AssembleTrivialPath: assembled line with %d segments, length=%lld" ),
498 const JOINT* jointA =
nullptr;
499 const JOINT* jointB =
nullptr;
503 if( aTerminalJoints )
505 wxASSERT( jointA && jointB );
506 *aTerminalJoints = std::make_pair( jointA, jointB );
507 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"AssembleTrivialPath: terminal joints at (%d,%d) and (%d,%d)" ),
511 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"AssembleTrivialPath: returning path with %d items" ),
path.Size() );
512 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"*** AssembleTrivialPath: END ***" ) );
513 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"" ) );
522 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"" ) );
523 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"########## AssembleTuningPath: START ##########" ) );
524 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"AssembleTuningPath: aStart=%p, kind=%s" ),
525 aStart, aStart->
KindStr().c_str() );
527 std::pair<const JOINT*, const JOINT*> joints;
530 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"AssembleTuningPath: initial path has %d items" ), initialPath.
Size() );
535 auto getPadFromJoint =
536 [](
const JOINT* aJoint,
PAD** aTargetPad,
SOLID** aTargetSolid )
546 *aTargetPad =
static_cast<PAD*
>( bi );
549 *aTargetSolid =
static_cast<SOLID*
>( item );
559 getPadFromJoint( joints.first, &padA, aStartPad );
561 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"AssembleTuningPath: found start pad at joint (%d,%d)" ),
562 joints.first->Pos().x, joints.first->Pos().y );
567 getPadFromJoint( joints.second, &padB, aEndPad );
569 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"AssembleTuningPath: found end pad at joint (%d,%d)" ),
570 joints.second->Pos().x, joints.second->Pos().y );
575 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"AssembleTuningPath: no pads found, returning initial path" ) );
576 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"########## AssembleTuningPath: END ##########" ) );
577 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"" ) );
581 auto processPad = [&](
PAD* aPad,
int aLayer )
583 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"AssembleTuningPath: processing pad, optimizing trace in pad" ) );
584 for(
int idx = 0; idx < initialPath.
Size(); idx++ )
589 LINE* line =
static_cast<LINE*
>( initialPath[idx] );
593 int lengthBefore = slc.
Length();
595 int lengthAfter = slc.
Length();
597 if( lengthBefore != lengthAfter )
598 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"AssembleTuningPath: optimized line %d, length changed from %d to %d" ),
599 idx, lengthBefore, lengthAfter );
604 processPad( padA, joints.first->Layer() );
607 processPad( padB, joints.second->Layer() );
612 for(
int idx = 0; idx < initialPath.
Size(); idx++ )
616 LINE* line =
static_cast<LINE*
>( initialPath[idx] );
622 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"AssembleTuningPath: final path has %d items, %d lines, total length=%d" ),
623 initialPath.
Size(), lineCount, totalLength );
624 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"########## AssembleTuningPath: END ##########" ) );
625 wxLogTrace( wxT(
"PNS_TUNE" ), wxT(
"" ) );
652 if( !coupledNet || !startItem )
657 std::vector<ITEM*> pItems;
658 std::vector<ITEM*> nItems;
663 pItems.push_back( item );
666 std::set<ITEM*> coupledItems;
667 m_world->AllItemsInNet( coupledNet, coupledItems );
669 for(
ITEM* item : coupledItems )
672 nItems.push_back( item );
677 SEG::ecoord minDist_sq = std::numeric_limits<SEG::ecoord>::max();
678 SEG::ecoord minDistTarget_sq = std::numeric_limits<SEG::ecoord>::max();
681 auto findNItem = [&](
ITEM* p_item )
683 for(
ITEM* n_item : nItems )
685 SEG::ecoord dist_sq = std::numeric_limits<SEG::ecoord>::max();
687 if( n_item->Kind() != p_item->Kind() )
710 const ARC* p_arc =
static_cast<const ARC*
>( p_item );
711 const ARC* n_arc =
static_cast<const ARC*
>( n_item );
725 if( dist_sq <= minDist_sq )
727 SEG::ecoord distTarget_sq = n_item->Shape( -1 )->SquaredDistance( targetPoint );
728 if( distTarget_sq < minDistTarget_sq )
730 minDistTarget_sq = distTarget_sq;
731 minDist_sq = dist_sq;
740 findNItem( startItem );
745 std::set<ITEM*> linksToTest;
757 linksToTest.emplace( link );
761 for(
ITEM* link : linksToTest )
770 if(
m_world->GetRuleResolver()->DpNetPolarity( refNet ) < 0 )
784 const ARC* refArc =
static_cast<ARC*
>( refItem );
785 const ARC* coupledArc =
static_cast<ARC*
>( coupledItem );
800 std::deque<ITEM*> pending;
807 pending.push_back( aStart );
810 int64_t initialArea = clusterBBox.
GetArea();
812 while( !pending.empty() )
821 m_world->QueryColliding(
top, obstacles, opts );
823 for(
const OBSTACLE& obs : obstacles )
830 if( aExcludedNet && obs.m_item->Net() == aExcludedNet )
836 clusterBBox.
Merge( line.CLine().BBox() );
840 clusterBBox.
Merge( obs.m_item->Shape( aLayer )->BBox() );
843 const int64_t currentArea = clusterBBox.
GetArea();
844 const double areaRatio = (double) currentArea / (
double) ( initialArea + 1 );
846 if( aAreaExpansionLimit > 0.0 && areaRatio > aAreaExpansionLimit )
849 if( cluster.
m_items.find( obs.m_item ) == cluster.
m_items.end() &&
850 obs.m_item->Layers().Overlaps( aLayer ) && !( obs.m_item->Marker() &
MK_HEAD ) )
852 cluster.
m_items.insert( obs.m_item );
853 pending.push_back( obs.m_item );
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
constexpr ecoord_type GetArea() const
Return the area of the rectangle.
KICAD_T Type() const
Returns the type of object.
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.
int Width() const override
const SHAPE_ARC & CArc() const
Basic class for a differential pair.
void SetWidth(int aWidth)
Base class for PNS router board items.
void SetLayers(const PNS_LAYER_RANGE &aLayers)
virtual const SHAPE * Shape(int aLayer) const
Return the geometrical shape of the item.
const PNS_LAYER_RANGE & Layers() const
virtual NET_HANDLE Net() const
PnsKind Kind() const
Return the type (kind) of the item.
virtual int Layer() const
bool OfKind(int aKindMask) const
virtual VECTOR2I Anchor(int n) const
std::string KindStr() const
virtual int AnchorCount() const
A 2D point on a given set of layers and belonging to a certain net, that links together a number of b...
const std::vector< ITEM * > & LinkList() const
NET_HANDLE Net() const override
int LinkCount(int aMask=-1) const
bool IsNonFanoutVia() const
const ITEM_SET & CLinks() const
const VECTOR2I & Pos() const
Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,...
const VECTOR2I & CPoint(int aIdx) const
void SetShape(const SHAPE_LINE_CHAIN &aLine)
Return the shape of the line.
const SHAPE_LINE_CHAIN & CLine() const
const VECTOR2I & CLastPoint() const
SHAPE_LINE_CHAIN & Line()
void Reverse()
Clip the line to the nearest obstacle, traversing from the line's start vertex (0).
int Width() const
Return true if the line is geometrically identical as line aOther.
bool IsLinked() const
Check if the segment aLink is a part of the line.
std::vector< LINKED_ITEM * > & Links()
LINKED_ITEM * GetLink(int aIndex) const
Erase the linking information. Used to detach the line from the owning node.
virtual void ClearLinks()
Return the number of segments that were assembled together to form this line.
std::set< OBSTACLE > OBSTACLES
virtual PCB_LAYER_ID GetBoardLayerFromPNSLayer(int aLayer) const =0
int Width() const override
ITEM * NearestUnconnectedItem(const JOINT *aStart, int *aAnchor=nullptr, int aKindMask=ITEM::ANY_T)
std::set< const JOINT * > JOINT_SET
bool LeadingRatLine(const LINE *aTrack, SHAPE_LINE_CHAIN &aRatLine)
const DIFF_PAIR AssembleDiffPair(SEGMENT *aStart)
ITEM_SET followTrivialPath(LINE *aLine, const JOINT **aTerminalJointA, const JOINT **aTerminalJointB, bool aFollowLockedSegments=false)
const ITEM_SET ConnectedItems(const JOINT *aStart, int aKindMask=ITEM::ANY_T)
bool NearestUnconnectedAnchorPoint(const LINE *aTrack, VECTOR2I &aPoint, PNS_LAYER_RANGE &aLayers, ITEM *&aItem)
const CLUSTER AssembleCluster(ITEM *aStart, int aLayer, double aAreaExpansionLimit=0.0, NET_HANDLE aExcludedNet=nullptr)
const JOINT_SET ConnectedJoints(const JOINT *aStart)
const ITEM_SET AssembleTuningPath(ROUTER_IFACE *aRouterIface, ITEM *aStart, SOLID **aStartPad=nullptr, SOLID **aEndPad=nullptr)
Like AssembleTrivialPath, but follows the track length algorithm, which discards segments that are fu...
const int DP_PARALLELITY_THRESHOLD
PATH_RESULT followBranch(const JOINT *aStartJoint, LINKED_ITEM *aPrev, std::set< ITEM * > &aVisited, bool aFollowLockedSegments)
const ITEM_SET AssembleTrivialPath(ITEM *aStart, std::pair< const JOINT *, const JOINT * > *aTerminalJoints=nullptr, bool aFollowLockedSegments=false)
Assemble a trivial path between two joints given a starting item.
bool SimplifyLine(LINE *aLine)
Represent a contiguous set of PCB layers.
ecoord SquaredDistance(const SEG &aSeg) const
VECTOR2I::extended_type ecoord
static SEG::ecoord Square(int a)
bool ApproxParallel(const SEG &aSeg, int aDistanceThreshold=1) const
const VECTOR2I & GetCenter() const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int PointCount() const
Return the number of points (vertices) in this line chain.
void Clear()
Remove all points from the line chain.
void Simplify(int aTolerance=0)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
long long int Length() const
Return length of the line chain in Euclidean metric.
virtual VECTOR2I Centre() const
Compute a center-of-mass of the shape.
virtual const BOX2I BBox(int aClearance=0) const =0
Compute a bounding box of the shape, with a margin of aClearance a collision.
constexpr extended_type Cross(const VECTOR2< T > &aVector) const
Compute cross product of self with aVector.
constexpr extended_type SquaredEuclideanNorm() const
Compute the squared euclidean norm of the vector, which is defined as (x ** 2 + y ** 2).
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
int m_FollowBranchTimeout
Timeout for the PNS router's followBranch path search, in milliseconds.
PCB_LAYER_ID
A quick note on layer IDs:
Push and Shove diff pair dimensions (gap) settings dialog.
bool commonParallelProjection(SEG p, SEG n, SEG &pClip, SEG &nClip)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Hold an object colliding with another object, along with some useful data about the collision.
std::set< ITEM * > m_items
KIBIS top(path, &reporter)
@ PCB_PAD_T
class PAD, a pad in a footprint
VECTOR2< int32_t > VECTOR2I