Improve zone-layer-connections terminology and comments.

This makes it clearer that the overrides are not inverses of each
other -- one overrides the flashing state and the other overrides
the connection state (to other zones, not to everything).

Also fixes a bug where we were failing to check the force-no-connect
for pads.
This commit is contained in:
Jeff Young 2023-02-05 13:07:30 +00:00
parent c122fd0e36
commit f2f54fe926
9 changed files with 82 additions and 76 deletions

View File

@ -41,11 +41,23 @@ class SHAPE;
class PCB_GROUP;
enum ZONE_LAYER_CONNECTION
/**
* Conditionally flashed vias and pads that interact with zones of different priority can be
* very squirrelly.
*
* In particular, when filling a higher-priority zone that does -not- connect to a via/pad, we
* don't know whether or not a lower-priority zone will subsequently connect -- so we can't
* determine clearance because we don't know what the final flashing state will be.
*
* We therefore force the flashing state if the highest-priority zone with the same net -can-
* connect (whether or not it does in the end), and otherwise force the zone-connection state
* to no-connection (even though a lower priority zone -might- have otherwise connected to it.
*/
enum ZONE_LAYER_OVERRIDE
{
ZLC_UNRESOLVED,
ZLC_CONNECTED,
ZLC_UNCONNECTED
ZLO_NONE,
ZLO_FORCE_FLASHED,
ZLO_FORCE_NO_ZONE_CONNECTION
};

View File

@ -745,15 +745,21 @@ void CN_VISITOR::checkZoneItemConnection( CN_ZONE_LAYER* aZoneLayer, CN_ITEM* aI
{
PAD* pad = static_cast<PAD*>( item );
if( pad->ConditionallyFlashed( layer ) && pad->ZoneConnectionCache( layer ) == ZLC_UNCONNECTED )
if( pad->ConditionallyFlashed( layer )
&& pad->GetZoneLayerOverride( layer ) == ZLO_FORCE_NO_ZONE_CONNECTION )
{
return;
}
}
else if( item->Type() == PCB_VIA_T )
{
PCB_VIA* via = static_cast<PCB_VIA*>( item );
if( via->ConditionallyFlashed( layer ) && via->ZoneConnectionCache( layer ) == ZLC_UNCONNECTED )
if( via->ConditionallyFlashed( layer )
&& via->GetZoneLayerOverride( layer ) == ZLO_FORCE_NO_ZONE_CONNECTION )
{
return;
}
}
for( int i = 0; i < aItem->AnchorCount(); ++i )

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -105,8 +105,8 @@ PAD::PAD( FOOTPRINT* parent ) :
m_removeUnconnectedLayer = false;
m_keepTopBottomLayer = true;
for( size_t ii = 0; ii < arrayDim( m_zoneLayerConnections ); ++ii )
m_zoneLayerConnections[ ii ] = ZLC_UNCONNECTED;
for( size_t ii = 0; ii < arrayDim( m_zoneLayerOverrides ); ++ii )
m_zoneLayerOverrides[ ii ] = ZLO_NONE;
}
@ -314,27 +314,12 @@ bool PAD::FlashLayer( int aLayer, bool aOnlyCheckIfPermitted ) const
static std::initializer_list<KICAD_T> types = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T,
PCB_PAD_T };
// Only the highest priority zone that a via interacts with on any given layer gets
// to determine if it is connected or not. This keeps us from deciding it's not
// flashed when filling the first zone, and then later having another zone connect to
// it, causing it to become flashed, resulting in the first zone having insufficient
// clearance.
// See https://gitlab.com/kicad/code/kicad/-/issues/11299.
if( m_zoneLayerConnections[ aLayer ] == ZLC_CONNECTED )
{
if( m_zoneLayerOverrides[ aLayer ] == ZLO_FORCE_FLASHED )
return true;
}
else if( m_zoneLayerConnections[ aLayer ] == ZLC_UNCONNECTED )
{
return false;
}
else /* ZLC_UNRESOLVED */
{
if( aOnlyCheckIfPermitted )
return true;
else
return board->GetConnectivity()->IsConnectedOnLayer( this, aLayer, types );
}
else if( aOnlyCheckIfPermitted )
return true;
else
return board->GetConnectivity()->IsConnectedOnLayer( this, aLayer, types );
}
}

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -739,21 +739,21 @@ public:
virtual const BOX2I ViewBBox() const override;
void ClearZoneConnectionCache()
void ClearZoneLayerOverrides()
{
for( size_t ii = 0; ii < arrayDim( m_zoneLayerConnections ); ++ii )
m_zoneLayerConnections[ ii ] = ZLC_UNRESOLVED;
for( size_t ii = 0; ii < arrayDim( m_zoneLayerOverrides ); ++ii )
m_zoneLayerOverrides[ ii ] = ZLO_NONE;
}
const ZONE_LAYER_CONNECTION& ZoneConnectionCache( PCB_LAYER_ID aLayer ) const
const ZONE_LAYER_OVERRIDE& GetZoneLayerOverride( PCB_LAYER_ID aLayer ) const
{
return m_zoneLayerConnections[ aLayer ];
return m_zoneLayerOverrides[ aLayer ];
}
void SetZoneConnectionCache( PCB_LAYER_ID aLayer, ZONE_LAYER_CONNECTION aConnection )
void SetZoneLayerOverride( PCB_LAYER_ID aLayer, ZONE_LAYER_OVERRIDE aOverride )
{
std::unique_lock<std::mutex> cacheLock( m_zoneLayerConnectionsMutex );
m_zoneLayerConnections[ aLayer ] = aConnection;
std::unique_lock<std::mutex> cacheLock( m_zoneLayerOverridesMutex );
m_zoneLayerOverrides[ aLayer ] = aOverride;
}
#if defined(DEBUG)
@ -874,8 +874,8 @@ private:
// while 90° will produce a +.
int m_thermalGap;
std::mutex m_zoneLayerConnectionsMutex;
ZONE_LAYER_CONNECTION m_zoneLayerConnections[B_Cu + 1];
std::mutex m_zoneLayerOverridesMutex;
ZONE_LAYER_OVERRIDE m_zoneLayerOverrides[B_Cu + 1];
};
#endif // PAD_H

View File

@ -4,7 +4,7 @@
* Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -89,8 +89,8 @@ PCB_VIA::PCB_VIA( BOARD_ITEM* aParent ) :
m_removeUnconnectedLayer = false;
m_keepStartEndLayer = true;
for( size_t ii = 0; ii < arrayDim( m_zoneLayerConnections ); ++ii )
m_zoneLayerConnections[ ii ] = ZLC_UNCONNECTED;
for( size_t ii = 0; ii < arrayDim( m_zoneLayerOverrides ); ++ii )
m_zoneLayerOverrides[ ii ] = ZLO_NONE;
m_isFree = false;
}
@ -654,15 +654,10 @@ bool PCB_VIA::FlashLayer( int aLayer ) const
static std::initializer_list<KICAD_T> connectedTypes = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T,
PCB_PAD_T };
// Only the highest priority zone that a via interacts with on any given layer gets to
// determine if it is connected or not. This keeps us from deciding it's not flashed when
// filling the first zone, and then later having another zone connect to it, causing it to
// become flashed, resulting in the first zone having insufficient clearance.
// See https://gitlab.com/kicad/code/kicad/-/issues/11299.
if( m_zoneLayerConnections[ aLayer ] == ZLC_CONNECTED )
if( m_zoneLayerOverrides[ aLayer ] == ZLO_FORCE_FLASHED )
return true;
return board->GetConnectivity()->IsConnectedOnLayer( this, aLayer, connectedTypes );
else
return board->GetConnectivity()->IsConnectedOnLayer( this, aLayer, connectedTypes );
}

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -553,21 +553,21 @@ public:
std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER,
FLASHING aFlash = FLASHING::DEFAULT ) const override;
void ClearZoneConnectionCache()
void ClearZoneLayerOverrides()
{
for( size_t ii = 0; ii < arrayDim( m_zoneLayerConnections ); ++ii )
m_zoneLayerConnections[ ii ] = ZLC_UNRESOLVED;
for( size_t ii = 0; ii < arrayDim( m_zoneLayerOverrides ); ++ii )
m_zoneLayerOverrides[ ii ] = ZLO_NONE;
}
const ZONE_LAYER_CONNECTION& ZoneConnectionCache( PCB_LAYER_ID aLayer ) const
const ZONE_LAYER_OVERRIDE& GetZoneLayerOverride( PCB_LAYER_ID aLayer ) const
{
return m_zoneLayerConnections[ aLayer ];
return m_zoneLayerOverrides[ aLayer ];
}
void SetZoneConnectionCache( PCB_LAYER_ID aLayer, ZONE_LAYER_CONNECTION aConnection )
void SetZoneLayerOverride( PCB_LAYER_ID aLayer, ZONE_LAYER_OVERRIDE aOverride )
{
std::unique_lock<std::mutex> cacheLock( m_zoneLayerConnectionsMutex );
m_zoneLayerConnections[ aLayer ] = aConnection;
std::unique_lock<std::mutex> cacheLock( m_zoneLayerOverridesMutex );
m_zoneLayerOverrides[ aLayer ] = aOverride;
}
protected:
@ -587,8 +587,8 @@ private:
bool m_keepStartEndLayer; ///< Keep the start and end annular rings
bool m_isFree; ///< "Free" vias don't get their nets auto-updated
std::mutex m_zoneLayerConnectionsMutex;
ZONE_LAYER_CONNECTION m_zoneLayerConnections[B_Cu + 1];
std::mutex m_zoneLayerOverridesMutex;
ZONE_LAYER_OVERRIDE m_zoneLayerOverrides[B_Cu + 1];
};

View File

@ -5025,6 +5025,9 @@ PAD* PCB_PARSER::parsePAD( FOOTPRINT* aParent )
break;
case T_zone_layer_connections:
for( PCB_LAYER_ID layer : pad->GetLayerSet().Seq() )
pad->SetZoneLayerOverride( layer, ZLO_FORCE_NO_ZONE_CONNECTION );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
PCB_LAYER_ID layer = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
@ -5032,7 +5035,7 @@ PAD* PCB_PARSER::parsePAD( FOOTPRINT* aParent )
if( layer < F_Cu || layer > B_Cu )
Expecting( "copper layer name" );
pad->SetZoneConnectionCache( layer, ZLC_CONNECTED );
pad->SetZoneLayerOverride( layer, ZLO_FORCE_FLASHED );
}
break;
@ -5449,6 +5452,9 @@ PCB_VIA* PCB_PARSER::parsePCB_VIA()
break;
case T_zone_layer_connections:
for( PCB_LAYER_ID layer : via->GetLayerSet().Seq() )
via->SetZoneLayerOverride( layer, ZLO_FORCE_NO_ZONE_CONNECTION );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
PCB_LAYER_ID layer = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
@ -5456,7 +5462,7 @@ PCB_VIA* PCB_PARSER::parsePCB_VIA()
if( layer < F_Cu || layer > B_Cu )
Expecting( "copper layer name" );
via->SetZoneConnectionCache( layer, ZLC_CONNECTED );
via->SetZoneLayerOverride( layer, ZLO_FORCE_FLASHED );
}
break;

View File

@ -1535,7 +1535,7 @@ void PCB_PLUGIN::format( const PAD* aPad, int aNestLevel ) const
for( LSEQ cu = board->GetEnabledLayers().CuStack(); cu; ++cu )
{
if( aPad->ZoneConnectionCache( *cu ) == ZLC_CONNECTED )
if( aPad->GetZoneLayerOverride( *cu ) == ZLO_FORCE_FLASHED )
m_out->Print( 0, " %s", m_out->Quotew( LSET::Name( *cu ) ).c_str() );
}
@ -2085,7 +2085,7 @@ void PCB_PLUGIN::format( const PCB_TRACK* aTrack, int aNestLevel ) const
for( LSEQ cu = board->GetEnabledLayers().CuStack(); cu; ++cu )
{
if( via->ZoneConnectionCache( *cu ) == ZLC_CONNECTED )
if( via->GetZoneLayerOverride( *cu ) == ZLO_FORCE_FLASHED )
m_out->Print( 0, " %s", m_out->Quotew( LSET::Name( *cu ) ).c_str() );
}

View File

@ -225,7 +225,7 @@ bool ZONE_FILLER::Fill( std::vector<ZONE*>& aZones, bool aCheck, wxWindow* aPare
{
PCB_VIA* via = static_cast<PCB_VIA*>( track );
via->ClearZoneConnectionCache();
via->ClearZoneLayerOverrides();
if( !via->GetRemoveUnconnected() )
continue;
@ -249,16 +249,16 @@ bool ZONE_FILLER::Fill( std::vector<ZONE*>& aZones, bool aCheck, wxWindow* aPare
if( isInPourKeepoutArea( bbox, layer, center ) )
{
via->SetZoneConnectionCache( layer, ZLC_UNCONNECTED );
via->SetZoneLayerOverride( layer, ZLO_FORCE_NO_ZONE_CONNECTION );
}
else
{
ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, viaTestFn );
if( zone && zone->GetNetCode() == via->GetNetCode() )
via->SetZoneConnectionCache( layer, ZLC_CONNECTED );
via->SetZoneLayerOverride( layer, ZLO_FORCE_FLASHED );
else
via->SetZoneConnectionCache( layer, ZLC_UNCONNECTED );
via->SetZoneLayerOverride( layer, ZLO_FORCE_NO_ZONE_CONNECTION );
}
}
}
@ -269,7 +269,7 @@ bool ZONE_FILLER::Fill( std::vector<ZONE*>& aZones, bool aCheck, wxWindow* aPare
{
for( PAD* pad : footprint->Pads() )
{
pad->ClearZoneConnectionCache();
pad->ClearZoneLayerOverrides();
if( !pad->GetRemoveUnconnected() )
continue;
@ -291,16 +291,16 @@ bool ZONE_FILLER::Fill( std::vector<ZONE*>& aZones, bool aCheck, wxWindow* aPare
if( isInPourKeepoutArea( bbox, layer, center ) )
{
pad->SetZoneConnectionCache( layer, ZLC_UNCONNECTED );
pad->SetZoneLayerOverride( layer, ZLO_FORCE_NO_ZONE_CONNECTION );
}
else
{
ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, padTestFn );
if( zone && zone->GetNetCode() == pad->GetNetCode() )
pad->SetZoneConnectionCache( layer, ZLC_CONNECTED );
pad->SetZoneLayerOverride( layer, ZLO_FORCE_FLASHED );
else
pad->SetZoneConnectionCache( layer, ZLC_UNCONNECTED );
pad->SetZoneLayerOverride( layer, ZLO_FORCE_NO_ZONE_CONNECTION );
}
}
}
@ -890,7 +890,9 @@ void ZONE_FILLER::knockoutThermalReliefs( const ZONE* aZone, PCB_LAYER_ID aLayer
if( !padBBox.Intersects( aZone->GetBoundingBox() ) )
continue;
if( pad->GetNetCode() != aZone->GetNetCode() || pad->GetNetCode() <= 0 )
if( pad->GetNetCode() != aZone->GetNetCode()
|| pad->GetNetCode() <= 0
|| pad->GetZoneLayerOverride( aLayer ) == ZLO_FORCE_NO_ZONE_CONNECTION )
{
// collect these for knockout in buildCopperItemClearances()
aNoConnectionPads.push_back( pad );
@ -1057,7 +1059,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLa
{
PCB_VIA* via = static_cast<PCB_VIA*>( aTrack );
if( via->ZoneConnectionCache( aLayer ) == ZLC_UNCONNECTED )
if( via->GetZoneLayerOverride( aLayer ) == ZLO_FORCE_NO_ZONE_CONNECTION )
sameNet = false;
}