37static void drawGateways( PNS::DEBUG_DECORATOR *dbg,
const wxString& groupName, PNS::DP_PRIMITIVE_PAIR& prims, PNS::DP_GATEWAYS& gws,
VECTOR2D offset,
VECTOR2D step );
154 bool solidsOnly =
true;
174 bool collided =
false;
176 std::set<const ITEM*> handled;
189 while( iter < maxIter )
192 if( !obs || handled.count( obs->m_item ) )
201 collided |= obs->m_item->Shape( viaLayer )->Collide( virtHead.
Shape( viaLayer ),
clearance, &layerForce );
210 virtHead.
SetPos( virtHead.
Pos() + force );
213 handled.insert( obs->m_item );
218 bool succeeded = ( !collided || iter != maxIter );
231 bool aPFirst,
bool aWindCw,
bool aSolidsOnly )
236 auto excludeHeadDp = [aCurrent](
const ITEM* aTestItem,
const ITEM* aRefItem ) ->
bool
238 if( aTestItem->
Net() == aCurrent->
NetN() || aTestItem->
Net() == aCurrent->
NetP() )
261 bool currentIsP = aPFirst;
276 currentIsP = !currentIsP;
284 PNS_DBG(
Dbg(), AddItem, &preWalk,
GREEN, 100000, wxString::Format(
"preWalk") );
293 PNS_DBG(
Dbg(), AddItem, &postWalk,
BLUE, 100000, wxString::Format(
"postWalk") );
295 LINE postShove( preShove );
311 currentIsP = !currentIsP;
332 double bestScore = 100000000000000.0;
334 for(
int attempt = 0; attempt <= 3; attempt++ )
339 bool pfirst = ( attempt & 1 ) ?
true :
false;
340 bool wind_cw = ( attempt & 2 ) ?
true :
false;
342 if(
attemptWalk( tmp, &aPair, p, pfirst, wind_cw, aSolidsOnly ) )
345 double skew = p.
Skew();
347 double score = cl + fabs( skew ) * 3.0;
349 if( score < bestScore )
352 best = std::move( p );
359 if( bestScore > 0.0 )
424 auto collisionFilter = [&](
const PNS::ITEM* aTestItem,
const PNS::ITEM* aRefItem ) ->
bool
433 m_shove->SetCollisionFilter( collisionFilter );
443 if(
m_shove->HeadsModified( 0 ))
444 pLine =
m_shove->GetModifiedHead(0);
446 if(
m_shove->HeadsModified( 1 ))
447 nLine =
m_shove->GetModifiedHead(1);
510 m_prevPair->PrimP()->Layers().Overlaps( aLayer ) ) )
525 switch( aItem->
Kind() )
529 LINE* l =
static_cast<LINE*
>( aItem );
541 ARC* a =
static_cast<ARC*
>( aItem );
581 NET_HANDLE coupledNet = ( refNet == netP ) ? netN : netP;
584 ITEM* primRef = aStartItem;
586 double distThreshold = 10000000;
590 distThreshold = seg->Width() / 2;
594 distThreshold = arc->Width() / 2;
597 if( !refAnchor || ( refAnchor->Distance( aP ) > distThreshold ) )
601 *aErrorMsg =
_(
"Can't find a suitable starting point. If starting "
602 "from an existing differential pair make sure you are "
609 std::set<ITEM*> coupledItems;
612 double bestDist = std::numeric_limits<double>::max();
615 for(
ITEM* item : coupledItems )
617 if( item->Kind() == aStartItem->
Kind() )
624 double dist = ( *
anchor - *refAnchor ).EuclideanNorm();
626 bool shapeMatches =
true;
630 shapeMatches =
false;
633 if( dist < bestDist && shapeMatches )
680 ppair->SetIsMidtrace(
true );
692 wxString* aErrorMsg )
702 *aErrorMsg =
_(
"Unable to find complementary differential pair "
703 "nets. Make sure the names of the nets belonging "
704 "to a differential pair end with either N/P or +/-." );
712 wxString::Format(
"EP=%d target-p [%d,%d] target-n [%d,%d]", found ? 1 : 0, aPair.
AnchorP().
x,
720 wxString::Format(
"MT=%d target-p [%d,%d] target-n [%d,%d]", found ? 1 : 0, aPair.
AnchorP().
x,
729 *aErrorMsg = wxString::Format(
_(
"Can't find a suitable starting point for the diff pair" ) );
741 return m_sizes.EffectiveDiffPairViaGap();
797 PNS_DBG(
Dbg(), Message, wxString::Format(
"Start-is-mid %d wd %d rd %d",
m_start.IsMidtrace()?1:0, (
int) world->
Depth(), (
int) rootNode->
Depth() ) );
816 PNS_DBG( dbg, BeginGroup, grpName, 0 );
843 std::optional<int> minClearance = 0;
852 auto updateMinClearance = [&minClearance, ruleResolver](
const DP_PRIMITIVE_PAIR& aTarget )
854 if( aTarget.PrimN() && aTarget.PrimP() )
858 minClearance = std::max(
clearance, minClearance.value() );
874 minClearance.value() );
883 bool snapVias =
false;
884 bool foundTarget =
false;
896 updateMinClearance( target );
898 minClearance.value() );
906 wxString::Format(
"target-p [%d,%d] target-n [%d,%d], cursor [%d,%d]",
m_target->AnchorP().x,
929 m_prevPair->CursorOrientation( fp, midp, dirV );
935 int lead_dist = ( fpProj - fp ).EuclideanNorm();
939 minClearance.value() );
942 int snapThreshold = (
m_sizes.DiffPairGap() +
m_sizes.DiffPairWidth() ) / 2;
945 wxString::Format(
"leadDist %d snapVias %d thr %d dirv %s", lead_dist, snapVias ? 1 : 0, snapThreshold,
949 if( !snapVias && lead_dist > snapThreshold )
985 for(
bool rejectNonObtuseAngles : {
true,
false } )
987 bestestFit =
nullptr;
988 bestFits[0] = bestFits[1] =
nullptr;
990 int bestScore[2] = { -100, -100 };
991 float bestCpr[2] = { 0.0f, 0.0f };
993 for(
const auto& f : fits )
998 wxString::Format( wxT(
"fit: bestCpr0=%.3f bestCpr1=%.3f diag=%d cpr=%.2f ar=%.2f score=%d" ),
999 bestCpr[0], bestCpr[1], f.diagonal ? 1 : 0, f.coupledRatio, f.aspectRatio,
1009 if( rejectNonObtuseAngles )
1013 auto angP = startDirP.
Angle( dp.
DirP(
false ) );
1014 auto angN = startDirN.
Angle( dp.
DirN(
false ) );
1016 if( !( angP & angleMask ) || !( angN & angleMask ) )
1019 wxString::Format(
" reject dp %s dn %s sd %s %s", dp.
DirP(
false ).
Format(),
1028 int index = f.diagonal ? 1 : 0;
1029 int score = f.score;
1031 if( score > bestScore[
index] || f.coupledRatio > bestCpr[
index] * 2.0 )
1033 bestFits[
index] = &f;
1034 bestScore[
index] = score;
1037 else if( score == bestScore[
index] )
1039 if( f.coupledRatio > bestCpr[
index] )
1041 bestCpr[
index] = f.coupledRatio;
1042 bestFits[
index] = &f;
1047 if( bestFits[0] || bestFits[1] )
1060 wxString::Format( wxT(
"best: diag=%d cpr=%.2f ar=%.2f score=%d cl=%d" ), f->
diagonal ? 1 : 0,
1074 bestestFit = bestFits[1];
1076 bestestFit = bestFits[0];
1077 else if( bestFits[1] )
1078 bestestFit = bestFits[1];
1079 else if( bestFits[0] )
1080 bestestFit = bestFits[0];
1114 bool retval =
route( aP );
1123 wxString::Format(
"target %d, p-sc %d n-sc %d",
m_target ? 1 : 0,
1157 PNS_DBG( dbg, BeginGroup, groupName, 0 );
1160 PNS_DBG( dbg, BeginGroup, wxString::Format( wxT(
"gw-%s" ), gw.GetName() ), 0 );
1165 if( gw.EntryP().SegmentCount() )
1173 if( gw.EntryN().SegmentCount() )
1181 auto midpoint = ( gw.AnchorN() + gw.AnchorP() ) / 2;
1183 if( gw.HasPrimaryDirection() )
1185 for(
int dir = 0; dir < 8; dir++ )
1188 if( dirV.
Mask() & gw.PrimaryDirectionMask() )
1205 int prevDiffPairWidth =
m_sizes.DiffPairWidth();
1215 m_sizes.SetDiffPairWidth( prevDiffPairWidth );
1356 aNets.push_back(
m_netP );
1357 aNets.push_back(
m_netN );
1376 std::vector<NET_HANDLE> rv;
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 VECTOR2I ToVector() const
Directions
Available directions, there are 8 of them, as on a rectilinear map (north = up) + an extra undefined ...
bool IsDiagonal() const
Returns true if the direction is diagonal (e.g.
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.
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
NODE * CurrentNode(bool aLoopsRemoved=false) const override
Return the most recent world state.
void SetOrthoMode(bool aOrthoMode) override
Function SetOrthoMode()
bool HasPlacedAnything() const override
NODE * m_world
current routing start point (end of tail, beginning of head)
bool tryWalkDp(NODE *aNode, DIFF_PAIR &aPair, bool aSolidsOnly)
route step, walk around mode
bool propagateDpHeadForces(const VECTOR2I &aP, VECTOR2I &aNewP)
bool rhMarkObstacles(const VECTOR2I &aP)
int m_viaDiameter
current via drill
static constexpr int DP_DEFAULT_GAP_EPSILON
std::optional< DP_PRIMITIVE_PAIR > m_prevPair
current algorithm iteration
bool ToggleVia(bool aEnabled) override
Enable/disable a via at the end of currently routed trace.
bool route(const VECTOR2I &aP)
Re-route the current track to point aP.
bool AbortPlacement() override
int m_iteration
pointer to world to search colliding items
bool rhShoveOnly(const VECTOR2I &aP)
route step, mark obstacles mode
bool Start(const VECTOR2I &aP, ITEM *aStartItem) override
Start routing a single track at point aP, taking item aStartItem as anchor (unless NULL).
bool CommitPlacement() override
bool findDpEndingPrimitives(NODE *aWorld, const VECTOR2I &aP, ITEM *aStartItem, DP_PRIMITIVE_PAIR &aPair, wxString *aErrorMsg)
const ITEM_SET Traces() override
Return the complete routed line, as a single-member ITEM_SET.
void GetModifiedNets(std::vector< NET_HANDLE > &aNets) const override
Function GetModifiedNets.
int m_viaDrill
current track width
void FlipPosture() override
Toggle the current posture (straight/diagonal) of the trace head.
DIFF_PAIR_PLACER(ROUTER *aRouter)
bool findDpMidtraceIntersection(NODE *aWorld, const VECTOR2I &aP, ITEM *aStartItem, DP_PRIMITIVE_PAIR &aPair, wxString *aErrorMsg)
bool attemptWalk(NODE *aNode, DIFF_PAIR *aCurrent, DIFF_PAIR &aWalk, bool aPFirst, bool aWindCw, bool aSolidsOnly)
void setWorld(NODE *aWorld)
Set the board to route.
NODE * m_currentNode
Postprocessed world state (including marked collisions & removed loops)
void initPlacement()
Initialize placement of a new line with given parameters.
const std::vector< NET_HANDLE > CurrentNets() const override
Return the net of currently routed track.
std::optional< DP_PRIMITIVE_PAIR > m_target
bool routeHead(const VECTOR2I &aP)
void UpdateSizes(const SIZES_SETTINGS &aSizes) override
Perform on-the-fly update of the width, via diameter & drill size from a settings class.
bool FindDpPrimitivePair(NODE *aWorld, const VECTOR2I &aP, ITEM *aItem, DP_PRIMITIVE_PAIR &aPair, wxString *aErrorMsg=nullptr)
bool rhWalkOnly(const VECTOR2I &aP)
route step, shove mode
bool Move(const VECTOR2I &aP, ITEM *aEndItem) override
Move the end of the currently routed trace to the point aP, taking aEndItem as anchor (if not NULL).
DP_PRIMITIVE_PAIR m_start
bool FixRoute(const VECTOR2I &aP, ITEM *aEndItem, bool aForceFinish) override
Commit the currently routed track to the parent node, taking aP as the final end point and aEndItem a...
bool m_placingVia
current via diameter
void updateLeadingRatLine()
Draw the "leading" ratsnest line, which connects the end of currently routed track and the nearest ye...
const VIA makeVia(const VECTOR2I &aP, NET_HANDLE aNet)
SIZES_SETTINGS m_sizes
Are we placing a via?
bool SetLayer(int aLayer) override
Set the current routing layer.
std::unique_ptr< SHOVE > m_shove
Current world state.
Basic class for a differential pair.
const SHAPE_LINE_CHAIN & CN() const
DIRECTION_45 DirP(bool aEnd) const
double CoupledLength() const
void SetDimensions(const DP_DIMENSIONS &aDims)
const DP_DIMENSIONS & Dimensions() const
void SetShape(const SHAPE_LINE_CHAIN &aP, const SHAPE_LINE_CHAIN &aN, bool aSwapLanes=false)
std::optional< DP_PRIMITIVE_PAIR > BuildMidpairIntersection(PNS::SEGMENT *aStartSeg, const VECTOR2I &aP)
const SHAPE_LINE_CHAIN & CP() const
DIRECTION_45 DirN(bool aEnd) const
void SetMinClearance(int aClearance)
void SetGapConstraint(const DP_GAP_CONSTRAINT &aGapConstraint)
A set of gateways calculated for the cursor or starting/ending primitive pair.
void BuildForCursor(const VECTOR2I &aCursorPos, int aDirectionMask=-1)
void BuildFromPrimitivePair(const DP_PRIMITIVE_PAIR &aPair, bool aPreferDiagonal)
std::vector< DP_GATEWAY > & Gateways()
void SetFitVias(bool aEnable)
void SetDimensions(const DP_DIMENSIONS &aDims)
std::vector< FIT_RESULT > FitGateways(DP_GATEWAYS &aEntry, DP_GATEWAYS &aTarget, bool aFitVias)
Define a "gateway" for routing a differential pair - e.g.
const SHAPE_LINE_CHAIN & EntryP() const
const VECTOR2I & AnchorN() const
const VECTOR2I & AnchorP() const
const SHAPE_LINE_CHAIN & EntryN() const
const wxString GetName() const
Store starting/ending primitives (pads, vias or segments) for a differential pair.
DIRECTION_45 DirN() const
const VECTOR2I & AnchorN() const
const VECTOR2I & AnchorP() const
void SetIsMidtrace(bool aMidtrace)
void SetAnchors(const VECTOR2I &aAnchorP, const VECTOR2I &aAnchorN)
DIRECTION_45 DirP() const
void Add(const LINE &aLine)
Base class for PNS router board items.
const PNS_LAYER_RANGE & Layers() const
virtual NET_HANDLE Net() const
PnsKind Kind() const
Return the type (kind) of the item.
std::set< int > RelevantShapeLayers(const ITEM *aOther) const
Returns the set of layers on which either this or the other item can have a unique shape.
void SetLayer(int aLayer)
bool OfKind(int aKindMask) const
virtual VECTOR2I Anchor(int n) const
A 2D point on a given set of layers and belonging to a certain net, that links together a number of b...
int LinkCount(int aMask=-1) const
Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,...
const VECTOR2I & CPoint(int aIdx) const
const SHAPE_LINE_CHAIN & CLine() const
SHAPE_LINE_CHAIN & Line()
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...
OPT_OBSTACLE CheckColliding(const ITEM *aItem, int aKindMask=ITEM::ANY_T)
Check if the item collides with anything else in the world, and if found, returns the obstacle.
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.
std::optional< OBSTACLE > OPT_OBSTACLE
RULE_RESOLVER * GetRuleResolver() const
Return the number of joints.
void AllItemsInNet(NET_HANDLE aNet, std::set< ITEM * > &aItems, int aKindMask=-1)
Perform various optimizations of the lines being routed, attempting to make the lines shorter and les...
static bool Optimize(LINE *aLine, int aEffortLevel, NODE *aWorld, const VECTOR2I &aV=VECTOR2I(0, 0))
virtual bool removeLoops(NODE *aNode, LINE &aLatest)
PLACEMENT_ALGO(ROUTER *aRouter)
PNS_LAYER_RANGE GetViaLayerRange(const SIZES_SETTINGS &aSizes) const
Return the layer span a via placed with aSizes occupies.
virtual RULE_RESOLVER * GetRuleResolver()=0
ROUTER_IFACE * GetInterface() const
void SetFailureReason(const wxString &aReason)
virtual int Clearance(const ITEM *aA, const ITEM *aB, bool aUseClearanceEpsilon=true)=0
virtual bool DpNetPair(const ITEM *aItem, NET_HANDLE &aNetP, NET_HANDLE &aNetN)=0
The actual Push and Shove algorithm.
void ForceClearance(bool aEnabled, int aClearance)
bool ShoveObstacleLine(const LINE &aCurLine, const LINE &aObstacleLine, LINE &aResultLine)
bool LeadingRatLine(const LINE *aTrack, SHAPE_LINE_CHAIN &aRatLine)
const DIFF_PAIR AssembleDiffPair(SEGMENT *aStart)
int Diameter(int aLayer) const
void SetDiameter(int aLayer, int aDiameter)
const VECTOR2I & Pos() const
const SHAPE * Shape(int aLayer) const override
Return the geometrical shape of the item.
void SetPos(const VECTOR2I &aPos)
void SetIterationLimit(const int aIterLimit)
void SetSolidsOnly(bool aSolidsOnly)
STATUS Route(const LINE &aInitialPath, LINE &aWalkPath, bool aOptimize=true)
void SetCollisionFilter(COLLISION_FILTER_FUNC aFilter)
void SetAllowedPolicies(std::vector< WALK_POLICY > aPolicies)
Represent a contiguous set of PCB layers.
VECTOR2I LineProject(const VECTOR2I &aP) const
Compute the perpendicular projection point of aP on a line passing through ends of the segment.
const VECTOR2I & GetP1() const
const VECTOR2I & GetP0() const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void Simplify(int aTolerance=0)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
int SegmentCount() const
Return the number of segments in this line chain.
void Remove(int aStartIndex, int aEndIndex)
Remove the range of points [start_index, end_index] from the line chain.
constexpr extended_type SquaredEuclideanNorm() const
Compute the squared euclidean norm of the vector, which is defined as (x ** 2 + y ** 2).
constexpr VECTOR2< T > Perpendicular() const
Compute the perpendicular vector.
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.
MINOPTMAX< int > DP_GAP_CONSTRAINT
static void drawGateways(PNS::DEBUG_DECORATOR *dbg, const wxString &groupName, PNS::DP_PRIMITIVE_PAIR &prims, PNS::DP_GATEWAYS &gws, VECTOR2D offset, VECTOR2D step)
OPT_VECTOR2I getDanglingAnchor(NODE *aNode, ITEM *aItem)
const wxString Format(const MINOPTMAX< int > x)
bool SplitAdjacentSegments(NODE *aNode, ITEM *aSeg, const VECTOR2I &aP)
Snaps the point aP to segment aSeg.
@ RM_MarkObstacles
Ignore collisions, mark obstacles.
@ RM_Walkaround
Only walk around.
static void drawSingleGateway(DEBUG_DECORATOR *dbg, DP_GATEWAY gw, wxString grpName)
std::unique_ptr< typename std::remove_const< T >::type > Clone(const T &aItem)
#define PNS_DBG(dbg, method,...)
#define PNS_DBGN(dbg, method)
std::optional< VECTOR2I > OPT_VECTOR2I
COLLISION_FILTER_FUNC m_filter
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.
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D