52 if( rr->DpCoupledNet( aStart->
Net() ) )
59 return std::make_shared<DIFF_PAIR>( dp );
68 DIFF_PAIR& aReconstructedDP,
int& aLeaderSegmentN,
69 int& aLeaderSegmentP )
73 std::optional<MINOPTMAX<int>> gapValue;
83 aOrigDP.
Layer(), &gapConstraint ) )
85 gapValue = gapConstraint.
m_Value;
95 PNS_DBG(
Dbg(), Message, wxString::Format( wxT(
"Coupled pairs: %d"), (
int) csv.size() ) );
100 if( sp.linkP == aAnchorItem || sp.linkN == aAnchorItem )
107 if ( leaderIndex < 0 )
110 auto nearestCoupledSegmentPair = [&](
const SEG aRefSeg ) ->
int
112 SEG::ecoord minDist = std::numeric_limits<SEG::ecoord>::max();
115 for(
size_t i = 0; i < csv.size(); i++ )
117 auto distP = csv[i].coupledP.SquaredDistance( aRefSeg );
118 auto distN = csv[i].coupledN.SquaredDistance( aRefSeg );
120 if( distP < minDist )
125 if( distN < minDist )
135 if( leaderIndex < 0 )
140 leaderIndex = nearestCoupledSegmentPair( leadSegment->Seg() );
156 if( leaderIndex >= 0 )
158 int start = leaderIndex,
end = leaderIndex;
160 for(
int i = leaderIndex - 1; i >= 0; i-- )
162 if( areParallel( csv[i], csv[leaderIndex] ) )
167 for(
size_t i = leaderIndex + 1; i < csv.size(); i++ )
169 if( areParallel( csv[i], csv[leaderIndex] ) )
176 auto cs_start = csv[start];
177 auto cs_end = csv[
end];
183 int p_start = aOrigDP.
CP().
Find( longestP.A );
184 int p_end = aOrigDP.
CP().
Find( longestP.B );
185 int n_start = aOrigDP.
CN().
Find( longestN.A );
186 int n_end = aOrigDP.
CN().
Find( longestN.B );
195 wxString::Format( wxT(
"reconstruct p %d/%d n %d/%d SE %d %d"), p_start, p_end, n_start, n_end, start,
end ) );
200 aReconstructedDP = aOrigDP;
202 aReconstructedDP.
SetShape( shape_p, shape_n );
207 aLeaderSegmentN = n_start;
208 aLeaderSegmentP = p_start;
226 if( aPrimitives.
Empty() )
237 bool redundant =
false;
240 if( l.assembledOrigLine.ContainsLink( litem ) )
242 l.originalLeaders.push_back( litem );
253 if(
Settings().GetKeepDPCouplingWhenDragging() )
260 int leaderIndexN, leaderIndexP;
266 wxString::Format( wxT(
"DP assembled OK, leaders: %d/%d reconstructed=%d lc %d %d" ), leaderIndexP,
267 leaderIndexN, reconstructOK ? 1 : 0,
268 diffPair->PLine().LinkCount(), diffPair->NLine().LinkCount()) );
278 if( diffPair->PLine().ContainsLink( litem ) )
293 if( diffPair->NLine().ContainsLink( litem ) )
320 bool anyStrictCornersFound =
false;
321 bool anyStrictMidSegsFound =
false;
325 const int thr = l.originalLine.Width() / 2;
327 const VECTOR2I& origFirst = l.originalLine.CLine().CPoint( 0 );
328 const int distFirst = ( origFirst - aP ).EuclideanNorm();
330 const VECTOR2I& origLast = l.originalLine.CLine().CLastPoint();
331 const int distLast = ( origLast - aP ).EuclideanNorm();
335 l.cornerDistance = std::min( distFirst, distLast );
337 bool takeFirst =
false;
338 auto ilast = aPrimitives.
FindVertex( origLast );
339 auto ifirst = aPrimitives.
FindVertex( origFirst );
341 if( ilast && ifirst )
342 takeFirst = distFirst < distLast;
348 if( ifirst || ilast )
352 l.cornerIsLast =
false;
353 l.leaderSegIndex = 0;
354 l.cornerDistance = distFirst;
357 if( distFirst <= thr )
360 l.cornerDistance = 0;
365 l.cornerIsLast =
true;
366 l.leaderSegIndex = l.originalLine.SegmentCount() - 1;
367 l.cornerDistance = distLast;
370 if( distLast <= thr )
373 l.cornerDistance = 0;
379 for(
int lidx = 0; lidx < (int) l.originalLine.SegmentCount(); lidx++ )
381 const SEG& origSeg = l.originalLine.CSegment( lidx );
384 if( l.leaderSegIndex < 0 && !origLink )
395 if( l.leaderSegIndex < 0 )
396 l.leaderSegIndex = lidx;
398 if( lidx == l.leaderSegIndex )
401 l.leaderSegDistance = d + thr;
403 if( d < thr && !l.isStrict )
407 l.leaderSegDistance = 0;
414 anyStrictCornersFound |= l.isCorner;
415 anyStrictMidSegsFound |= !l.isCorner;
419 if( anyStrictCornersFound )
421 else if (anyStrictMidSegsFound )
425 int minLeadSegDist = std::numeric_limits<int>::max();
426 int minCornerDist = std::numeric_limits<int>::max();
432 if( l.cornerDistance < minCornerDist )
434 minCornerDist = l.cornerDistance;
437 if( l.leaderSegDistance < minLeadSegDist )
439 minLeadSegDist = l.leaderSegDistance;
444 if( bestCorner && bestSeg )
446 if( minCornerDist < minLeadSegDist )
457 else if ( bestCorner )
475 if ( !l.cornerIsLast )
477 l.originalLine.Reverse();
478 l.cornerIsLast =
true;
482 const JOINT* jt =
m_world->FindJoint( l.originalLine.CLastPoint(), &l.originalLine );
499 if( (anyStrictCornersFound || anyStrictMidSegsFound) && l.isStrict )
501 l.isPrimaryLine =
true;
539 std::set<OBSTACLE> obstacles;
542 constexpr int clipLengthThreshold = 100;
549 bool didClip =
false;
551 int step = curL / 2 - 1;
553 while( step > clipLengthThreshold )
557 int idx = sl_tmp.
Split( pclip );
558 sl_tmp = sl_tmp.
Slice(0, idx);
572 tightest = std::move( sl_tmp );
596 std::set<NET_HANDLE> uniqueNets;
601 uniqueNets.insert( net );
604 return std::vector<NET_HANDLE>( uniqueNets.begin(), uniqueNets.end() );
661 PNS_DBG(
Dbg(), Message, wxString::Format(
"s %d ip=%d c=%s o=%s", i, ip?1:0, curDir.
Format(), origLeaderDir.
Format() ));
664 if( curDir == origLeaderDir || curDir == origLeaderDir.
Opposite() )
676 for(
auto& l : aCompletedLines )
682 if( l.draggedLine.LinkCount() > 0 )
685 static_cast<PNS::ITEM*
>( l.draggedLine.GetLink( -1 ) ) );
691 if( newLeaderIdx >= 0 && newLeaderIdx < l.draggedLine.LinkCount() )
694 static_cast<PNS::ITEM*
>( l.draggedLine.GetLink( newLeaderIdx ) ) );
715 std::sort( aCompletedLines.begin(), aCompletedLines.end(), compareDragStartDist );
720 for(
auto& l : aCompletedLines )
722 PNS_DBG(
Dbg(), AddItem, &l.assembledOrigLine,
BLUE, 100000, wxString::Format(
"prewalk-remove lc=%d", l.originalLine.LinkCount() ) );
723 preWalkNode->
Remove( l.assembledOrigLine );
730 std::vector<LINE> postWalkLines;
734 WALK_STATE walkState[2];
736 for(
int attempt = 0; attempt < 2; attempt++ )
738 WALK_STATE *state = &walkState[ attempt ];
739 state->node = preWalkNode->
Branch();
740 state->postWalkLines.resize( aCompletedLines.size() );
742 for(
int lidx = 0; lidx < (int) aCompletedLines.size(); lidx++ )
744 MDRAG_LINE& l = aCompletedLines[attempt ? aCompletedLines.size() - 1 - lidx : lidx];
750 PNS_DBG(
Dbg(), AddItem, &walk,
BLUE, 100000, wxString::Format(
"walk lidx=%d attempt=%d", lidx, attempt) );
754 state->node->Add( walk );
756 state->postWalkLines[lidx] = walk;
766 std::optional<int> bestAttempt;
768 if( !walkState[0].fail && !walkState[1].fail )
770 if ( walkState[0].totalLength < walkState[1].totalLength )
779 else if ( !walkState[0].fail )
783 else if ( !walkState[1].fail )
790 delete walkState[0].node;
791 delete walkState[1].node;
796 for(
int lidx = 0; lidx < (int) aCompletedLines.size(); lidx++ )
798 aCompletedLines[lidx].draggedLine = walkState[ *bestAttempt ].postWalkLines[ lidx ];
803 delete walkState[1 - *bestAttempt].node;
834 for(
int l1 = 0; l1 < (int)aCompletedLines.size(); l1++ )
836 for(
int l2 = l1 + 1; l2 < (int)aCompletedLines.size(); l2++ )
838 const auto& l1l = aCompletedLines[l1].draggedLine;
839 auto l2l = aCompletedLines[l2].draggedLine;
842 aCompletedLines[l2].draggedLine = l2l;
846 for (
auto&l : aCompletedLines )
874 std::sort( aCompletedLines.begin(), aCompletedLines.end(), compareDragStartDist );
880 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"),
881 iface->GetNetName( l.draggedLine.Net() ),
882 (
int) l.isCorner?1:0,
883 (
int) l.isStrict?1:0,
884 (
int) l.cornerDistance,
885 (
int) l.leaderSegDistance,
886 (
int) l.leaderSegIndex,
887 (
int) l.cornerIsLast?1:0,
888 (
int) l.dragDist ) );
895 for(
auto& l : aCompletedLines )
908 std::set<int> completedIndices;
910 for(
const auto& cl : aCompletedLines )
911 completedIndices.insert( cl.mdragIndex );
915 if( completedIndices.find( ml.mdragIndex ) == completedIndices.end() )
917 LINE preserved( ml.originalLine );
925 for(
int i = 0; i < (int) aCompletedLines.size(); i++ )
929 if(
m_shove->HeadsModified( i ) )
951 std::optional<LINE> primaryPreDrag, primaryDragged;
959 std::vector<MDRAG_LINE> completed;
961 auto tryPosture = [&] (
int aVariant ) ->
bool
968 l.preDragLine = l.originalLine;
969 PNS_DBG(
Dbg(), AddItem, &l.originalLine,
GREEN, 30000, wxString::Format( wxT(
"original is-prim: %d"), l.isPrimaryLine?1:0) );
971 if( l.isPrimaryLine )
979 primaryDragged = l.originalLine;
980 primaryDragged->ClearLinks();
981 primaryPreDrag = l.originalLine;
987 if( aVariant == 1 && (primaryPreDrag->PointCount() > 2) )
989 primaryPreDrag->Line().Remove( -1 );
990 primaryDragged->Line().Remove( -1 );
994 l.preDragLine.Line().Remove(-1);
1005 PNS_DBG(
Dbg(), AddPoint, primaryDragged->CLastPoint(),
YELLOW, 600000, wxT(
"mdrag-sec"));
1007 lastPreDrag = primaryPreDrag->CSegment( -1 );
1010 primaryDragged->SetSnapThreshhold( snapThreshold );
1011 primaryDragged->DragCorner( aP, primaryDragged->PointCount() - 1,
false );
1014 if( primaryDragged->SegmentCount() > 0 )
1016 SEG lastPrimDrag = primaryDragged->CSegment( -1 );
1018 if ( aVariant == 2 )
1019 lastPrimDrag = lastPreDrag;
1021 auto lastSeg = primaryDragged->CSegment( -1 );
1024 if( lastSeg.Length() < primaryDragged->Width() )
1026 lastPrimDrag = lastPreDrag;
1030 perp = (lastPrimDrag.
B - lastPrimDrag.
A).Perpendicular();
1035 PNS_DBG(
Dbg(), AddShape,
SEG(lastPrimDrag.
B, lastPrimDrag.
B + perp),
LIGHTGRAY, 100000, wxString::Format(
"prim-perp-seg") );
1048 lastPreDrag = primaryDragged->CSegment( primaryLine->
leaderSegIndex );
1053 primaryDragged->SetSnapThreshhold( snapThreshold );
1054 PNS_DBG(
Dbg(), AddItem, &primaryDragged.value(),
GREEN, 30000,
"primary-orig" );
1056 PNS_DBG(
Dbg(), AddItem, &primaryDragged.value(),
GREEN, 30000,
"primary-dragged" );
1058 perp = (primaryLine->
midSeg.
B - primaryLine->
midSeg.
A).Perpendicular();
1073 PNS_DBG(
Dbg(), AddItem, &l.originalLine,
GREEN, 100000, wxT(
"mdrag-noprim"));
1076 if( l.preDragLine.SegmentCount() >= 1 )
1089 DIRECTION_45 parallelDir( l.preDragLine.CSegment( -1 ) );
1091 auto leadAngle = primaryDir.
Angle( parallelDir );
1099 int dist = lastPreDrag.
LineDistance( l.preDragLine.CLastPoint(),
true );
1102 auto projected = aP + perp.
Resize( dist );
1105 LINE parallelDragged( l.preDragLine );
1114 false, primaryLastSegDir );
1126 if( !l.isPrimaryLine )
1128 l.draggedLine = parallelDragged;
1129 completed.push_back( l );
1135 SEG sdrag = l.midSeg;
1138 auto ang = refDir.
Angle( curDir );
1146 l.preDragLine.CPoint( l.leaderSegIndex ),
true );
1147 auto projected = aP + perp.
Resize( dist );
1149 SEG sperp( aP, aP + perp.
Resize( 10000000 ) );
1158 VECTOR2I v = projected - startProj;
1162 if( !l.isPrimaryLine )
1164 l.draggedLine = l.preDragLine;
1165 l.draggedLine.ClearLinks();
1166 l.draggedLine.SetSnapThreshhold( snapThreshold );
1167 l.draggedLine.DragSegment( projected, l.leaderSegIndex,
false );
1168 completed.push_back( l );
1175 wxT(
"startProj" ) );
1177 wxString::Format(
"pro dd=%d", l.dragDist ) );
1183 if (l.isPrimaryLine)
1185 l.draggedLine = *primaryDragged;
1187 completed.push_back( l );
1195 for (
const auto &l: completed )
1197 if( !l.dragOK && aVariant < 2 )
1200 if( l.isPrimaryLine )
1205 if( l.draggedLine.SegmentCount() < 1 )
1210 if( lastDir != primaryLastSegDir )
1220 for(
int variant = 0; variant < 3; variant++ )
1222 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()
Return the logger object, allowing to dump geometry to a file.
ROUTER * Router() const
Return the instance of our router.
ROUTING_SETTINGS & Settings() const
Return current router settings.
DEBUG_DECORATOR * Dbg() const
Basic class for a differential pair.
const SHAPE_LINE_CHAIN & CN() const
std::vector< COUPLED_SEGMENTS > COUPLED_SEGMENTS_VEC
virtual void ClearLinks() override
Erase the linking information. Used to detach the line from the owning node.
void SetShape(const SHAPE_LINE_CHAIN &aP, const SHAPE_LINE_CHAIN &aN, bool aSwapLanes=false)
static constexpr int DP_PARALLELITY_THRESHOLD
const SHAPE_LINE_CHAIN & CP() const
void CoupledSegmentPairs(COUPLED_SEGMENTS_VEC &aPairs, bool aUseGapConstraint=true, const std::optional< DP_GAP_CONSTRAINT > &aOverrideGapConstraint=std::optional< DP_GAP_CONSTRAINT >()) const
DRAG_ALGO(ROUTER *aRouter)
ITEM * FindSegment(const SEG &aSeg) const
std::vector< ITEM * > & Items()
ITEM * FindVertex(const VECTOR2I &aV) const
Base class for PNS router board items.
virtual NET_HANDLE Net() const
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)
Assign a shape to the line (a polyline/line chain).
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
std::vector< LINKED_ITEM * > & Links()
Return the list of links from the owning node that constitute this line (or NULL if the line is not l...
int LinkCount() const
Return the number of segments that were assembled together to form this line.
virtual void ClearLinks()
Erase the linking information. Used to detach the line from the owning node.
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
std::shared_ptr< DIFF_PAIR > tryAssembleDiffPair(ITEM *aStart)
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()
bool reconstructOriginalDpCoupling(DIFF_PAIR &aOrigDP, PNS::ITEM *aAnchorItem, DIFF_PAIR &aReconstructedDP, int &aLeaderSegmentN, int &aLeaderSegmentP)
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...
void Remove(ARC *aArc)
Remove an item from this branch.
ROUTER_IFACE * GetInterface() const
RULE_RESOLVER * GetRuleResolver() const
bool SmoothDraggedSegments() const
Return true if smoothing segments during dragging is enabled.
The actual Push and Shove algorithm.
@ SHP_DONT_LOCK_ENDPOINTS
const DIFF_PAIR AssembleDiffPair(SEGMENT *aStart)
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...
VECTOR2I::extended_type ecoord
OPT_VECTOR2I IntersectLines(const SEG &aSeg) const
Compute the intersection point of lines passing through ends of (this) and aSeg.
bool ApproxCollinear(const SEG &aSeg, int aDistanceThreshold=1) const
int Distance(const SEG &aSeg) const
Compute minimum Euclidean distance to segment 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.
void Replace(int aStartIndex, int aEndIndex, const VECTOR2I &aP)
Replace points with indices in range [start_index, end_index] with a single point aP.
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.
int Find(const VECTOR2I &aP, int aThreshold=0) const
Search for point aP.
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)
const SEG LongestCoveringSegment(const SEG &a, const SEG &b)
#define PNS_DBG(dbg, method,...)
An abstract function object, returning a design rule (clearance, diff pair gap, etc) required between...
std::vector< PNS::ITEM * > originalLeaders
std::shared_ptr< DIFF_PAIR > assembledDiffPair
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