router: multiple fixes:

- PNS_ITEMSET now keeps ownership info (does not rely on PNS_ITEM::Owner(), avoiding the risk of dangling pointers)
- fixed vias losing connected traces when dragging in mark obstacles mode
- fixed rare segfault when board item returned null netclass
This commit is contained in:
Tomasz Wlostowski 2015-08-19 17:27:23 +02:00 committed by Maciej Suminski
parent 33a9f7ecc8
commit 95c59c8060
14 changed files with 185 additions and 217 deletions

View File

@ -142,21 +142,22 @@ bool PNS_DRAGGER::dragMarkObstacles( const VECTOR2I& aP )
case CORNER:
{
int thresh = Settings().SmoothDraggedSegments() ? m_draggedLine.Width() / 4 : 0;
PNS_LINE tmp( m_draggedLine );
PNS_LINE dragged( m_draggedLine );
if( m_mode == SEGMENT )
tmp.DragSegment( aP, m_draggedSegmentIndex, thresh );
dragged.DragSegment( aP, m_draggedSegmentIndex, thresh );
else
tmp.DragCorner( aP, m_draggedSegmentIndex, thresh );
dragged.DragCorner( aP, m_draggedSegmentIndex, thresh );
m_lastNode = m_shove->CurrentNode()->Branch();
m_lastValidDraggedLine = tmp;
m_lastValidDraggedLine = dragged;
m_lastValidDraggedLine.ClearSegmentLinks();
m_lastValidDraggedLine.Unmark();
m_lastNode->Add( &m_lastValidDraggedLine );
m_draggedItems = PNS_ITEMSET( &m_lastValidDraggedLine );
m_draggedItems.Clear();
m_draggedItems.Add( m_lastValidDraggedLine );
break;
}
@ -181,10 +182,12 @@ bool PNS_DRAGGER::dragMarkObstacles( const VECTOR2I& aP )
void PNS_DRAGGER::dumbDragVia( PNS_VIA* aVia, PNS_NODE* aNode, const VECTOR2I& aP )
{
m_draggedItems.Clear();
// fixme: this is awful.
m_draggedVia = aVia->Clone();
m_draggedVia->SetPos( aP );
m_draggedItems.Clear();
m_draggedItems.Add( m_draggedVia );
m_lastNode->Remove( aVia );
@ -192,12 +195,12 @@ void PNS_DRAGGER::dumbDragVia( PNS_VIA* aVia, PNS_NODE* aNode, const VECTOR2I& a
BOOST_FOREACH( PNS_ITEM* item, m_origViaConnections.Items() )
{
if ( const PNS_LINE* l = dyn_cast<const PNS_LINE*>( item ) )
if( const PNS_LINE* l = dyn_cast<const PNS_LINE*>( item ) )
{
PNS_LINE origLine( *l );
PNS_LINE draggedLine( *l );
draggedLine.DragCorner( aP, 0 );
draggedLine.DragCorner( aP, origLine.CLine().Find( aVia->Pos() ) );
draggedLine.ClearSegmentLinks();
m_draggedItems.Add( draggedLine );
@ -225,32 +228,33 @@ bool PNS_DRAGGER::dragShove( const VECTOR2I& aP )
case CORNER:
{
int thresh = Settings().SmoothDraggedSegments() ? m_draggedLine.Width() / 4 : 0;
PNS_LINE tmp( m_draggedLine );
PNS_LINE dragged( m_draggedLine );
if( m_mode == SEGMENT )
tmp.DragSegment( aP, m_draggedSegmentIndex, thresh );
dragged.DragSegment( aP, m_draggedSegmentIndex, thresh );
else
tmp.DragCorner( aP, m_draggedSegmentIndex, thresh );
dragged.DragCorner( aP, m_draggedSegmentIndex, thresh );
PNS_SHOVE::SHOVE_STATUS st = m_shove->ShoveLines( tmp );
PNS_SHOVE::SHOVE_STATUS st = m_shove->ShoveLines( dragged );
if( st == PNS_SHOVE::SH_OK )
ok = true;
else if( st == PNS_SHOVE::SH_HEAD_MODIFIED )
{
tmp = m_shove->NewHead();
dragged = m_shove->NewHead();
ok = true;
}
m_lastNode = m_shove->CurrentNode()->Branch();
if( ok )
m_lastValidDraggedLine = tmp;
m_lastValidDraggedLine = dragged;
m_lastValidDraggedLine.ClearSegmentLinks();
m_lastValidDraggedLine.Unmark();
m_lastNode->Add( &m_lastValidDraggedLine );
m_draggedItems = PNS_ITEMSET( &m_lastValidDraggedLine );
m_draggedItems.Clear();
m_draggedItems.Add( m_lastValidDraggedLine );
break;
}

View File

@ -96,9 +96,6 @@ public:
virtual PNS_LOGGER* Logger();
private:
typedef std::pair<PNS_LINE*, PNS_LINE*> LinePair;
typedef std::vector<LinePair> LinePairVec;
enum DragMode {
CORNER = 0,
SEGMENT,
@ -122,9 +119,8 @@ private:
bool m_dragStatus;
PNS_MODE m_currentMode;
PNS_ITEMSET m_origViaConnections;
PNS_ITEMSET m_draggedViaConnections;
PNS_VIA* m_initialVia;
PNS_ITEMSET m_draggedItems;
PNS_VIA* m_initialVia;
PNS_ITEMSET m_draggedItems;
};
#endif

View File

@ -41,60 +41,13 @@ enum LineMarker {
};
/**
* Class PNS_OBJECT
*
* Abstract base class to hold ownership information about items/nodes
* used by the router.
*/
class PNS_OBJECT
{
public:
PNS_OBJECT():
m_owner( NULL ) {}
virtual ~PNS_OBJECT() {}
/**
* Functon SetOwner()
*
* Sets the node that owns this item. An item can belong to a single
* PNS_OBJECT or stay unowned.
*/
void SetOwner( PNS_OBJECT* aOwner )
{
m_owner = aOwner;
}
/**
* Function BelongsTo()
*
* @return true if the item is owned by aObj
*/
bool BelongsTo( const PNS_OBJECT* aObj ) const
{
return m_owner == aObj;
}
/**
* Function Owner()
*
* Returns the owner of this item, or NULL if there's none.
*/
PNS_OBJECT* Owner() const { return m_owner; }
protected:
PNS_OBJECT* m_owner;
};
/**
* Class PNS_ITEM
*
* Base class for PNS router board items. Implements the shared properties of all PCB items -
* net, spanned layers, geometric shape & refererence to owning model.
*/
class PNS_ITEM : public PNS_OBJECT
class PNS_ITEM
{
public:
static const int UnusedNet = INT_MAX;
@ -274,6 +227,34 @@ public:
return Layers().Overlaps( aOther->Layers() );
}
/**
* Functon SetOwner()
*
* Sets the node that owns this item. An item can belong to a single
* PNS_NODE or stay unowned.
*/
void SetOwner( PNS_NODE* aOwner )
{
m_owner = aOwner;
}
/**
* Function BelongsTo()
*
* @return true if the item is owned by the node aNode.
*/
bool BelongsTo( PNS_NODE* aNode ) const
{
return m_owner == aNode;
}
/**
* Function Owner()
*
* Returns the owner of this item, or NULL if there's none.
*/
PNS_NODE* Owner() const { return m_owner; }
/**
* Function Collide()
*
@ -357,6 +338,7 @@ protected:
PnsKind m_kind;
BOARD_CONNECTED_ITEM* m_parent;
PNS_NODE* m_owner;
PNS_LAYERSET m_layers;
bool m_movable;

View File

@ -24,43 +24,28 @@
#include "pns_line.h"
void PNS_ITEMSET::release()
{
BOOST_FOREACH( PNS_ITEM* item, m_items )
{
if( item->BelongsTo( this ) )
delete item;
}
m_items.clear();
}
PNS_ITEMSET::~PNS_ITEMSET()
{
release();
}
void PNS_ITEMSET::Add( const PNS_LINE& aLine )
{
PNS_LINE* copy = aLine.Clone();
copy->SetOwner( this );
m_items.push_back( copy );
m_items.push_back( ENTRY( copy, true ) );
}
void PNS_ITEMSET::Prepend( const PNS_LINE& aLine )
{
PNS_LINE* copy = aLine.Clone();
copy->SetOwner( this );
m_items.push_front( copy );
m_items.insert( m_items.begin(), ENTRY( copy, true ) );
}
PNS_ITEMSET& PNS_ITEMSET::FilterLayers( int aStart, int aEnd, bool aInvert )
{
ITEMS newItems;
ENTRIES newItems;
PNS_LAYERSET l;
if( aEnd < 0 )
@ -68,16 +53,12 @@ PNS_ITEMSET& PNS_ITEMSET::FilterLayers( int aStart, int aEnd, bool aInvert )
else
l = PNS_LAYERSET( aStart, aEnd );
BOOST_FOREACH( PNS_ITEM* item, m_items )
if( item->Layers().Overlaps( l ) ^ aInvert )
BOOST_FOREACH( const ENTRY& ent, m_items )
{
newItems.push_back( item );
}
else
{
if( item->BelongsTo( this ) )
item->SetOwner( NULL );
if( ent.item->Layers().Overlaps( l ) ^ aInvert )
{
newItems.push_back( ent );
}
}
m_items = newItems;
@ -88,18 +69,13 @@ PNS_ITEMSET& PNS_ITEMSET::FilterLayers( int aStart, int aEnd, bool aInvert )
PNS_ITEMSET& PNS_ITEMSET::FilterKinds( int aKindMask, bool aInvert )
{
ITEMS newItems;
ENTRIES newItems;
BOOST_FOREACH( PNS_ITEM* item, m_items )
BOOST_FOREACH( const ENTRY& ent, m_items )
{
if( item->OfKind( aKindMask ) ^ aInvert )
if( ent.item->OfKind( aKindMask ) ^ aInvert )
{
newItems.push_back( item );
}
else
{
if( item->BelongsTo( this ) )
item->SetOwner( NULL );
newItems.push_back( ent );
}
}
@ -111,18 +87,13 @@ PNS_ITEMSET& PNS_ITEMSET::FilterKinds( int aKindMask, bool aInvert )
PNS_ITEMSET& PNS_ITEMSET::FilterMarker( int aMarker, bool aInvert )
{
ITEMS newItems;
ENTRIES newItems;
BOOST_FOREACH( PNS_ITEM* item, m_items )
BOOST_FOREACH( const ENTRY& ent, m_items )
{
if( item->Marker() & aMarker )
if( ent.item->Marker() & aMarker )
{
newItems.push_back( item );
}
else
{
if( item->BelongsTo( this ) )
item->SetOwner( NULL );
newItems.push_back( ent );
}
}
@ -134,18 +105,13 @@ PNS_ITEMSET& PNS_ITEMSET::FilterMarker( int aMarker, bool aInvert )
PNS_ITEMSET& PNS_ITEMSET::FilterNet( int aNet, bool aInvert )
{
ITEMS newItems;
ENTRIES newItems;
BOOST_FOREACH( PNS_ITEM* item, m_items )
BOOST_FOREACH( const ENTRY& ent, m_items )
{
if( ( item->Net() == aNet ) ^ aInvert )
if( ( ent.item->Net() == aNet ) ^ aInvert )
{
newItems.push_back( item );
}
else
{
if( item->BelongsTo( this ) )
item->SetOwner( NULL );
newItems.push_back( ent );
}
}
@ -157,19 +123,13 @@ PNS_ITEMSET& PNS_ITEMSET::FilterNet( int aNet, bool aInvert )
PNS_ITEMSET& PNS_ITEMSET::ExcludeItem( const PNS_ITEM* aItem )
{
ITEMS newItems;
ENTRIES newItems;
BOOST_FOREACH( PNS_ITEM* item, m_items )
BOOST_FOREACH( const ENTRY& ent, m_items )
{
if( item == aItem )
{
if( item->BelongsTo( this ) )
item->SetOwner( NULL );
if( ent.item != aItem )
break;
}
newItems.push_back( item );
newItems.push_back( ent );
}
m_items = newItems;

View File

@ -21,7 +21,7 @@
#ifndef __PNS_ITEMSET_H
#define __PNS_ITEMSET_H
#include <deque>
#include <vector>
#include <boost/foreach.hpp>
#include "pns_item.h"
@ -34,32 +34,83 @@
**/
class PNS_LINE;
class PNS_ITEMSET : public PNS_OBJECT
class PNS_ITEMSET
{
public:
typedef std::deque<PNS_ITEM*> ITEMS;
struct ENTRY {
ENTRY( PNS_ITEM* aItem, bool aOwned = false ) :
item( aItem ),
owned( aOwned )
{}
ENTRY( const ENTRY& aOther )
{
owned = aOther.owned;
if( aOther.owned )
item = aOther.item->Clone();
else
item = aOther.item;
}
~ENTRY()
{
if( owned )
delete item;
}
bool operator== ( const ENTRY& b ) const
{
return item == b.item;
}
bool operator< ( const ENTRY& b ) const
{
return item < b.item;
}
ENTRY& operator= ( const ENTRY& aOther )
{
owned = aOther.owned;
if( aOther.owned )
item = aOther.item->Clone();
else
item = aOther.item;
return *this;
}
operator PNS_ITEM* () const
{
return item;
}
PNS_ITEM *item;
bool owned;
};
typedef std::vector<ENTRY> ENTRIES;
PNS_ITEMSET( PNS_ITEM* aInitialItem = NULL, bool aBecomeOwner = false )
{
if( aInitialItem )
{
if( aBecomeOwner )
aInitialItem->SetOwner( this );
m_items.push_back( aInitialItem );
m_items.push_back( ENTRY( aInitialItem, aBecomeOwner ) );
}
}
PNS_ITEMSET( const PNS_ITEMSET& aOther )
{
copyFrom( aOther );
m_items = aOther.m_items;
}
~PNS_ITEMSET();
const PNS_ITEMSET& operator=( const PNS_ITEMSET& aOther )
{
copyFrom( aOther );
m_items = aOther.m_items;
return *this;
}
@ -81,8 +132,8 @@ public:
return m_items.empty();
}
ITEMS& Items() { return m_items; }
const ITEMS& CItems() const { return m_items; }
ENTRIES& Items() { return m_items; }
const ENTRIES& CItems() const { return m_items; }
PNS_ITEMSET& FilterLayers( int aStart, int aEnd = -1, bool aInvert = false );
PNS_ITEMSET& FilterKinds( int aKindMask, bool aInvert = false );
@ -114,57 +165,39 @@ public:
void Add( const PNS_LINE& aLine );
void Prepend( const PNS_LINE& aLine );
PNS_ITEM* operator[] ( int index ) const
{
return m_items[index].item;
}
void Add( PNS_ITEM* aItem, bool aBecomeOwner = false )
{
if( aBecomeOwner )
aItem->SetOwner( this );
m_items.push_back( aItem );
m_items.push_back( ENTRY( aItem, aBecomeOwner ) );
}
void Prepend( PNS_ITEM* aItem, bool aBecomeOwner = false )
{
if( aBecomeOwner )
aItem->SetOwner( this );
m_items.push_front( aItem );
}
PNS_ITEM* Get( int index ) const
{
return m_items[index];
}
PNS_ITEM* operator[] ( int index ) const
{
return m_items[index];
m_items.insert( m_items.begin(), ENTRY( aItem, aBecomeOwner ) );
}
void Clear()
{
BOOST_FOREACH( PNS_ITEM* item, m_items )
{
if( item->BelongsTo( this ) )
delete item;
}
m_items.clear();
}
bool Contains( const PNS_ITEM* aItem ) const
bool Contains( PNS_ITEM* aItem ) const
{
return std::find( m_items.begin(), m_items.end(), aItem ) != m_items.end();
const ENTRY ent( aItem );
return std::find( m_items.begin(), m_items.end(), ent ) != m_items.end();
}
void Erase( PNS_ITEM* aItem )
{
ITEMS::iterator f = std::find( m_items.begin(), m_items.end(), aItem );
ENTRY ent( aItem );
ENTRIES::iterator f = std::find( m_items.begin(), m_items.end(), ent );
if( f != m_items.end() )
m_items.erase( f );
if( aItem->BelongsTo( this ) )
delete aItem;
}
template<class T>
@ -172,7 +205,7 @@ public:
{
int n = 0;
BOOST_FOREACH( PNS_ITEM* item, m_items )
BOOST_FOREACH( const PNS_ITEM* item, m_items )
{
if( item->OfKind( kind ) )
{
@ -187,22 +220,8 @@ public:
}
private:
void release();
void copyFrom( const PNS_ITEMSET& aOther )
{
release();
BOOST_FOREACH( PNS_ITEM* item, aOther.m_items )
{
if( item->BelongsTo( &aOther ) )
m_items.push_back( item->Clone() );
else
m_items.push_back( item );
}
}
ITEMS m_items;
ENTRIES m_items;
};
#endif

View File

@ -41,7 +41,7 @@
class PNS_JOINT : public PNS_ITEM
{
public:
typedef std::deque<PNS_ITEM*> LINKED_ITEMS;
typedef PNS_ITEMSET::ENTRIES LINKED_ITEMS;
///> Joints are hashed by their position, layers and net.
/// Linked items are, obviously, not hashed
@ -87,10 +87,7 @@ public:
if( m_locked )
return false;
if( m_linkedItems.Size() != 2 )
return false;
if( m_linkedItems[0]->Kind() != SEGMENT || m_linkedItems[1]->Kind() != SEGMENT )
if( m_linkedItems.Size() != 2 || m_linkedItems.Count( SEGMENT ) != 2 )
return false;
PNS_SEGMENT* seg1 = static_cast<PNS_SEGMENT*>( m_linkedItems[0] );
@ -102,18 +99,10 @@ public:
bool IsNonFanoutVia() const
{
if( m_linkedItems.Size() != 3 )
return false;
int vias = m_linkedItems.Count( VIA );
int segs = m_linkedItems.Count( SEGMENT );
int vias = 0, segs = 0;
for( int i = 0; i < 3; i++ )
{
vias += m_linkedItems[i]->Kind() == VIA ? 1 : 0;
segs += m_linkedItems[i]->Kind() == SEGMENT ? 1 : 0;
}
return ( vias == 1 && segs == 2 );
return ( m_linkedItems.Size() == 3 && vias == 1 && segs == 2 );
}
///> Links the joint to a given board item (when it's added to the PNS_NODE)

View File

@ -41,7 +41,6 @@ PNS_LINE::PNS_LINE( const PNS_LINE& aOther ) :
m_net = aOther.m_net;
m_movable = aOther.m_movable;
m_layers = aOther.m_layers;
m_owner = aOther.m_owner;
m_via = aOther.m_via;
m_hasVia = aOther.m_hasVia;
m_marker = aOther.m_marker;
@ -63,7 +62,6 @@ const PNS_LINE& PNS_LINE::operator=( const PNS_LINE& aOther )
m_width = aOther.m_width;
m_net = aOther.m_net;
m_movable = aOther.m_movable;
m_owner = aOther.m_owner;
m_layers = aOther.m_layers;
m_via = aOther.m_via;
m_hasVia = aOther.m_hasVia;
@ -146,7 +144,6 @@ PNS_SEGMENT* PNS_SEGMENT::Clone() const
s->m_layers = m_layers;
s->m_marker = m_marker;
s->m_rank = m_rank;
s->m_owner = NULL;
return s;
}
@ -361,6 +358,13 @@ SHAPE_LINE_CHAIN dragCornerInternal( const SHAPE_LINE_CHAIN& aOrigin, const VECT
int i;
int d = 2;
if( aOrigin.SegmentCount() == 1)
{
DIRECTION_45 dir( aOrigin.CPoint( 0 ) - aOrigin.CPoint( 1 ) );
return DIRECTION_45().BuildInitialTrace( aOrigin.CPoint( 0 ), aP, dir.IsDiagonal() );
}
if( aOrigin.CSegment( -1 ).Length() > 100000 * 30 ) // fixme: constant/parameter?
d = 1;
@ -411,7 +415,9 @@ SHAPE_LINE_CHAIN dragCornerInternal( const SHAPE_LINE_CHAIN& aOrigin, const VECT
return path;
}
return DIRECTION_45().BuildInitialTrace( aOrigin.CPoint( 0 ), aP, true );
DIRECTION_45 dir( aOrigin.CPoint( -1 ) - aOrigin.CPoint( -2 ) );
return DIRECTION_45().BuildInitialTrace( aOrigin.CPoint( -1 ), aP, dir.IsDiagonal() );
}

View File

@ -152,7 +152,7 @@ bool PNS_MEANDER_PLACER::doMove( const VECTOR2I& aP, PNS_ITEM* aEndItem, int aTa
{
if( const PNS_LINE* l = dyn_cast<const PNS_LINE*>( item ) )
{
Router()->DisplayDebugLine( l->CLine(), 5, 10000 );
Router()->DisplayDebugLine( l->CLine(), 5, 30000 );
}
}

View File

@ -130,6 +130,18 @@ int PNS_MEANDER_SKEW_PLACER::currentSkew() const
bool PNS_MEANDER_SKEW_PLACER::Move( const VECTOR2I& aP, PNS_ITEM* aEndItem )
{
BOOST_FOREACH( const PNS_ITEM* item, m_tunedPathP.CItems() )
{
if( const PNS_LINE* l = dyn_cast<const PNS_LINE*>( item ) )
Router()->DisplayDebugLine( l->CLine(), 5, 10000 );
}
BOOST_FOREACH( const PNS_ITEM* item, m_tunedPathN.CItems() )
{
if( const PNS_LINE* l = dyn_cast<const PNS_LINE*>( item ) )
Router()->DisplayDebugLine( l->CLine(), 4, 10000 );
}
return doMove( aP, aEndItem, m_coupledLength + m_settings.m_targetSkew );
}

View File

@ -634,7 +634,6 @@ void PNS_NODE::removeLine( PNS_LINE* aLine )
std::vector<PNS_SEGMENT*>* segRefs = aLine->LinkedSegments();
assert( segRefs != NULL );
assert( aLine->Owner() );
BOOST_FOREACH( PNS_SEGMENT* seg, *segRefs )
{
@ -642,7 +641,6 @@ void PNS_NODE::removeLine( PNS_LINE* aLine )
}
}
void PNS_NODE::removeVia( PNS_VIA* aVia )
{
// We have to split a single joint (associated with a via, binding together multiple layers)

View File

@ -128,7 +128,7 @@ struct PNS_COLLISION_FILTER {
* - lightweight cloning/branching (for recursive optimization and shove
* springback)
**/
class PNS_NODE : public PNS_OBJECT
class PNS_NODE
{
public:
typedef boost::optional<PNS_OBSTACLE> OPT_OBSTACLE;

View File

@ -87,7 +87,6 @@ PNS_VIA* PNS_VIA::Clone() const
v->m_pos = m_pos;
v->m_diameter = m_diameter;
v->m_drill = m_drill;
v->m_owner = NULL;
v->m_shape = SHAPE_CIRCLE( m_pos, m_diameter / 2 );
v->m_rank = m_rank;
v->m_marker = m_marker;

View File

@ -72,7 +72,6 @@ public:
m_shape = SHAPE_CIRCLE( m_pos, m_diameter / 2 );
m_marker = aB.m_marker;
m_rank = aB.m_rank;
m_owner = aB.m_owner;
m_drill = aB.m_drill;
m_viaType = aB.m_viaType;
}

View File

@ -438,7 +438,11 @@ bool ROUTER_TOOL::prepareInteractive()
// fixme: switch on invisible layer
if( m_startItem && m_startItem->Net() >= 0 )
// for some reason I don't understand, GetNetclass() may return null sometimes...
if( m_startItem &&
m_startItem->Net() >= 0 &&
m_startItem->Parent() &&
m_startItem->Parent()->GetNetClass() )
{
highlightNet( true, m_startItem->Net() );
// Update track width and via size shown in main toolbar comboboxes