Handle various keepout flags independently.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/16037
This commit is contained in:
Jeff Young 2023-11-07 11:57:06 +00:00
parent 23676eb988
commit abda3c0d33
4 changed files with 88 additions and 106 deletions

View File

@ -151,6 +151,7 @@ bool ITEM::collideSimple( const ITEM* aHead, const NODE* aNode,
ROUTER* router = ROUTER::GetInstance(); ROUTER* router = ROUTER::GetInstance();
ROUTER_IFACE* iface = router ? router->GetInterface() : nullptr; ROUTER_IFACE* iface = router ? router->GetInterface() : nullptr;
bool differentNetsOnly = true; bool differentNetsOnly = true;
bool enforce = false;
int clearance; int clearance;
if( aCtx ) if( aCtx )
@ -170,9 +171,12 @@ bool ITEM::collideSimple( const ITEM* aHead, const NODE* aNode,
// a pad associated with a "free" pin (NIC) doesn't have a net until it has been used // a pad associated with a "free" pin (NIC) doesn't have a net until it has been used
clearance = -1; clearance = -1;
} }
else if( aNode->GetRuleResolver()->IsKeepout( this, aHead ) ) else if( aNode->GetRuleResolver()->IsKeepout( this, aHead, &enforce ) )
{ {
clearance = 0; // keepouts are exact boundary; no clearance if( enforce )
clearance = 0; // keepouts are exact boundary; no clearance
else
clearance = -1;
} }
else if( iface && !iface->IsFlashedOnLayer( this, aHead->Layers() ) ) else if( iface && !iface->IsFlashedOnLayer( this, aHead->Layers() ) )
{ {

View File

@ -105,32 +105,39 @@ public:
PNS_PCBNEW_RULE_RESOLVER( BOARD* aBoard, PNS::ROUTER_IFACE* aRouterIface ); PNS_PCBNEW_RULE_RESOLVER( BOARD* aBoard, PNS::ROUTER_IFACE* aRouterIface );
virtual ~PNS_PCBNEW_RULE_RESOLVER(); virtual ~PNS_PCBNEW_RULE_RESOLVER();
virtual int Clearance( const PNS::ITEM* aA, const PNS::ITEM* aB, int Clearance( const PNS::ITEM* aA, const PNS::ITEM* aB,
bool aUseClearanceEpsilon = true ) override; bool aUseClearanceEpsilon = true ) override;
virtual PNS::NET_HANDLE DpCoupledNet( PNS::NET_HANDLE aNet ) override; PNS::NET_HANDLE DpCoupledNet( PNS::NET_HANDLE aNet ) override;
virtual int DpNetPolarity( PNS::NET_HANDLE aNet ) override; int DpNetPolarity( PNS::NET_HANDLE aNet ) override;
virtual bool DpNetPair( const PNS::ITEM* aItem, PNS::NET_HANDLE& aNetP, bool DpNetPair( const PNS::ITEM* aItem, PNS::NET_HANDLE& aNetP,
PNS::NET_HANDLE& aNetN ) override; PNS::NET_HANDLE& aNetN ) override;
virtual int NetCode( PNS::NET_HANDLE aNet ) override; int NetCode( PNS::NET_HANDLE aNet ) override;
virtual wxString NetName( PNS::NET_HANDLE aNet ) override; wxString NetName( PNS::NET_HANDLE aNet ) override;
virtual bool IsInNetTie( const PNS::ITEM* aA ) override; bool IsInNetTie( const PNS::ITEM* aA ) override;
virtual bool IsNetTieExclusion( const PNS::ITEM* aItem, const VECTOR2I& aCollisionPos, bool IsNetTieExclusion( const PNS::ITEM* aItem, const VECTOR2I& aCollisionPos,
const PNS::ITEM* aCollidingItem ) override; const PNS::ITEM* aCollidingItem ) override;
virtual bool IsKeepout( const PNS::ITEM* aA, const PNS::ITEM* aB ) override; /**
* @return true if \a aObstacle is a keepout. Set \a aEnforce if said keepout's rules
* exclude \a aItem.
*/
bool IsKeepout( const PNS::ITEM* aObstacle, const PNS::ITEM* aItem, bool* aEnforce ) override;
virtual bool QueryConstraint( PNS::CONSTRAINT_TYPE aType, const PNS::ITEM* aItemA, bool QueryConstraint( PNS::CONSTRAINT_TYPE aType, const PNS::ITEM* aItemA,
const PNS::ITEM* aItemB, int aLayer, const PNS::ITEM* aItemB, int aLayer,
PNS::CONSTRAINT* aConstraint ) override; PNS::CONSTRAINT* aConstraint ) override;
int ClearanceEpsilon() const override { return m_clearanceEpsilon; } int ClearanceEpsilon() const override { return m_clearanceEpsilon; }
void ClearCacheForItems( std::vector<const PNS::ITEM*>& aItems ) override; void ClearCacheForItems( std::vector<const PNS::ITEM*>& aItems ) override;
void ClearCaches() override; void ClearCaches() override;
private:
BOARD_ITEM* getBoardItem( const PNS::ITEM* aItem, int aLayer, int aIdx = 0 );
private: private:
PNS::ROUTER_IFACE* m_routerIface; PNS::ROUTER_IFACE* m_routerIface;
BOARD* m_board; BOARD* m_board;
@ -209,7 +216,8 @@ bool PNS_PCBNEW_RULE_RESOLVER::IsNetTieExclusion( const PNS::ITEM* aItem,
} }
bool PNS_PCBNEW_RULE_RESOLVER::IsKeepout( const PNS::ITEM* aA, const PNS::ITEM* aB ) bool PNS_PCBNEW_RULE_RESOLVER::IsKeepout( const PNS::ITEM* aObstacle, const PNS::ITEM* aItem,
bool* aEnforce )
{ {
auto checkKeepout = auto checkKeepout =
[]( const ZONE* aKeepout, const BOARD_ITEM* aOther ) []( const ZONE* aKeepout, const BOARD_ITEM* aOther )
@ -233,20 +241,15 @@ bool PNS_PCBNEW_RULE_RESOLVER::IsKeepout( const PNS::ITEM* aA, const PNS::ITEM*
return false; return false;
}; };
if( aA->Parent() && aA->Parent()->Type() == PCB_ZONE_T ) if( aObstacle->Parent() && aObstacle->Parent()->Type() == PCB_ZONE_T )
{ {
const ZONE* zoneA = static_cast<ZONE*>( aA->Parent() ); const ZONE* zone = static_cast<ZONE*>( aObstacle->Parent() );
if( zoneA->GetIsRuleArea() && aB->Parent() ) if( zone->GetIsRuleArea() )
return checkKeepout( zoneA, aB->Parent() ); {
} *aEnforce = checkKeepout( zone, getBoardItem( aItem, aObstacle->Layer() ) );
return true;
if( aB->Parent() && aB->Parent()->Type() == PCB_ZONE_T ) }
{
const ZONE* zoneB = static_cast<ZONE*>( aB->Parent() );
if( zoneB->GetIsRuleArea() && aA->Parent() )
return checkKeepout( zoneB, aA->Parent() );
} }
return false; return false;
@ -312,6 +315,38 @@ static bool isEdge( const PNS::ITEM* aItem )
} }
BOARD_ITEM* PNS_PCBNEW_RULE_RESOLVER::getBoardItem( const PNS::ITEM* aItem, int aLayer, int aIdx )
{
switch( aItem->Kind() )
{
case PNS::ITEM::ARC_T:
m_dummyArcs[aIdx].SetLayer( ToLAYER_ID( aLayer ) );
m_dummyArcs[aIdx].SetNet( static_cast<NETINFO_ITEM*>( aItem->Net() ) );
m_dummyArcs[aIdx].SetStart( aItem->Anchor( 0 ) );
m_dummyArcs[aIdx].SetEnd( aItem->Anchor( 1 ) );
return &m_dummyArcs[aIdx];
case PNS::ITEM::VIA_T:
case PNS::ITEM::HOLE_T:
m_dummyVias[aIdx].SetLayer( ToLAYER_ID( aLayer ) );
m_dummyVias[aIdx].SetNet( static_cast<NETINFO_ITEM*>( aItem->Net() ) );
m_dummyVias[aIdx].SetStart( aItem->Anchor( 0 ) );
return &m_dummyVias[aIdx];
case PNS::ITEM::SEGMENT_T:
case PNS::ITEM::LINE_T:
m_dummyTracks[aIdx].SetLayer( ToLAYER_ID( aLayer ) );
m_dummyTracks[aIdx].SetNet( static_cast<NETINFO_ITEM*>( aItem->Net() ) );
m_dummyTracks[aIdx].SetStart( aItem->Anchor( 0 ) );
m_dummyTracks[aIdx].SetEnd( aItem->Anchor( 1 ) );
return &m_dummyTracks[aIdx];
default:
return nullptr;
}
}
bool PNS_PCBNEW_RULE_RESOLVER::QueryConstraint( PNS::CONSTRAINT_TYPE aType, bool PNS_PCBNEW_RULE_RESOLVER::QueryConstraint( PNS::CONSTRAINT_TYPE aType,
const PNS::ITEM* aItemA, const PNS::ITEM* aItemB, const PNS::ITEM* aItemA, const PNS::ITEM* aItemB,
int aLayer, PNS::CONSTRAINT* aConstraint ) int aLayer, PNS::CONSTRAINT* aConstraint )
@ -346,72 +381,10 @@ bool PNS_PCBNEW_RULE_RESOLVER::QueryConstraint( PNS::CONSTRAINT_TYPE aType,
// A track being routed may not have a BOARD_ITEM associated yet. // A track being routed may not have a BOARD_ITEM associated yet.
if( aItemA && !parentA ) if( aItemA && !parentA )
{ parentA = getBoardItem( aItemA, aLayer, 0 );
switch( aItemA->Kind() )
{
case PNS::ITEM::ARC_T:
m_dummyArcs[0].SetLayer( ToLAYER_ID( aLayer ) );
m_dummyArcs[0].SetNet( static_cast<NETINFO_ITEM*>( aItemA->Net() ) );
m_dummyArcs[0].SetStart( aItemA->Anchor( 0 ) );
m_dummyArcs[0].SetEnd( aItemA->Anchor( 1 ) );
parentA = &m_dummyArcs[0];
break;
case PNS::ITEM::VIA_T:
case PNS::ITEM::HOLE_T:
m_dummyVias[0].SetLayer( ToLAYER_ID( aLayer ) );
m_dummyVias[0].SetNet( static_cast<NETINFO_ITEM*>( aItemA->Net() ) );
m_dummyVias[0].SetStart( aItemA->Anchor( 0 ) );
parentA = &m_dummyVias[0];
break;
case PNS::ITEM::SEGMENT_T:
case PNS::ITEM::LINE_T:
m_dummyTracks[0].SetLayer( ToLAYER_ID( aLayer ) );
m_dummyTracks[0].SetNet( static_cast<NETINFO_ITEM*>( aItemA->Net() ) );
m_dummyTracks[0].SetStart( aItemA->Anchor( 0 ) );
m_dummyTracks[0].SetEnd( aItemA->Anchor( 1 ) );
parentA = &m_dummyTracks[0];
break;
default:
break;
}
}
if( aItemB && !parentB ) if( aItemB && !parentB )
{ parentB = getBoardItem( aItemB, aLayer, 1 );
switch( aItemB->Kind() )
{
case PNS::ITEM::ARC_T:
m_dummyArcs[1].SetLayer( ToLAYER_ID( aLayer ) );
m_dummyArcs[1].SetNet( static_cast<NETINFO_ITEM*>( aItemB->Net() ) );
m_dummyArcs[1].SetStart( aItemB->Anchor( 0 ) );
m_dummyArcs[1].SetEnd( aItemB->Anchor( 1 ) );
parentB = &m_dummyArcs[1];
break;
case PNS::ITEM::VIA_T:
case PNS::ITEM::HOLE_T:
m_dummyVias[1].SetLayer( ToLAYER_ID( aLayer ) );
m_dummyVias[1].SetNet( static_cast<NETINFO_ITEM*>( aItemB->Net() ) );
m_dummyVias[1].SetStart( aItemB->Anchor( 0 ) );
parentB = &m_dummyVias[1];
break;
case PNS::ITEM::SEGMENT_T:
case PNS::ITEM::LINE_T:
m_dummyTracks[1].SetLayer( ToLAYER_ID( aLayer ) );
m_dummyTracks[1].SetNet( static_cast<NETINFO_ITEM*>( aItemB->Net() ) );
m_dummyTracks[1].SetStart( aItemB->Anchor( 0 ) );
m_dummyTracks[1].SetEnd( aItemB->Anchor( 1 ) );
parentB = &m_dummyTracks[1];
break;
default:
break;
}
}
if( parentA ) if( parentA )
hostConstraint = drcEngine->EvalRules( hostType, parentA, parentB, ToLAYER_ID( aLayer ) ); hostConstraint = drcEngine->EvalRules( hostType, parentA, parentB, ToLAYER_ID( aLayer ) );
@ -1230,14 +1203,13 @@ std::unique_ptr<PNS::VIA> PNS_KICAD_IFACE_BASE::syncVia( PCB_VIA* aVia )
bool PNS_KICAD_IFACE_BASE::syncZone( PNS::NODE* aWorld, ZONE* aZone, SHAPE_POLY_SET* aBoardOutline ) bool PNS_KICAD_IFACE_BASE::syncZone( PNS::NODE* aWorld, ZONE* aZone, SHAPE_POLY_SET* aBoardOutline )
{ {
static wxString msg;
SHAPE_POLY_SET* poly; SHAPE_POLY_SET* poly;
// TODO handle aZone->GetDoNotAllowVias() if( !aZone->GetIsRuleArea() )
// TODO handle rules which disallow tracks & vias
if( !aZone->GetIsRuleArea() || !aZone->GetDoNotAllowTracks() )
return false; return false;
LSET layers = aZone->GetLayerSet(); LSET layers = aZone->GetLayerSet();
poly = aZone->Outline(); poly = aZone->Outline();
poly->CacheTriangulation( false ); poly->CacheTriangulation( false );
@ -1245,12 +1217,11 @@ bool PNS_KICAD_IFACE_BASE::syncZone( PNS::NODE* aWorld, ZONE* aZone, SHAPE_POLY_
if( !poly->IsTriangulationUpToDate() ) if( !poly->IsTriangulationUpToDate() )
{ {
UNITS_PROVIDER unitsProvider( pcbIUScale, GetUnits() ); UNITS_PROVIDER unitsProvider( pcbIUScale, GetUnits() );
KIDIALOG dlg( nullptr, wxString::Format( _( "%s is malformed." ), msg.Printf( _( "%s is malformed." ), aZone->GetItemDescription( &unitsProvider ) );
aZone->GetItemDescription( &unitsProvider ) ),
KIDIALOG::KD_WARNING ); KIDIALOG dlg( nullptr, msg, KIDIALOG::KD_WARNING );
dlg.ShowDetailedText( wxString::Format( _( "This zone cannot be handled by the router.\n" dlg.ShowDetailedText( _( "This zone cannot be handled by the router.\n"
"Please verify it is not a self-intersecting " "Please verify it is not a self-intersecting polygon." ) );
"polygon." ) ) );
dlg.DoNotShowCheckbox( __FILE__, __LINE__ ); dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
dlg.ShowModal(); dlg.ShowModal();

View File

@ -153,7 +153,11 @@ public:
virtual bool IsNetTieExclusion( const ITEM* aItem, const VECTOR2I& aCollisionPos, virtual bool IsNetTieExclusion( const ITEM* aItem, const VECTOR2I& aCollisionPos,
const ITEM* aCollidingItem )= 0; const ITEM* aCollidingItem )= 0;
virtual bool IsKeepout( const ITEM* aA, const ITEM* aB ) = 0; /**
* @return true if \a aObstacle is a keepout. Set \a aEnforce if said keepout's rules
* exclude \a aItem.
*/
virtual bool IsKeepout( const ITEM* aObstacle, const ITEM* aItem, bool* aEnforce ) = 0;
virtual bool QueryConstraint( CONSTRAINT_TYPE aType, const ITEM* aItemA, const ITEM* aItemB, virtual bool QueryConstraint( CONSTRAINT_TYPE aType, const ITEM* aItemA, const ITEM* aItemB,
int aLayer, CONSTRAINT* aConstraint ) = 0; int aLayer, CONSTRAINT* aConstraint ) = 0;

View File

@ -249,7 +249,10 @@ public:
return false; return false;
} }
bool IsKeepout( const PNS::ITEM* aA, const PNS::ITEM* aB ) override { return false; } bool IsKeepout( const PNS::ITEM* aObstacle, const PNS::ITEM* aItem, bool* aEnforce ) override
{
return false;
}
void AddMockRule( PNS::CONSTRAINT_TYPE aType, const PNS::ITEM* aItemA, const PNS::ITEM* aItemB, void AddMockRule( PNS::CONSTRAINT_TYPE aType, const PNS::ITEM* aItemA, const PNS::ITEM* aItemB,
PNS::CONSTRAINT& aConstraint ) PNS::CONSTRAINT& aConstraint )