Overhaul of remove-unconnected's zone filling and drawing strategies.
1) The highest priority zone that a via/pad collides with "owns" its connectivity state. Once set, lower priority zones cannot change it -- and in fact, if they would have connected to it are forced not to. 2) The connectivity state goes with the zone fill state, and therefore must be saved in the file. 3) Display of remove-unconnected's pads is no longer done in GetViewLOD() (which isn't called for selected items), and is instead done in PCB_PAINTER. This allows us to draw the full pad in outline mode when a via/pad is selected which would otherwise only show the hole. 4) Note that in some cases this will still generate DRC errors -- in particular when a via nearly collides with a higher priority zone it won't get "owned" by that zone and may therefore have insufficient clearance if said zone concludes it's unconnected and a subsequent (lower priority) zone connects to it (causing it to now become flashed). Fixes https://gitlab.com/kicad/code/kicad/issues/11299
This commit is contained in:
parent
ebd8ebb756
commit
437d2c4589
|
@ -338,5 +338,6 @@ zone
|
|||
zone_45_only
|
||||
zone_clearance
|
||||
zone_connect
|
||||
zone_layer_connections
|
||||
zone_type
|
||||
zones
|
||||
|
|
|
@ -41,6 +41,14 @@ class SHAPE;
|
|||
class PCB_GROUP;
|
||||
|
||||
|
||||
enum ZONE_LAYER_CONNECTION
|
||||
{
|
||||
ZLC_UNRESOLVED,
|
||||
ZLC_CONNECTED,
|
||||
ZLC_UNCONNECTED
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A base class for any item which can be embedded within the #BOARD container class, and
|
||||
* therefore instances of derived classes should only be found in Pcbnew or other programs
|
||||
|
|
|
@ -392,8 +392,7 @@ void CONNECTIVITY_DATA::PropagateNets( BOARD_COMMIT* aCommit, PROPAGATE_MODE aMo
|
|||
|
||||
|
||||
bool CONNECTIVITY_DATA::IsConnectedOnLayer( const BOARD_CONNECTED_ITEM *aItem, int aLayer,
|
||||
const std::initializer_list<KICAD_T>& aTypes,
|
||||
bool aCheckOptionalFlashing ) const
|
||||
const std::initializer_list<KICAD_T>& aTypes ) const
|
||||
{
|
||||
CN_CONNECTIVITY_ALGO::ITEM_MAP_ENTRY &entry = m_connAlgo->ItemEntry( aItem );
|
||||
|
||||
|
|
|
@ -200,8 +200,7 @@ public:
|
|||
unsigned int GetUnconnectedCount( bool aVisibileOnly ) const;
|
||||
|
||||
bool IsConnectedOnLayer( const BOARD_CONNECTED_ITEM* aItem, int aLayer,
|
||||
const std::initializer_list<KICAD_T>& aTypes = {},
|
||||
bool aCheckOptionalFlashing = false ) const;
|
||||
const std::initializer_list<KICAD_T>& aTypes = {} ) const;
|
||||
|
||||
unsigned int GetNodeCount( int aNet = -1 ) const;
|
||||
|
||||
|
|
|
@ -1575,6 +1575,9 @@ unsigned int DIALOG_NET_INSPECTOR::calculateViaLength( const PCB_TRACK* aTrack )
|
|||
|
||||
BOARD_DESIGN_SETTINGS& bds = m_brd->GetDesignSettings();
|
||||
|
||||
// Must be static to keep from raising its ugly head in performance profiles
|
||||
static std::initializer_list<KICAD_T> traceAndPadTypes = { PCB_TRACE_T, PCB_ARC_T, PCB_PAD_T };
|
||||
|
||||
// calculate the via length individually from the board stackup and via's start and end layer.
|
||||
if( bds.m_HasStackup )
|
||||
{
|
||||
|
@ -1583,8 +1586,7 @@ unsigned int DIALOG_NET_INSPECTOR::calculateViaLength( const PCB_TRACK* aTrack )
|
|||
|
||||
for( int layer = via->TopLayer(); layer <= via->BottomLayer(); ++layer )
|
||||
{
|
||||
if( m_brd->GetConnectivity()->IsConnectedOnLayer( via, layer,
|
||||
{ PCB_TRACE_T, PCB_ARC_T, PCB_PAD_T }, true ) )
|
||||
if( m_brd->GetConnectivity()->IsConnectedOnLayer( via, layer, traceAndPadTypes ) )
|
||||
{
|
||||
if( top_layer == UNDEFINED_LAYER )
|
||||
top_layer = PCB_LAYER_ID( layer );
|
||||
|
|
|
@ -102,6 +102,9 @@ PAD::PAD( FOOTPRINT* parent ) :
|
|||
m_effectiveBoundingRadius = 0;
|
||||
m_removeUnconnectedLayer = false;
|
||||
m_keepTopBottomLayer = true;
|
||||
|
||||
for( size_t ii = 0; ii < arrayDim( m_zoneLayerConnections ); ++ii )
|
||||
m_zoneLayerConnections[ ii ] = ZLC_UNCONNECTED;
|
||||
}
|
||||
|
||||
|
||||
|
@ -292,11 +295,16 @@ bool PAD::FlashLayer( int aLayer ) const
|
|||
static std::initializer_list<KICAD_T> types = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T,
|
||||
PCB_PAD_T };
|
||||
|
||||
// Do not check zones. Doing so results in race conditions when the via collides with
|
||||
// two different zones of different priorities.
|
||||
// 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 )
|
||||
return true;
|
||||
|
||||
return board->GetConnectivity()->IsConnectedOnLayer( this, aLayer, types, true );
|
||||
return board->GetConnectivity()->IsConnectedOnLayer( this, aLayer, types );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1384,25 +1392,9 @@ double PAD::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
|
|||
if( IsBackLayer( (PCB_LAYER_ID) aLayer ) && !aView->IsLayerVisible( LAYER_PAD_BK ) )
|
||||
return HIDE;
|
||||
|
||||
LSET visible = LSET::AllLayersMask();
|
||||
LSET visible = board->GetVisibleLayers() & board->GetEnabledLayers();
|
||||
|
||||
// Handle board visibility
|
||||
if( board )
|
||||
visible &= board->GetEnabledLayers();
|
||||
|
||||
// Handle view visibility
|
||||
for( int layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
|
||||
{
|
||||
if( !aView->IsLayerVisible( layer ) )
|
||||
visible.set( layer, false );
|
||||
}
|
||||
|
||||
if( aLayer == LAYER_PADS_TH )
|
||||
{
|
||||
if( !FlashLayer( visible ) )
|
||||
return HIDE;
|
||||
}
|
||||
else if( IsHoleLayer( aLayer ) )
|
||||
if( IsHoleLayer( aLayer ) )
|
||||
{
|
||||
if( !( visible & LSET::PhysicalLayersMask() ).any() )
|
||||
return HIDE;
|
||||
|
@ -1425,8 +1417,8 @@ double PAD::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
|
|||
// Netnames will be shown only if zoom is appropriate
|
||||
int divisor = std::min( GetBoundingBox().GetWidth(), GetBoundingBox().GetHeight() );
|
||||
|
||||
// Pad sizes can be zero briefly when someone is typing a number like "0.5"
|
||||
// in the pad properties dialog
|
||||
// Pad sizes can be zero briefly when someone is typing a number like "0.5" in the pad
|
||||
// properties dialog
|
||||
if( divisor == 0 )
|
||||
return HIDE;
|
||||
|
||||
|
@ -1440,8 +1432,7 @@ double PAD::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
|
|||
|
||||
const BOX2I PAD::ViewBBox() const
|
||||
{
|
||||
// Bounding box includes soldermask too. Remember mask and/or paste
|
||||
// margins can be < 0
|
||||
// Bounding box includes soldermask too. Remember mask and/or paste margins can be < 0
|
||||
int solderMaskMargin = std::max( GetSolderMaskExpansion(), 0 );
|
||||
VECTOR2I solderPasteMargin = VECTOR2D( GetSolderPasteMargin() );
|
||||
BOX2I bbox = GetBoundingBox();
|
||||
|
|
14
pcbnew/pad.h
14
pcbnew/pad.h
|
@ -32,6 +32,7 @@
|
|||
#include <geometry/shape_compound.h>
|
||||
#include <pad_shapes.h>
|
||||
#include <geometry/eda_angle.h>
|
||||
#include <core/arraydim.h>
|
||||
|
||||
class PCB_SHAPE;
|
||||
class PARAM_CFG;
|
||||
|
@ -718,6 +719,17 @@ public:
|
|||
|
||||
virtual void SwapData( BOARD_ITEM* aImage ) override;
|
||||
|
||||
void ClearZoneConnectionCache()
|
||||
{
|
||||
for( size_t ii = 0; ii < arrayDim( m_zoneLayerConnections ); ++ii )
|
||||
m_zoneLayerConnections[ ii ] = ZLC_UNRESOLVED;
|
||||
}
|
||||
|
||||
ZONE_LAYER_CONNECTION& ZoneConnectionCache( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
return m_zoneLayerConnections[ aLayer ];
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
virtual void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
|
||||
#endif
|
||||
|
@ -833,6 +845,8 @@ private:
|
|||
EDA_ANGLE m_thermalSpokeAngle; // Rotation of the spokes. 45° will produce an X,
|
||||
// while 90° will produce a +.
|
||||
int m_thermalGap;
|
||||
|
||||
mutable ZONE_LAYER_CONNECTION m_zoneLayerConnections[B_Cu + 1];
|
||||
};
|
||||
|
||||
#endif // PAD_H
|
||||
|
|
|
@ -1075,7 +1075,12 @@ void PCB_BASE_FRAME::SetDisplayOptions( const PCB_DISPLAY_OPTIONS& aOptions, boo
|
|||
if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
|
||||
{
|
||||
return via->GetViaType() == VIATYPE::BLIND_BURIED
|
||||
|| via->GetViaType() == VIATYPE::MICROVIA;
|
||||
|| via->GetViaType() == VIATYPE::MICROVIA
|
||||
|| via->GetRemoveUnconnected();
|
||||
}
|
||||
else if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
|
||||
{
|
||||
return pad->GetRemoveUnconnected();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -803,8 +803,9 @@ void PCB_PAINTER::draw( const PCB_ARC* aArc, int aLayer )
|
|||
|
||||
void PCB_PAINTER::draw( const PCB_VIA* aVia, int aLayer )
|
||||
{
|
||||
COLOR4D color = m_pcbSettings.GetColor( aVia, aLayer );
|
||||
VECTOR2D center( aVia->GetStart() );
|
||||
const BOARD* board = aVia->GetBoard();
|
||||
COLOR4D color = m_pcbSettings.GetColor( aVia, aLayer );
|
||||
VECTOR2D center( aVia->GetStart() );
|
||||
|
||||
if( color == COLOR4D::CLEAR )
|
||||
return;
|
||||
|
@ -901,10 +902,21 @@ void PCB_PAINTER::draw( const PCB_VIA* aVia, int aLayer )
|
|||
{
|
||||
int annular_width = ( aVia->GetWidth() - getDrillSize( aVia ) ) / 2.0;
|
||||
double radius = aVia->GetWidth() / 2.0;
|
||||
bool draw = aLayer == LAYER_VIA_THROUGH;
|
||||
bool draw = false;
|
||||
|
||||
if( m_pcbSettings.IsPrinting() )
|
||||
{
|
||||
draw = aVia->FlashLayer( m_pcbSettings.GetPrintLayers() );
|
||||
}
|
||||
else if( aVia->FlashLayer( board->GetVisibleLayers() & board->GetEnabledLayers() ) )
|
||||
{
|
||||
draw = true;
|
||||
}
|
||||
else if( aVia->IsSelected() )
|
||||
{
|
||||
draw = true;
|
||||
outline_mode = true;
|
||||
}
|
||||
|
||||
if( !outline_mode )
|
||||
{
|
||||
|
@ -983,7 +995,8 @@ void PCB_PAINTER::draw( const PCB_VIA* aVia, int aLayer )
|
|||
|
||||
void PCB_PAINTER::draw( const PAD* aPad, int aLayer )
|
||||
{
|
||||
COLOR4D color = m_pcbSettings.GetColor( aPad, aLayer );
|
||||
const BOARD* board = aPad->GetBoard();
|
||||
COLOR4D color = m_pcbSettings.GetColor( aPad, aLayer );
|
||||
|
||||
if( IsNetnameLayer( aLayer ) )
|
||||
{
|
||||
|
@ -1196,6 +1209,8 @@ void PCB_PAINTER::draw( const PAD* aPad, int aLayer )
|
|||
m_gal->SetFillColor( color );
|
||||
}
|
||||
|
||||
bool drawShape = false;
|
||||
|
||||
if( aLayer == LAYER_PAD_PLATEDHOLES || aLayer == LAYER_NON_PLATEDHOLES )
|
||||
{
|
||||
std::shared_ptr<SHAPE_SEGMENT> slot = aPad->GetEffectiveHoleShape();
|
||||
|
@ -1205,7 +1220,21 @@ void PCB_PAINTER::draw( const PAD* aPad, int aLayer )
|
|||
else
|
||||
m_gal->DrawSegment( slot->GetSeg().A, slot->GetSeg().B, slot->GetWidth() );
|
||||
}
|
||||
else
|
||||
else if( m_pcbSettings.IsPrinting() )
|
||||
{
|
||||
drawShape = aPad->FlashLayer( m_pcbSettings.GetPrintLayers() );
|
||||
}
|
||||
else if( aPad->FlashLayer( board->GetVisibleLayers() & board->GetEnabledLayers() ) )
|
||||
{
|
||||
drawShape = true;
|
||||
}
|
||||
else if( aPad->IsSelected() )
|
||||
{
|
||||
drawShape = true;
|
||||
outline_mode = true;
|
||||
}
|
||||
|
||||
if( drawShape )
|
||||
{
|
||||
VECTOR2I pad_size = aPad->GetSize();
|
||||
VECTOR2I margin;
|
||||
|
|
|
@ -83,8 +83,13 @@ PCB_VIA::PCB_VIA( BOARD_ITEM* aParent ) :
|
|||
SetViaType( VIATYPE::THROUGH );
|
||||
m_bottomLayer = B_Cu;
|
||||
SetDrillDefault();
|
||||
|
||||
m_removeUnconnectedLayer = false;
|
||||
m_keepTopBottomLayer = true;
|
||||
|
||||
for( size_t ii = 0; ii < arrayDim( m_zoneLayerConnections ); ++ii )
|
||||
m_zoneLayerConnections[ ii ] = ZLC_UNCONNECTED;
|
||||
|
||||
m_isFree = false;
|
||||
}
|
||||
|
||||
|
@ -613,13 +618,17 @@ bool PCB_VIA::FlashLayer( int aLayer ) const
|
|||
|
||||
// Must be static to keep from raising its ugly head in performance profiles
|
||||
static std::initializer_list<KICAD_T> connectedTypes = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T,
|
||||
PCB_PAD_T, PCB_ZONE_T, PCB_FP_ZONE_T };
|
||||
PCB_PAD_T };
|
||||
|
||||
// Do not check zones. Doing so results in race conditions when the via collides with
|
||||
// two different zones of different priorities.
|
||||
// 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 )
|
||||
return true;
|
||||
|
||||
return board->GetConnectivity()->IsConnectedOnLayer( this, aLayer, connectedTypes, true );
|
||||
return board->GetConnectivity()->IsConnectedOnLayer( this, aLayer, connectedTypes );
|
||||
}
|
||||
|
||||
|
||||
|
@ -762,12 +771,7 @@ double PCB_VIA::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
|
|||
return HIDE;
|
||||
}
|
||||
|
||||
if( IsViaPadLayer( aLayer ) )
|
||||
{
|
||||
if( !FlashLayer( visible ) )
|
||||
return HIDE;
|
||||
}
|
||||
else if( IsHoleLayer( aLayer ) )
|
||||
if( IsHoleLayer( aLayer ) )
|
||||
{
|
||||
if( m_viaType == VIATYPE::BLIND_BURIED || m_viaType == VIATYPE::MICROVIA )
|
||||
{
|
||||
|
|
|
@ -39,7 +39,8 @@
|
|||
#include <board_connected_item.h>
|
||||
#include <base_units.h>
|
||||
#include <geometry/shape_segment.h>
|
||||
#include "core/minoptmax.h"
|
||||
#include <core/minoptmax.h>
|
||||
#include <core/arraydim.h>
|
||||
|
||||
class PCB_TRACK;
|
||||
class PCB_VIA;
|
||||
|
@ -504,6 +505,17 @@ public:
|
|||
std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER,
|
||||
FLASHING aFlash = FLASHING::DEFAULT ) const override;
|
||||
|
||||
void ClearZoneConnectionCache()
|
||||
{
|
||||
for( size_t ii = 0; ii < arrayDim( m_zoneLayerConnections ); ++ii )
|
||||
m_zoneLayerConnections[ ii ] = ZLC_UNRESOLVED;
|
||||
}
|
||||
|
||||
ZONE_LAYER_CONNECTION& ZoneConnectionCache( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
return m_zoneLayerConnections[ aLayer ];
|
||||
}
|
||||
|
||||
protected:
|
||||
wxString layerMaskDescribe() const override;
|
||||
|
||||
|
@ -518,6 +530,8 @@ private:
|
|||
bool m_removeUnconnectedLayer; ///< Remove unconnected copper on a via
|
||||
bool m_keepTopBottomLayer; ///< Keep the top and bottom annular rings
|
||||
bool m_isFree; ///< "Free" vias don't get their nets auto-updated
|
||||
|
||||
mutable ZONE_LAYER_CONNECTION m_zoneLayerConnections[B_Cu + 1];
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -4701,7 +4701,7 @@ PAD* PCB_PARSER::parsePAD( FOOTPRINT* aParent )
|
|||
|
||||
case T_drill:
|
||||
{
|
||||
bool haveWidth = false;
|
||||
bool haveWidth = false;
|
||||
VECTOR2I drillSize = pad->GetDrillSize();
|
||||
|
||||
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
|
||||
|
@ -4869,7 +4869,7 @@ PAD* PCB_PARSER::parsePAD( FOOTPRINT* aParent )
|
|||
|
||||
case T_chamfer:
|
||||
{
|
||||
int chamfers = 0;
|
||||
int chamfers = 0;
|
||||
bool end_list = false;
|
||||
|
||||
while( !end_list )
|
||||
|
@ -4912,7 +4912,6 @@ PAD* PCB_PARSER::parsePAD( FOOTPRINT* aParent )
|
|||
}
|
||||
|
||||
case T_property:
|
||||
{
|
||||
while( token != T_RIGHT )
|
||||
{
|
||||
token = NextTok();
|
||||
|
@ -4938,7 +4937,6 @@ PAD* PCB_PARSER::parsePAD( FOOTPRINT* aParent )
|
|||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case T_options:
|
||||
parsePAD_option( pad.get() );
|
||||
|
@ -5020,6 +5018,19 @@ PAD* PCB_PARSER::parsePAD( FOOTPRINT* aParent )
|
|||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_zone_layer_connections:
|
||||
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
|
||||
{
|
||||
PCB_LAYER_ID layer = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
|
||||
|
||||
if( layer < F_Cu || layer > B_Cu )
|
||||
Expecting( "copper layer name" );
|
||||
|
||||
pad->ZoneConnectionCache( layer ) = ZLC_CONNECTED;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Continue to process "(locked)" format which was output during 5.99 development
|
||||
case T_locked:
|
||||
// Pad locking is now a session preference
|
||||
|
@ -5431,6 +5442,19 @@ PCB_VIA* PCB_PARSER::parsePCB_VIA()
|
|||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_zone_layer_connections:
|
||||
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
|
||||
{
|
||||
PCB_LAYER_ID layer = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
|
||||
|
||||
if( layer < F_Cu || layer > B_Cu )
|
||||
Expecting( "copper layer name" );
|
||||
|
||||
via->ZoneConnectionCache( layer ) = ZLC_CONNECTED;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case T_tstamp:
|
||||
NextTok();
|
||||
const_cast<KIID&>( via->m_Uuid ) = CurStrToKIID();
|
||||
|
|
|
@ -1496,7 +1496,8 @@ void PCB_PLUGIN::formatLayers( LSET aLayerMask, int aNestLevel ) const
|
|||
|
||||
void PCB_PLUGIN::format( const PAD* aPad, int aNestLevel ) const
|
||||
{
|
||||
const char* shape;
|
||||
const BOARD* board = aPad->GetBoard();
|
||||
const char* shape;
|
||||
|
||||
switch( aPad->GetShape() )
|
||||
{
|
||||
|
@ -1600,6 +1601,16 @@ void PCB_PLUGIN::format( const PAD* aPad, int aNestLevel ) const
|
|||
|
||||
if( aPad->GetKeepTopBottom() )
|
||||
m_out->Print( 0, " (keep_end_layers)" );
|
||||
|
||||
m_out->Print( 0, " (zone_layer_connections" );
|
||||
|
||||
for( LSEQ cu = board->GetEnabledLayers().CuStack(); cu; ++cu )
|
||||
{
|
||||
if( aPad->ZoneConnectionCache( *cu ) == ZLC_CONNECTED )
|
||||
m_out->Print( 0, " %s", m_out->Quotew( LSET::Name( *cu ) ).c_str() );
|
||||
}
|
||||
|
||||
m_out->Print( 0, ")" );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2075,7 +2086,7 @@ void PCB_PLUGIN::format( const PCB_TRACK* aTrack, int aNestLevel ) const
|
|||
PCB_LAYER_ID layer1, layer2;
|
||||
|
||||
const PCB_VIA* via = static_cast<const PCB_VIA*>( aTrack );
|
||||
BOARD* board = (BOARD*) via->GetParent();
|
||||
const BOARD* board = via->GetBoard();
|
||||
|
||||
wxCHECK_RET( board != nullptr, wxT( "Via has no parent." ) );
|
||||
|
||||
|
@ -2137,6 +2148,19 @@ void PCB_PLUGIN::format( const PCB_TRACK* aTrack, int aNestLevel ) const
|
|||
|
||||
if( via->GetIsFree() )
|
||||
m_out->Print( 0, " (free)" );
|
||||
|
||||
if( via->GetRemoveUnconnected() )
|
||||
{
|
||||
m_out->Print( 0, " (zone_layer_connections" );
|
||||
|
||||
for( LSEQ cu = board->GetEnabledLayers().CuStack(); cu; ++cu )
|
||||
{
|
||||
if( via->ZoneConnectionCache( *cu ) == ZLC_CONNECTED )
|
||||
m_out->Print( 0, " %s", m_out->Quotew( LSET::Name( *cu ) ).c_str() );
|
||||
}
|
||||
|
||||
m_out->Print( 0, ")" );
|
||||
}
|
||||
}
|
||||
else if( aTrack->Type() == PCB_ARC_T )
|
||||
{
|
||||
|
|
|
@ -127,7 +127,8 @@ class SHAPE_LINE_CHAIN;
|
|||
//#define SEXPR_BOARD_FILE_VERSION 20220621 // Add Image support
|
||||
//#define SEXPR_BOARD_FILE_VERSION 20220815 // Add allow-soldermask-bridges-in-FPs flag
|
||||
//#define SEXPR_BOARD_FILE_VERSION 20220818 // First-class storage for net-ties
|
||||
#define SEXPR_BOARD_FILE_VERSION 20220914 // Number boxes for custom-shape pads
|
||||
//#define SEXPR_BOARD_FILE_VERSION 20220914 // Number boxes for custom-shape pads
|
||||
#define SEXPR_BOARD_FILE_VERSION 20221018 // Via & pad zone-layer-connections
|
||||
|
||||
#define BOARD_FILE_HOST_VERSION 20200825 ///< Earlier files than this include the host tag
|
||||
#define LEGACY_ARC_FORMATTING 20210925 ///< These were the last to use old arc formatting
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include <bitmaps.h>
|
||||
#include <board.h>
|
||||
#include <board_design_settings.h>
|
||||
#include <pad.h>
|
||||
#include <pcb_track.h>
|
||||
#include <eda_list_dialog.h>
|
||||
#include <string_utils.h>
|
||||
#include <footprint_edit_frame.h>
|
||||
|
@ -1203,16 +1205,31 @@ void APPEARANCE_CONTROLS::SetObjectVisible( GAL_LAYER_ID aLayer, bool isVisible
|
|||
|
||||
void APPEARANCE_CONTROLS::setVisibleLayers( LSET aLayers )
|
||||
{
|
||||
KIGFX::VIEW* view = m_frame->GetCanvas()->GetView();
|
||||
|
||||
if( m_isFpEditor )
|
||||
{
|
||||
KIGFX::VIEW* view = m_frame->GetCanvas()->GetView();
|
||||
|
||||
for( PCB_LAYER_ID layer : LSET::AllLayersMask().Seq() )
|
||||
view->SetLayerVisible( layer, aLayers.Contains( layer ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_frame->GetBoard()->SetVisibleLayers( aLayers );
|
||||
|
||||
view->UpdateAllItemsConditionally( KIGFX::REPAINT,
|
||||
[]( KIGFX::VIEW_ITEM* aItem ) -> bool
|
||||
{
|
||||
if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
|
||||
{
|
||||
return via->GetRemoveUnconnected();
|
||||
}
|
||||
else if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
|
||||
{
|
||||
return pad->GetRemoveUnconnected();
|
||||
}
|
||||
|
||||
return false;
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include <zone.h>
|
||||
#include <footprint.h>
|
||||
#include <pad.h>
|
||||
#include <pcb_shape.h>
|
||||
#include <pcb_target.h>
|
||||
#include <pcb_track.h>
|
||||
#include <pcb_text.h>
|
||||
|
@ -136,6 +135,8 @@ bool ZONE_FILLER::Fill( std::vector<ZONE*>& aZones, bool aCheck, wxWindow* aPare
|
|||
pad->BuildEffectivePolygon();
|
||||
}
|
||||
|
||||
pad->ClearZoneConnectionCache();
|
||||
|
||||
m_worstClearance = std::max( m_worstClearance, pad->GetLocalClearance() );
|
||||
}
|
||||
|
||||
|
@ -149,6 +150,12 @@ bool ZONE_FILLER::Fill( std::vector<ZONE*>& aZones, bool aCheck, wxWindow* aPare
|
|||
footprint->BuildCourtyardCaches();
|
||||
}
|
||||
|
||||
for( PCB_TRACK* track : m_board->Tracks() )
|
||||
{
|
||||
if( track->Type() == PCB_VIA_T )
|
||||
static_cast<PCB_VIA*>( track )->ClearZoneConnectionCache();
|
||||
}
|
||||
|
||||
// Sort by priority to reduce deferrals waiting on higher priority zones.
|
||||
//
|
||||
std::sort( aZones.begin(), aZones.end(),
|
||||
|
@ -775,6 +782,14 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLa
|
|||
int gap = evalRulesForItems( PHYSICAL_CLEARANCE_CONSTRAINT,
|
||||
aZone, aTrack, aLayer );
|
||||
|
||||
if( aTrack->Type() == PCB_VIA_T )
|
||||
{
|
||||
PCB_VIA* via = static_cast<PCB_VIA*>( aTrack );
|
||||
|
||||
if( via->ZoneConnectionCache( aLayer ) == ZLC_UNCONNECTED )
|
||||
sameNet = false;
|
||||
}
|
||||
|
||||
if( !sameNet )
|
||||
{
|
||||
gap = std::max( gap, evalRulesForItems( CLEARANCE_CONSTRAINT,
|
||||
|
@ -1401,7 +1416,69 @@ bool ZONE_FILLER::fillSingleZone( ZONE* aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_S
|
|||
if( aZone->IsOnCopperLayer() )
|
||||
{
|
||||
if( fillCopperZone( aZone, aLayer, debugLayer, smoothedPoly, maxExtents, aFillPolys ) )
|
||||
{
|
||||
aZone->SetNeedRefill( false );
|
||||
|
||||
BOX2I zone_boundingbox = aZone->GetBoundingBox();
|
||||
|
||||
// Check all conditionally-flashed vias and pads which aren't owned yet to see if
|
||||
// we own them. If so, set their connection caches. See FlashLayer() for additional
|
||||
// background.
|
||||
|
||||
for( PCB_TRACK* track : m_board->Tracks() )
|
||||
{
|
||||
if( track->Type() == PCB_VIA_T )
|
||||
{
|
||||
PCB_VIA* via = static_cast<PCB_VIA*>( track );
|
||||
|
||||
if( !via->IsOnLayer( aLayer ) || !via->GetRemoveUnconnected() )
|
||||
continue;
|
||||
|
||||
if( via->ZoneConnectionCache( aLayer ) == ZLC_UNRESOLVED
|
||||
&& via->GetBoundingBox().Intersects( zone_boundingbox ) )
|
||||
{
|
||||
auto viaShape = via->GetEffectiveShape( aLayer, FLASHING::ALWAYS_FLASHED );
|
||||
|
||||
// If the via collides with the zone's outline then we "own" the via.
|
||||
// If it collides with the fill then it's connected; otherwise not.
|
||||
|
||||
if( aZone->Outline()->Collide( viaShape.get() ) )
|
||||
{
|
||||
if( aFillPolys.Collide( viaShape.get() ) )
|
||||
via->ZoneConnectionCache( aLayer ) = ZLC_CONNECTED;
|
||||
else
|
||||
via->ZoneConnectionCache( aLayer ) = ZLC_UNCONNECTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for( FOOTPRINT* footprint : m_board->Footprints() )
|
||||
{
|
||||
for( PAD* pad : footprint->Pads() )
|
||||
{
|
||||
if( !pad->IsOnLayer( aLayer ) || !pad->GetRemoveUnconnected() )
|
||||
continue;
|
||||
|
||||
if( pad->ZoneConnectionCache( aLayer ) == ZLC_UNRESOLVED
|
||||
&& pad->GetBoundingBox().Intersects( zone_boundingbox ) )
|
||||
{
|
||||
auto padShape = pad->GetEffectiveShape( aLayer, FLASHING::ALWAYS_FLASHED );
|
||||
|
||||
// If the pad collides with the zone's outline then we "own" the pad.
|
||||
// If it collides with the fill then it's connected; otherwise not.
|
||||
|
||||
if( aZone->Outline()->Collide( padShape.get() ) )
|
||||
{
|
||||
if( aFillPolys.Collide( padShape.get() ) )
|
||||
pad->ZoneConnectionCache( aLayer ) = ZLC_CONNECTED;
|
||||
else
|
||||
pad->ZoneConnectionCache( aLayer ) = ZLC_UNCONNECTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue