From 323a2d83fa4b6e3d05f5a28684613ba0773f3e53 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Sun, 9 Apr 2023 18:31:11 +0100 Subject: [PATCH] Ease acquisition of a target item. pickSingleItem() had a two-attempt algorithm, but the second attempt was never made because we'd check for no hits before throwing out the aAvoidItems. The second attempt would fail anyway because QueryHoverItems() ignored the aUseClearance flag when not idle, and didn't factor in the actual clearance. (cherry picked from commit d040690f60724d553b54926b3f3831fe50470721) --- pcbnew/router/pns_router.cpp | 46 ++++++---- pcbnew/router/pns_tool_base.cpp | 155 +++++++++++++++++--------------- 2 files changed, 113 insertions(+), 88 deletions(-) diff --git a/pcbnew/router/pns_router.cpp b/pcbnew/router/pns_router.cpp index 4766ff0314..f5338b8324 100644 --- a/pcbnew/router/pns_router.cpp +++ b/pcbnew/router/pns_router.cpp @@ -119,31 +119,43 @@ bool ROUTER::RoutingInProgress() const const ITEM_SET ROUTER::QueryHoverItems( const VECTOR2I& aP, bool aUseClearance ) { + NODE* node; + int clearance; + if( m_state == IDLE || m_placer == nullptr ) { - if( aUseClearance ) - { - SEGMENT test( SEG( aP, aP ), -1 ); - test.SetWidth( 1 ); - test.SetLayers( LAYER_RANGE::All() ); - NODE::OBSTACLES obs; - m_world->QueryColliding( &test, obs, ITEM::ANY_T, -1, false ); + node = m_world.get(); + clearance = 0; + } + else if( m_mode == PNS_MODE_ROUTE_SINGLE ) + { + node = m_placer->CurrentNode(); + clearance = m_sizes.Clearance() + m_sizes.TrackWidth() / 2; + } + else if( m_mode == PNS_MODE_ROUTE_DIFF_PAIR ) + { + node = m_placer->CurrentNode(); + clearance = m_sizes.Clearance() + m_sizes.DiffPairWidth() / 2; + } - PNS::ITEM_SET ret; + if( aUseClearance ) + { + SEGMENT test( SEG( aP, aP ), -1 ); + test.SetWidth( 1 ); + test.SetLayers( LAYER_RANGE::All() ); + NODE::OBSTACLES obs; + node->QueryColliding( &test, obs, ITEM::ANY_T, -1, false, clearance ); - for( OBSTACLE& obstacle : obs ) - ret.Add( obstacle.m_item, false ); + PNS::ITEM_SET ret; - return ret; - } - else - { - return m_world->HitTest( aP ); - } + for( OBSTACLE& obstacle : obs ) + ret.Add( obstacle.m_item, false ); + + return ret; } else { - return m_placer->CurrentNode()->HitTest( aP ); + return node->HitTest( aP ); } } diff --git a/pcbnew/router/pns_tool_base.cpp b/pcbnew/router/pns_tool_base.cpp index 2884cf7505..fa309b6957 100644 --- a/pcbnew/router/pns_tool_base.cpp +++ b/pcbnew/router/pns_tool_base.cpp @@ -110,95 +110,108 @@ ITEM* TOOL_BASE::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLayer, b dist[i] = VECTOR2I::ECOORD_MAX; } - ITEM_SET candidates = m_router->QueryHoverItems( aWhere ); - - if( candidates.Empty() ) - candidates = m_router->QueryHoverItems( aWhere, true ); - - for( ITEM* item : candidates.Items() ) - { - if( !item->IsRoutable() ) - continue; - - if( !IsCopperLayer( item->Layers().Start() ) ) - continue; - - if( !m_iface->IsAnyLayerVisible( item->Layers() ) ) - continue; - - if( alg::contains( aAvoidItems, item ) ) - continue; - - // fixme: this causes flicker with live loop removal... - //if( item->Parent() && !item->Parent()->ViewIsVisible() ) - // continue; - - if( item->OfKind( ITEM::SOLID_T ) && aIgnorePads ) - { - continue; - } - else if( aNet <= 0 || item->Net() == aNet ) - { - if( item->OfKind( ITEM::VIA_T | ITEM::SOLID_T ) ) + auto haveCandidates = + [&]() { - SEG::ecoord d = ( item->Shape()->Centre() - aWhere ).SquaredEuclideanNorm(); - - if( d < dist[2] ) + for( ITEM* item : prioritized ) { - prioritized[2] = item; - dist[2] = d; + if( item ) + return true; } - if( item->Layers().Overlaps( tl ) && d < dist[0] ) + return false; + }; + + for( bool useClearance : { false, true } ) + { + ITEM_SET candidates = m_router->QueryHoverItems( aWhere, useClearance ); + + for( ITEM* item : candidates.Items() ) + { + if( !item->IsRoutable() ) + continue; + + if( !IsCopperLayer( item->Layers().Start() ) ) + continue; + + if( !m_iface->IsAnyLayerVisible( item->Layers() ) ) + continue; + + if( alg::contains( aAvoidItems, item ) ) + continue; + + // fixme: this causes flicker with live loop removal... + //if( item->Parent() && !item->Parent()->ViewIsVisible() ) + // continue; + + if( item->OfKind( ITEM::SOLID_T ) && aIgnorePads ) + { + continue; + } + else if( aNet <= 0 || item->Net() == aNet ) + { + if( item->OfKind( ITEM::VIA_T | ITEM::SOLID_T ) ) + { + SEG::ecoord d = ( item->Shape()->Centre() - aWhere ).SquaredEuclideanNorm(); + + if( d < dist[2] ) + { + prioritized[2] = item; + dist[2] = d; + } + + if( item->Layers().Overlaps( tl ) && d < dist[0] ) + { + prioritized[0] = item; + dist[0] = d; + } + } + else // ITEM::SEGMENT_T | ITEM::ARC_T + { + LINKED_ITEM* li = static_cast( item ); + SEG::ecoord d = std::min( ( li->Anchor( 0 ) - aWhere ).SquaredEuclideanNorm(), + ( li->Anchor( 1 ) - aWhere ).SquaredEuclideanNorm() ); + + if( d < dist[3] ) + { + prioritized[3] = item; + dist[3] = d; + } + + if( item->Layers().Overlaps( tl ) && d < dist[1] ) + { + prioritized[1] = item; + dist[1] = d; + } + } + } + else if( item->OfKind( ITEM::SOLID_T ) && item->IsFreePad() ) + { + // Allow free pads only when already inside pad + if( item->Shape()->Collide( aWhere ) ) { prioritized[0] = item; - dist[0] = d; + dist[0] = 0; } } - else // ITEM::SEGMENT_T | ITEM::ARC_T + else if ( item->Net() == 0 && m_router->Settings().Mode() == RM_MarkObstacles ) { - LINKED_ITEM* li = static_cast( item ); - SEG::ecoord d = std::min( ( li->Anchor( 0 ) - aWhere ).SquaredEuclideanNorm(), - ( li->Anchor( 1 ) - aWhere ).SquaredEuclideanNorm() ); - - if( d < dist[3] ) - { - prioritized[3] = item; - dist[3] = d; - } - - if( item->Layers().Overlaps( tl ) && d < dist[1] ) - { - prioritized[1] = item; - dist[1] = d; - } + // Allow unconnected items as last resort in RM_MarkObstacles mode + if( item->Layers().Overlaps( tl ) ) + prioritized[4] = item; } } - else if( item->OfKind( ITEM::SOLID_T ) && item->IsFreePad() ) - { - // Allow free pads only when already inside pad - if( item->Shape()->Collide( aWhere ) ) - { - prioritized[0] = item; - dist[0] = 0; - } - } - else if ( item->Net() == 0 && m_router->Settings().Mode() == RM_MarkObstacles ) - { - // Allow unconnected items as last resort in RM_MarkObstacles mode - if( item->Layers().Overlaps( tl ) ) - prioritized[4] = item; - } + + if( haveCandidates() ) + break; } ITEM* rv = nullptr; bool highContrast = ( frame()->GetDisplayOptions().m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL ); - for( int i = 0; i < candidateCount; i++ ) + for( ITEM* item : prioritized ) { - ITEM* item = prioritized[i]; - if( highContrast && item && !item->Layers().Overlaps( tl ) ) item = nullptr;