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:
parent
86263d6bb3
commit
4247e32cd6
|
@ -1504,20 +1504,86 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
|
||||||
TRACK* findTrack( VIA* aVia )
|
TRACK* findTrack( VIA* aVia )
|
||||||
{
|
{
|
||||||
const LSET lset = aVia->GetLayerSet();
|
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;
|
continue;
|
||||||
|
|
||||||
if( TestSegmentHit( aVia->GetPosition(), track->GetStart(), track->GetEnd(),
|
if( auto track = dyn_cast<TRACK*>( item ) )
|
||||||
( track->GetWidth() + aVia->GetWidth() ) / 2 ) )
|
{
|
||||||
return track;
|
if( TestSegmentHit( aVia->GetPosition(), track->GetStart(), track->GetEnd(),
|
||||||
|
( track->GetWidth() + aVia->GetWidth() ) / 2 ) )
|
||||||
|
return track;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
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 )
|
int findStitchedZoneNet( VIA* aVia )
|
||||||
{
|
{
|
||||||
const auto pos = aVia->GetPosition();
|
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
|
// That's not ideal, and is in fact probably worse than forcing snap in
|
||||||
// this situation.
|
// 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 ) );
|
m_gridHelper.SetSnap( !( m_modifiers & MD_SHIFT ) );
|
||||||
auto via = static_cast<VIA*>( aItem );
|
auto via = static_cast<VIA*>( aItem );
|
||||||
wxPoint pos = via->GetPosition();
|
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 );
|
auto via = static_cast<VIA*>( aItem );
|
||||||
int newNet;
|
int newNet;
|
||||||
TRACK* track = findTrack( via );
|
TRACK* track = findTrack( via );
|
||||||
|
|
||||||
|
if( hasDRCViolation( via ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
if( track )
|
if( track )
|
||||||
{
|
{
|
||||||
aCommit.Modify( track );
|
aCommit.Modify( track );
|
||||||
|
@ -1611,6 +1678,7 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
|
||||||
via->SetNetCode( newNet );
|
via->SetNetCode( newNet );
|
||||||
|
|
||||||
aCommit.Add( aItem );
|
aCommit.Add( aItem );
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<BOARD_ITEM> CreateItem() override
|
std::unique_ptr<BOARD_ITEM> CreateItem() override
|
||||||
|
|
|
@ -109,7 +109,7 @@ int MODULE_EDITOR_TOOLS::PlacePad( const TOOL_EVENT& aEvent )
|
||||||
return std::unique_ptr<BOARD_ITEM>( pad );
|
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 );
|
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 );
|
m_frame->Export_Pad_Settings( pad );
|
||||||
pad->SetLocalCoord();
|
pad->SetLocalCoord();
|
||||||
aCommit.Add( aItem );
|
aCommit.Add( aItem );
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -132,10 +132,16 @@ void PCB_TOOL::doInteractiveItemPlacement( INTERACTIVE_PLACER_BASE* aPlacer,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
auto oldFlags = newItem->GetFlags();
|
||||||
newItem->ClearFlags();
|
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 )
|
if( newItem->Type() == PCB_MODULE_T )
|
||||||
{
|
{
|
||||||
|
@ -262,7 +268,8 @@ void INTERACTIVE_PLACER_BASE::SnapItem( BOARD_ITEM *aItem )
|
||||||
// Base implementation performs no snapping
|
// 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 );
|
aCommit.Add( aItem );
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ struct INTERACTIVE_PLACER_BASE
|
||||||
{
|
{
|
||||||
virtual std::unique_ptr<BOARD_ITEM> CreateItem() = 0;
|
virtual std::unique_ptr<BOARD_ITEM> CreateItem() = 0;
|
||||||
virtual void SnapItem( BOARD_ITEM *aItem );
|
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;
|
PCB_EDIT_FRAME* m_frame;
|
||||||
BOARD* m_board;
|
BOARD* m_board;
|
||||||
|
|
Loading…
Reference in New Issue