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::map<int, int> m_DRCSeverities; // Map from DRCErrorCode to SEVERITY
std::set<wxString> m_DrcExclusions; 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 * Option to select different fill algorithms.
// the "new" option is using only filled polygons (no outline: give the faster redraw time * There are currenly two supported values:
// moreover when exporting zone filled areas, the excatct shape is exported. * 5:
// the legacy option can really create redraw time issues for large boards. * - Use thick outlines around filled polygons (gives smoothest shape but at the expense
bool m_ZoneUseNoOutlineInFill; * 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 // 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 // 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_DRCSeverities[ DRCE_NET_CONFLICT ] = RPT_SEVERITY_WARNING;
m_MaxError = ARC_HIGH_DEF; 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 m_ZoneKeepExternalFillets = false; // Use new algo by default. Legacy boards might
// want to set it to true for old algo.... // 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, 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 ) ); Millimeter2iu( 0.0001 ), Millimeter2iu( 1.0 ), MM_PER_IU ) );
m_params.emplace_back( new PARAM<bool>( "zones_use_no_outline", // TODO: replace with zones_fill_version parameter and migrate zones_use_no_outline?
&m_ZoneUseNoOutlineInFill, true ) ); 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_params.emplace_back( new PARAM<bool>( "zones_allow_external_fillets",
&m_ZoneKeepExternalFillets, false ) ); &m_ZoneKeepExternalFillets, false ) );
@ -639,7 +648,7 @@ void BOARD_DESIGN_SETTINGS::initFromOther( const BOARD_DESIGN_SETTINGS& aOther )
m_HoleToHoleMin = aOther.m_HoleToHoleMin; m_HoleToHoleMin = aOther.m_HoleToHoleMin;
m_DRCSeverities = aOther.m_DRCSeverities; m_DRCSeverities = aOther.m_DRCSeverities;
m_DrcExclusions = aOther.m_DrcExclusions; m_DrcExclusions = aOther.m_DrcExclusions;
m_ZoneUseNoOutlineInFill = aOther.m_ZoneUseNoOutlineInFill; m_ZoneFillVersion = aOther.m_ZoneFillVersion;
m_ZoneKeepExternalFillets= aOther.m_ZoneKeepExternalFillets; m_ZoneKeepExternalFillets= aOther.m_ZoneKeepExternalFillets;
m_MaxError = aOther.m_MaxError; m_MaxError = aOther.m_MaxError;
m_SolderMaskMargin = aOther.m_SolderMaskMargin; 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_area( 0.0 )
{ {
m_CornerSelection = nullptr; // no corner is selected m_CornerSelection = nullptr; // no corner is selected
m_IsFilled = false; // fill status : true when the zone is filled m_isFilled = false; // fill status : true when the zone is filled
m_FillMode = ZONE_FILL_MODE::POLYGONS; m_fillMode = ZONE_FILL_MODE::POLYGONS;
m_borderStyle = ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE; m_borderStyle = ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE;
m_borderHatchPitch = GetDefaultHatchPitch(); m_borderHatchPitch = GetDefaultHatchPitch();
m_hv45 = false; m_hv45 = false;
@ -67,7 +67,7 @@ ZONE_CONTAINER::ZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent, bool aInModule )
m_cornerRadius = 0; m_cornerRadius = 0;
SetLocalFlags( 0 ); // flags tempoarry used in zone calculations SetLocalFlags( 0 ); // flags tempoarry used in zone calculations
m_Poly = new SHAPE_POLY_SET(); // Outlines 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; m_islandRemovalMode = ISLAND_REMOVAL_MODE::ALWAYS;
aParent->GetZoneSettings().ExportSetting( *this ); aParent->GetZoneSettings().ExportSetting( *this );
@ -131,17 +131,17 @@ void ZONE_CONTAINER::InitDataFromSrcInCopyCtor( const ZONE_CONTAINER& aZone )
m_PadConnection = aZone.m_PadConnection; m_PadConnection = aZone.m_PadConnection;
m_ZoneClearance = aZone.m_ZoneClearance; // clearance value m_ZoneClearance = aZone.m_ZoneClearance; // clearance value
m_ZoneMinThickness = aZone.m_ZoneMinThickness; m_ZoneMinThickness = aZone.m_ZoneMinThickness;
m_FilledPolysUseThickness = aZone.m_FilledPolysUseThickness; m_fillVersion = aZone.m_fillVersion;
m_islandRemovalMode = aZone.m_islandRemovalMode; m_islandRemovalMode = aZone.m_islandRemovalMode;
m_minIslandArea = aZone.m_minIslandArea; m_minIslandArea = aZone.m_minIslandArea;
m_IsFilled = aZone.m_IsFilled; m_isFilled = aZone.m_isFilled;
m_needRefill = aZone.m_needRefill; m_needRefill = aZone.m_needRefill;
m_ThermalReliefGap = aZone.m_ThermalReliefGap; m_thermalReliefGap = aZone.m_thermalReliefGap;
m_ThermalReliefCopperBridge = aZone.m_ThermalReliefCopperBridge; 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_hatchThickness = aZone.m_hatchThickness;
m_hatchGap = aZone.m_hatchGap; m_hatchGap = aZone.m_hatchGap;
m_hatchOrientation = aZone.m_hatchOrientation; m_hatchOrientation = aZone.m_hatchOrientation;
@ -198,7 +198,8 @@ bool ZONE_CONTAINER::UnFill()
pair.second.clear(); pair.second.clear();
} }
m_IsFilled = false; m_isFilled = false;
m_fillFlags.clear();
return change; return change;
} }
@ -331,7 +332,7 @@ int ZONE_CONTAINER::GetThermalReliefGap( D_PAD* aPad, wxString* aSource ) const
if( aSource ) if( aSource )
*aSource = _( "zone" ); *aSource = _( "zone" );
return m_ThermalReliefGap; return m_thermalReliefGap;
} }
return aPad->GetEffectiveThermalGap( aSource ); 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( aPad->GetEffectiveThermalSpokeWidth() == 0 )
{ {
if( aSource ) if( aSource )
*aSource = _( "zone" ); *aSource = _( "zone" );
return m_ThermalReliefCopperBridge; return m_thermalReliefSpokeWidth;
} }
return aPad->GetEffectiveThermalSpokeWidth( aSource ); return aPad->GetEffectiveThermalSpokeWidth( aSource );
@ -600,7 +601,7 @@ void ZONE_CONTAINER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PA
if( !m_zoneName.empty() ) if( !m_zoneName.empty() )
aList.emplace_back( _( "Name" ), m_zoneName, DARKMAGENTA ); 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::POLYGONS: msg = _( "Solid" ); break;
case ZONE_FILL_MODE::HATCH_PATTERN: msg = _( "Hatched" ); break; case ZONE_FILL_MODE::HATCH_PATTERN: msg = _( "Hatched" ); break;
@ -1235,12 +1236,12 @@ double ZONE_CONTAINER::CalculateFilledArea()
/** /**
* Function TransformOutlinesShapeWithClearanceToPolygon * Function TransformSmoothedOutlineWithClearanceToPolygon
* Convert the filled areas to polygons (optionally inflated by \a aClearance) and copy them * Convert the smoothed outline to polygons (optionally inflated by \a aClearance) and copy them
* into \a aCornerBuffer. * into \a aCornerBuffer.
*/ */
void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, void ZONE_CONTAINER::TransformSmoothedOutlineWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearance ) const int aClearance ) const
{ {
// Creates the zone outline polygon (with holes if any) // Creates the zone outline polygon (with holes if any)
SHAPE_POLY_SET polybuffer; SHAPE_POLY_SET polybuffer;
@ -1367,8 +1368,8 @@ static struct ZONE_CONTAINER_DESC
&ZONE_CONTAINER::SetThermalReliefGap, &ZONE_CONTAINER::GetThermalReliefGap, &ZONE_CONTAINER::SetThermalReliefGap, &ZONE_CONTAINER::GetThermalReliefGap,
PROPERTY_DISPLAY::DISTANCE ) ); PROPERTY_DISPLAY::DISTANCE ) );
propMgr.AddProperty( new PROPERTY<ZONE_CONTAINER, int>( _( "Thermal Spoke Width" ), propMgr.AddProperty( new PROPERTY<ZONE_CONTAINER, int>( _( "Thermal Spoke Width" ),
&ZONE_CONTAINER::SetThermalReliefCopperBridge, &ZONE_CONTAINER::GetThermalReliefCopperBridge, &ZONE_CONTAINER::SetThermalReliefSpokeWidth, &ZONE_CONTAINER::GetThermalReliefSpokeWidth,
PROPERTY_DISPLAY::DISTANCE ) ); PROPERTY_DISPLAY::DISTANCE ) );
} }
} _ZONE_CONTAINER_DESC; } _ZONE_CONTAINER_DESC;

View File

@ -152,28 +152,28 @@ public:
unsigned int ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const override; unsigned int ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const override;
void SetFillMode( ZONE_FILL_MODE aFillMode ) { m_FillMode = aFillMode; } void SetFillMode( ZONE_FILL_MODE aFillMode ) { m_fillMode = aFillMode; }
ZONE_FILL_MODE GetFillMode() const { return m_FillMode; } ZONE_FILL_MODE GetFillMode() const { return m_fillMode; }
void SetThermalReliefGap( int aThermalReliefGap ) void SetThermalReliefGap( int aThermalReliefGap )
{ {
if( m_ThermalReliefGap != aThermalReliefGap ) if( m_thermalReliefGap != aThermalReliefGap )
SetNeedRefill( true ); 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; 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 ); SetNeedRefill( true );
m_ThermalReliefCopperBridge = aThermalReliefCopperBridge; m_thermalReliefSpokeWidth = aThermalReliefSpokeWidth;
} }
int GetThermalReliefCopperBridge() const { return m_ThermalReliefCopperBridge; } int GetThermalReliefSpokeWidth() const { return m_thermalReliefSpokeWidth; }
int GetThermalReliefCopperBridge( D_PAD* aPad, wxString* aSource = nullptr ) const; int GetThermalReliefSpokeWidth( D_PAD* aPad, wxString* aSource = nullptr ) const;
/** /**
* Compute the area currently occupied by the zone fill. * Compute the area currently occupied by the zone fill.
@ -198,8 +198,14 @@ public:
return m_lock; return m_lock;
} }
bool IsFilled() const { return m_IsFilled; } int GetFillFlag( PCB_LAYER_ID aLayer )
void SetIsFilled( bool isFilled ) { m_IsFilled = isFilled; } {
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; } bool NeedRefill() const { return m_needRefill; }
void SetNeedRefill( bool aNeedRefill ) { m_needRefill = aNeedRefill; } void SetNeedRefill( bool aNeedRefill ) { m_needRefill = aNeedRefill; }
@ -348,17 +354,17 @@ public:
int aError = ARC_HIGH_DEF ) const; int aError = ARC_HIGH_DEF ) const;
/** /**
* Function TransformOutlinesShapeWithClearanceToPolygon * Function TransformSmoothedOutlineWithClearanceToPolygon
* Convert the outlines shape to a polygon with no holes * Convert the outlines shape to a polygon with no holes
* inflated (optional) by max( aClearanceValue, the zone clearance) * inflated (optional) by max( aClearanceValue, the zone clearance)
* (holes are linked to external outline by overlapping segments) * (holes are linked to external outline by overlapping segments)
* Used in filling zones calculations * Used in filling zones calculations
* Circles (vias) and arcs (ends of tracks) are approximated by segments * Circles (vias) and arcs (ends of tracks) are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon * @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, void TransformSmoothedOutlineWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aMinClearanceValue ) const; int aClearance ) const;
/** /**
* Function TransformShapeWithClearanceToPolygon * Function TransformShapeWithClearanceToPolygon
@ -666,9 +672,10 @@ public:
unsigned int GetCornerRadius() const { return m_cornerRadius; } unsigned int GetCornerRadius() const { return m_cornerRadius; }
bool GetFilledPolysUseThickness() const { return m_FilledPolysUseThickness; } bool GetFilledPolysUseThickness() const { return m_fillVersion == 5; }
void SetFilledPolysUseThickness( bool aOption ) { m_FilledPolysUseThickness = aOption; }
int GetFillVersion() const { return m_fillVersion; }
void SetFillVersion( int aVersion ) { m_fillVersion = aVersion; }
/** /**
* Remove a cutout from the zone. * Remove a cutout from the zone.
@ -842,39 +849,36 @@ protected:
bool m_doNotAllowFootprints; bool m_doNotAllowFootprints;
ZONE_CONNECTION m_PadConnection; ZONE_CONNECTION m_PadConnection;
int m_ZoneClearance; ///< Clearance value in internal units. int m_ZoneClearance; // Clearance value in internal units.
int m_ZoneMinThickness; ///< Minimum thickness value in filled areas. int m_ZoneMinThickness; // Minimum thickness value in filled areas.
bool m_FilledPolysUseThickness; ///< outline of filled polygons have thickness. int m_fillVersion; // See BOARD_DESIGN_SETTINGS for version
// differences.
ISLAND_REMOVAL_MODE m_islandRemovalMode; ISLAND_REMOVAL_MODE m_islandRemovalMode;
/** /**
* When island removal mode is set to AREA, islands below this area will be removed. * 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. * 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. */ /** 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. /** 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 * m_needRefill = false does not imply filled areas are up to date, just
* the zone was refilled after edition, and does not need refilling * 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 gap in thermal reliefs.
int m_ThermalReliefGap; int m_thermalReliefSpokeWidth; // Width of the copper bridge in thermal reliefs.
///< Width of the copper bridge in thermal reliefs.
int m_ThermalReliefCopperBridge;
/** How to fill areas: /** How to fill areas:
* ZONE_FILL_MODE::POLYGONS => use solid polygons * ZONE_FILL_MODE::POLYGONS => use solid polygons
* ZONE_FILL_MODE::HATCH_PATTERN => use a grid pattern as shape * 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_hatchThickness; // thickness of lines (if 0 -> solid shape)
int m_hatchGap; // gap between lines (0 -> solid shape int m_hatchGap; // gap between lines (0 -> solid shape
double m_hatchOrientation; // orientation in degrees of grid lines 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. /// The index of the corner being moved or nullptr if no corner is selected.
SHAPE_POLY_SET::VERTEX_INDEX* m_CornerSelection; SHAPE_POLY_SET::VERTEX_INDEX* m_CornerSelection;
/// Variable used in polygon calculations. int m_localFlgs; // Variable used in polygon calculations.
int m_localFlgs;
/** Segments used to fill the zone (#m_FillMode ==1 ), when fill zone by segment is used. /** 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. * 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_FilledPolysList;
std::map<PCB_LAYER_ID, SHAPE_POLY_SET> m_RawPolysList; 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 /// 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; 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 // 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. // a module or pad overrides the zone to specify a thermal connection.
m_antipadClearance.SetValue( m_settings.m_ThermalReliefGap ); 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.SetDataType( EDA_DATA_TYPE::AREA );
m_islandThreshold.SetDoubleValue( static_cast<double>( m_settings.GetMinIslandArea() ) ); 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_Zone_45_Only = m_constrainOutline->GetValue();
m_settings.m_ThermalReliefGap = m_antipadClearance.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." ) ); DisplayError( this, _( "Thermal spoke width cannot be smaller than the minimum width." ) );
return false; 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.clearance = Iu2Mils( m_settings.m_ZoneClearance );
cfg->m_Zones.min_thickness = Iu2Mils( m_settings.m_ZoneMinThickness ); 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_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( m_settings.SetIslandRemovalMode(
static_cast<ISLAND_REMOVAL_MODE>( m_cbRemoveIslands->GetSelection() ) ); 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_maxError.SetValue( m_BrdSettings->m_MaxError );
m_rbOutlinePolygonFastest->SetValue( m_BrdSettings->m_ZoneUseNoOutlineInFill ); m_rbOutlinePolygonFastest->SetValue( m_BrdSettings->m_ZoneFillVersion == 6 );
m_rbOutlinePolygonBestQ->SetValue( !m_BrdSettings->m_ZoneUseNoOutlineInFill ); m_rbOutlinePolygonBestQ->SetValue( m_BrdSettings->m_ZoneFillVersion == 5 );
m_allowExternalFilletsOpt->SetValue( m_BrdSettings->m_ZoneKeepExternalFillets ); m_allowExternalFilletsOpt->SetValue( m_BrdSettings->m_ZoneKeepExternalFillets );
m_minClearance.SetValue( m_BrdSettings->m_MinClearance ); 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_BrdSettings->m_MaxError = Clamp<int>( IU_PER_MM * MINIMUM_ERROR_SIZE_MM,
m_maxError.GetValue(), IU_PER_MM * MAXIMUM_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_ZoneKeepExternalFillets = m_allowExternalFilletsOpt->GetValue();
m_BrdSettings->m_MinClearance = m_minClearance.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 ); 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 ); 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->Wrap( -1 );
m_stCircleToPolyWarning->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) ); 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; wxBoxSizer* bSizerOutlinesOpts;
bSizerOutlinesOpts = new wxBoxSizer( wxVERTICAL ); 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 ); bSizerOutlinesOpts->Add( m_rbOutlinePolygonBestQ, 0, wxALL, 4 );
m_rbOutlinePolygonFastest = new wxRadioButton( this, wxID_ANY, _("Smoothed polygons (best performance)"), wxDefaultPosition, wxDefaultSize, 0 ); m_rbOutlinePolygonFastest = new wxRadioButton( this, wxID_ANY, _("Smoothed polygons (best performance)"), wxDefaultPosition, wxDefaultSize, 0 );
m_rbOutlinePolygonFastest->SetValue( true ); 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 ); bSizerOutlinesOpts->Add( m_rbOutlinePolygonFastest, 0, wxALL, 4 );

View File

@ -837,7 +837,7 @@
<property name="gripper">0</property> <property name="gripper">0</property>
<property name="hidden">0</property> <property name="hidden">0</property>
<property name="id">wxID_ANY</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="markup">0</property>
<property name="max_size"></property> <property name="max_size"></property>
<property name="maximize_button">0</property> <property name="maximize_button">0</property>
@ -1106,7 +1106,7 @@
<property name="gripper">0</property> <property name="gripper">0</property>
<property name="hidden">0</property> <property name="hidden">0</property>
<property name="id">wxID_ANY</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="max_size"></property>
<property name="maximize_button">0</property> <property name="maximize_button">0</property>
<property name="maximum_size"></property> <property name="maximum_size"></property>
@ -1127,7 +1127,7 @@
<property name="style"></property> <property name="style"></property>
<property name="subclass">; ; forward_declare</property> <property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</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_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property> <property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property> <property name="validator_type">wxDefaultValidator</property>
@ -1192,7 +1192,7 @@
<property name="style"></property> <property name="style"></property>
<property name="subclass">; ; forward_declare</property> <property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</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_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property> <property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</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) // (i.e. width of spoke is half of the smaller side of an smd pad)
// This is a basic workaround // This is a basic workaround
zone->SetThermalReliefGap( p.width.ToPcbUnits() + 50000 ); // 50000nm == 0.05mm 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; 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)", m_out->Print( aNestLevel+1, "(min_thickness %s)",
FormatInternalUnits( aZone->GetMinThickness() ).c_str() ); FormatInternalUnits( aZone->GetMinThickness() ).c_str() );
// write it only if V 6.O version option is not used (i.e. do not write if the // write it only if V 6.O version option is used (i.e. do not write if the "legacy"
// "legacy" algorithm is used) // algorithm is used)
if( !aZone->GetFilledPolysUseThickness() ) if( !aZone->GetFilledPolysUseThickness() )
m_out->Print( 0, " (filled_areas_thickness no)" ); 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)", m_out->Print( 0, " (thermal_gap %s) (thermal_bridge_width %s)",
FormatInternalUnits( aZone->GetThermalReliefGap() ).c_str(), FormatInternalUnits( aZone->GetThermalReliefGap() ).c_str(),
FormatInternalUnits( aZone->GetThermalReliefCopperBridge() ).c_str() ); FormatInternalUnits( aZone->GetThermalReliefSpokeWidth() ).c_str() );
if( aZone->GetCornerSmoothingType() != ZONE_SETTINGS::SMOOTHING_NONE ) if( aZone->GetCornerSmoothingType() != ZONE_SETTINGS::SMOOTHING_NONE )
{ {

View File

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

View File

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

View File

@ -492,6 +492,8 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
for( ZONE_CONTAINER* zone : aBoard->Zones() ) for( ZONE_CONTAINER* zone : aBoard->Zones() )
{ {
int outlineThickness = zone->GetFilledPolysUseThickness() ? zone->GetMinThickness() : 0;
for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() ) for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
{ {
auto pair = std::make_pair( layer, zone ); auto pair = std::make_pair( layer, zone );
@ -529,17 +531,12 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
if( candidate->GetNetCode() != zone->GetNetCode() ) if( candidate->GetNetCode() != zone->GetNetCode() )
continue; continue;
// Merging zones of the same net can be done only for areas // Merging zones of the same net can be done only for areas having compatible
// having compatible settings for drawings: // settings for filling as the merged zone can only have a single setting.
// use or not outline thickness, and if using outline thickness, int candidateOutlineThickness = candidate->GetFilledPolysUseThickness() ?
// having the same thickness candidate->GetMinThickness() : 0;
// 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;
if( zone->GetFilledPolysUseThickness() if( candidateOutlineThickness != outlineThickness )
&& ( candidate->GetMinThickness() != zone->GetMinThickness() ) )
continue; continue;
plotted.insert( candidate_pair ); plotted.insert( candidate_pair );
@ -867,9 +864,9 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
continue; continue;
// add shapes inflated by aMinThickness/2 in areas // 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 // 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; int maxError = aBoard->GetDesignSettings().m_MaxError;

View File

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

View File

@ -1098,8 +1098,8 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadTemplates()
if( csTemplate.Pouring.ThermalReliefOnPads ) if( csTemplate.Pouring.ThermalReliefOnPads )
{ {
zone->SetThermalReliefGap( getKiCadLength( csTemplate.Pouring.ClearanceWidth ) ); zone->SetThermalReliefGap( getKiCadLength( csTemplate.Pouring.ClearanceWidth ) );
zone->SetThermalReliefCopperBridge( getKiCadLength( zone->SetThermalReliefSpokeWidth( getKiCadLength(
getCopperCode( csTemplate.Pouring.ReliefCopperCodeID ).CopperWidth ) ); getCopperCode( csTemplate.Pouring.ReliefCopperCodeID ).CopperWidth ));
zone->SetPadConnection( ZONE_CONNECTION::THERMAL ); zone->SetPadConnection( ZONE_CONNECTION::THERMAL );
} }
else 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<std::pair<ZONE_CONTAINER*, PCB_LAYER_ID>> toFill;
std::vector<CN_ZONE_ISOLATED_ISLAND_LIST> islandsList; std::vector<CN_ZONE_ISOLATED_ISLAND_LIST> islandsList;
auto connectivity = m_board->GetConnectivity(); std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
bool filledPolyWithOutline = not m_board->GetDesignSettings().m_ZoneUseNoOutlineInFill;
std::unique_lock<std::mutex> lock( connectivity->GetLock(), std::try_to_lock ); 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 ) if( !lock )
return false; 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 // Remove existing fill first to prevent drawing invalid polygons
// on some platforms // on some platforms
zone->UnFill(); zone->UnFill();
zone->SetFillVersion( bds.m_ZoneFillVersion );
} }
std::atomic<size_t> nextItem( 0 ); std::atomic<size_t> nextItem( 0 );
size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(), size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
aZones.size() ); toFill.size() );
std::vector<std::future<size_t>> returns( parallelThreadCount ); std::vector<std::future<size_t>> returns( parallelThreadCount );
auto fill_lambda = auto fill_lambda =
[&]( PROGRESS_REPORTER* aReporter ) -> size_t [&]( 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; size_t i = nextItem++;
ZONE_CONTAINER* zone = toFill[i].first;
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; SHAPE_POLY_SET rawPolys, finalPolys;
fillSingleZone( zone, layer, 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->SetRawPolysList( layer, rawPolys );
zone->SetFilledPolysList( layer, finalPolys ); zone->SetFilledPolysList( layer, finalPolys );
zone->SetIsFilled( true ); zone->SetFillFlag( layer, true );
if( m_progressReporter ) 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() ) if( m_progressReporter && m_progressReporter->IsCancelled() )
return false; 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() // Re-add not connected zones to list, connectivity->FindIsolatedCopperIslands()
// populates islandsList only with zones having a net // populates islandsList only with zones having a net
for( ZONE_CONTAINER* zone : aZones ) 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 ) ) for( ZONE_CONTAINER* zone : m_board->GetZoneList( true ) )
{ {
// If the zones share no common layers // If the zones share no common layers
if( !zone->GetLayerSet().test( aLayer ) ) if( !zone->GetLayerSet().test( aLayer ) )
continue; continue;
@ -764,15 +838,28 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, PCB_LA
if( item_boundingbox.Intersects( zone_boundingbox ) ) if( item_boundingbox.Intersects( zone_boundingbox ) )
{ {
// Add the zone outline area. Don't use any clearance for keepouts, or for zones if( zone->GetIsKeepout() || aZone->GetNetCode() == zone->GetNetCode() )
// with the same net (they will be connected but will honor their own clearance, {
// thermal connections, etc.). // Keepouts and same-net zones use outline with no clearance
int gap = 0; zone->TransformSmoothedOutlineWithClearanceToPolygon( aHoles, 0 );
}
else
{
int gap = aZone->GetClearance( aLayer, zone );
if( !zone->GetIsKeepout() && aZone->GetNetCode() != zone->GetNetCode() ) if( bds.m_ZoneFillVersion == 5 )
gap = aZone->GetClearance( aLayer, zone ); {
// 5.x used outline with clearance
zone->TransformOutlinesShapeWithClearanceToPolygon( aHoles, gap ); 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 ); int thermalReliefGap = aZone->GetThermalReliefGap( pad );
// Calculate thermal bridge half width // 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 // Avoid spoke_w bigger than the smaller pad size, because
// it is not possible to create stubs bigger than the pad. // it is not possible to create stubs bigger than the pad.
// Possible refinement: have a separate size for vertical and horizontal stubs // 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: // thickness of the gap in thermal reliefs:
m_ThermalReliefGap = Mils2iu( ZONE_THERMAL_RELIEF_GAP_MIL ); m_ThermalReliefGap = Mils2iu( ZONE_THERMAL_RELIEF_GAP_MIL );
// thickness of the copper bridge in thermal reliefs: // 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; m_Zone_45_Only = false;
@ -104,10 +104,10 @@ ZONE_SETTINGS& ZONE_SETTINGS::operator << ( const ZONE_CONTAINER& aSource )
m_HatchHoleMinArea = aSource.GetHatchHoleMinArea(); m_HatchHoleMinArea = aSource.GetHatchHoleMinArea();
m_NetcodeSelection = aSource.GetNetCode(); m_NetcodeSelection = aSource.GetNetCode();
m_Name = aSource.GetZoneName(); m_Name = aSource.GetZoneName();
m_ZoneBorderDisplayStyle = aSource.GetHatchStyle(); m_ZoneBorderDisplayStyle = aSource.GetHatchStyle();
m_ThermalReliefGap = aSource.GetThermalReliefGap(); m_ThermalReliefGap = aSource.GetThermalReliefGap();
m_ThermalReliefCopperBridge = aSource.GetThermalReliefCopperBridge(); m_ThermalReliefSpokeWidth = aSource.GetThermalReliefSpokeWidth();
m_PadConnection = aSource.GetPadConnection(); m_padConnection = aSource.GetPadConnection();
m_cornerSmoothingType = aSource.GetCornerSmoothingType(); m_cornerSmoothingType = aSource.GetCornerSmoothingType();
m_cornerRadius = aSource.GetCornerRadius(); m_cornerRadius = aSource.GetCornerRadius();
m_isKeepout = aSource.GetIsKeepout(); m_isKeepout = aSource.GetIsKeepout();
@ -139,8 +139,8 @@ void ZONE_SETTINGS::ExportSetting( ZONE_CONTAINER& aTarget, bool aFullExport ) c
aTarget.SetHatchBorderAlgorithm( m_HatchBorderAlgorithm ); aTarget.SetHatchBorderAlgorithm( m_HatchBorderAlgorithm );
aTarget.SetHatchHoleMinArea( m_HatchHoleMinArea ); aTarget.SetHatchHoleMinArea( m_HatchHoleMinArea );
aTarget.SetThermalReliefGap( m_ThermalReliefGap ); aTarget.SetThermalReliefGap( m_ThermalReliefGap );
aTarget.SetThermalReliefCopperBridge( m_ThermalReliefCopperBridge ); aTarget.SetThermalReliefSpokeWidth( m_ThermalReliefSpokeWidth );
aTarget.SetPadConnection( m_PadConnection ); aTarget.SetPadConnection( m_padConnection );
aTarget.SetCornerSmoothingType( m_cornerSmoothingType ); aTarget.SetCornerSmoothingType( m_cornerSmoothingType );
aTarget.SetCornerRadius( m_cornerRadius ); aTarget.SetCornerRadius( m_cornerRadius );
aTarget.SetIsKeepout( GetIsKeepout() ); aTarget.SetIsKeepout( GetIsKeepout() );

View File

@ -76,52 +76,50 @@ public:
SMOOTHING_LAST // sentinel 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; ZONE_FILL_MODE m_FillMode;
int m_ZoneClearance; // Minimal clearance value int m_ZoneClearance; // Minimal clearance value
int m_ZoneMinThickness; // Min thickness value in filled areas int m_ZoneMinThickness; // Min thickness value in filled areas
int m_HatchThickness; // HatchBorder thickness of lines (if 0 -> solid shape) int m_HatchThickness; // HatchBorder thickness of lines (if 0 -> solid shape)
int m_HatchGap; // HatchBorder clearance between lines (0 -> solid shape) int m_HatchGap; // HatchBorder clearance between lines (0 -> solid shape)
double m_HatchOrientation; // HatchBorder orientation of grid lines in degrees double m_HatchOrientation; // HatchBorder orientation of grid lines in degrees
int m_HatchSmoothingLevel; // HatchBorder smoothing type, similar to corner smoothing type int m_HatchSmoothingLevel; // HatchBorder smoothing type, similar to corner smoothing type
// 0 = no smoothing, 1 = fillet, >= 2 = arc // 0 = no smoothing, 1 = fillet, >= 2 = arc
double m_HatchSmoothingValue; // HatchBorder chamfer/fillet size as a ratio of hole size double m_HatchSmoothingValue; // HatchBorder chamfer/fillet size as a ratio of hole size
double m_HatchHoleMinArea; // min size before holes are dropped (ratio) double m_HatchHoleMinArea; // min size before holes are dropped (ratio)
int m_HatchBorderAlgorithm; // 0 = use min zone thickness 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 /// Option to show the zone area (outlines only, short hatches or full hatches
ZONE_BORDER_DISPLAY_STYLE m_ZoneBorderDisplayStyle; ZONE_BORDER_DISPLAY_STYLE m_ZoneBorderDisplayStyle;
long m_ThermalReliefGap; ///< thickness of the gap in thermal reliefs long m_ThermalReliefGap; // thickness of the gap in thermal reliefs
long m_ThermalReliefCopperBridge; ///< thickness of the copper bridge 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: private:
int m_cornerSmoothingType; ///< Corner smoothing type int m_cornerSmoothingType; // Corner smoothing type
unsigned int m_cornerRadius; ///< Corner chamfer distance / fillet radius unsigned int m_cornerRadius; // Corner chamfer distance / fillet radius
ZONE_CONNECTION m_PadConnection; 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: bool m_keepoutDoNotAllowCopperPour;
* what is not allowed inside the keepout ( pads, tracks and vias ) bool m_keepoutDoNotAllowVias;
*/ bool m_keepoutDoNotAllowTracks;
bool m_keepoutDoNotAllowCopperPour; bool m_keepoutDoNotAllowPads;
bool m_keepoutDoNotAllowVias; bool m_keepoutDoNotAllowFootprints;
bool m_keepoutDoNotAllowTracks;
bool m_keepoutDoNotAllowPads;
bool m_keepoutDoNotAllowFootprints;
ISLAND_REMOVAL_MODE m_removeIslands; ISLAND_REMOVAL_MODE m_removeIslands;
long long int m_minIslandArea; long long int m_minIslandArea;
@ -168,12 +166,12 @@ public:
ZONE_CONNECTION GetPadConnection() const ZONE_CONNECTION GetPadConnection() const
{ {
return m_PadConnection; return m_padConnection;
} }
void SetPadConnection( ZONE_CONNECTION aPadConnection ) 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() ) if( m_ZoneMinThickness != aZoneToCompare.GetMinThickness() )
return false; return false;
if( m_FillMode != aZoneToCompare.GetFillMode() ) if( m_fillMode != aZoneToCompare.GetFillMode() )
return false; return false;
if( m_PadConnection != aZoneToCompare.m_PadConnection ) if( m_PadConnection != aZoneToCompare.m_PadConnection )
return false; return false;
if( m_ThermalReliefGap != aZoneToCompare.m_ThermalReliefGap ) if( m_thermalReliefGap != aZoneToCompare.m_thermalReliefGap )
return false; return false;
if( m_ThermalReliefCopperBridge != aZoneToCompare.m_ThermalReliefCopperBridge ) if( m_thermalReliefSpokeWidth != aZoneToCompare.m_thermalReliefSpokeWidth )
return false; return false;
if( m_zoneName != aZoneToCompare.m_zoneName ) 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() ) if( area_to_test->GetThermalReliefGap() != area2->GetThermalReliefGap() )
continue; continue;
if( area_to_test->GetThermalReliefCopperBridge() != area2->GetThermalReliefCopperBridge() ) if( area_to_test->GetThermalReliefSpokeWidth() != area2->GetThermalReliefSpokeWidth() )
continue; continue;
if( area_to_test->GetLocalClearance() != area2->GetLocalClearance() ) if( area_to_test->GetLocalClearance() != area2->GetLocalClearance() )