When knocking out higher-priority zone use fill, not outline.

Also fixes a bunch of naming issues, primarily with lowercase for
protected variables, but also some for consistency with other parts
of the code.

Also changes the zone fill radio buttons in Board Setup to be more
generic referring to legacy vs. current, and to have tooltips.

Fixes https://gitlab.com/kicad/code/kicad/issues/5583
This commit is contained in:
Jeff Young 2020-09-17 14:14:45 +01:00
parent d468618411
commit f340636f70
20 changed files with 274 additions and 166 deletions

View File

@ -244,12 +244,19 @@ public:
std::map<int, int> m_DRCSeverities; // Map from DRCErrorCode to SEVERITY
std::set<wxString> m_DrcExclusions;
// Option to handle filled polygons in zones:
// the "legacy" option is using thick outlines around filled polygons: give the best shape
// the "new" option is using only filled polygons (no outline: give the faster redraw time
// moreover when exporting zone filled areas, the excatct shape is exported.
// the legacy option can really create redraw time issues for large boards.
bool m_ZoneUseNoOutlineInFill;
/*
* Option to select different fill algorithms.
* There are currenly two supported values:
* 5:
* - Use thick outlines around filled polygons (gives smoothest shape but at the expense
* of processing time and slight infidelity when exporting)
* - Use zone outline when knocking out higher-priority zones (just wrong, but mimics
* legacy behaviour.
* 6:
* - No thick outline.
* - Use filled areas when knocking out higher-priority zones.
*/
int m_ZoneFillVersion;
// When smoothing the zone's outline there's the question of external fillets (that is, those
// applied to concave corners). While it seems safer to never have copper extend outside the

View File

@ -162,7 +162,7 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std:
m_DRCSeverities[ DRCE_NET_CONFLICT ] = RPT_SEVERITY_WARNING;
m_MaxError = ARC_HIGH_DEF;
m_ZoneUseNoOutlineInFill = true; // Use new algo by default to fill zones
m_ZoneFillVersion = 6; // Use new algo by default to fill zones
m_ZoneKeepExternalFillets = false; // Use new algo by default. Legacy boards might
// want to set it to true for old algo....
@ -584,8 +584,17 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std:
m_params.emplace_back( new PARAM_SCALED<int>( "rules.max_error", &m_MaxError, ARC_HIGH_DEF,
Millimeter2iu( 0.0001 ), Millimeter2iu( 1.0 ), MM_PER_IU ) );
m_params.emplace_back( new PARAM<bool>( "zones_use_no_outline",
&m_ZoneUseNoOutlineInFill, true ) );
// TODO: replace with zones_fill_version parameter and migrate zones_use_no_outline?
m_params.emplace_back( new PARAM_LAMBDA<bool>( "zones_use_no_outline",
[this]() -> bool
{
return m_ZoneFillVersion >= 6;
},
[this]( bool aVal )
{
m_ZoneFillVersion = aVal ? 6 : 5;
},
6 ) );
m_params.emplace_back( new PARAM<bool>( "zones_allow_external_fillets",
&m_ZoneKeepExternalFillets, false ) );
@ -639,7 +648,7 @@ void BOARD_DESIGN_SETTINGS::initFromOther( const BOARD_DESIGN_SETTINGS& aOther )
m_HoleToHoleMin = aOther.m_HoleToHoleMin;
m_DRCSeverities = aOther.m_DRCSeverities;
m_DrcExclusions = aOther.m_DrcExclusions;
m_ZoneUseNoOutlineInFill = aOther.m_ZoneUseNoOutlineInFill;
m_ZoneFillVersion = aOther.m_ZoneFillVersion;
m_ZoneKeepExternalFillets= aOther.m_ZoneKeepExternalFillets;
m_MaxError = aOther.m_MaxError;
m_SolderMaskMargin = aOther.m_SolderMaskMargin;

View File

@ -43,8 +43,8 @@ ZONE_CONTAINER::ZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent, bool aInModule )
m_area( 0.0 )
{
m_CornerSelection = nullptr; // no corner is selected
m_IsFilled = false; // fill status : true when the zone is filled
m_FillMode = ZONE_FILL_MODE::POLYGONS;
m_isFilled = false; // fill status : true when the zone is filled
m_fillMode = ZONE_FILL_MODE::POLYGONS;
m_borderStyle = ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE;
m_borderHatchPitch = GetDefaultHatchPitch();
m_hv45 = false;
@ -67,7 +67,7 @@ ZONE_CONTAINER::ZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent, bool aInModule )
m_cornerRadius = 0;
SetLocalFlags( 0 ); // flags tempoarry used in zone calculations
m_Poly = new SHAPE_POLY_SET(); // Outlines
m_FilledPolysUseThickness = true; // set the "old" way to build filled polygon areas (before 6.0.x)
m_fillVersion = 6; // set the "old" way to build filled polygon areas (before 6.0.x)
m_islandRemovalMode = ISLAND_REMOVAL_MODE::ALWAYS;
aParent->GetZoneSettings().ExportSetting( *this );
@ -131,17 +131,17 @@ void ZONE_CONTAINER::InitDataFromSrcInCopyCtor( const ZONE_CONTAINER& aZone )
m_PadConnection = aZone.m_PadConnection;
m_ZoneClearance = aZone.m_ZoneClearance; // clearance value
m_ZoneMinThickness = aZone.m_ZoneMinThickness;
m_FilledPolysUseThickness = aZone.m_FilledPolysUseThickness;
m_fillVersion = aZone.m_fillVersion;
m_islandRemovalMode = aZone.m_islandRemovalMode;
m_minIslandArea = aZone.m_minIslandArea;
m_IsFilled = aZone.m_IsFilled;
m_needRefill = aZone.m_needRefill;
m_isFilled = aZone.m_isFilled;
m_needRefill = aZone.m_needRefill;
m_ThermalReliefGap = aZone.m_ThermalReliefGap;
m_ThermalReliefCopperBridge = aZone.m_ThermalReliefCopperBridge;
m_thermalReliefGap = aZone.m_thermalReliefGap;
m_thermalReliefSpokeWidth = aZone.m_thermalReliefSpokeWidth;
m_FillMode = aZone.m_FillMode; // solid vs. hatched
m_fillMode = aZone.m_fillMode; // solid vs. hatched
m_hatchThickness = aZone.m_hatchThickness;
m_hatchGap = aZone.m_hatchGap;
m_hatchOrientation = aZone.m_hatchOrientation;
@ -198,7 +198,8 @@ bool ZONE_CONTAINER::UnFill()
pair.second.clear();
}
m_IsFilled = false;
m_isFilled = false;
m_fillFlags.clear();
return change;
}
@ -331,7 +332,7 @@ int ZONE_CONTAINER::GetThermalReliefGap( D_PAD* aPad, wxString* aSource ) const
if( aSource )
*aSource = _( "zone" );
return m_ThermalReliefGap;
return m_thermalReliefGap;
}
return aPad->GetEffectiveThermalGap( aSource );
@ -339,14 +340,14 @@ int ZONE_CONTAINER::GetThermalReliefGap( D_PAD* aPad, wxString* aSource ) const
}
int ZONE_CONTAINER::GetThermalReliefCopperBridge( D_PAD* aPad, wxString* aSource ) const
int ZONE_CONTAINER::GetThermalReliefSpokeWidth( D_PAD* aPad, wxString* aSource ) const
{
if( aPad->GetEffectiveThermalSpokeWidth() == 0 )
{
if( aSource )
*aSource = _( "zone" );
return m_ThermalReliefCopperBridge;
return m_thermalReliefSpokeWidth;
}
return aPad->GetEffectiveThermalSpokeWidth( aSource );
@ -600,7 +601,7 @@ void ZONE_CONTAINER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PA
if( !m_zoneName.empty() )
aList.emplace_back( _( "Name" ), m_zoneName, DARKMAGENTA );
switch( m_FillMode )
switch( m_fillMode )
{
case ZONE_FILL_MODE::POLYGONS: msg = _( "Solid" ); break;
case ZONE_FILL_MODE::HATCH_PATTERN: msg = _( "Hatched" ); break;
@ -1235,12 +1236,12 @@ double ZONE_CONTAINER::CalculateFilledArea()
/**
* Function TransformOutlinesShapeWithClearanceToPolygon
* Convert the filled areas to polygons (optionally inflated by \a aClearance) and copy them
* Function TransformSmoothedOutlineWithClearanceToPolygon
* Convert the smoothed outline to polygons (optionally inflated by \a aClearance) and copy them
* into \a aCornerBuffer.
*/
void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearance ) const
void ZONE_CONTAINER::TransformSmoothedOutlineWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearance ) const
{
// Creates the zone outline polygon (with holes if any)
SHAPE_POLY_SET polybuffer;
@ -1367,8 +1368,8 @@ static struct ZONE_CONTAINER_DESC
&ZONE_CONTAINER::SetThermalReliefGap, &ZONE_CONTAINER::GetThermalReliefGap,
PROPERTY_DISPLAY::DISTANCE ) );
propMgr.AddProperty( new PROPERTY<ZONE_CONTAINER, int>( _( "Thermal Spoke Width" ),
&ZONE_CONTAINER::SetThermalReliefCopperBridge, &ZONE_CONTAINER::GetThermalReliefCopperBridge,
PROPERTY_DISPLAY::DISTANCE ) );
&ZONE_CONTAINER::SetThermalReliefSpokeWidth, &ZONE_CONTAINER::GetThermalReliefSpokeWidth,
PROPERTY_DISPLAY::DISTANCE ) );
}
} _ZONE_CONTAINER_DESC;

View File

@ -152,28 +152,28 @@ public:
unsigned int ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const override;
void SetFillMode( ZONE_FILL_MODE aFillMode ) { m_FillMode = aFillMode; }
ZONE_FILL_MODE GetFillMode() const { return m_FillMode; }
void SetFillMode( ZONE_FILL_MODE aFillMode ) { m_fillMode = aFillMode; }
ZONE_FILL_MODE GetFillMode() const { return m_fillMode; }
void SetThermalReliefGap( int aThermalReliefGap )
{
if( m_ThermalReliefGap != aThermalReliefGap )
if( m_thermalReliefGap != aThermalReliefGap )
SetNeedRefill( true );
m_ThermalReliefGap = aThermalReliefGap;
m_thermalReliefGap = aThermalReliefGap;
}
int GetThermalReliefGap() const { return m_ThermalReliefGap; }
int GetThermalReliefGap() const { return m_thermalReliefGap; }
int GetThermalReliefGap( D_PAD* aPad, wxString* aSource = nullptr ) const;
void SetThermalReliefCopperBridge( int aThermalReliefCopperBridge )
void SetThermalReliefSpokeWidth( int aThermalReliefSpokeWidth )
{
if( m_ThermalReliefCopperBridge != aThermalReliefCopperBridge )
if( m_thermalReliefSpokeWidth != aThermalReliefSpokeWidth )
SetNeedRefill( true );
m_ThermalReliefCopperBridge = aThermalReliefCopperBridge;
m_thermalReliefSpokeWidth = aThermalReliefSpokeWidth;
}
int GetThermalReliefCopperBridge() const { return m_ThermalReliefCopperBridge; }
int GetThermalReliefCopperBridge( D_PAD* aPad, wxString* aSource = nullptr ) const;
int GetThermalReliefSpokeWidth() const { return m_thermalReliefSpokeWidth; }
int GetThermalReliefSpokeWidth( D_PAD* aPad, wxString* aSource = nullptr ) const;
/**
* Compute the area currently occupied by the zone fill.
@ -198,8 +198,14 @@ public:
return m_lock;
}
bool IsFilled() const { return m_IsFilled; }
void SetIsFilled( bool isFilled ) { m_IsFilled = isFilled; }
int GetFillFlag( PCB_LAYER_ID aLayer )
{
return m_fillFlags.count( aLayer ) ? m_fillFlags[ aLayer ] : false;
}
void SetFillFlag( PCB_LAYER_ID aLayer, bool aFlag ) { m_fillFlags[ aLayer ] = aFlag; }
bool IsFilled() const { return m_isFilled; }
void SetIsFilled( bool isFilled ) { m_isFilled = isFilled; }
bool NeedRefill() const { return m_needRefill; }
void SetNeedRefill( bool aNeedRefill ) { m_needRefill = aNeedRefill; }
@ -348,17 +354,17 @@ public:
int aError = ARC_HIGH_DEF ) const;
/**
* Function TransformOutlinesShapeWithClearanceToPolygon
* Function TransformSmoothedOutlineWithClearanceToPolygon
* Convert the outlines shape to a polygon with no holes
* inflated (optional) by max( aClearanceValue, the zone clearance)
* (holes are linked to external outline by overlapping segments)
* Used in filling zones calculations
* Circles (vias) and arcs (ends of tracks) are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon
* @param aMinClearanceValue = the min clearance around outlines
* @param aClearance = the min clearance around outlines
*/
void TransformOutlinesShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aMinClearanceValue ) const;
void TransformSmoothedOutlineWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearance ) const;
/**
* Function TransformShapeWithClearanceToPolygon
@ -666,9 +672,10 @@ public:
unsigned int GetCornerRadius() const { return m_cornerRadius; }
bool GetFilledPolysUseThickness() const { return m_FilledPolysUseThickness; }
void SetFilledPolysUseThickness( bool aOption ) { m_FilledPolysUseThickness = aOption; }
bool GetFilledPolysUseThickness() const { return m_fillVersion == 5; }
int GetFillVersion() const { return m_fillVersion; }
void SetFillVersion( int aVersion ) { m_fillVersion = aVersion; }
/**
* Remove a cutout from the zone.
@ -842,39 +849,36 @@ protected:
bool m_doNotAllowFootprints;
ZONE_CONNECTION m_PadConnection;
int m_ZoneClearance; ///< Clearance value in internal units.
int m_ZoneMinThickness; ///< Minimum thickness value in filled areas.
bool m_FilledPolysUseThickness; ///< outline of filled polygons have thickness.
int m_ZoneClearance; // Clearance value in internal units.
int m_ZoneMinThickness; // Minimum thickness value in filled areas.
int m_fillVersion; // See BOARD_DESIGN_SETTINGS for version
// differences.
ISLAND_REMOVAL_MODE m_islandRemovalMode;
/**
* When island removal mode is set to AREA, islands below this area will be removed.
* If this value is negative, all islands will be removed.
*/
long long int m_minIslandArea;
long long int m_minIslandArea;
/** True when a zone was filled, false after deleting the filled areas. */
bool m_IsFilled;
bool m_isFilled;
/** False when a zone was refilled, true after changes in zone params.
* m_needRefill = false does not imply filled areas are up to date, just
* the zone was refilled after edition, and does not need refilling
*/
bool m_needRefill;
bool m_needRefill;
///< Width of the gap in thermal reliefs.
int m_ThermalReliefGap;
///< Width of the copper bridge in thermal reliefs.
int m_ThermalReliefCopperBridge;
int m_thermalReliefGap; // Width of the gap in thermal reliefs.
int m_thermalReliefSpokeWidth; // Width of the copper bridge in thermal reliefs.
/** How to fill areas:
* ZONE_FILL_MODE::POLYGONS => use solid polygons
* ZONE_FILL_MODE::HATCH_PATTERN => use a grid pattern as shape
*/
ZONE_FILL_MODE m_FillMode;
ZONE_FILL_MODE m_fillMode;
int m_hatchThickness; // thickness of lines (if 0 -> solid shape)
int m_hatchGap; // gap between lines (0 -> solid shape
double m_hatchOrientation; // orientation in degrees of grid lines
@ -890,8 +894,7 @@ protected:
/// The index of the corner being moved or nullptr if no corner is selected.
SHAPE_POLY_SET::VERTEX_INDEX* m_CornerSelection;
/// Variable used in polygon calculations.
int m_localFlgs;
int m_localFlgs; // Variable used in polygon calculations.
/** Segments used to fill the zone (#m_FillMode ==1 ), when fill zone by segment is used.
* In this case the segments have #m_ZoneMinThickness width.
@ -909,6 +912,9 @@ protected:
std::map<PCB_LAYER_ID, SHAPE_POLY_SET> m_FilledPolysList;
std::map<PCB_LAYER_ID, SHAPE_POLY_SET> m_RawPolysList;
/// A temp variable used while filling
std::map<PCB_LAYER_ID, bool> m_fillFlags;
/// A hash value used in zone filling calculations to see if the filled areas are up to date
std::map<PCB_LAYER_ID, MD5_HASH> m_filledPolysHash;

View File

@ -177,7 +177,7 @@ bool DIALOG_COPPER_ZONE::TransferDataToWindow()
// Do not enable/disable antipad clearance and spoke width. They might be needed if
// a module or pad overrides the zone to specify a thermal connection.
m_antipadClearance.SetValue( m_settings.m_ThermalReliefGap );
m_spokeWidth.SetValue( m_settings.m_ThermalReliefCopperBridge );
m_spokeWidth.SetValue( m_settings.m_ThermalReliefSpokeWidth );
m_islandThreshold.SetDataType( EDA_DATA_TYPE::AREA );
m_islandThreshold.SetDoubleValue( static_cast<double>( m_settings.GetMinIslandArea() ) );
@ -395,9 +395,9 @@ bool DIALOG_COPPER_ZONE::AcceptOptions( bool aUseExportableSetupOnly )
m_settings.m_Zone_45_Only = m_constrainOutline->GetValue();
m_settings.m_ThermalReliefGap = m_antipadClearance.GetValue();
m_settings.m_ThermalReliefCopperBridge = m_spokeWidth.GetValue();
m_settings.m_ThermalReliefSpokeWidth = m_spokeWidth.GetValue();
if( m_settings.m_ThermalReliefCopperBridge < m_settings.m_ZoneMinThickness )
if( m_settings.m_ThermalReliefSpokeWidth < m_settings.m_ZoneMinThickness )
{
DisplayError( this, _( "Thermal spoke width cannot be smaller than the minimum width." ) );
return false;
@ -406,7 +406,7 @@ bool DIALOG_COPPER_ZONE::AcceptOptions( bool aUseExportableSetupOnly )
cfg->m_Zones.clearance = Iu2Mils( m_settings.m_ZoneClearance );
cfg->m_Zones.min_thickness = Iu2Mils( m_settings.m_ZoneMinThickness );
cfg->m_Zones.thermal_relief_gap = Iu2Mils( m_settings.m_ThermalReliefGap );
cfg->m_Zones.thermal_relief_copper_width = Iu2Mils( m_settings.m_ThermalReliefCopperBridge );
cfg->m_Zones.thermal_relief_copper_width = Iu2Mils( m_settings.m_ThermalReliefSpokeWidth );
m_settings.SetIslandRemovalMode(
static_cast<ISLAND_REMOVAL_MODE>( m_cbRemoveIslands->GetSelection() ) );

View File

@ -64,8 +64,8 @@ bool PANEL_SETUP_FEATURE_CONSTRAINTS::TransferDataToWindow()
m_maxError.SetValue( m_BrdSettings->m_MaxError );
m_rbOutlinePolygonFastest->SetValue( m_BrdSettings->m_ZoneUseNoOutlineInFill );
m_rbOutlinePolygonBestQ->SetValue( !m_BrdSettings->m_ZoneUseNoOutlineInFill );
m_rbOutlinePolygonFastest->SetValue( m_BrdSettings->m_ZoneFillVersion == 6 );
m_rbOutlinePolygonBestQ->SetValue( m_BrdSettings->m_ZoneFillVersion == 5 );
m_allowExternalFilletsOpt->SetValue( m_BrdSettings->m_ZoneKeepExternalFillets );
m_minClearance.SetValue( m_BrdSettings->m_MinClearance );
@ -113,7 +113,7 @@ bool PANEL_SETUP_FEATURE_CONSTRAINTS::TransferDataFromWindow()
m_BrdSettings->m_MaxError = Clamp<int>( IU_PER_MM * MINIMUM_ERROR_SIZE_MM,
m_maxError.GetValue(), IU_PER_MM * MAXIMUM_ERROR_SIZE_MM );
m_BrdSettings->m_ZoneUseNoOutlineInFill = m_rbOutlinePolygonFastest->GetValue();
m_BrdSettings->m_ZoneFillVersion = m_rbOutlinePolygonFastest->GetValue() ? 6 : 5;
m_BrdSettings->m_ZoneKeepExternalFillets = m_allowExternalFilletsOpt->GetValue();
m_BrdSettings->m_MinClearance = m_minClearance.GetValue();

View File

@ -87,7 +87,7 @@ PANEL_SETUP_FEATURE_CONSTRAINTS_BASE::PANEL_SETUP_FEATURE_CONSTRAINTS_BASE( wxWi
m_bitmapInfo = new wxStaticBitmap( this, wxID_ANY, wxArtProvider::GetBitmap( wxART_INFORMATION, wxART_OTHER ), wxDefaultPosition, wxDefaultSize, 0 );
bSizer8->Add( m_bitmapInfo, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_stCircleToPolyWarning = new wxStaticText( this, wxID_ANY, _("Value < %s can be time consumming\nwhen filling zones."), wxDefaultPosition, wxDefaultSize, 0 );
m_stCircleToPolyWarning = new wxStaticText( this, wxID_ANY, _("Value < %s can be time consuming when \nfilling zones."), wxDefaultPosition, wxDefaultSize, 0 );
m_stCircleToPolyWarning->Wrap( -1 );
m_stCircleToPolyWarning->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
@ -119,11 +119,15 @@ PANEL_SETUP_FEATURE_CONSTRAINTS_BASE::PANEL_SETUP_FEATURE_CONSTRAINTS_BASE( wxWi
wxBoxSizer* bSizerOutlinesOpts;
bSizerOutlinesOpts = new wxBoxSizer( wxVERTICAL );
m_rbOutlinePolygonBestQ = new wxRadioButton( this, wxID_ANY, _("Stroked outlines (legacy)"), wxDefaultPosition, wxDefaultSize, 0 );
m_rbOutlinePolygonBestQ = new wxRadioButton( this, wxID_ANY, _("Mimic legacy behavior"), wxDefaultPosition, wxDefaultSize, 0 );
m_rbOutlinePolygonBestQ->SetToolTip( _("Produces a slightly smoother outline at the expense of performance, some export fidelity issues, and overly agressive higher-priority zone knockouts.") );
bSizerOutlinesOpts->Add( m_rbOutlinePolygonBestQ, 0, wxALL, 4 );
m_rbOutlinePolygonFastest = new wxRadioButton( this, wxID_ANY, _("Smoothed polygons (best performance)"), wxDefaultPosition, wxDefaultSize, 0 );
m_rbOutlinePolygonFastest->SetValue( true );
m_rbOutlinePolygonFastest->SetToolTip( _("Better performance, exact export fidelity, and more complete filling near higher-priority zones.") );
bSizerOutlinesOpts->Add( m_rbOutlinePolygonFastest, 0, wxALL, 4 );

View File

@ -837,7 +837,7 @@
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Value &lt; %s can be time consumming&#x0A;when filling zones.</property>
<property name="label">Value &lt; %s can be time consuming when &#x0A;filling zones.</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
@ -1106,7 +1106,7 @@
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Stroked outlines (legacy)</property>
<property name="label">Mimic legacy behavior</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
@ -1127,7 +1127,7 @@
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="tooltip">Produces a slightly smoother outline at the expense of performance, some export fidelity issues, and overly agressive higher-priority zone knockouts.</property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
@ -1192,7 +1192,7 @@
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="tooltip">Better performance, exact export fidelity, and more complete filling near higher-priority zones.</property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>

View File

@ -1357,7 +1357,7 @@ ZONE_CONTAINER* EAGLE_PLUGIN::loadPolygon( wxXmlNode* aPolyNode )
// (i.e. width of spoke is half of the smaller side of an smd pad)
// This is a basic workaround
zone->SetThermalReliefGap( p.width.ToPcbUnits() + 50000 ); // 50000nm == 0.05mm
zone->SetThermalReliefCopperBridge( p.width.ToPcbUnits() + 50000 );
zone->SetThermalReliefSpokeWidth( p.width.ToPcbUnits() + 50000 );
}
int rank = p.rank ? (p.max_priority - *p.rank) : p.max_priority;

View File

@ -1776,8 +1776,8 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const
m_out->Print( aNestLevel+1, "(min_thickness %s)",
FormatInternalUnits( aZone->GetMinThickness() ).c_str() );
// write it only if V 6.O version option is not used (i.e. do not write if the
// "legacy" algorithm is used)
// write it only if V 6.O version option is used (i.e. do not write if the "legacy"
// algorithm is used)
if( !aZone->GetFilledPolysUseThickness() )
m_out->Print( 0, " (filled_areas_thickness no)" );
@ -1805,7 +1805,7 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const
m_out->Print( 0, " (thermal_gap %s) (thermal_bridge_width %s)",
FormatInternalUnits( aZone->GetThermalReliefGap() ).c_str(),
FormatInternalUnits( aZone->GetThermalReliefCopperBridge() ).c_str() );
FormatInternalUnits( aZone->GetThermalReliefSpokeWidth() ).c_str() );
if( aZone->GetCornerSmoothingType() != ZONE_SETTINGS::SMOOTHING_NONE )
{

View File

@ -2610,7 +2610,7 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER()
zc->SetIsFilled( fillstate == 'S' );
zc->SetThermalReliefGap( thermalReliefGap );
zc->SetThermalReliefCopperBridge( thermalReliefCopperBridge );
zc->SetThermalReliefSpokeWidth( thermalReliefCopperBridge );
}
else if( TESTLINE( "ZClearance" ) ) // Clearance and pad options info found

View File

@ -1821,8 +1821,8 @@ void PCB_PARSER::parseSetup()
NeedRIGHT();
break;
case T_filled_areas_thickness:
designSettings.m_ZoneUseNoOutlineInFill = not parseBool();
case T_filled_areas_thickness: // Note: legacy (early 5.99) token
designSettings.m_ZoneFillVersion = parseBool() ? 5 : 6;
m_board->m_LegacyDesignSettingsLoaded = true;
NeedRIGHT();
break;
@ -4353,7 +4353,7 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent )
break;
case T_filled_areas_thickness:
zone->SetFilledPolysUseThickness( parseBool() );
zone->SetFillVersion( parseBool() ? 5 : 6 );
NeedRIGHT();
break;
@ -4454,8 +4454,7 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent )
NeedRIGHT();
break;
case T_thermal_bridge_width:
zone->SetThermalReliefCopperBridge( parseBoardUnits( T_thermal_bridge_width ) );
case T_thermal_bridge_width:zone->SetThermalReliefSpokeWidth( parseBoardUnits( T_thermal_bridge_width ));
NeedRIGHT();
break;

View File

@ -492,6 +492,8 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
for( ZONE_CONTAINER* zone : aBoard->Zones() )
{
int outlineThickness = zone->GetFilledPolysUseThickness() ? zone->GetMinThickness() : 0;
for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
{
auto pair = std::make_pair( layer, zone );
@ -529,17 +531,12 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
if( candidate->GetNetCode() != zone->GetNetCode() )
continue;
// Merging zones of the same net can be done only for areas
// having compatible settings for drawings:
// use or not outline thickness, and if using outline thickness,
// having the same thickness
// because after merging only one outline thickness is used
if( candidate->GetFilledPolysUseThickness() != zone->GetFilledPolysUseThickness() )
// Should not happens, because usually the same option is used for filling
continue;
// Merging zones of the same net can be done only for areas having compatible
// settings for filling as the merged zone can only have a single setting.
int candidateOutlineThickness = candidate->GetFilledPolysUseThickness() ?
candidate->GetMinThickness() : 0;
if( zone->GetFilledPolysUseThickness()
&& ( candidate->GetMinThickness() != zone->GetMinThickness() ) )
if( candidateOutlineThickness != outlineThickness )
continue;
plotted.insert( candidate_pair );
@ -867,9 +864,9 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
continue;
// add shapes inflated by aMinThickness/2 in areas
zone->TransformOutlinesShapeWithClearanceToPolygon( areas, inflate + zone_margin );
zone->TransformSmoothedOutlineWithClearanceToPolygon( areas, inflate + zone_margin );
// add shapes with their exact mask layer size in initialPolys
zone->TransformOutlinesShapeWithClearanceToPolygon( initialPolys, zone_margin );
zone->TransformSmoothedOutlineWithClearanceToPolygon( initialPolys, zone_margin );
}
int maxError = aBoard->GetDesignSettings().m_MaxError;

View File

@ -1311,7 +1311,7 @@ void ALTIUM_PCB::ParsePolygons6Data(
}
// TODO: correct variables?
zone->SetThermalReliefCopperBridge(
zone->SetThermalReliefSpokeWidth(
polygonConnectRule->polygonconnectReliefconductorwidth );
zone->SetThermalReliefGap( polygonConnectRule->polygonconnectAirgapwidth );

View File

@ -1098,8 +1098,8 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadTemplates()
if( csTemplate.Pouring.ThermalReliefOnPads )
{
zone->SetThermalReliefGap( getKiCadLength( csTemplate.Pouring.ClearanceWidth ) );
zone->SetThermalReliefCopperBridge( getKiCadLength(
getCopperCode( csTemplate.Pouring.ReliefCopperCodeID ).CopperWidth ) );
zone->SetThermalReliefSpokeWidth( getKiCadLength(
getCopperCode( csTemplate.Pouring.ReliefCopperCodeID ).CopperWidth ));
zone->SetPadConnection( ZONE_CONNECTION::THERMAL );
}
else

View File

@ -88,11 +88,12 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck,
std::vector<std::pair<ZONE_CONTAINER*, PCB_LAYER_ID>> toFill;
std::vector<CN_ZONE_ISOLATED_ISLAND_LIST> islandsList;
auto connectivity = m_board->GetConnectivity();
bool filledPolyWithOutline = not m_board->GetDesignSettings().m_ZoneUseNoOutlineInFill;
std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
std::unique_lock<std::mutex> lock( connectivity->GetLock(), std::try_to_lock );
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
int worstClearance = bds.GetBiggestClearanceValue();
if( !lock )
return false;
@ -141,25 +142,90 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck,
// Remove existing fill first to prevent drawing invalid polygons
// on some platforms
zone->UnFill();
zone->SetFillVersion( bds.m_ZoneFillVersion );
}
std::atomic<size_t> nextItem( 0 );
size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
aZones.size() );
toFill.size() );
std::vector<std::future<size_t>> returns( parallelThreadCount );
auto fill_lambda =
[&]( PROGRESS_REPORTER* aReporter ) -> size_t
{
size_t num = 0;
std::deque<std::pair<ZONE_CONTAINER*, PCB_LAYER_ID>> deferred;
for( size_t i = nextItem++; i < toFill.size(); i = nextItem++ )
size_t num = 0;
PCB_LAYER_ID layer = UNDEFINED_LAYER;
ZONE_CONTAINER* zone = nullptr;
while( true )
{
PCB_LAYER_ID layer = toFill[i].second;
ZONE_CONTAINER* zone = toFill[i].first;
size_t i = nextItem++;
zone->SetFilledPolysUseThickness( filledPolyWithOutline );
if( i < toFill.size() )
{
layer = toFill[i].second;
zone = toFill[i].first;
}
else if( !deferred.empty() )
{
layer = deferred.front().second;
zone = deferred.front().first;
deferred.pop_front();
}
else
{
// all done
break;
}
EDA_RECT zone_boundingbox = zone->GetBoundingBox();
bool canFill = true;
zone_boundingbox.Inflate( worstClearance );
// Check for any fill dependencies. If our zone needs to be clipped by
// another zone then we can't fill until that zone is filled.
for( ZONE_CONTAINER* candidate : m_board->GetZoneList( true ) )
{
// We don't care about keepouts; even if they exlclude copper pours
// the exclusion is by outline, not by filled area.
if( candidate->GetIsKeepout() )
continue;
// If the zones share no common layers
if( !candidate->GetLayerSet().test( layer ) )
continue;
if( candidate->GetPriority() <= zone->GetPriority() )
continue;
// Same-net zones always use outline to produce predictable results
if( candidate->GetNetCode() == zone->GetNetCode() )
continue;
// A higher priority zone is found: if we intersect and it's not
// filled yet then we have to wait.
if( zone_boundingbox.Intersects( candidate->GetBoundingBox() )
&& !candidate->GetFillFlag( layer ) )
{
canFill = false;
break;
}
}
if( !canFill )
{
// This isn't ideal from a load-balancing standpoint as another thread
// cannot pick up this thread's deferred zones. However a better
// solution would require a significantly more complex thread-safe queue.
deferred.push_back( { zone, layer } );
continue;
}
// Now we're ready to fill.
SHAPE_POLY_SET rawPolys, finalPolys;
fillSingleZone( zone, layer, rawPolys, finalPolys );
@ -167,7 +233,7 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck,
zone->SetRawPolysList( layer, rawPolys );
zone->SetFilledPolysList( layer, finalPolys );
zone->SetIsFilled( true );
zone->SetFillFlag( layer, true );
if( m_progressReporter )
{
@ -222,6 +288,15 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck,
if( m_progressReporter && m_progressReporter->IsCancelled() )
return false;
for( ZONE_CONTAINER* zone : aZones )
{
// Keepout zones are not filled
if( zone->GetIsKeepout() )
continue;
zone->SetIsFilled( true );
}
// Re-add not connected zones to list, connectivity->FindIsolatedCopperIslands()
// populates islandsList only with zones having a net
for( ZONE_CONTAINER* zone : aZones )
@ -748,7 +823,6 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, PCB_LA
//
for( ZONE_CONTAINER* zone : m_board->GetZoneList( true ) )
{
// If the zones share no common layers
if( !zone->GetLayerSet().test( aLayer ) )
continue;
@ -764,15 +838,28 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, PCB_LA
if( item_boundingbox.Intersects( zone_boundingbox ) )
{
// Add the zone outline area. Don't use any clearance for keepouts, or for zones
// with the same net (they will be connected but will honor their own clearance,
// thermal connections, etc.).
int gap = 0;
if( zone->GetIsKeepout() || aZone->GetNetCode() == zone->GetNetCode() )
{
// Keepouts and same-net zones use outline with no clearance
zone->TransformSmoothedOutlineWithClearanceToPolygon( aHoles, 0 );
}
else
{
int gap = aZone->GetClearance( aLayer, zone );
if( !zone->GetIsKeepout() && aZone->GetNetCode() != zone->GetNetCode() )
gap = aZone->GetClearance( aLayer, zone );
zone->TransformOutlinesShapeWithClearanceToPolygon( aHoles, gap );
if( bds.m_ZoneFillVersion == 5 )
{
// 5.x used outline with clearance
zone->TransformSmoothedOutlineWithClearanceToPolygon( aHoles, gap );
}
else
{
// 6.0 uses filled areas with clearance
SHAPE_POLY_SET knockout;
zone->TransformShapeWithClearanceToPolygon( knockout, aLayer, gap );
aHoles.Append( knockout );
}
}
}
}
@ -1050,7 +1137,7 @@ void ZONE_FILLER::buildThermalSpokes( const ZONE_CONTAINER* aZone, PCB_LAYER_ID
int thermalReliefGap = aZone->GetThermalReliefGap( pad );
// Calculate thermal bridge half width
int spoke_w = aZone->GetThermalReliefCopperBridge( pad );
int spoke_w = aZone->GetThermalReliefSpokeWidth( pad );
// Avoid spoke_w bigger than the smaller pad size, because
// it is not possible to create stubs bigger than the pad.
// Possible refinement: have a separate size for vertical and horizontal stubs

View File

@ -68,9 +68,9 @@ ZONE_SETTINGS::ZONE_SETTINGS()
// thickness of the gap in thermal reliefs:
m_ThermalReliefGap = Mils2iu( ZONE_THERMAL_RELIEF_GAP_MIL );
// thickness of the copper bridge in thermal reliefs:
m_ThermalReliefCopperBridge = Mils2iu( ZONE_THERMAL_RELIEF_COPPER_WIDTH_MIL );
m_ThermalReliefSpokeWidth = Mils2iu( ZONE_THERMAL_RELIEF_COPPER_WIDTH_MIL );
m_PadConnection = ZONE_CONNECTION::THERMAL; // How pads are covered by copper in zone
m_padConnection = ZONE_CONNECTION::THERMAL; // How pads are covered by copper in zone
m_Zone_45_Only = false;
@ -104,10 +104,10 @@ ZONE_SETTINGS& ZONE_SETTINGS::operator << ( const ZONE_CONTAINER& aSource )
m_HatchHoleMinArea = aSource.GetHatchHoleMinArea();
m_NetcodeSelection = aSource.GetNetCode();
m_Name = aSource.GetZoneName();
m_ZoneBorderDisplayStyle = aSource.GetHatchStyle();
m_ZoneBorderDisplayStyle = aSource.GetHatchStyle();
m_ThermalReliefGap = aSource.GetThermalReliefGap();
m_ThermalReliefCopperBridge = aSource.GetThermalReliefCopperBridge();
m_PadConnection = aSource.GetPadConnection();
m_ThermalReliefSpokeWidth = aSource.GetThermalReliefSpokeWidth();
m_padConnection = aSource.GetPadConnection();
m_cornerSmoothingType = aSource.GetCornerSmoothingType();
m_cornerRadius = aSource.GetCornerRadius();
m_isKeepout = aSource.GetIsKeepout();
@ -139,8 +139,8 @@ void ZONE_SETTINGS::ExportSetting( ZONE_CONTAINER& aTarget, bool aFullExport ) c
aTarget.SetHatchBorderAlgorithm( m_HatchBorderAlgorithm );
aTarget.SetHatchHoleMinArea( m_HatchHoleMinArea );
aTarget.SetThermalReliefGap( m_ThermalReliefGap );
aTarget.SetThermalReliefCopperBridge( m_ThermalReliefCopperBridge );
aTarget.SetPadConnection( m_PadConnection );
aTarget.SetThermalReliefSpokeWidth( m_ThermalReliefSpokeWidth );
aTarget.SetPadConnection( m_padConnection );
aTarget.SetCornerSmoothingType( m_cornerSmoothingType );
aTarget.SetCornerRadius( m_cornerRadius );
aTarget.SetIsKeepout( GetIsKeepout() );

View File

@ -76,52 +76,50 @@ public:
SMOOTHING_LAST // sentinel
};
int m_ZonePriority; ///< Priority (0 ... N) of the zone
int m_ZonePriority; // Priority (0 ... N) of the zone
ZONE_FILL_MODE m_FillMode;
int m_ZoneClearance; // Minimal clearance value
int m_ZoneMinThickness; // Min thickness value in filled areas
int m_HatchThickness; // HatchBorder thickness of lines (if 0 -> solid shape)
int m_HatchGap; // HatchBorder clearance between lines (0 -> solid shape)
double m_HatchOrientation; // HatchBorder orientation of grid lines in degrees
int m_HatchSmoothingLevel; // HatchBorder smoothing type, similar to corner smoothing type
// 0 = no smoothing, 1 = fillet, >= 2 = arc
double m_HatchSmoothingValue; // HatchBorder chamfer/fillet size as a ratio of hole size
double m_HatchHoleMinArea; // min size before holes are dropped (ratio)
int m_HatchBorderAlgorithm; // 0 = use min zone thickness
ZONE_FILL_MODE m_FillMode;
int m_ZoneClearance; // Minimal clearance value
int m_ZoneMinThickness; // Min thickness value in filled areas
int m_HatchThickness; // HatchBorder thickness of lines (if 0 -> solid shape)
int m_HatchGap; // HatchBorder clearance between lines (0 -> solid shape)
double m_HatchOrientation; // HatchBorder orientation of grid lines in degrees
int m_HatchSmoothingLevel; // HatchBorder smoothing type, similar to corner smoothing type
// 0 = no smoothing, 1 = fillet, >= 2 = arc
double m_HatchSmoothingValue; // HatchBorder chamfer/fillet size as a ratio of hole size
double m_HatchHoleMinArea; // min size before holes are dropped (ratio)
int m_HatchBorderAlgorithm; // 0 = use min zone thickness
int m_NetcodeSelection; ///< Net code selection for the current zone
int m_NetcodeSelection; // Net code selection for the current zone
wxString m_Name; ///< Unique name for the current zone (can be blank)
wxString m_Name; // Unique name for the current zone (can be blank)
LSET m_Layers; ///< Layers that this zone exists on
LSET m_Layers; // Layers that this zone exists on
/// Option to show the zone area (outlines only, short hatches or full hatches
ZONE_BORDER_DISPLAY_STYLE m_ZoneBorderDisplayStyle;
long m_ThermalReliefGap; ///< thickness of the gap in thermal reliefs
long m_ThermalReliefCopperBridge; ///< thickness of the copper bridge in thermal reliefs
long m_ThermalReliefGap; // thickness of the gap in thermal reliefs
long m_ThermalReliefSpokeWidth; // thickness of the copper bridge in thermal reliefs
bool m_Zone_45_Only;
bool m_Zone_45_Only;
private:
int m_cornerSmoothingType; ///< Corner smoothing type
unsigned int m_cornerRadius; ///< Corner chamfer distance / fillet radius
ZONE_CONNECTION m_PadConnection;
int m_cornerSmoothingType; // Corner smoothing type
unsigned int m_cornerRadius; // Corner chamfer distance / fillet radius
ZONE_CONNECTION m_padConnection;
/* A zone outline can be a keepout zone.
* It will be never filled, and DRC should test for pads, tracks and vias
/*
* Keepout zones and keepout flags.
* Note that DRC rules can set keepouts on zones whether they're a keepout or not.
*/
bool m_isKeepout;
bool m_isKeepout;
/* For keepout zones only:
* what is not allowed inside the keepout ( pads, tracks and vias )
*/
bool m_keepoutDoNotAllowCopperPour;
bool m_keepoutDoNotAllowVias;
bool m_keepoutDoNotAllowTracks;
bool m_keepoutDoNotAllowPads;
bool m_keepoutDoNotAllowFootprints;
bool m_keepoutDoNotAllowCopperPour;
bool m_keepoutDoNotAllowVias;
bool m_keepoutDoNotAllowTracks;
bool m_keepoutDoNotAllowPads;
bool m_keepoutDoNotAllowFootprints;
ISLAND_REMOVAL_MODE m_removeIslands;
long long int m_minIslandArea;
@ -168,12 +166,12 @@ public:
ZONE_CONNECTION GetPadConnection() const
{
return m_PadConnection;
return m_padConnection;
}
void SetPadConnection( ZONE_CONNECTION aPadConnection )
{
m_PadConnection = aPadConnection;
m_padConnection = aPadConnection;
}
/**

View File

@ -99,16 +99,16 @@ bool ZONE_CONTAINER::IsSame( const ZONE_CONTAINER& aZoneToCompare )
if( m_ZoneMinThickness != aZoneToCompare.GetMinThickness() )
return false;
if( m_FillMode != aZoneToCompare.GetFillMode() )
if( m_fillMode != aZoneToCompare.GetFillMode() )
return false;
if( m_PadConnection != aZoneToCompare.m_PadConnection )
return false;
if( m_ThermalReliefGap != aZoneToCompare.m_ThermalReliefGap )
if( m_thermalReliefGap != aZoneToCompare.m_thermalReliefGap )
return false;
if( m_ThermalReliefCopperBridge != aZoneToCompare.m_ThermalReliefCopperBridge )
if( m_thermalReliefSpokeWidth != aZoneToCompare.m_thermalReliefSpokeWidth )
return false;
if( m_zoneName != aZoneToCompare.m_zoneName )

View File

@ -175,7 +175,7 @@ bool BOARD::TestAreaIntersections( ZONE_CONTAINER* area_to_test )
if( area_to_test->GetThermalReliefGap() != area2->GetThermalReliefGap() )
continue;
if( area_to_test->GetThermalReliefCopperBridge() != area2->GetThermalReliefCopperBridge() )
if( area_to_test->GetThermalReliefSpokeWidth() != area2->GetThermalReliefSpokeWidth() )
continue;
if( area_to_test->GetLocalClearance() != area2->GetLocalClearance() )