diff --git a/pcbnew/tools/drawing_tool.cpp b/pcbnew/tools/drawing_tool.cpp index f16dee8734..a1b73ae114 100644 --- a/pcbnew/tools/drawing_tool.cpp +++ b/pcbnew/tools/drawing_tool.cpp @@ -48,6 +48,7 @@ #include #include #include +#include "grid_helper.h" #include @@ -1418,20 +1419,36 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent ) { struct VIA_PLACER : public INTERACTIVE_PLACER_BASE { + GRID_HELPER m_gridHelper; + + VIA_PLACER( PCB_EDIT_FRAME* aFrame ) : m_gridHelper( aFrame ) + {} + + TRACK* findTrack( VIA* aVia ) + { + const LSET lset = aVia->GetLayerSet(); + + for( TRACK* track : m_board->Tracks() ) + { + if( !(track->GetLayerSet() & lset ).any() ) + continue; + + if( TestSegmentHit( aVia->GetPosition(), track->GetStart(), track->GetEnd(), + ( track->GetWidth() + aVia->GetWidth() ) / 2 ) ) + return track; + } + + return nullptr; + } + int findStitchedZoneNet( VIA* aVia ) { const auto pos = aVia->GetPosition(); const auto lset = aVia->GetLayerSet(); - for( auto tv : m_board->Tracks() ) // fixme: move to BOARD class? - { - if( tv->HitTest( pos ) && ( tv->GetLayerSet() & lset ).any() ) - return -1; - } - for( auto mod : m_board->Modules() ) { - for( auto pad : mod->Pads() ) + for( D_PAD* pad : mod->Pads() ) { if( pad->HitTest( pos ) && ( pad->GetLayerSet() & lset ).any() ) return -1; @@ -1470,15 +1487,55 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent ) return -1; } - bool PlaceItem( BOARD_ITEM* aItem ) override + void SnapItem( BOARD_ITEM *aItem ) override + { +#if 0 + // If you place a Via on a track but not on its centerline, the current + // connectivity algorithm will require us to put a kink in the track when + // we break it (so that each of the two segments ends on the via center). + // That's not ideal, and is in fact probably worse than forcing snap in + // this situation. + if( m_frame->Settings().m_magneticTracks == CAPTURE_CURSOR_IN_TRACK_TOOL + || m_frame->Settings().m_magneticTracks == CAPTURE_ALWAYS ) +#endif + { + auto via = static_cast( aItem ); + wxPoint pos = via->GetPosition(); + TRACK* track = findTrack( via ); + + if( track ) + { + SEG trackSeg( track->GetStart(), track->GetEnd() ); + VECTOR2I snap = m_gridHelper.AlignToSegment( pos, trackSeg ); + + aItem->SetPosition( wxPoint( snap.x, snap.y ) ); + } + } + } + + void PlaceItem( BOARD_ITEM* aItem, BOARD_COMMIT& aCommit ) override { auto via = static_cast( aItem ); - int newNet = findStitchedZoneNet( via ); + int newNet; + TRACK* track = findTrack( via ); + + if( track ) + { + aCommit.Modify( track ); + TRACK* newTrack = dynamic_cast( track->Clone() ); + track->SetEnd( via->GetPosition() ); + newTrack->SetStart( via->GetPosition() ); + aCommit.Add( newTrack ); + + newNet = track->GetNetCode(); + } + else + newNet = findStitchedZoneNet( via ); if( newNet > 0 ) via->SetNetCode( newNet ); - return false; + aCommit.Add( aItem ); } std::unique_ptr CreateItem() override @@ -1550,7 +1607,7 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent ) } }; - VIA_PLACER placer; + VIA_PLACER placer( frame() ); frame()->SetToolID( ID_PCB_DRAW_VIA_BUTT, wxCURSOR_PENCIL, _( "Add vias" ) ); diff --git a/pcbnew/tools/pcb_tool.cpp b/pcbnew/tools/pcb_tool.cpp index 0347ca7ece..32571db75e 100644 --- a/pcbnew/tools/pcb_tool.cpp +++ b/pcbnew/tools/pcb_tool.cpp @@ -131,7 +131,7 @@ void PCB_TOOL::doInteractiveItemPlacement( INTERACTIVE_PLACER_BASE* aPlacer, newItem->ClearFlags(); preview.Remove( newItem.get() ); - aPlacer->PlaceItem( newItem.get() ); + aPlacer->PlaceItem( newItem.get(), commit ); if( newItem->Type() == PCB_MODULE_T ) { @@ -139,7 +139,7 @@ void PCB_TOOL::doInteractiveItemPlacement( INTERACTIVE_PLACER_BASE* aPlacer, module->RunOnChildren( std::bind( &KIGFX::VIEW_GROUP::Remove, &preview, _1 ) ); } - commit.Add( newItem.release() ); + newItem.release(); commit.Push( aCommitMessage ); controls()->CaptureCursor( false ); @@ -186,6 +186,7 @@ void PCB_TOOL::doInteractiveItemPlacement( INTERACTIVE_PLACER_BASE* aPlacer, { // track the cursor newItem->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); + aPlacer->SnapItem( newItem.get() ); // Show a preview of the item view()->Update( &preview ); @@ -228,3 +229,14 @@ SELECTION& PCB_TOOL::selection() auto& selection = selTool->GetSelection(); return selection; } + + +void INTERACTIVE_PLACER_BASE::SnapItem( BOARD_ITEM *aItem ) +{ + // Base implementation performs no snapping +} + +void INTERACTIVE_PLACER_BASE::PlaceItem( BOARD_ITEM *aItem, BOARD_COMMIT& aCommit ) +{ + aCommit.Add( aItem ); +} diff --git a/pcbnew/tools/pcb_tool.h b/pcbnew/tools/pcb_tool.h index 64f5c90f9b..011df7a207 100644 --- a/pcbnew/tools/pcb_tool.h +++ b/pcbnew/tools/pcb_tool.h @@ -52,7 +52,8 @@ class SELECTION; struct INTERACTIVE_PLACER_BASE { virtual std::unique_ptr CreateItem() = 0; - virtual bool PlaceItem( BOARD_ITEM *aItem ) { return false; } + virtual void SnapItem( BOARD_ITEM *aItem ); + virtual void PlaceItem( BOARD_ITEM *aItem, BOARD_COMMIT& aCommit ); PCB_EDIT_FRAME* m_frame; BOARD* m_board;