diff --git a/pcbnew/router/pns_node.cpp b/pcbnew/router/pns_node.cpp index 2473a31a42..6c89b6240f 100644 --- a/pcbnew/router/pns_node.cpp +++ b/pcbnew/router/pns_node.cpp @@ -1068,19 +1068,23 @@ int NODE::FindLinesBetweenJoints( const JOINT& aA, const JOINT& aB, std::vector< void NODE::FixupVirtualVias() { + SEGMENT* locked_seg = nullptr; std::vector vvias; - for( auto& joint : m_joints ) + for( auto& jointPair : m_joints ) { - if( joint.second.Layers().IsMultilayer() ) + JOINT joint = jointPair.second; + + if( joint.Layers().IsMultilayer() ) continue; int n_seg = 0, n_solid = 0, n_vias = 0; - int prev_w = -1; - int max_w = -1; + int prev_w = -1; + int max_w = -1; bool is_width_change = false; + bool is_locked = false; - for( const auto& lnk : joint.second.LinkList() ) + for( const auto& lnk : joint.LinkList() ) { if( lnk.item->OfKind( ITEM::VIA_T ) ) { @@ -1101,15 +1105,28 @@ void NODE::FixupVirtualVias() max_w = std::max( w, max_w ); prev_w = w; + + is_locked = t->IsLocked(); + locked_seg = t; } } - if( ( is_width_change || n_seg >= 3 ) && n_solid == 0 && n_vias == 0 ) + if( ( is_width_change || n_seg >= 3 || is_locked ) && n_solid == 0 && n_vias == 0 ) { // fixme: the hull margin here is an ugly temporary workaround. The real fix // is to use octagons for via force propagation. - vvias.push_back( new VVIA( joint.second.Pos(), joint.second.Layers().Start(), - max_w + 2 * PNS_HULL_MARGIN, joint.second.Net() ) ); + vvias.push_back( new VVIA( joint.Pos(), joint.Layers().Start(), + max_w + 2 * PNS_HULL_MARGIN, joint.Net() ) ); + } + + if( is_locked ) + { + const VECTOR2I& secondPos = ( locked_seg->Seg().A == joint.Pos() ) ? + locked_seg->Seg().B : + locked_seg->Seg().A; + + vvias.push_back( new VVIA( secondPos, joint.Layers().Start(), + max_w + 2 * PNS_HULL_MARGIN, joint.Net() ) ); } } diff --git a/pcbnew/router/router_tool.cpp b/pcbnew/router/router_tool.cpp index e56376e3c7..475dbe0e00 100644 --- a/pcbnew/router/router_tool.cpp +++ b/pcbnew/router/router_tool.cpp @@ -1564,7 +1564,7 @@ int ROUTER_TOOL::InlineDrag( const TOOL_EVENT& aEvent ) if( selection.Size() != 1 ) return 0; - const BOARD_ITEM* item = static_cast( selection.Front() ); + BOARD_ITEM* item = static_cast( selection.Front() ); if( item->Type() != PCB_TRACE_T && item->Type() != PCB_VIA_T @@ -1573,6 +1573,19 @@ int ROUTER_TOOL::InlineDrag( const TOOL_EVENT& aEvent ) return 0; } + // If we overrode locks, we want to clear the flag from the source item before SyncWorld is + // called so that virtual vias are not generated for the (now unlocked) track segment. Note in + // this case the lock can't be reliably re-applied, because there is no guarantee that the end + // state of the drag results in the same number of segments so it's not clear which segment to + // apply the lock state to. + bool wasLocked = false; + + if( item->IsLocked() ) + { + wasLocked = true; + item->SetLocked( false ); + } + Activate(); m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true ); @@ -1643,7 +1656,12 @@ int ROUTER_TOOL::InlineDrag( const TOOL_EVENT& aEvent ) bool dragStarted = m_router->StartDragging( p, itemsToDrag, dragMode ); if( !dragStarted ) + { + if( wasLocked ) + item->SetLocked( true ); + return 0; + } m_gridHelper->SetAuxAxes( true, p ); controls()->ShowCursor( true ); @@ -1677,6 +1695,9 @@ int ROUTER_TOOL::InlineDrag( const TOOL_EVENT& aEvent ) if( evt->IsCancelInteractive() ) { + if( wasLocked ) + item->SetLocked( true ); + break; } else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) )