router: abstract segment links into a LINK_HOLDER interface. DIFF_PAIRS are now also linkable

This commit is contained in:
Tomasz Wlostowski 2020-04-15 22:16:24 +02:00
parent 151b4e4e5e
commit fd07e94760
12 changed files with 184 additions and 138 deletions

View File

@ -120,7 +120,7 @@ bool COMPONENT_DRAGGER::Drag( const VECTOR2I& aP )
{
auto l_new( cn.origLine );
l_new.Unmark();
l_new.ClearSegmentLinks();
l_new.ClearLinks();
l_new.DragCorner( cn.p_next, cn.origLine.CLine().Find( cn.p_orig ) );
Dbg()->AddLine( l_new.CLine(), 4, 100000 );

View File

@ -30,6 +30,7 @@
#include "pns_line.h"
#include "pns_via.h"
#include "pns_link_holder.h"
#include "ranged_num.h"
@ -262,7 +263,7 @@ class DP_GATEWAYS
* Basic class for a differential pair. Stores two PNS_LINEs (for positive and negative nets, respectively),
* the gap and coupling constraints.
**/
class DIFF_PAIR : public ITEM {
class DIFF_PAIR : public LINK_HOLDER {
public:
struct COUPLED_SEGMENTS {
@ -286,7 +287,7 @@ public:
typedef std::vector<COUPLED_SEGMENTS> COUPLED_SEGMENTS_VEC;
DIFF_PAIR() : ITEM( DIFF_PAIR_T ), m_hasVias( false )
DIFF_PAIR() : LINK_HOLDER( ITEM::DIFF_PAIR_T ), m_hasVias( false )
{
// Initialize some members, to avoid uninitialized variables.
m_net_p = 0;
@ -299,7 +300,7 @@ public:
}
DIFF_PAIR( int aGap ) :
ITEM( DIFF_PAIR_T ),
LINK_HOLDER( ITEM::DIFF_PAIR_T ),
m_hasVias( false )
{
m_gapConstraint = aGap;
@ -315,7 +316,7 @@ public:
}
DIFF_PAIR( const SHAPE_LINE_CHAIN &aP, const SHAPE_LINE_CHAIN& aN, int aGap = 0 ):
ITEM( DIFF_PAIR_T ),
LINK_HOLDER( ITEM::DIFF_PAIR_T ),
m_n( aN ),
m_p( aP ),
m_hasVias( false )
@ -333,7 +334,7 @@ public:
}
DIFF_PAIR( const LINE &aLineP, const LINE &aLineN, int aGap = 0 ):
ITEM( DIFF_PAIR_T ),
LINK_HOLDER( ITEM::DIFF_PAIR_T ),
m_line_p( aLineP ),
m_line_n( aLineN ),
m_hasVias( false )
@ -354,11 +355,18 @@ public:
static inline bool ClassOf( const ITEM* aItem )
{
return aItem && DIFF_PAIR_T == aItem->Kind();
return aItem && ITEM::DIFF_PAIR_T == aItem->Kind();
}
DIFF_PAIR* Clone() const override { assert( false ); return NULL; }
virtual void ClearLinks() override
{
m_links.clear();
m_line_p.ClearLinks();
m_line_n.ClearLinks();
}
static DIFF_PAIR* AssembleDp( LINE *aLine );
void SetShape( const SHAPE_LINE_CHAIN &aP, const SHAPE_LINE_CHAIN& aN, bool aSwapLanes = false )

View File

@ -206,7 +206,7 @@ bool DRAGGER::dragMarkObstacles( const VECTOR2I& aP )
LINE origLine( m_draggedLine );
LINE dragged( m_draggedLine );
dragged.SetSnapThreshhold( thresh );
dragged.ClearSegmentLinks();
dragged.ClearLinks();
if( m_mode == DM_SEGMENT )
dragged.DragSegment( aP, m_draggedSegmentIndex );
@ -258,7 +258,7 @@ void DRAGGER::dragViaMarkObstacles( const VIA_HANDLE& aHandle, NODE* aNode, cons
LINE draggedLine( *l );
draggedLine.DragCorner( aP, origLine.CLine().Find( aHandle.pos ), m_freeAngleMode );
draggedLine.ClearSegmentLinks();
draggedLine.ClearLinks();
m_draggedItems.Add( draggedLine );
@ -298,7 +298,7 @@ void DRAGGER::dragViaWalkaround( const VIA_HANDLE& aHandle, NODE* aNode, const V
LINE draggedLine( *l );
draggedLine.DragCorner( aP, origLine.CLine().Find( aHandle.pos ), m_freeAngleMode );
draggedLine.ClearSegmentLinks();
draggedLine.ClearLinks();
m_draggedItems.Add( draggedLine );
@ -322,7 +322,7 @@ void DRAGGER::dragViaWalkaround( const VIA_HANDLE& aHandle, NODE* aNode, const V
void DRAGGER::optimizeAndUpdateDraggedLine( LINE& dragged, const VECTOR2I& aP )
{
VECTOR2D lockV;
dragged.ClearSegmentLinks();
dragged.ClearLinks();
dragged.Unmark();
lockV = dragged.CLine().NearestPoint( aP );
@ -462,7 +462,7 @@ bool DRAGGER::dragShove( const VECTOR2I& aP )
if( ok )
{
VECTOR2D lockV;
dragged.ClearSegmentLinks();
dragged.ClearLinks();
dragged.Unmark();
lockV = dragged.CLine().NearestPoint( aP );

View File

@ -78,6 +78,7 @@ std::string ITEM::KindStr() const
case VIA_T: return "via";
case JOINT_T: return "joint";
case SOLID_T: return "solid";
case DIFF_PAIR_T: return "diff-pair";
default: return "unknown";
}
}

View File

@ -35,7 +35,7 @@
namespace PNS {
LINE::LINE( const LINE& aOther )
: ITEM( aOther ),
: LINK_HOLDER( aOther ),
m_line( aOther.m_line ),
m_width( aOther.m_width ),
m_snapThreshhold( aOther.m_snapThreshhold )
@ -89,7 +89,7 @@ void LINE::Mark( int aMarker )
{
m_marker = aMarker;
for( auto s : m_segmentRefs )
for( auto s : m_links )
s->Mark( aMarker );
}
@ -97,7 +97,7 @@ void LINE::Mark( int aMarker )
void LINE::Unmark( int aMarker )
{
for( auto s : m_segmentRefs )
for( auto s : m_links )
s->Unmark( aMarker );
m_marker = 0;
@ -108,7 +108,7 @@ int LINE::Marker() const
{
int marker = m_marker;
for( auto s : m_segmentRefs )
for( auto s : m_links )
{
marker |= s->Marker();
}
@ -117,12 +117,6 @@ int LINE::Marker() const
}
void LINE::copyLinks( const LINE* aParent )
{
m_segmentRefs = aParent->m_segmentRefs;
}
SEGMENT* SEGMENT::Clone() const
{
SEGMENT* s = new SEGMENT;
@ -460,20 +454,6 @@ const LINE LINE::ClipToNearestObstacle( NODE* aNode ) const
}
void LINE::ShowLinks() const
{
if( !IsLinked() )
{
wxLogTrace( "PNS", "line %p: no links", this );
return;
}
wxLogTrace( "PNS", "line %p: %d linked segs", this, (int) m_segmentRefs.size() );
for( int i = 0; i < (int) m_segmentRefs.size(); i++ )
wxLogTrace( "PNS", "seg %d: %p\n", i, m_segmentRefs[i] );
}
SHAPE_LINE_CHAIN dragCornerInternal( const SHAPE_LINE_CHAIN& aOrigin, const VECTOR2I& aP )
{
@ -852,7 +832,7 @@ void LINE::Reverse()
{
m_line = m_line.Reverse();
std::reverse( m_segmentRefs.begin(), m_segmentRefs.end() );
std::reverse( m_links.begin(), m_links.end() );
}
@ -873,7 +853,7 @@ void LINE::SetRank( int aRank )
{
m_rank = aRank;
for( auto s : m_segmentRefs )
for( auto s : m_links )
s->SetRank( aRank );
}
@ -884,7 +864,7 @@ int LINE::Rank() const
int min_rank = INT_MAX;
if( IsLinked() ) {
for( auto s : m_segmentRefs )
for( auto s : m_links )
{
min_rank = std::min( min_rank, s->Rank() );
}
@ -903,17 +883,17 @@ void LINE::ClipVertexRange( int aStart, int aEnd )
m_line = m_line.Slice( aStart, aEnd );
if( IsLinked() ) {
assert( m_segmentRefs.size() < INT_MAX );
assert( (int) m_segmentRefs.size() >= (aEnd - aStart) );
assert( m_links.size() < INT_MAX );
assert( (int) m_links.size() >= (aEnd - aStart) );
// Note: The range includes aEnd, but we have n-1 segments.
std::rotate(
m_segmentRefs.begin(),
m_segmentRefs.begin() + aStart,
m_segmentRefs.begin() + aEnd
m_links.begin(),
m_links.begin() + aStart,
m_links.begin() + aEnd
);
m_segmentRefs.resize( aEnd - aStart );
m_links.resize( aEnd - aStart );
}
}
@ -933,12 +913,6 @@ bool LINE::HasLoops() const
}
void LINE::ClearSegmentLinks()
{
m_segmentRefs.clear();
}
static void extendBox( BOX2I& aBox, bool& aDefined, const VECTOR2I& aP )
{
if( aDefined )
@ -1036,7 +1010,7 @@ OPT_BOX2I LINE::ChangedArea( const LINE* aOther ) const
bool LINE::HasLockedSegments() const
{
for( const auto seg : m_segmentRefs )
for( const auto seg : m_links )
{
if( seg->Marker() & MK_LOCKED )
return true;

View File

@ -32,6 +32,7 @@
#include "pns_item.h"
#include "pns_via.h"
#include "pns_link_holder.h"
namespace PNS {
@ -58,16 +59,15 @@ class VIA;
#define PNS_HULL_MARGIN 10
class LINE : public ITEM
class LINE : public LINK_HOLDER
{
public:
typedef std::vector<LINKED_ITEM*> SEGMENT_REFS;
/**
* Constructor
* Makes an empty line.
*/
LINE() : ITEM( LINE_T )
LINE() : LINK_HOLDER( LINE_T )
{
m_hasVia = false;
m_width = 1; // Dummy value
@ -82,7 +82,7 @@ public:
* by another
**/
LINE( const LINE& aBase, const SHAPE_LINE_CHAIN& aLine )
: ITEM( aBase ),
: LINK_HOLDER( aBase ),
m_line( aLine ),
m_width( aBase.m_width ),
m_snapThreshhold( aBase.m_snapThreshhold )
@ -98,7 +98,7 @@ public:
* @param aVia
*/
LINE( const VIA& aVia ) :
ITEM( LINE_T )
LINK_HOLDER( LINE_T )
{
m_hasVia = true;
m_via = aVia;
@ -121,6 +121,11 @@ public:
LINE& operator=( const LINE& aOther );
bool IsLinkedChecked() const
{
return IsLinked() && LinkCount() == SegmentCount();
}
///> Assigns a shape to the line (a polyline/line chain)
void SetShape( const SHAPE_LINE_CHAIN& aLine )
{
@ -195,53 +200,6 @@ public:
///> Reverses the point/vertex order
void Reverse();
/* Linking functions */
///> Adds a reference to a segment registered in a NODE that is a part of this line.
void LinkSegment( LINKED_ITEM* aSeg )
{
m_segmentRefs.push_back( aSeg );
}
///> Returns the list of segments from the owning node that constitute this
///> line (or NULL if the line is not linked)
SEGMENT_REFS& LinkedSegments()
{
return m_segmentRefs;
}
bool IsLinked() const
{
return m_segmentRefs.size() != 0;
}
bool IsLinkedChecked() const
{
return IsLinked() && LinkCount() == SegmentCount();
}
///> Checks if the segment aSeg is a part of the line.
bool ContainsSegment( LINKED_ITEM* aSeg ) const
{
return std::find( m_segmentRefs.begin(), m_segmentRefs.end(),
aSeg ) != m_segmentRefs.end();
}
LINKED_ITEM* GetLink( int aIndex ) const
{
return m_segmentRefs[aIndex];
}
///> Erases the linking information. Used to detach the line from the owning node.
void ClearSegmentLinks();
///> Returns the number of segments that were assembled together to form this line.
int LinkCount() const
{
return m_segmentRefs.size();
}
///> Clips the line to the nearest obstacle, traversing from the line's start vertex (0).
///> Returns the clipped line.
const LINE ClipToNearestObstacle( NODE* aNode ) const;
@ -320,13 +278,6 @@ private:
VECTOR2I snapDraggedCorner(
const SHAPE_LINE_CHAIN& aPath, const VECTOR2I& aP, int aIndex ) const;
///> Copies m_segmentRefs from the line aParent.
void copyLinks( const LINE* aParent ) ;
///> List of segments in the owning NODE (ITEM::m_owner) that constitute this line, or NULL
///> if the line is not a part of any node.
SEGMENT_REFS m_segmentRefs;
///> The actual shape of the line
SHAPE_LINE_CHAIN m_line;

View File

@ -1294,9 +1294,9 @@ void LINE_PLACER::removeLoops( NODE* aNode, LINE& aLatest )
{
total++;
if( !( line.ContainsSegment( seg ) ) && line.SegmentCount() )
if( !( line.ContainsLink( seg ) ) && line.SegmentCount() )
{
for( auto ss : line.LinkedSegments() )
for( auto ss : line.Links() )
toErase.insert( ss );
removedCount++;

View File

@ -0,0 +1,109 @@
/*
* KiRouter - a push-and-(sometimes-)shove PCB router
*
* Copyright (C) 2019 CERN
* Author: Seth Hillbrand <hillbrand@ucdavis.edu>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.h>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PCBNEW_ROUTER_PNS_LINK_HOLDER_H_
#define PCBNEW_ROUTER_PNS_LINK_HOLDER_H_
#include "pns_item.h"
#include "pns_linked_item.h"
namespace PNS
{
class LINK_HOLDER : public ITEM
{
public:
typedef std::vector<LINKED_ITEM*> LINKS;
LINK_HOLDER( PnsKind aKind ) : ITEM( aKind )
{}
///> Adds a reference to an item registered in a NODE that is a part of this line.
void Link( LINKED_ITEM* aLink )
{
m_links.push_back( aLink );
}
///> Returns the list of links from the owning node that constitute this
///> line (or NULL if the line is not linked)
LINKS& Links()
{
return m_links;
}
bool IsLinked() const
{
return m_links.size() != 0;
}
///> Checks if the segment aLink is a part of the line.
bool ContainsLink( const LINKED_ITEM* aItem ) const
{
return std::find( m_links.begin(), m_links.end(),
aItem ) != m_links.end();
}
LINKED_ITEM* GetLink( int aIndex ) const
{
return m_links[aIndex];
}
///> Erases the linking information. Used to detach the line from the owning node.
virtual void ClearLinks()
{
m_links.clear();
}
///> Returns the number of segments that were assembled together to form this line.
int LinkCount() const
{
return m_links.size();
}
void ShowLinks() const
{
#if 0 // fixme: move outside header
if( !IsLinked() )
{
wxLogTrace( "PNS", "item %p: no links", this );
return;
}
wxLogTrace( "PNS", "item %p: %d links", this, (int) m_links.size() );
for( int i = 0; i < (int) m_links.size(); i++ )
wxLogTrace( "PNS", "item %d: %p\n", i, m_links[i] );
#endif
}
protected:
///> Copies m_links from the line aParent.
void copyLinks( const LINK_HOLDER* aParent )
{
m_links = aParent->m_links;
}
///> List of segments in the owning NODE (ITEM::m_owner) that constitute this line, or NULL
///> if the line is not a part of any node.
LINKS m_links;
};
} // namespace PNS
#endif /* PCBNEW_ROUTER_PNS_LINK_HOLDER_H_ */

View File

@ -574,11 +574,11 @@ void NODE::Add( LINE& aLine, bool aAllowRedundant )
ARC* rarc;
if( !aAllowRedundant && ( rarc = findRedundantArc( s.GetP0(), s.GetP1(), aLine.Layers(), aLine.Net() ) ) )
aLine.LinkSegment( rarc );
aLine.Link( rarc );
else
{
auto newarc = std::make_unique< ARC >( aLine, s );
aLine.LinkSegment( newarc.get() );
aLine.Link( newarc.get() );
Add( std::move( newarc ), true );
}
}
@ -597,12 +597,12 @@ void NODE::Add( LINE& aLine, bool aAllowRedundant )
(rseg = findRedundantSegment( s.A, s.B, aLine.Layers(), aLine.Net() )) )
{
// another line could be referencing this segment too :(
aLine.LinkSegment( rseg );
aLine.Link( rseg );
}
else
{
std::unique_ptr< SEGMENT > newseg( new SEGMENT( aLine, s ) );
aLine.LinkSegment( newseg.get() );
aLine.Link( newseg.get() );
Add( std::move( newseg ), true );
}
}
@ -819,7 +819,7 @@ void NODE::Remove( ITEM* aItem )
{
auto l = static_cast<LINE *> ( aItem );
for ( auto s : l->LinkedSegments() )
for ( auto s : l->Links() )
Remove( s );
break;
@ -838,7 +838,7 @@ void NODE::Remove( ITEM* aItem )
void NODE::Remove( LINE& aLine )
{
// LINE does not have a seperate remover, as LINEs are never truly a member of the tree
std::vector<LINKED_ITEM*>& segRefs = aLine.LinkedSegments();
std::vector<LINKED_ITEM*>& segRefs = aLine.Links();
for( auto li : segRefs )
{
@ -849,7 +849,7 @@ void NODE::Remove( LINE& aLine )
}
aLine.SetOwner( nullptr );
aLine.ClearSegmentLinks();
aLine.ClearLinks();
}
@ -925,7 +925,7 @@ const LINE NODE::AssembleLine( LINKED_ITEM* aSeg, int* aOriginSegmentIndex, bool
if( segs[i] && prev_seg != segs[i] )
{
pl.LinkSegment( segs[i] );
pl.Link( segs[i] );
// latter condition to avoid loops
if( segs[i] == aSeg && aOriginSegmentIndex && !originSet )

View File

@ -190,14 +190,14 @@ void OPTIMIZER::removeCachedSegments( LINE* aLine, int aStartVertex, int aEndVer
{
if( !aLine->IsLinked() ) return;
LINE::SEGMENT_REFS& segs = aLine->LinkedSegments();
auto links = aLine->Links();
if( aEndVertex < 0 )
aEndVertex += aLine->PointCount();
for( int i = aStartVertex; i < aEndVertex - 1; i++ )
{
LINKED_ITEM* s = segs[i];
LINKED_ITEM* s = links[i];
m_cacheTags.erase( s );
m_cache.Remove( s );
}
@ -594,7 +594,10 @@ bool OPTIMIZER::Optimize( LINE* aLine, LINE* aResult )
if( !aResult )
aResult = aLine;
else
{
*aResult = *aLine;
aResult->ClearLinks();
}
m_keepPostures = false;

View File

@ -266,11 +266,11 @@ SHOVE::SHOVE_STATUS SHOVE::processHullSet( LINE& aCurrent, LINE& aObstacle,
*/
SHOVE::SHOVE_STATUS SHOVE::ProcessSingleLine( LINE& aCurrent, LINE& aObstacle, LINE& aShoved )
{
aShoved.ClearSegmentLinks();
aShoved.ClearLinks();
bool obstacleIsHead = false;
for( auto s : aObstacle.LinkedSegments() )
for( auto s : aObstacle.Links() )
{
if( s->Marker() & MK_HEAD )
{
@ -555,7 +555,7 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingSolid( LINE& aCurrent, ITEM* aObstacle )
if( status != WALKAROUND::DONE )
continue;
walkaroundLine.ClearSegmentLinks();
walkaroundLine.ClearLinks();
walkaroundLine.Unmark();
walkaroundLine.Line().Simplify();
@ -742,7 +742,7 @@ SHOVE::SHOVE_STATUS SHOVE::pushOrShoveVia( VIA* aVia, const VECTOR2I& aForce, in
lp.first.Reverse();
lp.second = lp.first;
lp.second.ClearSegmentLinks();
lp.second.ClearLinks();
lp.second.DragCorner( p0_pushed, lp.second.CLine().Find( p0 ) );
lp.second.AppendVia( *pushedVia );
draggedLines.push_back( lp );
@ -891,11 +891,11 @@ SHOVE::SHOVE_STATUS SHOVE::onReverseCollidingVia( LINE& aCurrent, VIA* aObstacle
{
int n = 0;
LINE cur( aCurrent );
cur.ClearSegmentLinks();
cur.ClearLinks();
JOINT* jt = m_currentNode->FindJoint( aObstacleVia->Pos(), aObstacleVia );
LINE shoved( aCurrent );
shoved.ClearSegmentLinks();
shoved.ClearLinks();
cur.RemoveVia();
unwindLineStack( &aCurrent );
@ -939,7 +939,7 @@ SHOVE::SHOVE_STATUS SHOVE::onReverseCollidingVia( LINE& aCurrent, VIA* aObstacle
LINE head( aCurrent );
head.Line().Clear();
head.AppendVia( *aObstacleVia );
head.ClearSegmentLinks();
head.ClearLinks();
SHOVE_STATUS st = ProcessSingleLine( head, aCurrent, shoved );
@ -974,7 +974,7 @@ void SHOVE::unwindLineStack( LINKED_ITEM* aSeg )
{
for( std::vector<LINE>::iterator i = m_lineStack.begin(); i != m_lineStack.end() ; )
{
if( i->ContainsSegment( aSeg ) )
if( i->ContainsLink( aSeg ) )
i = m_lineStack.erase( i );
else
i++;
@ -982,7 +982,7 @@ void SHOVE::unwindLineStack( LINKED_ITEM* aSeg )
for( std::vector<LINE>::iterator i = m_optimizerQueue.begin(); i != m_optimizerQueue.end() ; )
{
if( i->ContainsSegment( aSeg ) )
if( i->ContainsLink( aSeg ) )
i = m_optimizerQueue.erase( i );
else
i++;
@ -998,7 +998,7 @@ void SHOVE::unwindLineStack( ITEM* aItem )
{
LINE* l = static_cast<LINE*>( aItem );
for( auto seg : l->LinkedSegments() )
for( auto seg : l->Links() )
unwindLineStack( seg );
}
}
@ -1031,9 +1031,9 @@ void SHOVE::popLineStack( )
{
bool found = false;
for( auto s : l.LinkedSegments() )
for( auto s : l.Links() )
{
if( i->ContainsSegment( s ) )
if( i->ContainsLink( s ) )
{
i = m_optimizerQueue.erase( i );
found = true;
@ -1254,7 +1254,7 @@ SHOVE::SHOVE_STATUS SHOVE::ShoveLines( const LINE& aCurrentHead )
return SH_INCOMPLETE;
LINE head( aCurrentHead );
head.ClearSegmentLinks();
head.ClearLinks();
m_lineStack.clear();
m_optimizerQueue.clear();
@ -1382,7 +1382,7 @@ SHOVE::SHOVE_STATUS SHOVE::ShoveMultiLines( const ITEM_SET& aHeadSet )
{
const LINE* headOrig = static_cast<const LINE*>( item );
LINE head( *headOrig );
head.ClearSegmentLinks();
head.ClearLinks();
m_currentNode->Add( head );

View File

@ -182,7 +182,7 @@ bool TOPOLOGY::followTrivialPath( LINE* aLine, bool aLeft, ITEM_SET& aSet, std::
VECTOR2I anchor = aLeft ? aLine->CPoint( 0 ) : aLine->CPoint( -1 );
LINKED_ITEM* last =
aLeft ? aLine->LinkedSegments().front() : aLine->LinkedSegments().back();
aLeft ? aLine->Links().front() : aLine->Links().back();
JOINT* jt = m_world->FindJoint( anchor, aLine );
assert( jt != NULL );