router: improvements to shove algorithm

This commit is contained in:
Tomasz Wlostowski 2015-08-19 18:07:16 +02:00 committed by Maciej Suminski
parent 95c59c8060
commit a96299d456
16 changed files with 236 additions and 73 deletions

View File

@ -282,6 +282,12 @@ static inline bool Collide( const SHAPE_CONVEX& aA, const SHAPE_SEGMENT& aB, int
return Collide( aA.Vertices(), aB, aClearance, aNeedMTV, aMTV ); return Collide( aA.Vertices(), aB, aClearance, aNeedMTV, aMTV );
} }
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_RECT& aB, int aClearance,
bool aNeedMTV, VECTOR2I& aMTV )
{
return Collide( aA.Outline(), aB.Outline(), aClearance, aNeedMTV, aMTV );
}
template<class ShapeAType, class ShapeBType> template<class ShapeAType, class ShapeBType>
inline bool CollCase( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV ) inline bool CollCase( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV )
@ -310,11 +316,8 @@ bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeed
case SH_RECT: case SH_RECT:
switch( aB->Type() ) switch( aB->Type() )
{ {
case SH_RECT: // RECT to RECT not yet in use in p&s router case SH_RECT:
// Should be (todo) somethink like: return CollCase<SHAPE_RECT, SHAPE_RECT>( aA, aB, aClearance, aNeedMTV, aMTV );
//return CollCaseReversed<SHAPE_RECT, SHAPE_RECT>( aA, aB, aClearance, aNeedMTV, aMTV );
assert( aB->Type() != SH_RECT );
return true;
case SH_CIRCLE: case SH_CIRCLE:
return CollCase<SHAPE_RECT, SHAPE_CIRCLE>( aA, aB, aClearance, aNeedMTV, aMTV ); return CollCase<SHAPE_RECT, SHAPE_CIRCLE>( aA, aB, aClearance, aNeedMTV, aMTV );

View File

@ -206,8 +206,6 @@ const SHAPE_LINE_CHAIN SHAPE_POLY_SET::convertFromClipper( const Path& aPath )
return lc; return lc;
} }
#include <common.h>
#include <wx/wx.h>
void SHAPE_POLY_SET::booleanOp( ClipType aType, const SHAPE_POLY_SET& aOtherShape, void SHAPE_POLY_SET::booleanOp( ClipType aType, const SHAPE_POLY_SET& aOtherShape,
bool aFastMode ) bool aFastMode )
{ {

View File

@ -142,6 +142,18 @@ public:
return true; return true;
} }
const SHAPE_LINE_CHAIN Outline() const
{
SHAPE_LINE_CHAIN rv;
rv.Append( m_p0 );
rv.Append( m_p0.x, m_p0.y + m_w );
rv.Append( m_p0.x + m_h, m_p0.y + m_w );
rv.Append( m_p0.x + m_h, m_p0.y );
rv.Append( m_p0 );
rv.SetClosed( true );
return rv;
}
private: private:
///> Top-left corner ///> Top-left corner
VECTOR2I m_p0; VECTOR2I m_p0;

View File

@ -22,10 +22,10 @@
#include "pns_line.h" #include "pns_line.h"
bool PNS_ITEM::collideSimple( const PNS_ITEM* aOther, int aClearance, bool aNeedMTV, bool PNS_ITEM::collideSimple( const PNS_ITEM* aOther, int aClearance, bool aNeedMTV,
VECTOR2I& aMTV ) const VECTOR2I& aMTV, bool aDifferentNetsOnly ) const
{ {
// same nets? no collision! // same nets? no collision!
if( m_net == aOther->m_net ) if( aDifferentNetsOnly && m_net == aOther->m_net )
return false; return false;
// check if we are not on completely different layers first // check if we are not on completely different layers first
@ -39,9 +39,9 @@ bool PNS_ITEM::collideSimple( const PNS_ITEM* aOther, int aClearance, bool aNeed
bool PNS_ITEM::Collide( const PNS_ITEM* aOther, int aClearance, bool aNeedMTV, bool PNS_ITEM::Collide( const PNS_ITEM* aOther, int aClearance, bool aNeedMTV,
VECTOR2I& aMTV ) const VECTOR2I& aMTV, bool aDifferentNetsOnly ) const
{ {
if( collideSimple( aOther, aClearance, aNeedMTV, aMTV ) ) if( collideSimple( aOther, aClearance, aNeedMTV, aMTV, aDifferentNetsOnly ) )
return true; return true;
// special case for "head" line with a via attached at the end. // special case for "head" line with a via attached at the end.
@ -50,7 +50,7 @@ bool PNS_ITEM::Collide( const PNS_ITEM* aOther, int aClearance, bool aNeedMTV,
const PNS_LINE* line = static_cast<const PNS_LINE*>( aOther ); const PNS_LINE* line = static_cast<const PNS_LINE*>( aOther );
if( line->EndsWithVia() ) if( line->EndsWithVia() )
return collideSimple( &line->Via(), aClearance - line->Width() / 2, aNeedMTV, aMTV ); return collideSimple( &line->Via(), aClearance - line->Width() / 2, aNeedMTV, aMTV, aDifferentNetsOnly );
} }
return false; return false;

View File

@ -270,18 +270,18 @@ public:
* @return true, if a collision was found. * @return true, if a collision was found.
*/ */
virtual bool Collide( const PNS_ITEM* aOther, int aClearance, bool aNeedMTV, virtual bool Collide( const PNS_ITEM* aOther, int aClearance, bool aNeedMTV,
VECTOR2I& aMTV ) const; VECTOR2I& aMTV, bool aDifferentNetsOnly = true ) const;
/** /**
* Function Collide() * Function Collide()
* *
* A shortcut for PNS_ITEM::Colllide() without MTV stuff. * A shortcut for PNS_ITEM::Colllide() without MTV stuff.
*/ */
bool Collide( const PNS_ITEM* aOther, int aClearance ) const bool Collide( const PNS_ITEM* aOther, int aClearance, bool aDifferentNetsOnly = true ) const
{ {
VECTOR2I dummy; VECTOR2I dummy;
return Collide( aOther, aClearance, false, dummy ); return Collide( aOther, aClearance, false, dummy, aDifferentNetsOnly );
} }
/** /**
@ -332,7 +332,7 @@ public:
private: private:
bool collideSimple( const PNS_ITEM* aOther, int aClearance, bool aNeedMTV, bool collideSimple( const PNS_ITEM* aOther, int aClearance, bool aNeedMTV,
VECTOR2I& aMTV ) const; VECTOR2I& aMTV, bool aDifferentNetsOnly ) const;
protected: protected:
PnsKind m_kind; PnsKind m_kind;

View File

@ -477,8 +477,13 @@ bool PNS_LINE_PLACER::rhShoveOnly( const VECTOR2I& aP, PNS_LINE& aNewHead )
m_currentNode = m_shove->CurrentNode(); m_currentNode = m_shove->CurrentNode();
if( status == PNS_SHOVE::SH_OK ) if( status == PNS_SHOVE::SH_OK || status == PNS_SHOVE::SH_HEAD_MODIFIED )
{ {
if( status == PNS_SHOVE::SH_HEAD_MODIFIED )
{
l2 = m_shove->NewHead();
}
optimizer.SetWorld( m_currentNode ); optimizer.SetWorld( m_currentNode );
optimizer.SetEffortLevel( PNS_OPTIMIZER::MERGE_OBTUSE | PNS_OPTIMIZER::SMART_PADS ); optimizer.SetEffortLevel( PNS_OPTIMIZER::MERGE_OBTUSE | PNS_OPTIMIZER::SMART_PADS );
optimizer.SetCollisionMask( PNS_ITEM::ANY ); optimizer.SetCollisionMask( PNS_ITEM::ANY );
@ -1087,3 +1092,11 @@ void PNS_LINE_PLACER::GetModifiedNets( std::vector<int>& aNets ) const
{ {
aNets.push_back( m_currentNet ); aNets.push_back( m_currentNet );
} }
PNS_LOGGER* PNS_LINE_PLACER::Logger()
{
if( m_shove )
return m_shove->Logger();
return NULL;
}

View File

@ -184,6 +184,10 @@ public:
bool IsPlacingVia() const { return m_placingVia; } bool IsPlacingVia() const { return m_placingVia; }
void GetModifiedNets( std::vector<int>& aNets ) const; void GetModifiedNets( std::vector<int>& aNets ) const;
PNS_LOGGER* Logger();
private: private:
/** /**
* Function route() * Function route()

View File

@ -185,7 +185,11 @@ struct PNS_NODE::OBSTACLE_VISITOR
///> additional clearance ///> additional clearance
int m_extraClearance; int m_extraClearance;
OBSTACLE_VISITOR( PNS_NODE::OBSTACLES& aTab, const PNS_ITEM* aItem, int aKindMask ) : bool m_differentNetsOnly;
int m_forceClearance;
OBSTACLE_VISITOR( PNS_NODE::OBSTACLES& aTab, const PNS_ITEM* aItem, int aKindMask, bool aDifferentNetsOnly ) :
m_node( NULL ), m_node( NULL ),
m_override( NULL ), m_override( NULL ),
m_tab( aTab ), m_tab( aTab ),
@ -193,7 +197,9 @@ struct PNS_NODE::OBSTACLE_VISITOR
m_kindMask( aKindMask ), m_kindMask( aKindMask ),
m_limitCount( -1 ), m_limitCount( -1 ),
m_matchCount( 0 ), m_matchCount( 0 ),
m_extraClearance( 0 ) m_extraClearance( 0 ),
m_differentNetsOnly( aDifferentNetsOnly ),
m_forceClearance( -1 )
{ {
if( aItem->Kind() == PNS_ITEM::LINE ) if( aItem->Kind() == PNS_ITEM::LINE )
m_extraClearance += static_cast<const PNS_LINE*>( aItem )->Width() / 2; m_extraClearance += static_cast<const PNS_LINE*>( aItem )->Width() / 2;
@ -228,7 +234,10 @@ struct PNS_NODE::OBSTACLE_VISITOR
if( aItem->Kind() == PNS_ITEM::LINE ) if( aItem->Kind() == PNS_ITEM::LINE )
clearance += static_cast<PNS_LINE*>( aItem )->Width() / 2; clearance += static_cast<PNS_LINE*>( aItem )->Width() / 2;
if( !aItem->Collide( m_item, clearance ) ) if( m_forceClearance >= 0 )
clearance = m_forceClearance;
if( !aItem->Collide( m_item, clearance, m_differentNetsOnly ) )
return true; return true;
PNS_OBSTACLE obs; PNS_OBSTACLE obs;
@ -248,9 +257,9 @@ struct PNS_NODE::OBSTACLE_VISITOR
int PNS_NODE::QueryColliding( const PNS_ITEM* aItem, int PNS_NODE::QueryColliding( const PNS_ITEM* aItem,
PNS_NODE::OBSTACLES& aObstacles, int aKindMask, int aLimitCount ) PNS_NODE::OBSTACLES& aObstacles, int aKindMask, int aLimitCount, bool aDifferentNetsOnly, int aForceClearance )
{ {
OBSTACLE_VISITOR visitor( aObstacles, aItem, aKindMask ); OBSTACLE_VISITOR visitor( aObstacles, aItem, aKindMask, aDifferentNetsOnly );
#ifdef DEBUG #ifdef DEBUG
assert( allocNodes.find( this ) != allocNodes.end() ); assert( allocNodes.find( this ) != allocNodes.end() );
@ -258,7 +267,7 @@ int PNS_NODE::QueryColliding( const PNS_ITEM* aItem,
visitor.SetCountLimit( aLimitCount ); visitor.SetCountLimit( aLimitCount );
visitor.SetWorld( this, NULL ); visitor.SetWorld( this, NULL );
visitor.m_forceClearance = aForceClearance;
// first, look for colliding items in the local index // first, look for colliding items in the local index
m_index->Query( aItem, m_maxClearance, visitor ); m_index->Query( aItem, m_maxClearance, visitor );
@ -273,7 +282,9 @@ int PNS_NODE::QueryColliding( const PNS_ITEM* aItem,
} }
PNS_NODE::OPT_OBSTACLE PNS_NODE::NearestObstacle( const PNS_LINE* aItem, int aKindMask ) PNS_NODE::OPT_OBSTACLE PNS_NODE::NearestObstacle( const PNS_LINE* aItem,
int aKindMask,
const std::set<PNS_ITEM*>* aRestrictedSet )
{ {
OBSTACLES obs_list; OBSTACLES obs_list;
bool found_isects = false; bool found_isects = false;
@ -293,7 +304,6 @@ PNS_NODE::OPT_OBSTACLE PNS_NODE::NearestObstacle( const PNS_LINE* aItem, int aKi
if( aItem->EndsWithVia() ) if( aItem->EndsWithVia() )
n += QueryColliding( &aItem->Via(), obs_list, aKindMask ); n += QueryColliding( &aItem->Via(), obs_list, aKindMask );
// if(! QueryColliding ( aItem, obs_list, aKindMask ))
if( !n ) if( !n )
return OPT_OBSTACLE(); return OPT_OBSTACLE();
@ -308,6 +318,9 @@ PNS_NODE::OPT_OBSTACLE PNS_NODE::NearestObstacle( const PNS_LINE* aItem, int aKi
VECTOR2I ip_first, ip_last; VECTOR2I ip_first, ip_last;
int dist_max = INT_MIN; int dist_max = INT_MIN;
if( aRestrictedSet && aRestrictedSet->find( obs.m_item ) == aRestrictedSet->end() )
continue;
std::vector<SHAPE_LINE_CHAIN::INTERSECTION> isect_list; std::vector<SHAPE_LINE_CHAIN::INTERSECTION> isect_list;
int clearance = GetClearance( obs.m_item, &aLine ); int clearance = GetClearance( obs.m_item, &aLine );

View File

@ -184,7 +184,9 @@ public:
int QueryColliding( const PNS_ITEM* aItem, int QueryColliding( const PNS_ITEM* aItem,
OBSTACLES& aObstacles, OBSTACLES& aObstacles,
int aKindMask = PNS_ITEM::ANY, int aKindMask = PNS_ITEM::ANY,
int aLimitCount = -1 ); int aLimitCount = -1,
bool aDifferentNetsOnly = true,
int aForceClearance = -1 );
/** /**
* Function NearestObstacle() * Function NearestObstacle()
@ -195,8 +197,9 @@ public:
* @param aKindMask mask of obstacle types to take into account * @param aKindMask mask of obstacle types to take into account
* @return the obstacle, if found, otherwise empty. * @return the obstacle, if found, otherwise empty.
*/ */
OPT_OBSTACLE NearestObstacle( const PNS_LINE* aItem, OPT_OBSTACLE NearestObstacle( const PNS_LINE* aItem,
int aKindMask = PNS_ITEM::ANY ); int aKindMask = PNS_ITEM::ANY,
const std::set<PNS_ITEM*>* aRestrictedSet = NULL );
/** /**
* Function CheckColliding() * Function CheckColliding()

View File

@ -125,6 +125,9 @@ int PNS_PCBNEW_CLEARANCE_FUNC::operator()( const PNS_ITEM* aA, const PNS_ITEM* a
bool linesOnly = aA->OfKind( PNS_ITEM::SEGMENT | PNS_ITEM::LINE ) && aB->OfKind( PNS_ITEM::SEGMENT | PNS_ITEM::LINE ); bool linesOnly = aA->OfKind( PNS_ITEM::SEGMENT | PNS_ITEM::LINE ) && aB->OfKind( PNS_ITEM::SEGMENT | PNS_ITEM::LINE );
if( net_a == net_b )
return 0;
if( linesOnly && net_a >= 0 && net_b >= 0 && m_clearanceCache[net_a].coupledNet == net_b ) if( linesOnly && net_a >= 0 && net_b >= 0 && m_clearanceCache[net_a].coupledNet == net_b )
{ {
cl_a = cl_b = m_router->Sizes().DiffPairGap() - 2 * PNS_HULL_MARGIN; cl_a = cl_b = m_router->Sizes().DiffPairGap() - 2 * PNS_HULL_MARGIN;
@ -1041,6 +1044,10 @@ void PNS_ROUTER::DumpLog()
logger = m_dragger->Logger(); logger = m_dragger->Logger();
break; break;
case ROUTE_TRACK:
logger = m_placer->Logger();
break;
default: default:
break; break;
} }

View File

@ -39,6 +39,7 @@
#include "pns_router.h" #include "pns_router.h"
#include "pns_shove.h" #include "pns_shove.h"
#include "pns_utils.h" #include "pns_utils.h"
#include "pns_topology.h"
#include "time_limit.h" #include "time_limit.h"
@ -242,7 +243,7 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::processHullSet( PNS_LINE& aCurrent, PNS_LINE&
return SH_OK; return SH_OK;
} }
return failingDirCheck ? SH_OK : SH_INCOMPLETE; return SH_INCOMPLETE;
} }
@ -277,7 +278,7 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::ProcessSingleLine( PNS_LINE& aCurrent, PNS_LI
int w = aObstacle.Width(); int w = aObstacle.Width();
int n_segs = aCurrent.SegmentCount(); int n_segs = aCurrent.SegmentCount();
int clearance = getClearance( &aCurrent, &aObstacle ); int clearance = getClearance( &aCurrent, &aObstacle ) + 1;
HULL_SET hulls; HULL_SET hulls;
@ -313,6 +314,18 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingSegment( PNS_LINE& aCurrent, PNS_S
SHOVE_STATUS rv = ProcessSingleLine( aCurrent, obstacleLine, shovedLine ); SHOVE_STATUS rv = ProcessSingleLine( aCurrent, obstacleLine, shovedLine );
const double extensionWalkThreshold = 1.0;
double obsLen = obstacleLine.CLine().Length();
double shovedLen = shovedLine.CLine().Length();
double extensionFactor = 0.0;
if( obsLen != 0.0f )
extensionFactor = shovedLen / obsLen - 1.0;
if( extensionFactor > extensionWalkThreshold )
return SH_TRY_WALK;
assert( obstacleLine.LayersOverlap( &shovedLine ) ); assert( obstacleLine.LayersOverlap( &shovedLine ) );
#ifdef DEBUG #ifdef DEBUG
@ -333,12 +346,12 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingSegment( PNS_LINE& aCurrent, PNS_S
m_newHead = shovedLine; m_newHead = shovedLine;
} }
sanityCheck( &obstacleLine, &shovedLine );
replaceItems( &obstacleLine, &shovedLine );
int rank = aCurrent.Rank(); int rank = aCurrent.Rank();
shovedLine.SetRank( rank - 1 ); shovedLine.SetRank( rank - 1 );
sanityCheck( &obstacleLine, &shovedLine );
replaceItems( &obstacleLine, &shovedLine );
if( !pushLine( shovedLine ) ) if( !pushLine( shovedLine ) )
rv = SH_INCOMPLETE; rv = SH_INCOMPLETE;
} }
@ -380,15 +393,13 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingLine( PNS_LINE& aCurrent, PNS_LINE
if( !pushLine( shovedLine ) ) if( !pushLine( shovedLine ) )
{ {
rv = SH_INCOMPLETE; rv = SH_INCOMPLETE;
//printf( "pushLine failed\n" );
} }
} }
return rv; return rv;
} }
PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingSolid( PNS_LINE& aCurrent, PNS_ITEM* aObstacle )
PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingSolid( PNS_LINE& aCurrent, PNS_SOLID* aObstacleSolid )
{ {
PNS_WALKAROUND walkaround( m_currentNode, Router() ); PNS_WALKAROUND walkaround( m_currentNode, Router() );
PNS_LINE walkaroundLine( aCurrent ); PNS_LINE walkaroundLine( aCurrent );
@ -411,54 +422,87 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingSolid( PNS_LINE& aCurrent, PNS_SOL
} }
} }
if( via && m_currentNode->CheckColliding( via, aObstacleSolid ) ) if( via && m_currentNode->CheckColliding( via, aObstacle ) )
return onCollidingVia( aObstacleSolid, via ); return onCollidingVia( aObstacle, via );
} }
walkaround.SetSolidsOnly( true ); PNS_TOPOLOGY topo( m_currentNode );
walkaround.SetIterationLimit ( 8 ); // fixme: make configurable
std::set<PNS_ITEM*> cluster = topo.AssembleCluster( aObstacle, aCurrent.Layers().Start() );
#ifdef DEBUG
m_logger.NewGroup( "on-colliding-solid-cluster", m_iter );
BOOST_FOREACH( PNS_ITEM* item, cluster )
{
m_logger.Log( item, 0, "cluster-entry" );
}
#endif
walkaround.SetSolidsOnly( false );
walkaround.RestrictToSet( true, cluster );
walkaround.SetIterationLimit( 16 ); // fixme: make configurable
int currentRank = aCurrent.Rank(); int currentRank = aCurrent.Rank();
int nextRank; int nextRank;
if( !Settings().JumpOverObstacles() ) for( int attempt = 0; attempt < 2; attempt++ )
{ {
nextRank = currentRank + 10000;
walkaround.SetSingleDirection( false );
}
else
{
nextRank = currentRank - 1;
walkaround.SetSingleDirection( true );
}
if( walkaround.Route( aCurrent, walkaroundLine, false ) != PNS_WALKAROUND::DONE ) if( attempt == 1 || Settings().JumpOverObstacles() )
return SH_INCOMPLETE; {
nextRank = currentRank - 1;
walkaround.SetSingleDirection( true );
}
else
{
nextRank = currentRank + 10000;
walkaround.SetSingleDirection( false );
}
walkaroundLine.ClearSegmentLinks();
walkaroundLine.Unmark();
walkaroundLine.Line().Simplify();
if( walkaroundLine.HasLoops() ) if( walkaround.Route( aCurrent, walkaroundLine, false ) != PNS_WALKAROUND::DONE )
return SH_INCOMPLETE;
if( aCurrent.Marker() & MK_HEAD )
{
walkaroundLine.Mark( MK_HEAD );
if( m_multiLineMode )
return SH_INCOMPLETE; return SH_INCOMPLETE;
m_newHead = walkaroundLine; walkaroundLine.ClearSegmentLinks();
walkaroundLine.Unmark();
walkaroundLine.Line().Simplify();
if( walkaroundLine.HasLoops() )
return SH_INCOMPLETE;
if( aCurrent.Marker() & MK_HEAD )
{
walkaroundLine.Mark( MK_HEAD );
if( m_multiLineMode )
return SH_INCOMPLETE;
m_newHead = walkaroundLine;
}
sanityCheck( &aCurrent, &walkaroundLine );
if( !m_lineStack.empty() )
{
PNS_LINE lastLine = m_lineStack.front();
if( m_currentNode->CheckColliding( &lastLine, &walkaroundLine ) )
{
PNS_LINE dummy ( lastLine );
if( ProcessSingleLine( walkaroundLine, lastLine, dummy ) == SH_OK )
break;
} else
break;
}
} }
sanityCheck( &aCurrent, &walkaroundLine );
replaceItems( &aCurrent, &walkaroundLine ); replaceItems( &aCurrent, &walkaroundLine );
walkaroundLine.SetRank( nextRank ); walkaroundLine.SetRank( nextRank );
#ifdef DEBUG #ifdef DEBUG
m_logger.NewGroup( "on-colliding-solid", m_iter ); m_logger.NewGroup( "on-colliding-solid", m_iter );
m_logger.Log( aObstacleSolid, 0, "obstacle-solid" ); m_logger.Log( aObstacle, 0, "obstacle-solid" );
m_logger.Log( &aCurrent, 1, "current-line" ); m_logger.Log( &aCurrent, 1, "current-line" );
m_logger.Log( &walkaroundLine, 3, "walk-line" ); m_logger.Log( &walkaroundLine, 3, "walk-line" );
#endif #endif
@ -620,7 +664,7 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::pushVia( PNS_VIA* aVia, const VECTOR2I& aForc
replaceItems( &lp.first, &lp.second ); replaceItems( &lp.first, &lp.second );
lp.second.SetRank( aCurrentRank - 1 ); lp.second.SetRank( aCurrentRank - 1 );
if( !pushLine( lp.second ) ) if( !pushLine( lp.second, true ) )
return SH_INCOMPLETE; return SH_INCOMPLETE;
} }
else else
@ -807,12 +851,20 @@ void PNS_SHOVE::unwindStack( PNS_ITEM* aItem )
} }
bool PNS_SHOVE::pushLine( const PNS_LINE& aL ) bool PNS_SHOVE::pushLine( const PNS_LINE& aL, bool aKeepCurrentOnTop )
{ {
if( aL.LinkCount() >= 0 && ( aL.LinkCount() != aL.SegmentCount() ) ) if( aL.LinkCount() >= 0 && ( aL.LinkCount() != aL.SegmentCount() ) )
return false; return false;
m_lineStack.push_back( aL ); if( aKeepCurrentOnTop && m_lineStack.size() > 0)
{
m_lineStack.insert( m_lineStack.begin() + m_lineStack.size() - 1, aL );
}
else
{
m_lineStack.push_back( aL );
}
m_optimizerQueue.push_back( aL ); m_optimizerQueue.push_back( aL );
return true; return true;
@ -919,6 +971,11 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::shoveIteration( int aIter )
case PNS_ITEM::SEGMENT: case PNS_ITEM::SEGMENT:
TRACE( 2, "iter %d: collide-segment ", aIter ); TRACE( 2, "iter %d: collide-segment ", aIter );
st = onCollidingSegment( currentLine, (PNS_SEGMENT*) ni ); st = onCollidingSegment( currentLine, (PNS_SEGMENT*) ni );
if( st == SH_TRY_WALK )
{
st = onCollidingSolid( currentLine, (PNS_SOLID*) ni );
}
break; break;
case PNS_ITEM::VIA: case PNS_ITEM::VIA:

View File

@ -49,7 +49,8 @@ public:
SH_OK = 0, SH_OK = 0,
SH_NULL, SH_NULL,
SH_INCOMPLETE, SH_INCOMPLETE,
SH_HEAD_MODIFIED SH_HEAD_MODIFIED,
SH_TRY_WALK
}; };
PNS_SHOVE( PNS_NODE* aWorld, PNS_ROUTER* aRouter ); PNS_SHOVE( PNS_NODE* aWorld, PNS_ROUTER* aRouter );
@ -110,7 +111,7 @@ private:
SHOVE_STATUS onCollidingLine( PNS_LINE& aCurrent, PNS_LINE& aObstacle ); SHOVE_STATUS onCollidingLine( PNS_LINE& aCurrent, PNS_LINE& aObstacle );
SHOVE_STATUS onCollidingSegment( PNS_LINE& aCurrent, PNS_SEGMENT* aObstacleSeg ); SHOVE_STATUS onCollidingSegment( PNS_LINE& aCurrent, PNS_SEGMENT* aObstacleSeg );
SHOVE_STATUS onCollidingSolid( PNS_LINE& aCurrent, PNS_SOLID* aObstacleSolid ); SHOVE_STATUS onCollidingSolid( PNS_LINE& aCurrent, PNS_ITEM* aObstacle );
SHOVE_STATUS onCollidingVia( PNS_ITEM* aCurrent, PNS_VIA* aObstacleVia ); SHOVE_STATUS onCollidingVia( PNS_ITEM* aCurrent, PNS_VIA* aObstacleVia );
SHOVE_STATUS onReverseCollidingVia( PNS_LINE& aCurrent, PNS_VIA* aObstacleVia ); SHOVE_STATUS onReverseCollidingVia( PNS_LINE& aCurrent, PNS_VIA* aObstacleVia );
SHOVE_STATUS pushVia( PNS_VIA* aVia, const VECTOR2I& aForce, int aCurrentRank, bool aDryRun = false ); SHOVE_STATUS pushVia( PNS_VIA* aVia, const VECTOR2I& aForce, int aCurrentRank, bool aDryRun = false );
@ -122,7 +123,7 @@ private:
void runOptimizer( PNS_NODE* aNode ); void runOptimizer( PNS_NODE* aNode );
bool pushLine( const PNS_LINE& aL ); bool pushLine( const PNS_LINE& aL, bool aKeepCurrentOnTop = false );
void popLine(); void popLine();
PNS_LINE assembleLine( const PNS_SEGMENT* aSeg, int* aIndex = NULL ); PNS_LINE assembleLine( const PNS_SEGMENT* aSeg, int* aIndex = NULL );

View File

@ -396,3 +396,34 @@ bool PNS_TOPOLOGY::AssembleDiffPair( PNS_ITEM* aStart, PNS_DIFF_PAIR& aPair )
return true; return true;
} }
const std::set<PNS_ITEM*> PNS_TOPOLOGY::AssembleCluster( PNS_ITEM* aStart, int aLayer )
{
std::set<PNS_ITEM*> visited;
std::deque<PNS_ITEM*> pending;
pending.push_back( aStart );
while( !pending.empty() )
{
PNS_NODE::OBSTACLES obstacles;
PNS_ITEM* top = pending.front();
pending.pop_front();
visited.insert( top );
m_world->QueryColliding( top, obstacles, PNS_ITEM::ANY, -1, false, 0 );
BOOST_FOREACH( PNS_OBSTACLE& obs, obstacles )
{
if( visited.find( obs.m_item ) == visited.end() && obs.m_item->Layers().Overlaps( aLayer ) && !( obs.m_item->Marker() & MK_HEAD ) )
{
visited.insert( obs.m_item );
pending.push_back( obs.m_item );
}
}
}
return visited;
}

View File

@ -61,6 +61,8 @@ public:
const PNS_LINE DpCoupledLine( PNS_LINE* aLine ); const PNS_LINE DpCoupledLine( PNS_LINE* aLine );
bool AssembleDiffPair( PNS_ITEM* aStart, PNS_DIFF_PAIR& aPair ); bool AssembleDiffPair( PNS_ITEM* aStart, PNS_DIFF_PAIR& aPair );
const std::set<PNS_ITEM*> AssembleCluster( PNS_ITEM* aStart, int aLayer );
private: private:
bool followTrivialPath( PNS_LINE* aLine, bool aLeft, PNS_ITEMSET& aSet, std::set<PNS_ITEM*>& aVisited ); bool followTrivialPath( PNS_LINE* aLine, bool aLeft, PNS_ITEMSET& aSet, std::set<PNS_ITEM*>& aVisited );

View File

@ -38,7 +38,15 @@ void PNS_WALKAROUND::start( const PNS_LINE& aInitialPath )
PNS_NODE::OPT_OBSTACLE PNS_WALKAROUND::nearestObstacle( const PNS_LINE& aPath ) PNS_NODE::OPT_OBSTACLE PNS_WALKAROUND::nearestObstacle( const PNS_LINE& aPath )
{ {
return m_world->NearestObstacle( &aPath, m_itemMask ); PNS_NODE::OPT_OBSTACLE obs = m_world->NearestObstacle( &aPath, m_itemMask, m_restrictedSet.empty() ? NULL : &m_restrictedSet );
if( m_restrictedSet.empty() )
return obs;
else if( obs && m_restrictedSet.find ( obs->m_item ) != m_restrictedSet.end() )
return obs;
return PNS_NODE::OPT_OBSTACLE();
} }
@ -93,7 +101,7 @@ PNS_WALKAROUND::WALKAROUND_STATUS PNS_WALKAROUND::singleStep( PNS_LINE& aPath,
SHAPE_LINE_CHAIN pnew; SHAPE_LINE_CHAIN pnew;
if( !m_forceSingleDirection && len_alt < len_pre && !alt_collides && !prev_recursive ) if( !m_forceLongerPath && len_alt < len_pre && !alt_collides && !prev_recursive )
{ {
pnew = path_pre[1]; pnew = path_pre[1];
pnew.Append( path_walk[1] ); pnew.Append( path_walk[1] );

View File

@ -21,6 +21,8 @@
#ifndef __PNS_WALKAROUND_H #ifndef __PNS_WALKAROUND_H
#define __PNS_WALKAROUND_H #define __PNS_WALKAROUND_H
#include <set>
#include "pns_line.h" #include "pns_line.h"
#include "pns_node.h" #include "pns_node.h"
#include "pns_router.h" #include "pns_router.h"
@ -105,6 +107,14 @@ public:
m_forceWinding = aEnabled; m_forceWinding = aEnabled;
} }
void RestrictToSet( bool aEnabled, const std::set<PNS_ITEM*>& aSet )
{
if( aEnabled )
m_restrictedSet = aSet;
else
m_restrictedSet.clear();
}
WALKAROUND_STATUS Route( const PNS_LINE& aInitialPath, PNS_LINE& aWalkPath, WALKAROUND_STATUS Route( const PNS_LINE& aInitialPath, PNS_LINE& aWalkPath,
bool aOptimize = true ); bool aOptimize = true );
@ -133,6 +143,7 @@ private:
PNS_NODE::OPT_OBSTACLE m_currentObstacle[2]; PNS_NODE::OPT_OBSTACLE m_currentObstacle[2];
bool m_recursiveCollision[2]; bool m_recursiveCollision[2];
PNS_LOGGER m_logger; PNS_LOGGER m_logger;
std::set<PNS_ITEM*> m_restrictedSet;
}; };
#endif // __PNS_WALKAROUND_H #endif // __PNS_WALKAROUND_H