router: support for drag/walkaround/shove for joints between lines of different widths.

fixes: https://gitlab.com/kicad/code/kicad/-/issues/1773
This commit is contained in:
Tomasz Wlostowski 2021-06-03 22:36:06 +02:00
parent af26eab5fb
commit 63fc7a1908
6 changed files with 130 additions and 9 deletions

View File

@ -67,6 +67,48 @@ bool DRAGGER::propagateViaForces( NODE* node, std::set<VIA*>& vias )
return false;
}
VVIA* DRAGGER::checkVirtualVia( const VECTOR2D& aP, SEGMENT* aSeg )
{
int w2 = aSeg->Width() / 2;
auto distA = ( aP - aSeg->Seg().A ).EuclideanNorm();
auto distB = ( aP - aSeg->Seg().B ).EuclideanNorm();
VECTOR2I psnap;
if( distA <= w2 )
{
psnap = aSeg->Seg().A;
}
else if( distB <= w2 )
{
psnap = aSeg->Seg().B;
}
else
{
return nullptr;
}
JOINT *jt = m_world->FindJoint( psnap, aSeg );
if ( !jt )
{
return nullptr;
}
for( auto lnk : jt->LinkList() )
{
if( lnk.item->IsVirtual() && lnk.item->OfKind( ITEM::VIA_T ))
{
return static_cast<VVIA*>( lnk.item );
}
}
return nullptr;
}
bool DRAGGER::startDragSegment( const VECTOR2D& aP, SEGMENT* aSeg )
{
int w2 = aSeg->Width() / 2;
@ -111,7 +153,6 @@ bool DRAGGER::startDragSegment( const VECTOR2D& aP, SEGMENT* aSeg )
}
bool DRAGGER::startDragArc( const VECTOR2D& aP, ARC* aArc )
{
m_draggedLine = m_world->AssembleLine( aArc, &m_draggedSegmentIndex );
@ -193,8 +234,19 @@ bool DRAGGER::Start( const VECTOR2I& aP, ITEM_SET& aPrimitives )
switch( startItem->Kind() )
{
case ITEM::SEGMENT_T:
return startDragSegment( aP, static_cast<SEGMENT*>( startItem ) );
{
SEGMENT* seg = static_cast<SEGMENT*>( startItem );
VVIA* vvia = checkVirtualVia( aP, seg );
if( vvia )
{
return startDragVia( vvia );
}
else
{
return startDragSegment( aP, seg );
}
}
case ITEM::VIA_T:
return startDragVia( static_cast<VIA*>( startItem ) );

View File

@ -126,6 +126,7 @@ private:
void optimizeAndUpdateDraggedLine( LINE& aDragged, const LINE& aOrig, const VECTOR2I& aP );
bool propagateViaForces( NODE* node, std::set<VIA*>& vias );
bool tryWalkaround( NODE* aNode, LINE& aOrig, LINE& aWalk );
VVIA* checkVirtualVia( const VECTOR2D& aP, SEGMENT* aSeg );
VIA_HANDLE m_initialVia;

View File

@ -1051,6 +1051,58 @@ int NODE::FindLinesBetweenJoints( const JOINT& aA, const JOINT& aB, std::vector<
}
void NODE::FixupVirtualVias()
{
int n;
std::vector<VVIA*> vvias;
for( auto& joint : m_joints )
{
if( joint.second.Layers().IsMultilayer() )
continue;
int n_seg = 0, n_solid = 0, n_vias = 0;
int prev_w = -1;
int max_w = -1;
bool is_width_change = false;
for( const auto& lnk : joint.second.LinkList() )
{
if( lnk.item->OfKind( ITEM::VIA_T ) )
n_vias++;
else if( lnk.item->OfKind( ITEM::SOLID_T ) )
n_solid++;
else if( const auto t = dyn_cast<PNS::SEGMENT*>( lnk.item ) )
{
int w = t->Width();
if( prev_w >= 0 && w != prev_w )
{
is_width_change = true;
}
max_w = std::max( w, max_w );
prev_w = w;
}
}
if( ( is_width_change || n_seg >= 3 ) && 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() ) );
}
}
for( auto vvia : vvias )
{
Add( ItemCast<VIA>( std::move( std::unique_ptr<VVIA>( vvia ) ) ) );
}
}
JOINT* NODE::FindJoint( const VECTOR2I& aPos, int aLayer, int aNet )
{
JOINT::HASH_TAG tag;

View File

@ -380,6 +380,8 @@ public:
return m_override.find( aItem ) != m_override.end();
}
void FixupVirtualVias();
private:
void Add( std::unique_ptr< ITEM > aItem, bool aAllowRedundant = false );

View File

@ -96,9 +96,10 @@ void ROUTER::SyncWorld()
m_world = std::make_unique<NODE>( );
m_iface->SyncWorld( m_world.get() );
m_world->FixupVirtualVias();
}
void ROUTER::ClearWorld()
{
if( m_world )
@ -612,15 +613,25 @@ void ROUTER::CommitRouting( NODE* aNode )
}
}
if( !is_changed )
if( !is_changed && !item->IsVirtual() )
m_iface->RemoveItem( item );
}
for( ITEM* item : added )
{
if( !item->IsVirtual() )
{
m_iface->AddItem( item );
}
}
for( ITEM* item : changed )
{
if( !item->IsVirtual() )
{
m_iface->UpdateItem( item );
}
}
m_iface->Commit();
m_world->Commit( aNode );

View File

@ -70,13 +70,16 @@ void ROUTER_PREVIEW_ITEM::Update( const PNS::ITEM* aItem )
{
m_originLayer = aItem->Layers().Start();
if( aItem->OfKind( PNS::ITEM::LINE_T ) )
if( const auto l = dyn_cast<const PNS::LINE*>( aItem ) )
{
const PNS::LINE* l = static_cast<const PNS::LINE*>( aItem );
if( !l->SegmentCount() )
return;
}
else if( const auto v = dyn_cast<const PNS::VIA*>( aItem ) )
{
if( v->IsVirtual() )
return;
}
assert( m_originLayer >= 0 );