Break a track when placing a via on it.

Fixes: lp:1737349
* https://bugs.launchpad.net/kicad/+bug/1737349
This commit is contained in:
Jeff Young 2018-04-08 17:47:39 +01:00
parent d54a252eaa
commit a597ebc85e
3 changed files with 84 additions and 14 deletions

View File

@ -48,6 +48,7 @@
#include <hotkeys.h>
#include <painter.h>
#include <status_popup.h>
#include "grid_helper.h"
#include <preview_items/arc_assistant.h>
@ -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<VIA*>( 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<VIA*>( aItem );
int newNet = findStitchedZoneNet( via );
int newNet;
TRACK* track = findTrack( via );
if( track )
{
aCommit.Modify( track );
TRACK* newTrack = dynamic_cast<TRACK*>( 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<BOARD_ITEM> 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" ) );

View File

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

View File

@ -52,7 +52,8 @@ class SELECTION;
struct INTERACTIVE_PLACER_BASE
{
virtual std::unique_ptr<BOARD_ITEM> 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;