49 if( aPrimitives.
Empty() )
60 bool redundant =
false;
63 if( l.originalLine.ContainsLink( litem ) )
65 l.originalLeaders.push_back( litem );
85 bool anyStrictCornersFound =
false;
86 bool anyStrictMidSegsFound =
false;
90 const int thr = l.originalLine.Width() / 2;
92 const VECTOR2I& origFirst = l.originalLine.CLine().CPoint( 0 );
93 const int distFirst = ( origFirst - aP ).EuclideanNorm();
95 const VECTOR2I& origLast = l.originalLine.CLine().CPoint( -1 );
96 const int distLast = ( origLast - aP ).EuclideanNorm();
98 l.cornerDistance = std::min( distFirst, distLast );
102 l.cornerIsLast =
true;
103 l.leaderSegIndex = l.originalLine.SegmentCount() - 1;
104 l.cornerDistance = distLast;
107 if( distLast <= thr )
110 l.cornerDistance = 0;
116 l.cornerIsLast =
false;
117 l.leaderSegIndex = 0;
118 l.cornerDistance = distFirst;
121 if( distFirst <= thr )
124 l.cornerDistance = 0;
130 const auto& links = l.originalLine.Links();
132 for(
int lidx = 0; lidx < (int) links.size(); lidx++ )
134 if(
auto lseg = dyn_cast<SEGMENT*>( links[lidx] ) )
140 int d = lseg->Seg().Distance( aP );
142 l.midSeg = lseg->Seg();
144 l.leaderSegIndex = lidx;
145 l.leaderSegDistance = d + thr;
147 if( d < thr && !l.isStrict )
151 l.leaderSegDistance = 0;
158 anyStrictCornersFound |= l.isCorner;
159 anyStrictMidSegsFound |= !l.isCorner;
163 if( anyStrictCornersFound )
165 else if (anyStrictMidSegsFound )
169 int minLeadSegDist = std::numeric_limits<int>::max();
170 int minCornerDist = std::numeric_limits<int>::max();
176 if( l.cornerDistance < minCornerDist )
181 if( l.leaderSegDistance < minLeadSegDist )
188 if( bestCorner && bestSeg )
190 if( minCornerDist < minLeadSegDist )
201 else if ( bestCorner )
219 if ( !l.cornerIsLast )
221 l.originalLine.Reverse();
222 l.cornerIsLast =
true;
228 assert (jt !=
nullptr);
239 if( (anyStrictCornersFound || anyStrictMidSegsFound) && l.isStrict )
241 l.isPrimaryLine =
true;
279 std::set<OBSTACLE> obstacles;
282 constexpr int clipLengthThreshold = 100;
289 bool didClip =
false;
291 int step = curL / 2 - 1;
293 while( step > clipLengthThreshold )
297 int idx = sl_tmp.
Split( pclip );
298 sl_tmp = sl_tmp.
Slice(0, idx);
331 std::set<NET_HANDLE> uniqueNets;
336 uniqueNets.insert( net );
339 return std::vector<NET_HANDLE>( uniqueNets.begin(), uniqueNets.end() );
397 PNS_DBG(
Dbg(), Message, wxString::Format(
"s %d ip=%d c=%s o=%s", i, ip?1:0, curDir.
Format(), origLeaderDir.
Format() ));
400 if( curDir == origLeaderDir || curDir == origLeaderDir.
Opposite() )
412 for(
auto& l : aCompletedLines )
418 if( l.draggedLine.LinkCount() > 0 )
421 static_cast<PNS::ITEM*
>( l.draggedLine.GetLink( -1 ) ) );
427 if( newLeaderIdx >= 0 )
430 static_cast<PNS::ITEM*
>( l.draggedLine.GetLink( newLeaderIdx ) ) );
451 std::sort( aCompletedLines.begin(), aCompletedLines.end(), compareDragStartDist );
456 for(
auto& l : aCompletedLines )
458 PNS_DBG(
Dbg(), AddItem, &l.originalLine,
BLUE, 100000, wxString::Format(
"prewalk-remove lc=%d", l.originalLine.LinkCount() ) );
459 preWalkNode->
Remove( l.originalLine );
467 for(
int attempt = 0; attempt < 2; attempt++ )
469 NODE *node = tmpNodes[attempt] = preWalkNode->
Branch();
470 totalLength[attempt] = 0;
473 for(
int lidx = 0; lidx < aCompletedLines.size(); lidx++ )
475 MDRAG_LINE& l = aCompletedLines[attempt ? aCompletedLines.size() - 1 - lidx : lidx];
481 PNS_DBG(
Dbg(), AddItem, &walk,
BLUE, 100000, wxString::Format(
"walk lidx=%d attempt=%d", lidx, attempt) );
493 tmpNodes[attempt] =
nullptr;
506 if( tmpNodes[0] && tmpNodes[1] )
508 if ( totalLength[0] < totalLength[1] )
521 else if ( tmpNodes[0] )
526 else if ( tmpNodes[1] )
556 for(
int l1 = 0; l1 < aCompletedLines.size(); l1++ )
558 for(
int l2 = l1 + 1; l2 < aCompletedLines.size(); l2++ )
560 auto l1l = aCompletedLines[l1].draggedLine;
561 auto l2l = aCompletedLines[l2].draggedLine;
565 aCompletedLines[l2].draggedLine = l2l;
571 for (
auto&l : aCompletedLines )
598 std::sort( aCompletedLines.begin(), aCompletedLines.end(), compareDragStartDist );
604 PNS_DBG(
Dbg(), Message, wxString::Format ( wxT(
"net %-30s: isCorner %d isStrict %d c-Dist %-10d l-dist %-10d leadIndex %-2d CisLast %d dragDist %-10d"),
605 iface->GetNetName( l.draggedLine.Net() ),
606 (
int) l.isCorner?1:0,
607 (
int) l.isStrict?1:0,
608 (
int) l.cornerDistance,
609 (
int) l.leaderSegDistance,
610 (
int) l.leaderSegIndex,
611 (
int) l.cornerIsLast?1:0,
612 (
int) l.dragDist ) );
619 for(
auto& l : aCompletedLines )
631 for(
int i = 0; i < aCompletedLines.size(); i++ )
634 if(
m_shove->HeadsModified( i ) )
654 std::optional<LINE> primaryPreDrag, primaryDragged;
663 std::vector<MDRAG_LINE> completed;
665 auto tryPosture = [&] (
int aVariant ) ->
bool
672 l.preDragLine = l.originalLine;
674 if( l.isPrimaryLine )
682 primaryDragged = l.originalLine;
683 primaryDragged->ClearLinks();
684 primaryPreDrag = l.originalLine;
690 if( aVariant == 1 && (primaryPreDrag->PointCount() > 2) )
692 primaryPreDrag->Line().Remove( -1 );
693 primaryDragged->Line().Remove( -1 );
710 lastPreDrag = primaryPreDrag->CSegment( -1 );
713 primaryDragged->SetSnapThreshhold( snapThreshold );
714 primaryDragged->DragCorner( aP, primaryDragged->PointCount() - 1,
false );
716 SEG lastPrimDrag = primaryDragged->CSegment( -1 );
719 lastPrimDrag = lastPreDrag;
721 if( primaryDragged->SegmentCount() > 0 )
723 auto lastSeg = primaryDragged->CSegment( -1 );
726 if( lastSeg.Length() < primaryDragged->Width() )
728 lastPrimDrag = lastPreDrag;
733 perp = (lastPrimDrag.
B - lastPrimDrag.
A).Perpendicular();
745 lastPreDrag = primaryDragged->CSegment( primaryLine->
leaderSegIndex );
746 primaryDragged->SetSnapThreshhold( snapThreshold );
748 perp = (primaryLine->
midSeg.
B - primaryLine->
midSeg.
A).Perpendicular();
766 if( l.preDragLine.SegmentCount() >= 1 )
779 DIRECTION_45 parallelDir( l.preDragLine.CSegment( -1 ) );
781 auto leadAngle = primaryDir.
Angle( parallelDir );
788 int dist = lastPreDrag.
LineDistance( l.preDragLine.CPoint( -1 ),
true );
791 auto projected = aP + perp.
Resize( dist );
794 LINE parallelDragged( l.preDragLine );
801 false, primaryLastSegDir );
808 if( !l.isPrimaryLine )
810 l.draggedLine = parallelDragged;
811 completed.push_back( l );
818 SEG sdrag = l.midSeg;
821 auto ang = refDir.
Angle( curDir );
826 l.preDragLine.CPoint( l.leaderSegIndex ),
true );
827 auto projected = aP + perp.
Resize( dist );
829 SEG sperp( aP, aP + perp.
Resize( 10000000 ) );
842 if( !l.isPrimaryLine )
844 l.draggedLine = l.preDragLine;
845 l.draggedLine.ClearLinks();
846 l.draggedLine.SetSnapThreshhold( snapThreshold );
847 l.draggedLine.DragSegment( projected, l.leaderSegIndex,
false );
848 completed.push_back( l );
855 wxT(
"startProj" ) );
857 wxString::Format(
"pro dd=%d", l.dragDist ) );
865 l.draggedLine = *primaryDragged;
867 completed.push_back( l );
875 for (
const auto &l: completed )
877 if( !l.dragOK && aVariant < 2 )
880 if( l.isPrimaryLine )
885 if( lastDir != primaryLastSegDir )
895 for(
int variant = 0; variant < 3; variant++ )
897 res = tryPosture( 0 );
Represent route directions & corner angles in a 45-degree metric.
AngleType Angle(const DIRECTION_45 &aOther) const
Return the type of angle between directions (this) and aOther.
const std::string Format() const
Format the direction in a human readable word.
DIRECTION_45 Opposite() const
Return a direction opposite (180 degree) to (this).
void SetDebugDecorator(DEBUG_DECORATOR *aDecorator)
Assign a debug decorator allowing this algo to draw extra graphics for visual debugging.
void SetLogger(LOGGER *aLogger)
virtual LOGGER * Logger()
ROUTER * Router() const
Return current router settings.
ROUTING_SETTINGS & Settings() const
Return the logger object, allowing to dump geometry to a file.
DEBUG_DECORATOR * Dbg() const
void Add(const LINE &aLine)
bool Contains(ITEM *aItem) const
std::vector< ITEM * > & Items()
ITEM * FindVertex(const VECTOR2I &aV) const
const std::vector< ITEM * > & CItems() const
Base class for PNS router board items.
virtual int Layer() const
bool Collide(const ITEM *aHead, const NODE *aNode, int aLayer, COLLISION_SEARCH_CONTEXT *aCtx=nullptr) const
Check for a collision (clearance violation) with between us and item aOther.
A 2D point on a given set of layers and belonging to a certain net, that links together a number of b...
bool IsTrivialEndpoint() const
Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,...
void SetShape(const SHAPE_LINE_CHAIN &aLine)
Return the shape of the line.
const SHAPE_LINE_CHAIN & CLine() const
SHAPE_LINE_CHAIN & Line()
void DragCorner(const VECTOR2I &aP, int aIndex, bool aFreeAngle=false, DIRECTION_45 aPreferredEndingDirection=DIRECTION_45())
const SEG CSegment(int aIdx) const
Set line width.
virtual void ClearLinks()
Return the number of segments that were assembled together to form this line.
bool multidragShove(std::vector< MDRAG_LINE > &aCompletedLines)
bool multidragMarkObstacles(std::vector< MDRAG_LINE > &aCompletedLines)
std::vector< PNS::ITEM * > m_leaderSegments
virtual bool Start(const VECTOR2I &aP, ITEM_SET &aPrimitives) override
Function Start()
bool FixRoute(bool aForceCommit) override
Function FixRoute()
bool Drag(const VECTOR2I &aP) override
Function Drag()
ITEM_SET m_origDraggedItems
int CurrentLayer() const override
Function CurrentLayer()
NODE * CurrentNode() const override
Function CurrentNode()
std::vector< MDRAG_LINE > m_mdragLines
bool tryWalkaround(NODE *aNode, LINE &aOrig, LINE &aWalk)
VECTOR2I m_dragStartPoint
void SetMode(PNS::DRAG_MODE aDragMode) override
int findNewLeaderSegment(const MDRAG_LINE &aLine) const
void restoreLeaderSegments(std::vector< MDRAG_LINE > &aCompletedLines)
bool multidragWalkaround(std::vector< MDRAG_LINE > &aCompletedLines)
const ITEM_SET Traces() override
Function Traces()
const std::vector< NET_HANDLE > CurrentNets() const override
Function CurrentNets()
MULTI_DRAGGER(ROUTER *aRouter)
PNS::DRAG_MODE Mode() const override
std::unique_ptr< SHOVE > m_shove
Keep the router "world" - i.e.
NODE * Branch()
Create a lightweight copy (called branch) of self that tracks the changes (added/removed items) wrs t...
const JOINT * FindJoint(const VECTOR2I &aPos, int aLayer, NET_HANDLE aNet) const
Search for a joint at a given position, layer and belonging to given net.
bool Add(std::unique_ptr< SEGMENT > aSegment, bool aAllowRedundant=false)
Add an item to the current node.
void Remove(ARC *aArc)
Remove an item from this branch.
const LINE AssembleLine(LINKED_ITEM *aSeg, int *aOriginSegmentIndex=nullptr, bool aStopAtLockedJoints=false, bool aFollowLockedSegments=false)
Follow the joint map to assemble a line connecting two non-trivial joints starting from segment aSeg.
virtual DEBUG_DECORATOR * GetDebugDecorator()=0
ROUTER_IFACE * GetInterface() const
static ROUTER * GetInstance()
bool SmoothDraggedSegments() const
Enable/disable smoothing segments during dragging.
The actual Push and Shove algorithm.
void SetIterationLimit(const int aIterLimit)
void SetLengthLimit(bool aEnable, double aLengthExpansionFactor)
void SetSolidsOnly(bool aSolidsOnly)
STATUS Route(const LINE &aInitialPath, LINE &aWalkPath, bool aOptimize=true)
void SetAllowedPolicies(std::vector< WALK_POLICY > aPolicies)
int LineDistance(const VECTOR2I &aP, bool aDetermineSide=false) const
Return the closest Euclidean distance between point aP and the line defined by the ends of segment (t...
OPT_VECTOR2I IntersectLines(const SEG &aSeg) const
Compute the intersection point of lines passing through ends of (this) and aSeg.
bool Contains(const SEG &aSeg) const
VECTOR2I LineProject(const VECTOR2I &aP) const
Compute the perpendicular projection point of aP on a line passing through ends of the segment.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const VECTOR2I PointAlong(int aPathLength) const
int Split(const VECTOR2I &aP, bool aExact=false)
Insert the point aP belonging to one of the our segments, splitting the adjacent segment in two.
const SHAPE_LINE_CHAIN Slice(int aStartIndex, int aEndIndex=-1) const
Return a subset of this line chain containing the [start_index, end_index] range of points.
void Remove(int aStartIndex, int aEndIndex)
Remove the range of points [start_index, end_index] from the line chain.
long long int Length() const
Return length of the line chain in Euclidean metric.
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
constexpr extended_type Dot(const VECTOR2< T > &aVector) const
Compute dot product of self with aVector.
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Push and Shove diff pair dimensions (gap) settings dialog.
@ RM_MarkObstacles
Ignore collisions, mark obstacles.
@ RM_Walkaround
Only walk around.
bool clipToOtherLine(NODE *aNode, const LINE &aRef, LINE &aClipped)
#define PNS_DBG(dbg, method,...)
std::vector< PNS::ITEM * > originalLeaders
LINE lines[MaxWalkPolicies]
STATUS status[MaxWalkPolicies]
constexpr int sign(T val)