From 02cd8c99cd97568f7495fff86b51a704d8a3cea4 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Tue, 5 Jan 2021 18:45:32 +0000 Subject: [PATCH] Better error messages when routing can't be started. Fixes https://gitlab.com/kicad/code/kicad/issues/6541 --- pcbnew/router/pns_diff_pair_placer.cpp | 54 ++--------- pcbnew/router/pns_diff_pair_placer.h | 8 +- pcbnew/router/pns_router.cpp | 126 +++++++++++++++++++++++-- 3 files changed, 133 insertions(+), 55 deletions(-) diff --git a/pcbnew/router/pns_diff_pair_placer.cpp b/pcbnew/router/pns_diff_pair_placer.cpp index 62038d0ca4..2ec4243c00 100644 --- a/pcbnew/router/pns_diff_pair_placer.cpp +++ b/pcbnew/router/pns_diff_pair_placer.cpp @@ -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 coupledItems; - m_currentNode->AllItemsInNet( coupledNet, coupledItems ); + aWorld->AllItemsInNet( coupledNet, coupledItems ); double bestDist = std::numeric_limits::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; diff --git a/pcbnew/router/pns_diff_pair_placer.h b/pcbnew/router/pns_diff_pair_placer.h index b639c3220e..c4d5b5529c 100644 --- a/pcbnew/router/pns_diff_pair_placer.h +++ b/pcbnew/router/pns_diff_pair_placer.h @@ -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 { diff --git a/pcbnew/router/pns_router.cpp b/pcbnew/router/pns_router.cpp index cac7f8aa68..f00716c42e 100644 --- a/pcbnew/router/pns_router.cpp +++ b/pcbnew/router/pns_router.cpp @@ -32,6 +32,8 @@ #include #include +#include +#include #include @@ -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 ) ) + { + BOARD_ITEM* parent = item->Parent(); + + switch( parent->Type() ) + { + case PCB_PAD_T: + { + PAD* pad = static_cast( 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( 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; + } + return false; + } } - if( m_mode == PNS_MODE_ROUTE_SINGLE && aStartItem ) + 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;