49 if( aPrimitives.
Empty() )
60 bool redundant =
false;
63 if( l.originalLine.ContainsLink( litem ) )
65 l.originalLeaders.push_back( litem );
86 bool anyStrictCornersFound =
false;
87 bool anyStrictMidSegsFound =
false;
91 const int thr = l.originalLine.Width() / 2;
93 const VECTOR2I& origFirst = l.originalLine.CLine().CPoint( 0 );
94 const int distFirst = ( origFirst - aP ).EuclideanNorm();
96 const VECTOR2I& origLast = l.originalLine.CLine().CLastPoint();
97 const int distLast = ( origLast - aP ).EuclideanNorm();
99 l.cornerDistance = std::min( distFirst, distLast );
101 bool takeFirst =
false;
102 auto ilast = aPrimitives.
FindVertex( origLast );
103 auto ifirst = aPrimitives.
FindVertex( origFirst );
105 if( ilast && ifirst )
106 takeFirst = distFirst < distLast;
112 if( ifirst || ilast )
116 l.cornerIsLast =
false;
117 l.leaderSegIndex = 0;
118 l.cornerDistance = distFirst;
121 if( distFirst <= thr )
124 l.cornerDistance = 0;
129 l.cornerIsLast =
true;
130 l.leaderSegIndex = l.originalLine.SegmentCount() - 1;
131 l.cornerDistance = distLast;
134 if( distLast <= thr )
137 l.cornerDistance = 0;
142 const auto& links = l.originalLine.Links();
144 for(
int lidx = 0; lidx < (int) links.size(); lidx++ )
152 int d = lseg->Seg().Distance( aP );
154 l.midSeg = lseg->Seg();
156 l.leaderSegIndex = lidx;
157 l.leaderSegDistance = d + thr;
159 if( d < thr && !l.isStrict )
163 l.leaderSegDistance = 0;
170 anyStrictCornersFound |= l.isCorner;
171 anyStrictMidSegsFound |= !l.isCorner;
175 if( anyStrictCornersFound )
177 else if (anyStrictMidSegsFound )
181 int minLeadSegDist = std::numeric_limits<int>::max();
182 int minCornerDist = std::numeric_limits<int>::max();
188 if( l.cornerDistance < minCornerDist )
190 minCornerDist = l.cornerDistance;
193 if( l.leaderSegDistance < minLeadSegDist )
195 minLeadSegDist = l.leaderSegDistance;
200 if( bestCorner && bestSeg )
202 if( minCornerDist < minLeadSegDist )
213 else if ( bestCorner )
231 if ( !l.cornerIsLast )
233 l.originalLine.Reverse();
234 l.cornerIsLast =
true;
238 const JOINT* jt =
m_world->FindJoint( l.originalLine.CLastPoint(), &l.originalLine );
240 assert (jt !=
nullptr);
251 if( (anyStrictCornersFound || anyStrictMidSegsFound) && l.isStrict )
253 l.isPrimaryLine =
true;
291 std::set<OBSTACLE> obstacles;
294 constexpr int clipLengthThreshold = 100;
301 bool didClip =
false;
303 int step = curL / 2 - 1;
305 while( step > clipLengthThreshold )
309 int idx = sl_tmp.
Split( pclip );
310 sl_tmp = sl_tmp.
Slice(0, idx);
324 tightest = std::move( sl_tmp );
348 std::set<NET_HANDLE> uniqueNets;
353 uniqueNets.insert( net );
356 return std::vector<NET_HANDLE>( uniqueNets.begin(), uniqueNets.end() );
414 PNS_DBG(
Dbg(), Message, wxString::Format(
"s %d ip=%d c=%s o=%s", i, ip?1:0, curDir.
Format(), origLeaderDir.
Format() ));
417 if( curDir == origLeaderDir || curDir == origLeaderDir.
Opposite() )
429 for(
auto& l : aCompletedLines )
435 if( l.draggedLine.LinkCount() > 0 )
438 static_cast<PNS::ITEM*
>( l.draggedLine.GetLink( -1 ) ) );
444 if( newLeaderIdx >= 0 && newLeaderIdx < l.draggedLine.LinkCount() )
447 static_cast<PNS::ITEM*
>( l.draggedLine.GetLink( newLeaderIdx ) ) );
468 std::sort( aCompletedLines.begin(), aCompletedLines.end(), compareDragStartDist );
473 for(
auto& l : aCompletedLines )
475 PNS_DBG(
Dbg(), AddItem, &l.originalLine,
BLUE, 100000, wxString::Format(
"prewalk-remove lc=%d", l.originalLine.LinkCount() ) );
476 preWalkNode->
Remove( l.originalLine );
484 for(
int attempt = 0; attempt < 2; attempt++ )
486 NODE *node = tmpNodes[attempt] = preWalkNode->
Branch();
487 totalLength[attempt] = 0;
490 for(
int lidx = 0; lidx < aCompletedLines.size(); lidx++ )
492 MDRAG_LINE& l = aCompletedLines[attempt ? aCompletedLines.size() - 1 - lidx : lidx];
498 PNS_DBG(
Dbg(), AddItem, &walk,
BLUE, 100000, wxString::Format(
"walk lidx=%d attempt=%d", lidx, attempt) );
510 tmpNodes[attempt] =
nullptr;
523 if( tmpNodes[0] && tmpNodes[1] )
525 if ( totalLength[0] < totalLength[1] )
538 else if ( tmpNodes[0] )
543 else if ( tmpNodes[1] )
573 for(
int l1 = 0; l1 < aCompletedLines.size(); l1++ )
575 for(
int l2 = l1 + 1; l2 < aCompletedLines.size(); l2++ )
577 const auto& l1l = aCompletedLines[l1].draggedLine;
578 auto l2l = aCompletedLines[l2].draggedLine;
582 aCompletedLines[l2].draggedLine = l2l;
588 for (
auto&l : aCompletedLines )
615 std::sort( aCompletedLines.begin(), aCompletedLines.end(), compareDragStartDist );
621 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"),
622 iface->GetNetName( l.draggedLine.Net() ),
623 (
int) l.isCorner?1:0,
624 (
int) l.isStrict?1:0,
625 (
int) l.cornerDistance,
626 (
int) l.leaderSegDistance,
627 (
int) l.leaderSegIndex,
628 (
int) l.cornerIsLast?1:0,
629 (
int) l.dragDist ) );
636 for(
auto& l : aCompletedLines )
649 std::set<int> completedIndices;
651 for(
const auto& cl : aCompletedLines )
652 completedIndices.insert( cl.mdragIndex );
656 if( completedIndices.find( ml.mdragIndex ) == completedIndices.end() )
658 LINE preserved( ml.originalLine );
666 for(
int i = 0; i < (int) aCompletedLines.size(); i++ )
670 if(
m_shove->HeadsModified( i ) )
692 std::optional<LINE> primaryPreDrag, primaryDragged;
701 std::vector<MDRAG_LINE> completed;
703 auto tryPosture = [&] (
int aVariant ) ->
bool
710 l.preDragLine = l.originalLine;
712 if( l.isPrimaryLine )
720 primaryDragged = l.originalLine;
721 primaryDragged->ClearLinks();
722 primaryPreDrag = l.originalLine;
728 if( aVariant == 1 && (primaryPreDrag->PointCount() > 2) )
730 primaryPreDrag->Line().Remove( -1 );
731 primaryDragged->Line().Remove( -1 );
735 l.preDragLine.Line().Remove(-1);
746 PNS_DBG(
Dbg(), AddPoint, primaryDragged->CLastPoint(),
YELLOW, 600000, wxT(
"mdrag-sec"));
748 lastPreDrag = primaryPreDrag->CSegment( -1 );
751 primaryDragged->SetSnapThreshhold( snapThreshold );
752 primaryDragged->DragCorner( aP, primaryDragged->PointCount() - 1,
false );
755 if( primaryDragged->SegmentCount() > 0 )
757 SEG lastPrimDrag = primaryDragged->CSegment( -1 );
760 lastPrimDrag = lastPreDrag;
762 auto lastSeg = primaryDragged->CSegment( -1 );
765 if( lastSeg.Length() < primaryDragged->Width() )
767 lastPrimDrag = lastPreDrag;
771 perp = (lastPrimDrag.
B - lastPrimDrag.
A).Perpendicular();
776 PNS_DBG(
Dbg(), AddShape,
SEG(lastPrimDrag.
B, lastPrimDrag.
B + perp),
LIGHTGRAY, 100000, wxString::Format(
"prim-perp-seg") );
791 lastPreDrag = primaryDragged->CSegment( primaryLine->
leaderSegIndex );
792 primaryDragged->SetSnapThreshhold( snapThreshold );
794 perp = (primaryLine->
midSeg.
B - primaryLine->
midSeg.
A).Perpendicular();
812 if( l.preDragLine.SegmentCount() >= 1 )
825 DIRECTION_45 parallelDir( l.preDragLine.CSegment( -1 ) );
827 auto leadAngle = primaryDir.
Angle( parallelDir );
835 int dist = lastPreDrag.
LineDistance( l.preDragLine.CLastPoint(),
true );
838 auto projected = aP + perp.
Resize( dist );
841 LINE parallelDragged( l.preDragLine );
850 false, primaryLastSegDir );
857 if( !l.isPrimaryLine )
859 l.draggedLine = parallelDragged;
860 completed.push_back( l );
867 SEG sdrag = l.midSeg;
870 auto ang = refDir.
Angle( curDir );
875 l.preDragLine.CPoint( l.leaderSegIndex ),
true );
876 auto projected = aP + perp.
Resize( dist );
878 SEG sperp( aP, aP + perp.
Resize( 10000000 ) );
891 if( !l.isPrimaryLine )
893 l.draggedLine = l.preDragLine;
894 l.draggedLine.ClearLinks();
895 l.draggedLine.SetSnapThreshhold( snapThreshold );
896 l.draggedLine.DragSegment( projected, l.leaderSegIndex,
false );
897 completed.push_back( l );
904 wxT(
"startProj" ) );
906 wxString::Format(
"pro dd=%d", l.dragDist ) );
914 l.draggedLine = *primaryDragged;
916 completed.push_back( l );
924 for (
const auto &l: completed )
926 if( !l.dragOK && aVariant < 2 )
929 if( l.isPrimaryLine )
934 if( lastDir != primaryLastSegDir )
944 for(
int variant = 0; variant < 3; variant++ )
946 res = tryPosture( variant );
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
DRAG_ALGO(ROUTER *aRouter)
bool Contains(ITEM *aItem) const
std::vector< ITEM * > & Items()
ITEM * FindVertex(const VECTOR2I &aV) 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
const VECTOR2I & CLastPoint() const
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...
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.
ROUTER_IFACE * GetInterface() const
bool SmoothDraggedSegments() const
Enable/disable smoothing segments during dragging.
The actual Push and Shove algorithm.
@ SHP_DONT_LOCK_ENDPOINTS
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) const
Return a subset of this line chain containing the [start_index, end_index] range of points.
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]
wxString result
Test unit parsing edge cases and error handling.
Casted dyn_cast(From aObject)
A lightweight dynamic downcast.
constexpr int sign(T val)
VECTOR2< int32_t > VECTOR2I