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:
parent
af26eab5fb
commit
63fc7a1908
|
@ -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 ) );
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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 )
|
||||
m_iface->AddItem( item );
|
||||
{
|
||||
if( !item->IsVirtual() )
|
||||
{
|
||||
m_iface->AddItem( item );
|
||||
}
|
||||
}
|
||||
|
||||
for( ITEM* item : changed )
|
||||
m_iface->UpdateItem( item );
|
||||
{
|
||||
if( !item->IsVirtual() )
|
||||
{
|
||||
m_iface->UpdateItem( item );
|
||||
}
|
||||
}
|
||||
|
||||
m_iface->Commit();
|
||||
m_world->Commit( aNode );
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
Loading…
Reference in New Issue