Better error messages when routing can't be started.
Fixes https://gitlab.com/kicad/code/kicad/issues/6541
This commit is contained in:
parent
f6578da824
commit
02cd8c99cd
|
@ -403,7 +403,7 @@ bool DIFF_PAIR_PLACER::SetLayer( int aLayer )
|
|||
}
|
||||
|
||||
|
||||
OPT_VECTOR2I DIFF_PAIR_PLACER::getDanglingAnchor( NODE* aNode, ITEM* aItem )
|
||||
OPT_VECTOR2I getDanglingAnchor( NODE* aNode, ITEM* aItem )
|
||||
{
|
||||
switch( aItem->Kind() )
|
||||
{
|
||||
|
@ -429,20 +429,19 @@ OPT_VECTOR2I DIFF_PAIR_PLACER::getDanglingAnchor( NODE* aNode, ITEM* aItem )
|
|||
|
||||
default:
|
||||
return OPT_VECTOR2I();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool DIFF_PAIR_PLACER::findDpPrimitivePair( const VECTOR2I& aP, ITEM* aItem,
|
||||
bool DIFF_PAIR_PLACER::FindDpPrimitivePair( NODE* aWorld, const VECTOR2I& aP, ITEM* aItem,
|
||||
DP_PRIMITIVE_PAIR& aPair, wxString* aErrorMsg )
|
||||
{
|
||||
int netP, netN;
|
||||
|
||||
wxLogTrace( "PNS", "world %p", m_world );
|
||||
wxLogTrace( "PNS", "world %p", aWorld );
|
||||
|
||||
bool result = m_world->GetRuleResolver()->DpNetPair( aItem, netP, netN );
|
||||
bool result = aWorld->GetRuleResolver()->DpNetPair( aItem, netP, netN );
|
||||
|
||||
if( !result )
|
||||
{
|
||||
|
@ -460,7 +459,7 @@ bool DIFF_PAIR_PLACER::findDpPrimitivePair( const VECTOR2I& aP, ITEM* aItem,
|
|||
|
||||
wxLogTrace( "PNS", "result %d", !!result );
|
||||
|
||||
OPT_VECTOR2I refAnchor = getDanglingAnchor( m_currentNode, aItem );
|
||||
OPT_VECTOR2I refAnchor = getDanglingAnchor( aWorld, aItem );
|
||||
ITEM* primRef = aItem;
|
||||
|
||||
wxLogTrace( "PNS", "refAnchor %p", aItem );
|
||||
|
@ -478,7 +477,7 @@ bool DIFF_PAIR_PLACER::findDpPrimitivePair( const VECTOR2I& aP, ITEM* aItem,
|
|||
|
||||
std::set<ITEM*> coupledItems;
|
||||
|
||||
m_currentNode->AllItemsInNet( coupledNet, coupledItems );
|
||||
aWorld->AllItemsInNet( coupledNet, coupledItems );
|
||||
double bestDist = std::numeric_limits<double>::max();
|
||||
bool found = false;
|
||||
|
||||
|
@ -486,7 +485,7 @@ bool DIFF_PAIR_PLACER::findDpPrimitivePair( const VECTOR2I& aP, ITEM* aItem,
|
|||
{
|
||||
if( item->Kind() == aItem->Kind() )
|
||||
{
|
||||
OPT_VECTOR2I anchor = getDanglingAnchor( m_currentNode, item );
|
||||
OPT_VECTOR2I anchor = getDanglingAnchor( aWorld, item );
|
||||
if( !anchor )
|
||||
continue;
|
||||
|
||||
|
@ -524,7 +523,7 @@ bool DIFF_PAIR_PLACER::findDpPrimitivePair( const VECTOR2I& aP, ITEM* aItem,
|
|||
{
|
||||
*aErrorMsg = wxString::Format( _( "Can't find a suitable starting point "
|
||||
"for coupled net \"%s\"." ),
|
||||
m_world->GetRuleResolver()->NetName( coupledNet ) );
|
||||
aWorld->GetRuleResolver()->NetName( coupledNet ) );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -548,49 +547,16 @@ int DIFF_PAIR_PLACER::gap() const
|
|||
bool DIFF_PAIR_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
|
||||
{
|
||||
VECTOR2I p( aP );
|
||||
wxString msg;
|
||||
|
||||
if( !aStartItem )
|
||||
{
|
||||
Router()->SetFailureReason( _( "Can't start a differential pair "
|
||||
" in the middle of nowhere." ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
setWorld( Router()->GetWorld() );
|
||||
m_currentNode = m_world;
|
||||
|
||||
if( !findDpPrimitivePair( aP, aStartItem, m_start, &msg ) )
|
||||
{
|
||||
Router()->SetFailureReason( msg );
|
||||
if( !FindDpPrimitivePair( m_currentNode, aP, aStartItem, m_start ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
m_netP = m_start.PrimP()->Net();
|
||||
m_netN = m_start.PrimN()->Net();
|
||||
|
||||
#if 0
|
||||
// FIXME: this also needs to be factored out but not so important right now
|
||||
// Check if the current track/via gap & track width settings are violated
|
||||
BOARD* brd = NULL; // FIXME Router()->GetBoard();
|
||||
NETCLASSPTR netclassP = brd->FindNet( m_netP )->GetNetClass();
|
||||
NETCLASSPTR netclassN = brd->FindNet( m_netN )->GetNetClass();
|
||||
int clearance = std::min( m_sizes.DiffPairGap(), m_sizes.DiffPairViaGap() );
|
||||
|
||||
if( clearance < netclassP->GetClearance() || clearance < netclassN->GetClearance() )
|
||||
{
|
||||
Router()->SetFailureReason( _( "Current track/via gap setting violates "
|
||||
"design rules for this net." ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( m_sizes.DiffPairWidth() < brd->GetDesignSettings().m_TrackMinWidth )
|
||||
{
|
||||
Router()->SetFailureReason( _( "Current track width setting violates design rules." ) );
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_currentStart = p;
|
||||
m_currentEnd = p;
|
||||
m_placingVia = false;
|
||||
|
@ -646,7 +612,7 @@ bool DIFF_PAIR_PLACER::routeHead( const VECTOR2I& aP )
|
|||
|
||||
DP_PRIMITIVE_PAIR target;
|
||||
|
||||
if( findDpPrimitivePair( aP, m_currentEndItem, target ) )
|
||||
if( FindDpPrimitivePair( m_currentNode, aP, m_currentEndItem, target ) )
|
||||
{
|
||||
gwsTarget.BuildFromPrimitivePair( target, m_startDiagonal );
|
||||
m_snapOnTarget = true;
|
||||
|
|
|
@ -58,6 +58,9 @@ public:
|
|||
DIFF_PAIR_PLACER( ROUTER* aRouter );
|
||||
~DIFF_PAIR_PLACER();
|
||||
|
||||
static bool FindDpPrimitivePair( NODE* aWorld, const VECTOR2I& aP, ITEM* aItem,
|
||||
DP_PRIMITIVE_PAIR& aPair, wxString* aErrorMsg = nullptr );
|
||||
|
||||
/**
|
||||
* Function Start()
|
||||
*
|
||||
|
@ -235,9 +238,8 @@ private:
|
|||
|
||||
const VIA makeVia ( const VECTOR2I& aP, int aNet );
|
||||
|
||||
bool findDpPrimitivePair( const VECTOR2I& aP, ITEM* aItem, DP_PRIMITIVE_PAIR& aPair, wxString* aErrorMsg = nullptr );
|
||||
OPT_VECTOR2I getDanglingAnchor( NODE* aNode, ITEM* aItem );
|
||||
bool attemptWalk( NODE* aNode, DIFF_PAIR* aCurrent, DIFF_PAIR& aWalk, bool aPFirst, bool aWindCw, bool aSolidsOnly );
|
||||
bool attemptWalk( NODE* aNode, DIFF_PAIR* aCurrent, DIFF_PAIR& aWalk, bool aPFirst,
|
||||
bool aWindCw, bool aSolidsOnly );
|
||||
bool propagateDpHeadForces ( const VECTOR2I& aP, VECTOR2I& aNewP );
|
||||
|
||||
enum State {
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
|
||||
#include <pcb_painter.h>
|
||||
#include <pcbnew_settings.h>
|
||||
#include <pad.h>
|
||||
#include <zone.h>
|
||||
|
||||
#include <geometry/shape.h>
|
||||
|
||||
|
@ -169,6 +171,7 @@ bool ROUTER::StartDragging( const VECTOR2I& aP, ITEM_SET aStartItems, int aDragM
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ROUTER::isStartingPointRoutable( const VECTOR2I& aWhere, ITEM* aStartItem, int aLayer )
|
||||
{
|
||||
if( Settings().CanViolateDRC() && Settings().Mode() == RM_MarkObstacles )
|
||||
|
@ -179,12 +182,69 @@ bool ROUTER::isStartingPointRoutable( const VECTOR2I& aWhere, ITEM* aStartItem,
|
|||
for( ITEM* item : candidates.Items() )
|
||||
{
|
||||
if( !item->IsRoutable() && item->Layers().Overlaps( aLayer ) )
|
||||
return false;
|
||||
{
|
||||
BOARD_ITEM* parent = item->Parent();
|
||||
|
||||
switch( parent->Type() )
|
||||
{
|
||||
case PCB_PAD_T:
|
||||
{
|
||||
PAD* pad = static_cast<PAD*>( parent );
|
||||
|
||||
if( pad->GetAttribute() == PAD_ATTRIB_NPTH )
|
||||
SetFailureReason( _( "Cannot start routing from a non-plated hole." ) );
|
||||
}
|
||||
break;
|
||||
|
||||
case PCB_ZONE_T:
|
||||
case PCB_FP_ZONE_T:
|
||||
{
|
||||
ZONE* zone = static_cast<ZONE*>( parent );
|
||||
|
||||
if( !zone->GetZoneName().IsEmpty() )
|
||||
{
|
||||
SetFailureReason( wxString::Format( _( "Rule area '%s' disallows tracks." ),
|
||||
zone->GetZoneName() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
SetFailureReason( _( "Rule area disallows tracks." ) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PCB_TEXT_T:
|
||||
case PCB_FP_TEXT_T:
|
||||
SetFailureReason( _( "Cannot start routing from a text item." ) );
|
||||
break;
|
||||
|
||||
case PCB_SHAPE_T:
|
||||
case PCB_FP_SHAPE_T:
|
||||
SetFailureReason( _( "Cannot start routing from a graphic." ) );
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if( m_mode == PNS_MODE_ROUTE_SINGLE && aStartItem )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
VECTOR2I startPoint = aStartItem ? aStartItem->Anchor( 0 ) : aWhere;
|
||||
|
||||
if( aStartItem && aStartItem->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T ) )
|
||||
{
|
||||
VECTOR2I otherEnd = aStartItem->Anchor( 1 );
|
||||
|
||||
if( ( otherEnd - aWhere ).SquaredEuclideanNorm()
|
||||
< ( startPoint - aWhere ).SquaredEuclideanNorm() )
|
||||
{
|
||||
startPoint = otherEnd;
|
||||
}
|
||||
}
|
||||
|
||||
if( m_mode == PNS_MODE_ROUTE_SINGLE )
|
||||
{
|
||||
VECTOR2I startPoint = aStartItem->Anchor( 0 );
|
||||
SHAPE_LINE_CHAIN dummyStartSeg;
|
||||
LINE dummyStartLine;
|
||||
|
||||
|
@ -193,7 +253,7 @@ bool ROUTER::isStartingPointRoutable( const VECTOR2I& aWhere, ITEM* aStartItem,
|
|||
|
||||
dummyStartLine.SetShape( dummyStartSeg );
|
||||
dummyStartLine.SetLayer( aLayer );
|
||||
dummyStartLine.SetNet( aStartItem->Net() );
|
||||
dummyStartLine.SetNet( aStartItem ? aStartItem->Net() : 0 );
|
||||
dummyStartLine.SetWidth( m_sizes.TrackWidth() );
|
||||
|
||||
if( m_world->CheckColliding( &dummyStartLine, ITEM::ANY_T ) )
|
||||
|
@ -206,12 +266,65 @@ bool ROUTER::isStartingPointRoutable( const VECTOR2I& aWhere, ITEM* aStartItem,
|
|||
for( ITEM* item : highlightedItems )
|
||||
m_iface->HideItem( item );
|
||||
|
||||
SetFailureReason( _( "The routing start point violates DRC." ) );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if( m_mode == PNS_MODE_ROUTE_DIFF_PAIR && aStartItem )
|
||||
else if( m_mode == PNS_MODE_ROUTE_DIFF_PAIR )
|
||||
{
|
||||
// TODO
|
||||
if( !aStartItem )
|
||||
{
|
||||
SetFailureReason( _( "Cannot start a differential pair in the middle of nowhere." ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
DP_PRIMITIVE_PAIR dpPair;
|
||||
wxString errorMsg;
|
||||
|
||||
if( !DIFF_PAIR_PLACER::FindDpPrimitivePair( m_world.get(), startPoint, aStartItem, dpPair,
|
||||
&errorMsg ) )
|
||||
{
|
||||
SetFailureReason( errorMsg );
|
||||
return false;
|
||||
}
|
||||
|
||||
SHAPE_LINE_CHAIN dummyStartSegA;
|
||||
SHAPE_LINE_CHAIN dummyStartSegB;
|
||||
LINE dummyStartLineA;
|
||||
LINE dummyStartLineB;
|
||||
|
||||
dummyStartSegA.Append( dpPair.AnchorN() );
|
||||
dummyStartSegA.Append( dpPair.AnchorN(), true );
|
||||
|
||||
dummyStartSegB.Append( dpPair.AnchorP() );
|
||||
dummyStartSegB.Append( dpPair.AnchorP(), true );
|
||||
|
||||
dummyStartLineA.SetShape( dummyStartSegA );
|
||||
dummyStartLineA.SetLayer( aLayer );
|
||||
dummyStartLineA.SetNet( dpPair.PrimN()->Net() );
|
||||
dummyStartLineA.SetWidth( m_sizes.DiffPairWidth() );
|
||||
|
||||
dummyStartLineB.SetShape( dummyStartSegB );
|
||||
dummyStartLineB.SetLayer( aLayer );
|
||||
dummyStartLineB.SetNet( dpPair.PrimP()->Net() );
|
||||
dummyStartLineB.SetWidth( m_sizes.DiffPairWidth() );
|
||||
|
||||
if( m_world->CheckColliding( &dummyStartLineA, ITEM::ANY_T )
|
||||
|| m_world->CheckColliding( &dummyStartLineB, ITEM::ANY_T ) )
|
||||
{
|
||||
ITEM_SET dummyStartSet;
|
||||
NODE::ITEM_VECTOR highlightedItems;
|
||||
|
||||
dummyStartSet.Add( dummyStartLineA );
|
||||
dummyStartSet.Add( dummyStartLineB );
|
||||
markViolations( m_world.get(), dummyStartSet, highlightedItems );
|
||||
|
||||
for( ITEM* item : highlightedItems )
|
||||
m_iface->HideItem( item );
|
||||
|
||||
SetFailureReason( _( "The routing start point violates DRC." ) );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -220,10 +333,7 @@ bool ROUTER::isStartingPointRoutable( const VECTOR2I& aWhere, ITEM* aStartItem,
|
|||
bool ROUTER::StartRouting( const VECTOR2I& aP, ITEM* aStartItem, int aLayer )
|
||||
{
|
||||
if( !isStartingPointRoutable( aP, aStartItem, aLayer ) )
|
||||
{
|
||||
SetFailureReason( _( "The routing start point violates DRC." ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
m_forceMarkObstaclesMode = false;
|
||||
|
||||
|
|
Loading…
Reference in New Issue