Better error messages when routing can't be started.

Fixes https://gitlab.com/kicad/code/kicad/issues/6541
This commit is contained in:
Jeff Young 2021-01-05 18:45:32 +00:00
parent f6578da824
commit 02cd8c99cd
3 changed files with 133 additions and 55 deletions

View File

@ -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;

View File

@ -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 {

View File

@ -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;