diff --git a/pcbnew/router/pns_hole.h b/pcbnew/router/pns_hole.h
index f75de4668b..a72b7a52c6 100644
--- a/pcbnew/router/pns_hole.h
+++ b/pcbnew/router/pns_hole.h
@@ -61,6 +61,11 @@ public:
ITEM* ParentPadVia() const { return m_parentPadVia; }
+ BOARD_ITEM* Parent() const override
+ {
+ return m_parentPadVia ? m_parentPadVia->Parent() : nullptr;
+ }
+
void SetCenter( const VECTOR2I& aCenter );
void SetRadius( int aRadius );
diff --git a/pcbnew/router/pns_item.cpp b/pcbnew/router/pns_item.cpp
index cfde15d769..4bbf81203d 100644
--- a/pcbnew/router/pns_item.cpp
+++ b/pcbnew/router/pns_item.cpp
@@ -19,12 +19,10 @@
* with this program. If not, see .
*/
-#include
#include "pns_node.h"
#include "pns_item.h"
#include "pns_line.h"
#include "pns_router.h"
-#include "pns_utils.h"
#include
#include
@@ -60,13 +58,43 @@ bool ITEM::collideSimple( const ITEM* aHead, const NODE* aNode,
int clearanceEpsilon = aNode->GetRuleResolver()->ClearanceEpsilon();
bool collisionsFound = false;
- printf( "******************** CollideSimple %lu\n", aCtx->obstacles.size() );
+ //printf( "******************** CollideSimple %lu\n", aCtx->obstacles.size() );
//printf( "h %p n %p t %p ctx %p\n", aHead, aNode, this, aCtx );
if( aHead == this ) // we cannot be self-colliding
return false;
+ // prevent bogus collisions between the item and its own hole.
+ // FIXME: figure out a cleaner way of doing that
+ if( holeI && aHead == holeI->ParentPadVia() )
+ return false;
+
+ if( holeH && this == holeH->ParentPadVia() )
+ return false;
+
+ if( holeH && this == holeH )
+ return false;
+
+ if( holeI && aHead == holeI )
+ return false;
+
+ // Special cases for "head" lines with vias attached at the end. Note that this does not
+ // support head-line-via to head-line-via collisions, but you can't route two independent
+ // tracks at once so it shouldn't come up.
+
+ if( const auto line = dyn_cast( this ) )
+ {
+ if( line->EndsWithVia() )
+ collisionsFound |= line->Via().collideSimple( aHead, aNode, aCtx );
+ }
+
+ if( const auto line = dyn_cast( aHead ) )
+ {
+ if( line->EndsWithVia() )
+ collisionsFound |= line->Via().collideSimple( this, aNode, aCtx );
+ }
+
// Sadly collision routines ignore SHAPE_POLY_LINE widths so we have to pass them in as part
// of the clearance value.
if( m_kind == LINE_T )
@@ -93,142 +121,14 @@ bool ITEM::collideSimple( const ITEM* aHead, const NODE* aNode,
if( !m_layers.Overlaps( aHead->m_layers ) )
return false;
- auto checkKeepout =
- []( const ZONE* aKeepout, const BOARD_ITEM* aOther )
- {
- if( aKeepout->GetDoNotAllowTracks() && aOther->IsType( { PCB_ARC_T, PCB_TRACE_T } ) )
- return true;
+ if( holeH )
+ collisionsFound |= collideSimple( holeH, aNode, aCtx );
- if( aKeepout->GetDoNotAllowVias() && aOther->Type() == PCB_VIA_T )
- return true;
+ if( holeI )
+ collisionsFound |= holeI->collideSimple( aHead, aNode, aCtx );
- if( aKeepout->GetDoNotAllowPads() && aOther->Type() == PCB_PAD_T )
- return true;
-
- // Incomplete test, but better than nothing:
- if( aKeepout->GetDoNotAllowFootprints() && aOther->Type() == PCB_PAD_T )
- {
- return !aKeepout->GetParentFootprint()
- || aKeepout->GetParentFootprint() != aOther->GetParentFootprint();
- }
-
- return false;
- };
-
- const ZONE* zoneA = dynamic_cast( Parent() );
- const ZONE* zoneB = dynamic_cast( aHead->Parent() );
-
- if( zoneA && aHead->Parent() && !checkKeepout( zoneA, aHead->Parent() ) )
- return false;
-
- if( zoneB && Parent() && !checkKeepout( zoneB, Parent() ) )
- return false;
-
- // fixme: this f***ing singleton must go...
- ROUTER *router = ROUTER::GetInstance();
- ROUTER_IFACE* iface = router ? router->GetInterface() : nullptr;
-
- bool thisNotFlashed = false;
- bool otherNotFlashed = false;
-
- if( iface )
- {
- thisNotFlashed = !iface->IsFlashedOnLayer( this, aHead->Layer() );
- otherNotFlashed = !iface->IsFlashedOnLayer( aHead, Layer() );
- }
-
- if( ( aNode->GetCollisionQueryScope() == NODE::CQS_ALL_RULES
- || ( thisNotFlashed || otherNotFlashed ) ) )
- {
- if( holeI && holeI->ParentPadVia() != aHead && holeI != aHead )
- {
- int holeClearance = aNode->GetClearance( this, holeI );
- printf("HCH1 %d\n", holeClearance);
-
- if( holeI->Shape()->Collide( shapeH, holeClearance + lineWidthH - clearanceEpsilon ) )
- {
- if( aCtx )
- {
- OBSTACLE obs;
- obs.m_clearance = holeClearance;
- obs.m_head = const_cast- ( aHead );
- obs.m_item = const_cast( holeI );
-
- aCtx->obstacles.insert( obs );
- dumpObstacles( aCtx->obstacles );
- collisionsFound = true;
- }
- else
- {
- return true;
- }
- }
- }
-
- if( holeH && holeH->ParentPadVia() != this && holeH != this )
- {
- int holeClearance = aNode->GetClearance( this, holeH );
-
- printf("HCH2 %d\n", holeClearance);
-
- if( holeH->Shape()->Collide( shapeI, holeClearance + lineWidthI - clearanceEpsilon ) )
- {
- if( aCtx )
- {
- OBSTACLE obs;
- obs.m_clearance = holeClearance;
- obs.m_head = const_cast( holeH );
- obs.m_item = const_cast
- ( this );
-
- aCtx->obstacles.insert( obs );
- dumpObstacles( aCtx->obstacles );
- collisionsFound = true;
- }
- else
- {
- return true;
- }
- }
- }
-
- if( holeI && holeH && ( holeI != holeH ) )
- {
- int holeClearance = aNode->GetClearance( holeI, holeH );
-
- printf("HCH3 %d\n", holeClearance);
-
- if( holeI->Shape()->Collide( holeH->Shape(), holeClearance - clearanceEpsilon ) )
- {
- if( aCtx )
- {
- OBSTACLE obs;
- obs.m_clearance = holeClearance;
-
- // printf("pushh3 %p %p\n", obs.m_head, obs.m_item );
-
- obs.m_head = const_cast( holeH );
- obs.m_item = const_cast( holeI );
-
- aCtx->obstacles.insert( obs );
- dumpObstacles( aCtx->obstacles );
-
- collisionsFound = true;
- }
- else
- {
- return true;
- }
- }
- }
- }
-
- printf("HCHE\n");
-
- if( !aHead->Layers().IsMultilayer() && thisNotFlashed )
- return false;
-
- if( !Layers().IsMultilayer() && otherNotFlashed )
- return false;
+ if( holeH && holeI )
+ collisionsFound |= holeI->collideSimple( holeH, aNode, aCtx );
int clearance;
@@ -236,28 +136,35 @@ bool ITEM::collideSimple( const ITEM* aHead, const NODE* aNode,
{
clearance = aCtx->options.m_overrideClearance;
}
+ else if( aNode->GetRuleResolver()->IsKeepout( this, aHead ) )
+ {
+ clearance = 0; // keepouts are exact boundary; no clearance
+ }
else
{
clearance = aNode->GetClearance( this, aHead );
}
- // prevent bogus collisions between the item and its own hole. FIXME: figure out a cleaner way of doing that
- if( holeI && aHead == holeI->ParentPadVia() )
- return false;
+ // fixme: this f***ing singleton must go...
+ ROUTER* router = ROUTER::GetInstance();
+ ROUTER_IFACE* iface = router ? router->GetInterface() : nullptr;
- if( holeH && this == holeH->ParentPadVia() )
- return false;
+ if( iface )
+ {
+ if( !iface->IsFlashedOnLayer( this, aHead->Layer() ) )
+ return collisionsFound;
- if( holeH && this == holeH )
- return false;
-
- if( holeI && aHead == holeI )
- return false;
+ if( !iface->IsFlashedOnLayer( aHead, Layer() ) )
+ return collisionsFound;
+ }
if( clearance >= 0 )
{
+ // Note: we can't do castellation or net-tie processing in GetClearance() because they
+ // depend on *where* the collision is.
+
bool checkCastellation = ( m_parent && m_parent->GetLayer() == Edge_Cuts );
- bool checkNetTie = aNode->GetRuleResolver()->IsInNetTie( this );
+ bool checkNetTie = ( m_parent && aNode->GetRuleResolver()->IsInNetTie( this ) );
if( checkCastellation || checkNetTie )
{
@@ -301,17 +208,7 @@ bool ITEM::collideSimple( const ITEM* aHead, const NODE* aNode,
obs.m_head = const_cast
- ( aHead );
obs.m_item = const_cast
- ( this );
obs.m_clearance = clearance;
-
- //printf( "i %p h %p ih %p hh %p\n", this ,aHead, holeI, holeH );
- printf( "HCHX %d %d\n", clearance, clearance + lineWidthH + lineWidthI - clearanceEpsilon);
- //printf( "pushc %p %p cl %d cle %d\n", obs.m_head, obs.m_item, clearance, clearance + lineWidthH + lineWidthI - clearanceEpsilon );
- //printf( "SH %s\n", shapeH->Format().c_str(), aHead );
- //printf( "SI %s\n", shapeI->Format().c_str(), this );
-
aCtx->obstacles.insert( obs );
-
- dumpObstacles( aCtx->obstacles );
- printf("--EndDump\n");
}
else
{
@@ -330,26 +227,6 @@ bool ITEM::Collide( const ITEM* aOther, const NODE* aNode, COLLISION_SEARCH_CONT
if( collideSimple( aOther, aNode, aCtx ) )
return true;
- // Special cases for "head" lines with vias attached at the end. Note that this does not
- // support head-line-via to head-line-via collisions, but you can't route two independent
- // tracks at once so it shouldn't come up.
-
- if( m_kind == LINE_T )
- {
- const LINE* line = static_cast( this );
-
- if( line->EndsWithVia() && line->Via().collideSimple( aOther, aNode, aCtx ) )
- return true;
- }
-
- if( aOther->m_kind == LINE_T )
- {
- const LINE* line = static_cast( aOther ); // fixme
-
- if( line->EndsWithVia() && line->Via().collideSimple( this, aNode, aCtx ) )
- return true;
- }
-
return false;
}
diff --git a/pcbnew/router/pns_item.h b/pcbnew/router/pns_item.h
index 7fd8963ab1..fb6eceb929 100644
--- a/pcbnew/router/pns_item.h
+++ b/pcbnew/router/pns_item.h
@@ -178,7 +178,7 @@ public:
std::string KindStr() const;
void SetParent( BOARD_ITEM* aParent ) { m_parent = aParent; }
- BOARD_ITEM* Parent() const { return m_parent; }
+ virtual BOARD_ITEM* Parent() const { return m_parent; }
void SetNet( int aNet ) { m_net = aNet; }
int Net() const { return m_net; }
diff --git a/pcbnew/router/pns_kicad_iface.cpp b/pcbnew/router/pns_kicad_iface.cpp
index 8847706fe4..864a7bf64f 100644
--- a/pcbnew/router/pns_kicad_iface.cpp
+++ b/pcbnew/router/pns_kicad_iface.cpp
@@ -116,6 +116,8 @@ public:
virtual bool IsNetTieExclusion( const PNS::ITEM* aItem, const VECTOR2I& aCollisionPos,
const PNS::ITEM* aCollidingItem ) override;
+ virtual bool IsKeepout( const PNS::ITEM* aA, const PNS::ITEM* aB ) override;
+
virtual bool QueryConstraint( PNS::CONSTRAINT_TYPE aType, const PNS::ITEM* aItemA,
const PNS::ITEM* aItemB, int aLayer,
PNS::CONSTRAINT* aConstraint ) override;
@@ -252,6 +254,46 @@ bool PNS_PCBNEW_RULE_RESOLVER::IsNetTieExclusion( const PNS::ITEM* aItem,
}
+bool PNS_PCBNEW_RULE_RESOLVER::IsKeepout( const PNS::ITEM* aA, const PNS::ITEM* aB )
+{
+ auto checkKeepout =
+ []( const ZONE* aKeepout, const BOARD_ITEM* aOther )
+ {
+ if( aKeepout->GetDoNotAllowTracks() && aOther->IsType( { PCB_ARC_T, PCB_TRACE_T } ) )
+ return true;
+
+ if( aKeepout->GetDoNotAllowVias() && aOther->Type() == PCB_VIA_T )
+ return true;
+
+ if( aKeepout->GetDoNotAllowPads() && aOther->Type() == PCB_PAD_T )
+ return true;
+
+ // Incomplete test, but better than nothing:
+ if( aKeepout->GetDoNotAllowFootprints() && aOther->Type() == PCB_PAD_T )
+ {
+ return !aKeepout->GetParentFootprint()
+ || aKeepout->GetParentFootprint() != aOther->GetParentFootprint();
+ }
+
+ return false;
+ };
+
+ if( const ZONE* zoneA = dynamic_cast( aA->Parent() ) )
+ {
+ if( zoneA->GetIsRuleArea() && aB->Parent() )
+ return checkKeepout( zoneA, aB->Parent() );
+ }
+
+ if( const ZONE* zoneB = dynamic_cast( aB->Parent() ) )
+ {
+ if( zoneB->GetIsRuleArea() && aA->Parent() )
+ return checkKeepout( zoneB, aA->Parent() );
+ }
+
+ return false;
+}
+
+
static bool isCopper( const PNS::ITEM* aItem )
{
if ( !aItem )
@@ -435,7 +477,8 @@ int PNS_PCBNEW_RULE_RESOLVER::Clearance( const PNS::ITEM* aA, const PNS::ITEM* a
rv = constraint.m_Value.Min();
}
}
- else if( isHole( aA ) || isHole( aB ) )
+
+ if( isHole( aA ) || isHole( aB ) )
{
if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_CLEARANCE, aA, aB, layer, &constraint ) )
{
@@ -1459,7 +1502,7 @@ bool PNS_KICAD_IFACE_BASE::IsFlashedOnLayer( const PNS::ITEM* aItem, int aLayer
if( aLayer < 0 )
return true;
- if( aItem->Parent() )
+ if( !aItem->OfKind( PNS::ITEM::HOLE_T ) && aItem->Parent() )
{
switch( aItem->Parent()->Type() )
{
diff --git a/pcbnew/router/pns_node.h b/pcbnew/router/pns_node.h
index c76a099fc9..20ea54aa1a 100644
--- a/pcbnew/router/pns_node.h
+++ b/pcbnew/router/pns_node.h
@@ -148,6 +148,7 @@ public:
virtual bool IsNetTieExclusion( const PNS::ITEM* aItem, const VECTOR2I& aCollisionPos,
const PNS::ITEM* aCollidingItem )= 0;
+ virtual bool IsKeepout( const ITEM* aA, const ITEM* aB ) = 0;
virtual bool QueryConstraint( CONSTRAINT_TYPE aType, const PNS::ITEM* aItemA,
const PNS::ITEM* aItemB, int aLayer,
diff --git a/qa/unittests/pcbnew/test_pns_basics.cpp b/qa/unittests/pcbnew/test_pns_basics.cpp
index 3527c8dbd0..d6c6b9a0bf 100644
--- a/qa/unittests/pcbnew/test_pns_basics.cpp
+++ b/qa/unittests/pcbnew/test_pns_basics.cpp
@@ -208,13 +208,16 @@ public:
}
};
- virtual bool IsInNetTie( const PNS::ITEM* aA ) override { return false; }
- virtual bool IsNetTieExclusion( const PNS::ITEM* aItem, const VECTOR2I& aCollisionPos,
- const PNS::ITEM* aCollidingItem ) override
+ bool IsInNetTie( const PNS::ITEM* aA ) override { return false; }
+
+ bool IsNetTieExclusion( const PNS::ITEM* aItem, const VECTOR2I& aCollisionPos,
+ const PNS::ITEM* aCollidingItem ) override
{
return false;
}
+ bool IsKeepout( const PNS::ITEM* aA, const PNS::ITEM* aB ) override { return false; }
+
void AddMockRule( PNS::CONSTRAINT_TYPE aType, const PNS::ITEM* aItemA, const PNS::ITEM* aItemB,
PNS::CONSTRAINT aConstraint )
{