pcbnew: Disallow new via where DRC is violated

Prior to placing the via, we check if the resulting via will pass too
close to different nets on different layers.

Fixes: lp:1718827
* https://bugs.launchpad.net/kicad/+bug/1718827
This commit is contained in:
Seth Hillbrand 2019-01-23 07:18:44 -08:00
parent 86263d6bb3
commit 4247e32cd6
4 changed files with 91 additions and 13 deletions

View File

@ -1504,20 +1504,86 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
TRACK* findTrack( VIA* aVia )
{
const LSET lset = aVia->GetLayerSet();
std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> items;
BOX2I bbox = aVia->GetBoundingBox();
auto view = m_frame->GetGalCanvas()->GetView();
for( TRACK* track : m_board->Tracks() )
view->Query( bbox, items );
for( auto it : items )
{
if( !(track->GetLayerSet() & lset ).any() )
BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it.first );
if( !(item->GetLayerSet() & lset ).any() )
continue;
if( TestSegmentHit( aVia->GetPosition(), track->GetStart(), track->GetEnd(),
( track->GetWidth() + aVia->GetWidth() ) / 2 ) )
return track;
if( auto track = dyn_cast<TRACK*>( item ) )
{
if( TestSegmentHit( aVia->GetPosition(), track->GetStart(), track->GetEnd(),
( track->GetWidth() + aVia->GetWidth() ) / 2 ) )
return track;
}
}
return nullptr;
}
bool hasDRCViolation( VIA* aVia )
{
const LSET lset = aVia->GetLayerSet();
std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> items;
int net = 0;
int clearance = 0;
BOX2I bbox = aVia->GetBoundingBox();
auto view = m_frame->GetGalCanvas()->GetView();
view->Query( bbox, items );
for( auto it : items )
{
BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it.first );
if( !(item->GetLayerSet() & lset ).any() )
continue;
if( auto track = dyn_cast<TRACK*>( item ) )
{
int max_clearance = std::max( clearance, track->GetClearance() );
if( TestSegmentHit( aVia->GetPosition(), track->GetStart(), track->GetEnd(),
( track->GetWidth() + aVia->GetWidth() ) / 2 + max_clearance ) )
{
if( net && track->GetNetCode() != net )
return true;
net = track->GetNetCode();
clearance = track->GetClearance();
}
}
if( auto mod = dyn_cast<MODULE*>( item ) )
{
for( auto pad : mod->Pads() )
{
int max_clearance = std::max( clearance, pad->GetClearance() );
if( pad->HitTest( aVia->GetBoundingBox(), false, max_clearance ) )
{
if( net && pad->GetNetCode() != net )
return true;
net = pad->GetNetCode();
clearance = pad->GetClearance();
}
}
}
}
return false;
}
int findStitchedZoneNet( VIA* aVia )
{
const auto pos = aVia->GetPosition();
@ -1572,8 +1638,6 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
// That's not ideal, and is in fact probably worse than forcing snap in
// this situation.
// bool do_snap = ( m_frame->Settings().m_magneticTracks == CAPTURE_CURSOR_IN_TRACK_TOOL
// || m_frame->Settings().m_magneticTracks == CAPTURE_ALWAYS );
m_gridHelper.SetSnap( !( m_modifiers & MD_SHIFT ) );
auto via = static_cast<VIA*>( aItem );
wxPoint pos = via->GetPosition();
@ -1588,12 +1652,15 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
}
}
void PlaceItem( BOARD_ITEM* aItem, BOARD_COMMIT& aCommit ) override
bool PlaceItem( BOARD_ITEM* aItem, BOARD_COMMIT& aCommit ) override
{
auto via = static_cast<VIA*>( aItem );
int newNet;
TRACK* track = findTrack( via );
if( hasDRCViolation( via ) )
return false;
if( track )
{
aCommit.Modify( track );
@ -1611,6 +1678,7 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
via->SetNetCode( newNet );
aCommit.Add( aItem );
return true;
}
std::unique_ptr<BOARD_ITEM> CreateItem() override

View File

@ -109,7 +109,7 @@ int MODULE_EDITOR_TOOLS::PlacePad( const TOOL_EVENT& aEvent )
return std::unique_ptr<BOARD_ITEM>( pad );
}
void PlaceItem( BOARD_ITEM *aItem, BOARD_COMMIT& aCommit ) override
bool PlaceItem( BOARD_ITEM *aItem, BOARD_COMMIT& aCommit ) override
{
D_PAD* pad = dynamic_cast<D_PAD*>( aItem );
@ -118,7 +118,10 @@ int MODULE_EDITOR_TOOLS::PlacePad( const TOOL_EVENT& aEvent )
m_frame->Export_Pad_Settings( pad );
pad->SetLocalCoord();
aCommit.Add( aItem );
return true;
}
return false;
}
};

View File

@ -132,10 +132,16 @@ void PCB_TOOL::doInteractiveItemPlacement( INTERACTIVE_PLACER_BASE* aPlacer,
}
else
{
auto oldFlags = newItem->GetFlags();
newItem->ClearFlags();
preview.Remove( newItem.get() );
aPlacer->PlaceItem( newItem.get(), commit );
if( !aPlacer->PlaceItem( newItem.get(), commit ) )
{
newItem->SetFlags( oldFlags );
continue;
}
preview.Remove( newItem.get() );
if( newItem->Type() == PCB_MODULE_T )
{
@ -262,7 +268,8 @@ void INTERACTIVE_PLACER_BASE::SnapItem( BOARD_ITEM *aItem )
// Base implementation performs no snapping
}
void INTERACTIVE_PLACER_BASE::PlaceItem( BOARD_ITEM *aItem, BOARD_COMMIT& aCommit )
bool INTERACTIVE_PLACER_BASE::PlaceItem( BOARD_ITEM *aItem, BOARD_COMMIT& aCommit )
{
aCommit.Add( aItem );
return true;
}

View File

@ -53,7 +53,7 @@ struct INTERACTIVE_PLACER_BASE
{
virtual std::unique_ptr<BOARD_ITEM> CreateItem() = 0;
virtual void SnapItem( BOARD_ITEM *aItem );
virtual void PlaceItem( BOARD_ITEM *aItem, BOARD_COMMIT& aCommit );
virtual bool PlaceItem( BOARD_ITEM *aItem, BOARD_COMMIT& aCommit );
PCB_EDIT_FRAME* m_frame;
BOARD* m_board;