router: pass collision query options in a structure

Selectively cherry-picked by Jeff Young <jeff@rokeby.ie> 4 April 2023
- Jon's user-clearance-epsilon algo kept intact
- Jeff's castellated-pad code kept intact
This commit is contained in:
Tomasz Wlostowski 2022-08-15 14:31:43 +01:00 committed by Jeff Young
parent 16b4ec3c7e
commit eed05191a9
9 changed files with 153 additions and 91 deletions

View File

@ -143,7 +143,7 @@ bool COMPONENT_DRAGGER::Start( const VECTOR2I& aP, ITEM_SET& aPrimitives )
{
LINKED_ITEM* li = static_cast<LINKED_ITEM*>( extraJoint->LinkList()[0].item );
if( li->Collide( solid, nullptr, m_world ) )
if( li->Collide( solid, m_world ) )
addLinked( solid, extraJoint, li, extraJoint->Pos() - solid->Pos() );
}
}

View File

@ -29,7 +29,8 @@ typedef VECTOR2I::extended_type ecoord;
namespace PNS {
bool ITEM::collideSimple( const ITEM* aOther, const NODE* aNode, bool aDifferentNetsOnly, int aOverrideClearance ) const
bool ITEM::collideSimple( const ITEM* aOther, const NODE* aNode,
const COLLISION_SEARCH_OPTIONS& aOpts, OBSTACLE *aObsInfo ) const
{
const ROUTER_IFACE* iface = ROUTER::GetInstance()->GetInterface();
const SHAPE* shapeA = Shape();
@ -38,6 +39,7 @@ bool ITEM::collideSimple( const ITEM* aOther, const NODE* aNode, bool aDifferent
const SHAPE* shapeB = aOther->Shape();
const SHAPE* holeB = aOther->Hole();
int lineWidthB = 0;
const int clearanceEpsilon = aNode->GetRuleResolver()->ClearanceEpsilon();
// Sadly collision routines ignore SHAPE_POLY_LINE widths so we have to pass them in as part
// of the clearance value.
@ -48,11 +50,11 @@ bool ITEM::collideSimple( const ITEM* aOther, const NODE* aNode, bool aDifferent
lineWidthB = static_cast<const LINE*>( aOther )->Width() / 2;
// same nets? no collision!
if( aDifferentNetsOnly && m_net == aOther->m_net && m_net >= 0 && aOther->m_net >= 0 )
if( aOpts.m_differentNetsOnly && m_net == aOther->m_net && m_net >= 0 && aOther->m_net >= 0 )
return false;
// a pad associated with a "free" pin (NIC) doesn't have a net until it has been used
if( aDifferentNetsOnly && ( IsFreePad() || aOther->IsFreePad() ) )
if( aOpts.m_differentNetsOnly && ( IsFreePad() || aOther->IsFreePad() ) )
return false;
// check if we are not on completely different layers first
@ -93,21 +95,35 @@ bool ITEM::collideSimple( const ITEM* aOther, const NODE* aNode, bool aDifferent
bool thisNotFlashed = !iface->IsFlashedOnLayer( this, aOther->Layer() );
bool otherNotFlashed = !iface->IsFlashedOnLayer( aOther, Layer() );
if( aObsInfo )
{
aObsInfo->m_headIsHole = false;
aObsInfo->m_itemIsHole = false;
}
if( ( aNode->GetCollisionQueryScope() == NODE::CQS_ALL_RULES
|| ( thisNotFlashed || otherNotFlashed ) )
&& ( holeA || holeB ) )
{
int holeClearance = aNode->GetHoleClearance( this, aOther );
if( holeClearance >= 0 && holeA && holeA->Collide( shapeB, holeClearance + lineWidthB ) )
if( holeA && holeA->Collide( shapeB, holeClearance + lineWidthB - clearanceEpsilon ) )
{
Mark( Marker() | MK_HOLE );
if( aObsInfo )
{
aObsInfo->m_headIsHole = true;
aObsInfo->m_clearance = holeClearance;
}
return true;
}
if( holeB && holeClearance >= 0 && holeB->Collide( shapeA, holeClearance + lineWidthA ) )
if( holeB && holeB->Collide( shapeA, holeClearance + lineWidthA - clearanceEpsilon ) )
{
aOther->Mark( aOther->Marker() | MK_HOLE );
if( aObsInfo )
{
aObsInfo->m_itemIsHole = true;
aObsInfo->m_clearance = holeClearance;
}
return true;
}
@ -115,10 +131,14 @@ bool ITEM::collideSimple( const ITEM* aOther, const NODE* aNode, bool aDifferent
{
int holeToHoleClearance = aNode->GetHoleToHoleClearance( this, aOther );
if( holeToHoleClearance >= 0 && holeA->Collide( holeB, holeToHoleClearance ) )
if( holeA->Collide( holeB, holeToHoleClearance - clearanceEpsilon ) )
{
Mark( Marker() | MK_HOLE );
aOther->Mark( aOther->Marker() | MK_HOLE );
if( aObsInfo )
{
aObsInfo->m_headIsHole = true;
aObsInfo->m_itemIsHole = true;
aObsInfo->m_clearance = holeToHoleClearance;
}
return true;
}
}
@ -130,7 +150,8 @@ bool ITEM::collideSimple( const ITEM* aOther, const NODE* aNode, bool aDifferent
if( !Layers().IsMultilayer() && otherNotFlashed )
return false;
int clearance = aOverrideClearance >= 0 ? aOverrideClearance : aNode->GetClearance( this, aOther );
int clearance = aOpts.m_overrideClearance >= 0 ? aOpts.m_overrideClearance
: aNode->GetClearance( this, aOther );
if( clearance >= 0 )
{
@ -151,14 +172,22 @@ bool ITEM::collideSimple( const ITEM* aOther, const NODE* aNode, bool aDifferent
if( checkNetTie && aNode->GetRuleResolver()->IsNetTieExclusion( aOther, pos, this ) )
return false;
if( aObsInfo )
aObsInfo->m_clearance = clearance;
return true;
}
}
else
{
// Fast method
if( shapeA->Collide( shapeB, clearance + lineWidthA + lineWidthB ) )
if( shapeA->Collide( shapeB, clearance + lineWidthA + lineWidthB - clearanceEpsilon ) )
{
if( aObsInfo )
aObsInfo->m_clearance = clearance;
return true;
}
}
}
@ -166,9 +195,10 @@ bool ITEM::collideSimple( const ITEM* aOther, const NODE* aNode, bool aDifferent
}
bool ITEM::Collide( const ITEM* aOther, const NODE* aNode, bool aDifferentNetsOnly, int aOverrideClearance ) const
bool ITEM::Collide( const ITEM* aOther, const NODE* aNode,
const COLLISION_SEARCH_OPTIONS& aOpts, OBSTACLE *aObsInfo ) const
{
if( collideSimple( aOther, aNode, aDifferentNetsOnly, aOverrideClearance ) )
if( collideSimple( aOther, aNode, aOpts, aObsInfo ) )
return true;
// Special cases for "head" lines with vias attached at the end. Note that this does not
@ -179,7 +209,7 @@ bool ITEM::Collide( const ITEM* aOther, const NODE* aNode, bool aDifferentNetsOn
{
const LINE* line = static_cast<const LINE*>( this );
if( line->EndsWithVia() && line->Via().collideSimple( aOther, aNode, aDifferentNetsOnly, aOverrideClearance ) )
if( line->EndsWithVia() && line->Via().collideSimple( aOther, aNode, aOpts, aObsInfo ) )
return true;
}
@ -187,7 +217,7 @@ bool ITEM::Collide( const ITEM* aOther, const NODE* aNode, bool aDifferentNetsOn
{
const LINE* line = static_cast<const LINE*>( aOther );
if( line->EndsWithVia() && line->Via().collideSimple( this, aNode, aDifferentNetsOnly, aOverrideClearance ) )
if( line->EndsWithVia() && line->Via().collideSimple( this, aNode, aOpts, aObsInfo ) )
return true;
}

View File

@ -41,10 +41,20 @@ enum LineMarker {
MK_HEAD = ( 1 << 0 ),
MK_VIOLATION = ( 1 << 3 ),
MK_LOCKED = ( 1 << 4 ),
MK_DP_COUPLED = ( 1 << 5 ),
MK_HOLE = ( 1 << 6 )
MK_DP_COUPLED = ( 1 << 5 )
};
struct OBSTACLE;
struct COLLISION_SEARCH_OPTIONS
{
bool m_differentNetsOnly = true;
int m_overrideClearance = -1;
int m_limitCount = -1;
int m_kindMask = -1;
bool m_useClearanceEpsilon = true;
};
/**
* Base class for PNS router board items.
@ -194,7 +204,9 @@ public:
* @param aOther is the item to check collision against.
* @return true, if a collision was found.
*/
bool Collide( const ITEM* aOther, const NODE* aNode, bool aDifferentNetsOnly = true, int aOverrideClearance = -1 ) const;
bool Collide( const ITEM* aOther, const NODE* aNode,
const COLLISION_SEARCH_OPTIONS& aOpts = COLLISION_SEARCH_OPTIONS(),
OBSTACLE *aObsInfo = nullptr ) const;
/**
* Return the geometrical shape of the item. Used for collision detection and spatial indexing.
@ -248,7 +260,9 @@ public:
virtual const std::string Format() const;
private:
bool collideSimple( const ITEM* aOther, const NODE* aNode, bool aDifferentNetsOnly, int aOverrideClearance ) const;
bool collideSimple( const ITEM* aOther, const NODE* aNode,
const COLLISION_SEARCH_OPTIONS& aOpts,
OBSTACLE *aObsInfo = nullptr ) const;
protected:
PnsKind m_kind;

View File

@ -211,23 +211,16 @@ bool OBSTACLE_VISITOR::visit( ITEM* aCandidate )
// function object that visits potential obstacles and performs the actual collision refining
struct NODE::DEFAULT_OBSTACLE_VISITOR : public OBSTACLE_VISITOR
{
OBSTACLES& m_tab;
OBSTACLES& m_tab;
int m_matchCount;
const COLLISION_SEARCH_OPTIONS& m_opts;
int m_kindMask; ///< (solids, vias, segments, etc...)
int m_limitCount;
int m_matchCount;
bool m_differentNetsOnly;
int m_overrideClearance;
DEFAULT_OBSTACLE_VISITOR( NODE::OBSTACLES& aTab, const ITEM* aItem, int aKindMask,
bool aDifferentNetsOnly, int aOverrideClearance ) :
DEFAULT_OBSTACLE_VISITOR( NODE::OBSTACLES& aTab, const ITEM* aItem,
const COLLISION_SEARCH_OPTIONS& aOpts ) :
OBSTACLE_VISITOR( aItem ),
m_tab( aTab ),
m_kindMask( aKindMask ),
m_limitCount( -1 ),
m_matchCount( 0 ),
m_differentNetsOnly( aDifferentNetsOnly ),
m_overrideClearance( aOverrideClearance )
m_opts( aOpts ),
m_matchCount( 0 )
{
}
@ -235,33 +228,28 @@ struct NODE::DEFAULT_OBSTACLE_VISITOR : public OBSTACLE_VISITOR
{
}
void SetCountLimit( int aLimit )
{
m_limitCount = aLimit;
}
bool operator()( ITEM* aCandidate ) override
{
if( !aCandidate->OfKind( m_kindMask ) )
if( !aCandidate->OfKind( m_opts.m_kindMask ) )
return true;
if( visit( aCandidate ) )
return true;
if( !aCandidate->Collide( m_item, m_node, m_differentNetsOnly, m_overrideClearance ) )
if( !aCandidate->Collide( m_item, m_node, m_opts ) )
return true;
OBSTACLE obs;
obs.m_item = aCandidate;
obs.m_head = m_item;
obs.m_item = aCandidate;
obs.m_distFirst = INT_MAX;
obs.m_maxFanoutWidth = 0;
m_tab.push_back( obs );
m_matchCount++;
if( m_limitCount > 0 && m_matchCount >= m_limitCount )
if( m_opts.m_limitCount > 0 && m_matchCount >= m_opts.m_limitCount )
return false;
return true;
@ -269,28 +257,26 @@ struct NODE::DEFAULT_OBSTACLE_VISITOR : public OBSTACLE_VISITOR
};
int NODE::QueryColliding( const ITEM* aItem, NODE::OBSTACLES& aObstacles, int aKindMask,
int aLimitCount, bool aDifferentNetsOnly, int aOverrideClearance )
int NODE::QueryColliding( const ITEM* aItem, NODE::OBSTACLES& aObstacles,
const COLLISION_SEARCH_OPTIONS& aOpts )
{
/// By default, virtual items cannot collide
if( aItem->IsVirtual() )
return 0;
DEFAULT_OBSTACLE_VISITOR visitor( aObstacles, aItem, aKindMask, aDifferentNetsOnly,
aOverrideClearance );
DEFAULT_OBSTACLE_VISITOR visitor( aObstacles, aItem, aOpts );
#ifdef DEBUG
assert( allocNodes.find( this ) != allocNodes.end() );
#endif
visitor.SetCountLimit( aLimitCount );
visitor.SetWorld( this, nullptr );
// first, look for colliding items in the local index
m_index->Query( aItem, m_maxClearance, visitor );
// if we haven't found enough items, look in the root branch as well.
if( !isRoot() && ( visitor.m_matchCount < aLimitCount || aLimitCount < 0 ) )
if( !isRoot() && ( visitor.m_matchCount < aOpts.m_limitCount || aOpts.m_limitCount < 0 ) )
{
visitor.SetWorld( m_root, this );
m_root->m_index->Query( aItem, m_maxClearance, visitor );
@ -302,8 +288,9 @@ int NODE::QueryColliding( const ITEM* aItem, NODE::OBSTACLES& aObstacles, int aK
NODE::OPT_OBSTACLE NODE::NearestObstacle( const LINE* aLine, int aKindMask,
const std::set<ITEM*>* aRestrictedSet,
bool aUseClearanceEpsilon )
const COLLISION_SEARCH_OPTIONS& aOpts )
{
const int clearanceEpsilon = GetRuleResolver()->ClearanceEpsilon();
OBSTACLES obstacleList;
obstacleList.reserve( 100 );
@ -314,11 +301,11 @@ NODE::OPT_OBSTACLE NODE::NearestObstacle( const LINE* aLine, int aKindMask,
// Disabling the cache will lead to slowness.
const SEGMENT s( *aLine, aLine->CLine().CSegment( i ) );
QueryColliding( &s, obstacleList, aKindMask );
QueryColliding( &s, obstacleList, aOpts );
}
if( aLine->EndsWithVia() )
QueryColliding( &aLine->Via(), obstacleList, aKindMask );
QueryColliding( &aLine->Via(), obstacleList, aOpts );
if( obstacleList.empty() )
return OPT_OBSTACLE();
@ -340,10 +327,12 @@ NODE::OPT_OBSTACLE NODE::NearestObstacle( const LINE* aLine, int aKindMask,
nearest.m_distFirst = dist;
nearest.m_ipFirst = pt.p;
nearest.m_item = obstacle;
nearest.m_hull = hull;
nearest.m_itemIsHole = isHole;
// JEY TODO: are these no longer needed?
//nearest.m_hull = hull;
obstacle->Mark( isHole ? obstacle->Marker() | MK_HOLE
: obstacle->Marker() & ~MK_HOLE );
//obstacle->Mark( isHole ? obstacle->Marker() | MK_HOLE
// : obstacle->Marker() & ~MK_HOLE );
}
};
@ -358,7 +347,7 @@ NODE::OPT_OBSTACLE NODE::NearestObstacle( const LINE* aLine, int aKindMask,
continue;
int clearance =
GetClearance( obstacle.m_item, aLine, aUseClearanceEpsilon ) + aLine->Width() / 2;
GetClearance( obstacle.m_item, aLine, aOpts.m_useClearanceEpsilon ) + aLine->Width() / 2;
obstacleHull = obstacle.m_item->Hull( clearance, 0, layer );
//debugDecorator->AddLine( obstacleHull, 2, 40000, "obstacle-hull-test" );
@ -381,10 +370,10 @@ NODE::OPT_OBSTACLE NODE::NearestObstacle( const LINE* aLine, int aKindMask,
int viaHoleRadius = static_cast<const SHAPE_CIRCLE*>( via.Hole() )->GetRadius();
int viaClearance = GetClearance( obstacle.m_item, &via, aUseClearanceEpsilon )
int viaClearance = GetClearance( obstacle.m_item, &via, aOpts.m_useClearanceEpsilon )
+ via.Diameter() / 2;
int holeClearance =
GetHoleClearance( obstacle.m_item, &via, aUseClearanceEpsilon ) + viaHoleRadius;
int holeClearance = GetHoleClearance( obstacle.m_item, &via, aOpts.m_useClearanceEpsilon )
+ viaHoleRadius;
if( holeClearance > viaClearance )
viaClearance = holeClearance;
@ -406,8 +395,8 @@ NODE::OPT_OBSTACLE NODE::NearestObstacle( const LINE* aLine, int aKindMask,
layer ) )
&& obstacle.m_item->Hole() )
{
clearance = GetHoleClearance( obstacle.m_item, aLine, aUseClearanceEpsilon );
int copperClearance = GetClearance( obstacle.m_item, aLine, aUseClearanceEpsilon );
clearance = GetHoleClearance( obstacle.m_item, aLine, aOpts.m_useClearanceEpsilon );
int copperClearance = GetClearance( obstacle.m_item, aLine, aOpts.m_useClearanceEpsilon );
clearance = std::max( clearance, copperClearance );
@ -425,12 +414,12 @@ NODE::OPT_OBSTACLE NODE::NearestObstacle( const LINE* aLine, int aKindMask,
// Don't use via.Drill(); it doesn't include the plating thickness
int viaHoleRadius = static_cast<const SHAPE_CIRCLE*>( via.Hole() )->GetRadius();
int viaClearance = GetClearance( obstacle.m_item, &via, aUseClearanceEpsilon )
int viaClearance = GetClearance( obstacle.m_item, &via, aOpts.m_useClearanceEpsilon )
+ via.Diameter() / 2;
int holeClearance = GetHoleClearance( obstacle.m_item, &via, aUseClearanceEpsilon )
int holeClearance = GetHoleClearance( obstacle.m_item, &via, aOpts.m_useClearanceEpsilon )
+ viaHoleRadius;
int holeToHole =
GetHoleToHoleClearance( obstacle.m_item, &via, aUseClearanceEpsilon )
GetHoleToHoleClearance( obstacle.m_item, &via, aOpts.m_useClearanceEpsilon )
+ viaHoleRadius;
if( holeClearance > viaClearance )
@ -475,6 +464,11 @@ NODE::OPT_OBSTACLE NODE::CheckColliding( const ITEM_SET& aSet, int aKindMask )
NODE::OPT_OBSTACLE NODE::CheckColliding( const ITEM* aItemA, int aKindMask )
{
OBSTACLES obs;
COLLISION_SEARCH_OPTIONS opts;
opts.m_kindMask = aKindMask;
opts.m_limitCount = 1;
opts.m_overrideClearance = 1;
obs.reserve( 100 );
@ -491,7 +485,7 @@ NODE::OPT_OBSTACLE NODE::CheckColliding( const ITEM* aItemA, int aKindMask )
// Disabling the cache will lead to slowness.
const SEGMENT s( *line, l.CSegment( i ) );
n += QueryColliding( &s, obs, aKindMask, 1 );
n += QueryColliding( &s, obs, opts );
if( n )
return OPT_OBSTACLE( obs[0] );
@ -499,13 +493,13 @@ NODE::OPT_OBSTACLE NODE::CheckColliding( const ITEM* aItemA, int aKindMask )
if( line->EndsWithVia() )
{
n += QueryColliding( &line->Via(), obs, aKindMask, 1 );
n += QueryColliding( &line->Via(), obs, opts );
if( n )
return OPT_OBSTACLE( obs[0] );
}
}
else if( QueryColliding( aItemA, obs, aKindMask, 1 ) > 0 )
else if( QueryColliding( aItemA, obs, opts ) > 0 )
{
return OPT_OBSTACLE( obs[0] );
}

View File

@ -104,6 +104,11 @@ public:
virtual void ClearCacheForItem( const ITEM* aItem ) {}
virtual void ClearCaches() {}
virtual int ClearanceEpsilon() const { return m_clearanceEpsilon; }
protected:
int m_clearanceEpsilon = 0;
};
/**
@ -111,11 +116,15 @@ public:
*/
struct OBSTACLE
{
const ITEM* m_head; ///< Item we search collisions with
const ITEM* m_head; ///< Line we search collisions against
ITEM* m_item; ///< Item found to be colliding with m_head
SHAPE_LINE_CHAIN m_hull; ///< Hull of the colliding m_item
VECTOR2I m_ipFirst; ///< First intersection between m_head and m_hull
int m_clearance;
int m_actual;
int m_walkaroundThickness;
bool m_headIsHole = false;
bool m_itemIsHole = false;
VECTOR2I m_pos;
int m_distFirst; ///< ... and the distance thereof
int m_maxFanoutWidth; ///< worst case (largest) width of the tracks connected to the item
};
@ -220,8 +229,8 @@ public:
* @param aLimitCount stop looking for collisions after finding this number of colliding items
* @return number of obstacles found
*/
int QueryColliding( const ITEM* aItem, OBSTACLES& aObstacles, int aKindMask = ITEM::ANY_T,
int aLimitCount = -1, bool aDifferentNetsOnly = true, int aOverrideClearance = -1 );
int QueryColliding( const ITEM* aItem, OBSTACLES& aObstacles,
const COLLISION_SEARCH_OPTIONS& aOpts = COLLISION_SEARCH_OPTIONS() );
int QueryJoints( const BOX2I& aBox, std::vector<JOINT*>& aJoints,
LAYER_RANGE aLayerMask = LAYER_RANGE::All(), int aKindMask = ITEM::ANY_T );
@ -233,12 +242,11 @@ public:
* @param aLine the item to find collisions with
* @param aKindMask mask of obstacle types to take into account
* @param aRestrictedSet is an optional set of items that should be considered as obstacles
* @param aUseClearanceEpsilon determines if the epsilon is subtracted from the hull size
* @return the obstacle, if found, otherwise empty.
*/
OPT_OBSTACLE NearestObstacle( const LINE* aLine, int aKindMask = ITEM::ANY_T,
const std::set<ITEM*>* aRestrictedSet = nullptr,
bool aUseClearanceEpsilon = true );
const COLLISION_SEARCH_OPTIONS& aOpts = COLLISION_SEARCH_OPTIONS() );
/**
* Check if the item collides with anything else in the world, and if found, returns the
@ -389,7 +397,7 @@ public:
void AllItemsInNet( int aNet, std::set<ITEM*>& aItems, int aKindMask = -1 );
void ClearRanks( int aMarkerMask = MK_HEAD | MK_VIOLATION | MK_HOLE );
void ClearRanks( int aMarkerMask = MK_HEAD | MK_VIOLATION );
void RemoveByMarker( int aMarker );

View File

@ -123,11 +123,15 @@ const ITEM_SET ROUTER::QueryHoverItems( const VECTOR2I& aP, bool aUseClearance )
{
if( aUseClearance )
{
SEGMENT test( SEG( aP, aP ), -1 );
NODE::OBSTACLES obs;
SEGMENT test( SEG( aP, aP ), -1 );
COLLISION_SEARCH_OPTIONS opts;
test.SetWidth( 1 );
test.SetLayers( LAYER_RANGE::All() );
NODE::OBSTACLES obs;
m_world->QueryColliding( &test, obs, ITEM::ANY_T, -1, false );
opts.m_differentNetsOnly = false;
m_world->QueryColliding( &test, obs, opts );
PNS::ITEM_SET ret;
@ -629,8 +633,8 @@ void ROUTER::markViolations( NODE* aNode, ITEM_SET& aCurrent, NODE::ITEM_VECTOR&
int clearance;
bool removeOriginal = true;
bool holeOnly = ( ( itemToMark->Marker() & MK_HOLE )
&& !( itemToMark->Marker() & MK_VIOLATION ) );
bool holeOnly = false; // JEY TODO ( ( itemToMark->Marker() & MK_HOLE )
//&& !( itemToMark->Marker() & MK_VIOLATION ) );
if( holeOnly )
clearance = aNode->GetHoleClearance( currentItem, itemToMark );
@ -673,7 +677,7 @@ void ROUTER::markViolations( NODE* aNode, ITEM_SET& aCurrent, NODE::ITEM_VECTOR&
{
NODE::OBSTACLES obstacles;
aNode->QueryColliding( item, obstacles, ITEM::ANY_T );
aNode->QueryColliding( item, obstacles );
if( item->OfKind( ITEM::LINE_T ) )
{
@ -682,7 +686,7 @@ void ROUTER::markViolations( NODE* aNode, ITEM_SET& aCurrent, NODE::ITEM_VECTOR&
if( l->EndsWithVia() )
{
VIA v( l->Via() );
aNode->QueryColliding( &v, obstacles, ITEM::ANY_T );
aNode->QueryColliding( &v, obstacles );
}
}

View File

@ -103,7 +103,6 @@ enum DRAG_MODE
virtual void Commit() = 0;
virtual bool ImportSizes( SIZES_SETTINGS& aSizes, ITEM* aStartItem, int aNet ) = 0;
virtual int StackupHeight( int aFirstLayer, int aSecondLayer ) const = 0;
virtual void EraseView() = 0;
virtual void UpdateNet( int aNetCode ) = 0;

View File

@ -538,6 +538,11 @@ const std::set<ITEM*> TOPOLOGY::AssembleCluster( ITEM* aStart, int aLayer )
std::set<ITEM*> visited;
std::deque<ITEM*> pending;
COLLISION_SEARCH_OPTIONS opts;
opts.m_differentNetsOnly = false;
opts.m_overrideClearance = 0;
pending.push_back( aStart );
while( !pending.empty() )
@ -549,7 +554,7 @@ const std::set<ITEM*> TOPOLOGY::AssembleCluster( ITEM* aStart, int aLayer )
visited.insert( top );
m_world->QueryColliding( top, obstacles, ITEM::ANY_T, -1, false, 0 ); // only query touching objects
m_world->QueryColliding( top, obstacles, opts ); // only query touching objects
for( OBSTACLE& obs : obstacles )
{

View File

@ -42,8 +42,13 @@ void WALKAROUND::start( const LINE& aInitialPath )
NODE::OPT_OBSTACLE WALKAROUND::nearestObstacle( const LINE& aPath )
{
NODE::OPT_OBSTACLE obs = m_world->NearestObstacle(
&aPath, m_itemMask, m_restrictedSet.empty() ? nullptr : &m_restrictedSet, false );
COLLISION_SEARCH_OPTIONS opts;
opts.m_useClearanceEpsilon = false;
NODE::OPT_OBSTACLE obs = m_world->NearestObstacle( &aPath, m_itemMask,
m_restrictedSet.empty() ? nullptr
: &m_restrictedSet,
opts );
if( m_restrictedSet.empty() )
return obs;
@ -86,10 +91,14 @@ WALKAROUND::WALKAROUND_STATUS WALKAROUND::singleStep( LINE& aPath, bool aWinding
SHAPE_LINE_CHAIN path_walk;
bool s_cw = aPath.Walkaround( current_obs->m_hull, path_walk, aWindingDirection );
SHAPE_LINE_CHAIN hull = current_obs->m_item->Hull( current_obs->m_clearance,
current_obs->m_walkaroundThickness );
bool s_cw = aPath.Walkaround( hull, path_walk, aWindingDirection );
PNS_DBG( Dbg(), BeginGroup, "hull/walk", 1 );
PNS_DBG( Dbg(), AddShape, &current_obs->m_hull, RED, 0, wxString::Format( "hull-%s-%d", aWindingDirection ? wxT( "cw" ) : wxT( "ccw" ), m_iteration ) );
PNS_DBG( Dbg(), AddShape, &hull, RED, 0, wxString::Format( "hull-%s-%d", aWindingDirection ? wxT( "cw" ) : wxT( "ccw" ), m_iteration ) );
PNS_DBG( Dbg(), AddShape, &aPath.CLine(), GREEN, 0, wxString::Format( "path-%s-%d", aWindingDirection ? wxT( "cw" ) : wxT( "ccw" ), m_iteration ) );
PNS_DBG( Dbg(), AddShape, &path_walk, BLUE, 0, wxString::Format( "result-%s-%d", aWindingDirection ? wxT( "cw" ) : wxT( "ccw" ), m_iteration ) );
PNS_DBG( Dbg(), Message, wxString::Format( wxT( "Stat cw %d" ), !!s_cw ) );
@ -100,8 +109,7 @@ WALKAROUND::WALKAROUND_STATUS WALKAROUND::singleStep( LINE& aPath, bool aWinding
// If the end of the line is inside an obstacle, additional walkaround iterations are not
// going to help. Exit now to prevent pegging the iteration limiter and causing lag.
if( current_obs && current_obs->m_hull.PointInside( initialLast ) &&
!current_obs->m_hull.PointOnEdge( initialLast ) )
if( current_obs && hull.PointInside( initialLast ) && !hull.PointOnEdge( initialLast ) )
{
return ALMOST_DONE;
}