7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-21 17:23:44 +00:00

ADDED: Per layer properties of zones used for control over zone hatching position

This commit is contained in:
Daniel Treffenstädt 2025-03-02 20:31:04 +00:00 committed by Jon Evans
parent b0eef3ee28
commit 27edf0b949
19 changed files with 421 additions and 17 deletions

View File

@ -647,6 +647,14 @@ message ZoneFilledPolygons
kiapi.common.types.PolySet shapes = 2;
}
message ZoneLayerProperties
{
BoardLayer layer = 1;
kiapi.common.types.Vector2 hatching_offset = 2;
}
message Zone
{
kiapi.common.types.KIID id = 1;
@ -673,6 +681,8 @@ message Zone
ZoneBorderSettings border = 11;
kiapi.common.types.LockedState locked = 12;
repeated ZoneLayerProperties layer_properties = 13;
}
// An aligned dimension is drawn parallel to the line segment between the start and end points

View File

@ -171,6 +171,7 @@ hatch
hatch_thickness
hatch_gap
hatch_orientation
hatch_position
hatch_smoothing_level
hatch_smoothing_value
hatch_border_algorithm
@ -398,4 +399,5 @@ zone_clearance
zone_connect
zone_layer_connections
zone_type
zone_defaults
zones

View File

@ -33,11 +33,13 @@ PROJECT_LOCAL_SETTINGS::PROJECT_LOCAL_SETTINGS( PROJECT* aProject, const wxStrin
JSON_SETTINGS( aFilename, SETTINGS_LOC::PROJECT, projectLocalSettingsVersion,
/* aCreateIfMissing = */ true, /* aCreateIfDefault = */ false,
/* aWriteFile = */ true ),
// clang-format off: suggestion is less readable.
m_ActiveLayer( UNDEFINED_LAYER ),
m_ContrastModeDisplay( HIGH_CONTRAST_MODE::NORMAL ),
m_NetColorMode( NET_COLOR_MODE::RATSNEST ),
m_AutoTrackWidth( true ),
m_ZoneDisplayMode( ZONE_DISPLAY_MODE::SHOW_FILLED ),
m_PrototypeZoneFill( false ),
m_TrackOpacity( 1.0 ),
m_ViaOpacity( 1.0 ),
m_PadOpacity( 1.0 ),
@ -47,6 +49,7 @@ PROJECT_LOCAL_SETTINGS::PROJECT_LOCAL_SETTINGS( PROJECT* aProject, const wxStrin
m_PcbSelectionFilter(),
m_project( aProject ),
m_wasMigrated( false )
// clang-format on: suggestion is less readable.
{
// Keep old files around
m_deleteLegacyAfterMigration = false;
@ -201,6 +204,9 @@ PROJECT_LOCAL_SETTINGS::PROJECT_LOCAL_SETTINGS( PROJECT* aProject, const wxStrin
ZONE_DISPLAY_MODE::SHOW_FILLED, ZONE_DISPLAY_MODE::SHOW_FILLED,
ZONE_DISPLAY_MODE::SHOW_TRIANGULATION ) );
m_params.emplace_back(
new PARAM<bool>( "board.prototype_zone_fills", &m_PrototypeZoneFill, false ) );
m_params.emplace_back( new PARAM<wxString>( "git.repo_username", &m_GitRepoUsername, "" ) );
m_params.emplace_back( new PARAM<wxString>( "git.repo_type", &m_GitRepoType, "" ) );

View File

@ -130,6 +130,9 @@ public:
/// How zones are drawn
ZONE_DISPLAY_MODE m_ZoneDisplayMode;
/// Whether Zone fill should always be solid for performance with large boards.
bool m_PrototypeZoneFill;
double m_TrackOpacity; ///< Opacity override for all tracks
double m_ViaOpacity; ///< Opacity override for all types of via
double m_PadOpacity; ///< Opacity override for SMD pads and PTH

View File

@ -44,6 +44,12 @@ void PCB_EDIT_FRAME::Edit_Zone_Params( ZONE* aZone )
ZONE_SETTINGS zoneInfo = m_pcb->GetDesignSettings().GetDefaultZoneSettings();
BOARD_COMMIT commit( this );
// store default layer properties
std::map<PCB_LAYER_ID, ZONE_LAYER_PROPERTIES> layer_properties;
std::ranges::copy( zoneInfo.m_layerProperties,
std::inserter( layer_properties, std::end( layer_properties ) ) );
if( aZone->GetIsRuleArea() )
{
// edit a rule area on a copper layer
@ -80,6 +86,11 @@ void PCB_EDIT_FRAME::Edit_Zone_Params( ZONE* aZone )
if( net ) // net == NULL should not occur
aZone->SetNetCode( net->GetNetCode() );
// restore default layer properties
zoneInfo.m_layerProperties.clear();
std::ranges::copy( layer_properties, std::inserter( zoneInfo.m_layerProperties,
std::end( zoneInfo.m_layerProperties ) ) );
m_pcb->GetDesignSettings().SetDefaultZoneSettings( zoneInfo );
commit.Push( _( "Edit Zone Properties" ), SKIP_CONNECTIVITY );

View File

@ -606,6 +606,19 @@ void PCB_IO_KICAD_SEXPR::formatSetup( const BOARD* aBoard ) const
KICAD_FORMAT::FormatBool( m_out, "filling", dsnSettings.m_FillVias );
if( !dsnSettings.GetDefaultZoneSettings().m_layerProperties.empty() )
{
m_out->Print( 0, " (zone_defaults" );
for( const auto& [layer, properties] :
dsnSettings.GetDefaultZoneSettings().m_layerProperties )
{
format( properties, 0, layer );
}
m_out->Print( 0, ")\n" );
}
VECTOR2I origin = dsnSettings.GetAuxOrigin();
if( origin != VECTOR2I( 0, 0 ) )
@ -2658,6 +2671,11 @@ void PCB_IO_KICAD_SEXPR::format( const ZONE* aZone ) const
m_out->Print( ")" );
for( const auto& [layer, properties] : aZone->LayerProperties() )
{
format( properties, 0, layer );
}
if( aZone->GetNumCorners() )
{
SHAPE_POLY_SET::POLYGON poly = aZone->Outline()->Polygon(0);
@ -2694,6 +2712,26 @@ void PCB_IO_KICAD_SEXPR::format( const ZONE* aZone ) const
}
void PCB_IO_KICAD_SEXPR::format( const ZONE_LAYER_PROPERTIES& aZoneLayerProperties, int aNestLevel,
PCB_LAYER_ID aLayer ) const
{
// Do not store the layer properties if no value is actually set.
if( !aZoneLayerProperties.hatching_offset.has_value() )
return;
m_out->Print( aNestLevel, "(property\n" );
m_out->Print( aNestLevel, "(layer %s)\n", m_out->Quotew( LSET::Name( aLayer ) ).c_str() );
if( aZoneLayerProperties.hatching_offset.has_value() )
{
m_out->Print( aNestLevel, "(hatch_position (xy %s))",
formatInternalUnits( aZoneLayerProperties.hatching_offset.value() ).c_str() );
}
m_out->Print( aNestLevel, ")\n" );
}
PCB_IO_KICAD_SEXPR::PCB_IO_KICAD_SEXPR( int aControlFlags ) : PCB_IO( wxS( "KiCad" ) ),
m_cache( nullptr ),
m_ctl( aControlFlags ),

View File

@ -33,6 +33,7 @@
#include <string>
#include <optional>
#include <layer_ids.h>
#include <zone_settings.h>
#include <lset.h>
#include <boost/ptr_container/ptr_map.hpp>
#include <wx_filename.h>
@ -177,7 +178,8 @@ class PCB_IO_KICAD_SEXPR; // forward decl
//----------------- Start of 10.0 development -----------------
//#define SEXPR_BOARD_FILE_VERSION 20250210 // Knockout for textboxes
//#define SEXPR_BOARD_FILE_VERSION 20250222 // Hatching for PCB shapes
#define SEXPR_BOARD_FILE_VERSION 20250228 // ipc-4761 via protection features
//#define SEXPR_BOARD_FILE_VERSION 20250228 // ipc-4761 via protection features
#define SEXPR_BOARD_FILE_VERSION 20250302 // Zone Hatching Offsets
#define BOARD_FILE_HOST_VERSION 20200825 ///< Earlier files than this include the host tag
@ -453,6 +455,9 @@ private:
void format( const ZONE* aZone ) const;
void format( const ZONE_LAYER_PROPERTIES& aZoneLayerProperties, int aNestLevel,
PCB_LAYER_ID aLayer ) const;
void formatPolyPts( const SHAPE_LINE_CHAIN& outline,
const FOOTPRINT* aParentFP = nullptr ) const;

View File

@ -27,6 +27,7 @@
* @brief Pcbnew s-expression file format parser implementation.
*/
#include "layer_ids.h"
#include <cerrno>
#include <charconv>
#include <confirm.h>
@ -2548,6 +2549,9 @@ void PCB_IO_KICAD_SEXPR_PARSER::parseSetup()
break;
}
case T_zone_defaults:
parseZoneDefaults( bds.GetDefaultZoneSettings() );
break;
default:
Unexpected( CurText() );
@ -2565,6 +2569,70 @@ void PCB_IO_KICAD_SEXPR_PARSER::parseSetup()
}
void PCB_IO_KICAD_SEXPR_PARSER::parseZoneDefaults( ZONE_SETTINGS& aZoneSettings )
{
T token;
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
{
Expecting( T_LEFT );
}
token = NextTok();
switch( token )
{
case T_property:
parseZoneLayerProperty( aZoneSettings.m_layerProperties );
break;
default:
Unexpected( CurText() );
}
}
}
void PCB_IO_KICAD_SEXPR_PARSER::parseZoneLayerProperty(
std::map<PCB_LAYER_ID, ZONE_LAYER_PROPERTIES>& aProperties )
{
T token;
PCB_LAYER_ID layer = UNDEFINED_LAYER;
ZONE_LAYER_PROPERTIES properties;
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
{
Expecting( T_LEFT );
}
token = NextTok();
switch( token )
{
case T_layer:
layer = parseBoardItemLayer();
NeedRIGHT();
break;
case T_hatch_position:
{
properties.hatching_offset = parseXY();
NeedRIGHT();
break;
}
default:
Unexpected( CurText() );
break;
}
}
aProperties.emplace( layer, properties );
}
void PCB_IO_KICAD_SEXPR_PARSER::parseDefaults( BOARD_DESIGN_SETTINGS& designSettings )
{
T token;
@ -6837,6 +6905,10 @@ ZONE* PCB_IO_KICAD_SEXPR_PARSER::parseZONE( BOARD_ITEM_CONTAINER* aParent )
zone->SetLayerSet( parseBoardItemLayersAsMask() );
break;
case T_property:
parseZoneLayerProperty( zone->LayerProperties() );
break;
case T_tstamp:
case T_uuid:
NextTok();

View File

@ -303,6 +303,10 @@ private:
void parseMargins( int& aLeft, int& aTop, int& aRight, int& aBottom );
void parseZoneDefaults( ZONE_SETTINGS& aZoneSettings );
void parseZoneLayerProperty( std::map<PCB_LAYER_ID, ZONE_LAYER_PROPERTIES>& aProperties );
std::pair<wxString, wxString> parseBoardProperty();
/**

View File

@ -95,6 +95,7 @@ std::unique_ptr<ZONE> ZONE_CREATE_HELPER::createNewZone( bool aKeepout )
// Get the current default settings for zones
ZONE_SETTINGS zoneInfo = board->GetDesignSettings().GetDefaultZoneSettings();
zoneInfo.m_Layers.reset().set( m_params.m_layer ); // TODO(JE) multilayer defaults?
zoneInfo.m_layerProperties.clear(); // Do not copy over layer properties
zoneInfo.m_NetcodeSelection = highlightedNets.empty() ? -1 : *highlightedNets.begin();
zoneInfo.SetIsRuleArea( m_params.m_keepout );

View File

@ -42,6 +42,7 @@
#include <trigo.h>
#include <i18n_utility.h>
#include <mutex>
#include <magic_enum.hpp>
#include <google/protobuf/any.pb.h>
#include <api/api_enums.h>
@ -84,7 +85,8 @@ ZONE::ZONE( BOARD_ITEM_CONTAINER* aParent ) :
SetIsRuleArea( true ); // Zones living in footprints have the rule area option
if( aParent->GetBoard() )
aParent->GetBoard()->GetDesignSettings().GetDefaultZoneSettings().ExportSetting( *this );
aParent->GetBoard()->GetDesignSettings().GetDefaultZoneSettings().ExportSetting( *this,
false );
else
ZONE_SETTINGS().ExportSetting( *this );
@ -191,6 +193,11 @@ void ZONE::InitDataFromSrcInCopyCtor( const ZONE& aZone )
m_insulatedIslands[layer] = aZone.m_insulatedIslands.at( layer );
} );
m_layerProperties.clear();
std::ranges::copy( aZone.LayerProperties(),
std::inserter( m_layerProperties, std::end( m_layerProperties ) ) );
m_borderStyle = aZone.m_borderStyle;
m_borderHatchPitch = aZone.m_borderHatchPitch;
m_borderHatchLines = aZone.m_borderHatchLines;
@ -213,6 +220,7 @@ void ZONE::Serialize( google::protobuf::Any& aContainer ) const
{
using namespace kiapi::board;
types::Zone zone;
using kiapi::common::PackVector2;
zone.mutable_id()->set_value( m_Uuid.AsStdString() );
PackLayerSet( *zone.mutable_layers(), GetLayerSet() );
@ -292,6 +300,18 @@ void ZONE::Serialize( google::protobuf::Any& aContainer ) const
kiapi::common::PackPolySet( *filledLayer->mutable_shapes(), *shape );
}
for( const auto& [layer, properties] : m_layerProperties )
{
types::ZoneLayerProperties* layerProperties = zone.add_layer_properties();
layerProperties->set_layer( ToProtoEnum<PCB_LAYER_ID, types::BoardLayer>( layer ) );
if( properties.hatching_offset.has_value() )
{
PackVector2( *layerProperties->mutable_hatching_offset(),
properties.hatching_offset.value() );
}
}
zone.mutable_border()->set_style(
ToProtoEnum<ZONE_BORDER_DISPLAY_STYLE, types::ZoneBorderStyle>( m_borderStyle ) );
zone.mutable_border()->mutable_pitch()->set_value_nm( m_borderHatchPitch );
@ -304,6 +324,7 @@ bool ZONE::Deserialize( const google::protobuf::Any& aContainer )
{
using namespace kiapi::board;
types::Zone zone;
using kiapi::common::UnpackVector2;
if( !aContainer.UnpackTo( &zone ) )
return false;
@ -366,6 +387,20 @@ bool ZONE::Deserialize( const google::protobuf::Any& aContainer )
SetNetCode( cu.net().code().value() );
m_teardropType = FromProtoEnum<TEARDROP_TYPE>( cu.teardrop().type() );
for( const auto& properties : zone.layer_properties() )
{
PCB_LAYER_ID layer = FromProtoEnum<PCB_LAYER_ID>( properties.layer() );
ZONE_LAYER_PROPERTIES layerProperties;
if( properties.has_hatching_offset() )
{
layerProperties.hatching_offset = UnpackVector2( properties.hatching_offset() );
}
m_layerProperties[layer] = layerProperties;
}
}
m_borderStyle = FromProtoEnum<ZONE_BORDER_DISPLAY_STYLE>( zone.border().style() );
@ -510,12 +545,49 @@ void ZONE::SetLayerSet( const LSET& aLayerSet )
m_filledPolysHash[layer] = {};
m_insulatedIslands[layer] = {};
} );
std::erase_if( m_layerProperties,
[&]( const auto& item )
{
return !aLayerSet.Contains( item.first );
} );
}
m_layerSet = aLayerSet;
}
const ZONE_LAYER_PROPERTIES& ZONE::LayerProperties( PCB_LAYER_ID aLayer ) const
{
wxCHECK_MSG( m_layerProperties.contains( aLayer ), m_layerProperties.at( GetFirstLayer() ),
"Attempt to retrieve properties for layer "
+ std::string( magic_enum::enum_name( aLayer ) )
+ " from a "
"zone that does not contain it" );
return m_layerProperties.at( aLayer );
}
void ZONE::SetLayerProperties( const std::map<PCB_LAYER_ID, ZONE_LAYER_PROPERTIES>& aOther )
{
m_layerProperties.clear();
std::ranges::copy( aOther, std::inserter( m_layerProperties, std::end( m_layerProperties ) ) );
}
const std::optional<VECTOR2I>& ZONE::HatchingOffset( PCB_LAYER_ID aLayer ) const
{
wxCHECK_MSG( m_layerProperties.contains( aLayer ),
m_layerProperties.at( GetFirstLayer() ).hatching_offset,
"Attempt to retrieve properties for layer "
+ std::string( magic_enum::enum_name( aLayer ) )
+ " from a "
"zone that does not contain it" );
return m_layerProperties.at( aLayer ).hatching_offset;
}
std::vector<int> ZONE::ViewGetLayers() const
{
std::vector<int> layers;
@ -963,8 +1035,19 @@ void ZONE::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
fillsCopy[oldLayer] = *shapePtr;
}
std::map<PCB_LAYER_ID, ZONE_LAYER_PROPERTIES> layerPropertiesCopy;
std::ranges::copy( m_layerProperties,
std::inserter( layerPropertiesCopy, std::end( layerPropertiesCopy ) ) );
SetLayerSet( GetLayerSet().Flip( GetBoard()->GetCopperLayerCount() ) );
for( auto& [oldLayer, properties] : layerPropertiesCopy )
{
PCB_LAYER_ID newLayer = GetBoard()->FlipLayer( oldLayer );
m_layerProperties[newLayer] = properties;
}
for( auto& [oldLayer, shape] : fillsCopy )
{
PCB_LAYER_ID newLayer = GetBoard()->FlipLayer( oldLayer );

View File

@ -28,6 +28,7 @@
#include <mutex>
#include <vector>
#include <map>
#include <gr_basic.h>
#include <board_item.h>
#include <board_connected_item.h>
@ -139,6 +140,24 @@ public:
*/
void SetLayerSetAndRemoveUnusedFills( const LSET& aLayerSet );
ZONE_LAYER_PROPERTIES& LayerProperties( PCB_LAYER_ID aLayer )
{
return m_layerProperties[aLayer];
}
const ZONE_LAYER_PROPERTIES& LayerProperties( PCB_LAYER_ID aLayer ) const;
std::map<PCB_LAYER_ID, ZONE_LAYER_PROPERTIES>& LayerProperties() { return m_layerProperties; }
const std::map<PCB_LAYER_ID, ZONE_LAYER_PROPERTIES>& LayerProperties() const
{
return m_layerProperties;
}
void SetLayerProperties( const std::map<PCB_LAYER_ID, ZONE_LAYER_PROPERTIES>& aOther );
const std::optional<VECTOR2I>& HatchingOffset( PCB_LAYER_ID aLayer ) const;
const wxString& GetZoneName() const { return m_zoneName; }
void SetZoneName( const wxString& aName ) { m_zoneName = aName; }
@ -849,6 +868,8 @@ protected:
LSET m_layerSet;
std::map<PCB_LAYER_ID, ZONE_LAYER_PROPERTIES> m_layerProperties;
/* Priority: when a zone outline is inside and other zone, if its priority is higher
* the other zone priority, it will be created inside.
* if priorities are equal, a DRC error is set

View File

@ -50,6 +50,8 @@
#include <thread_pool.h>
#include <math/util.h> // for KiROUND
#include "zone_filler.h"
#include "project.h"
#include "project/project_local_settings.h"
// Helper classes for connect_nearby_polys
class RESULTS
@ -881,6 +883,24 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE*>& aZones, bool aCheck, wxWindow*
}
}
if( ( m_board->GetProject()
&& m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill ) )
{
KIDIALOG dlg( aParent, _( "Prototype zone fill enabled. Disable setting and refill?" ),
_( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
dlg.SetOKCancelLabels( _( "Disable and refill" ), _( "Continue without Refill" ) );
dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
if( dlg.ShowModal() == wxID_OK )
{
m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill = false;
}
else if( !outOfDate )
{
return false;
}
}
if( outOfDate )
{
KIDIALOG dlg( aParent, _( "Zone fills are out-of-date. Refill?" ),
@ -1812,7 +1832,9 @@ bool ZONE_FILLER::fillCopperZone( const ZONE* aZone, PCB_LAYER_ID aLayer, PCB_LA
* Process the hatch pattern (note that we do this while deflated)
*/
if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN
&& ( !m_board->GetProject()
|| !m_board->GetProject()->GetLocalSettings().m_PrototypeZoneFill ) )
{
if( !addHatchFillTypeOnZone( aZone, aLayer, aDebugLayer, aFillPolys ) )
return false;
@ -2379,31 +2401,53 @@ bool ZONE_FILLER::addHatchFillTypeOnZone( const ZONE* aZone, PCB_LAYER_ID aLayer
// Build holes
SHAPE_POLY_SET holes;
for( int xx = 0; ; xx++ )
VECTOR2I offset_opt = VECTOR2I();
bool zone_has_offset = false;
if( aZone->LayerProperties().contains( aLayer ) )
{
int xpos = xx * gridsize;
zone_has_offset = aZone->HatchingOffset( aLayer ).has_value();
if( xpos > bbox.GetWidth() )
break;
offset_opt = aZone->HatchingOffset( aLayer ).value_or( VECTOR2I( 0, 0 ) );
}
for( int yy = 0; ; yy++ )
if( !zone_has_offset )
{
if( m_board->GetDesignSettings().GetDefaultZoneSettings().m_layerProperties.contains(
aLayer ) )
{
int ypos = yy * gridsize;
const ZONE_LAYER_PROPERTIES& properties =
m_board->GetDesignSettings().GetDefaultZoneSettings().m_layerProperties.at(
aLayer );
if( ypos > bbox.GetHeight() )
break;
offset_opt = properties.hatching_offset.value_or( VECTOR2I( 0, 0 ) );
}
}
int x_offset = bbox.GetX() - ( bbox.GetX() ) % gridsize - gridsize;
int y_offset = bbox.GetY() - ( bbox.GetY() ) % gridsize - gridsize;
for( int xx = x_offset; xx <= bbox.GetRight(); xx += gridsize )
{
for( int yy = y_offset; yy <= bbox.GetBottom(); yy += gridsize )
{
// Generate hole
SHAPE_LINE_CHAIN hole( hole_base );
hole.Move( VECTOR2I( xpos, ypos ) );
hole.Move( VECTOR2I( xx, yy ) );
if( !aZone->GetHatchOrientation().IsZero() )
{
hole.Rotate( aZone->GetHatchOrientation() );
}
hole.Move( VECTOR2I( offset_opt.x % gridsize, offset_opt.y % gridsize ) );
holes.AddOutline( hole );
}
}
holes.Move( bbox.GetPosition() );
if( !aZone->GetHatchOrientation().IsZero() )
holes.Rotate( aZone->GetHatchOrientation() );
DUMP_POLYS_TO_COPPER_LAYER( holes, In10_Cu, wxT( "hatch-holes" ) );

View File

@ -260,7 +260,7 @@ void DIALOG_ZONE_MANAGER::OnOk( wxCommandEvent& aEvt )
if( m_zoneInfo )
{
if( std::shared_ptr<ZONE_SETTINGS> zone = m_panelZoneProperties->GetZoneSettings() )
*m_zoneInfo = *zone;
m_zoneInfo->CopyFrom( *zone, false );
}
aEvt.Skip();

View File

@ -35,6 +35,11 @@
#include <wx/dataview.h>
#include <widgets/color_swatch.h>
bool ZONE_LAYER_PROPERTIES::operator==( const ZONE_LAYER_PROPERTIES& aOther ) const
{
return hatching_offset == aOther.hatching_offset;
}
ZONE_SETTINGS::ZONE_SETTINGS()
{
m_ZonePriority = 0;
@ -124,6 +129,10 @@ bool ZONE_SETTINGS::operator==( const ZONE_SETTINGS& aOther ) const
if( m_removeIslands != aOther.m_removeIslands ) return false;
if( m_minIslandArea != aOther.m_minIslandArea ) return false;
if( !std::equal( std::begin( m_layerProperties ), std::end( m_layerProperties ),
std::begin( aOther.m_layerProperties ) ) )
return false;
// Currently, the teardrop area type is not really a ZONE_SETTINGS parameter,
// but a ZONE parameter only.
// However it can be used in dialogs
@ -170,6 +179,11 @@ ZONE_SETTINGS& ZONE_SETTINGS::operator << ( const ZONE& aSource )
m_removeIslands = aSource.GetIslandRemovalMode();
m_minIslandArea = aSource.GetMinIslandArea();
m_layerProperties.clear();
std::ranges::copy( aSource.LayerProperties(),
std::inserter( m_layerProperties, std::end( m_layerProperties ) ) );
// Currently, the teardrop area type is not really a ZONE_SETTINGS parameter,
// but a ZONE parameter only.
// However it can be used in dialogs
@ -220,7 +234,10 @@ void ZONE_SETTINGS::ExportSetting( ZONE& aTarget, bool aFullExport ) const
if( aFullExport )
{
aTarget.SetAssignedPriority( m_ZonePriority );
aTarget.SetLayerProperties( m_layerProperties );
aTarget.SetLayerSet( m_Layers );
aTarget.SetZoneName( m_Name );
if( !m_isRuleArea )
@ -233,6 +250,56 @@ void ZONE_SETTINGS::ExportSetting( ZONE& aTarget, bool aFullExport ) const
m_BorderHatchPitch, true );
}
void ZONE_SETTINGS::CopyFrom( const ZONE_SETTINGS& aOther, bool aCopyFull )
{
// clang-format off
m_ZonePriority = aOther.m_ZonePriority;
m_FillMode = aOther.m_FillMode;
m_ZoneClearance = aOther.m_ZoneClearance;
m_ZoneMinThickness = aOther.m_ZoneMinThickness;
m_HatchThickness = aOther.m_HatchThickness;
m_HatchGap = aOther.m_HatchGap;
m_HatchOrientation = aOther.m_HatchOrientation;
m_HatchSmoothingLevel = aOther.m_HatchSmoothingLevel;
m_HatchSmoothingValue = aOther.m_HatchSmoothingValue;
m_HatchBorderAlgorithm = aOther.m_HatchBorderAlgorithm;
m_HatchHoleMinArea = aOther.m_HatchHoleMinArea;
m_NetcodeSelection = aOther.m_NetcodeSelection;
m_Name = aOther.m_Name;
m_ZoneBorderDisplayStyle = aOther.m_ZoneBorderDisplayStyle;
m_BorderHatchPitch = aOther.m_BorderHatchPitch;
m_ThermalReliefGap = aOther.m_ThermalReliefGap;
m_ThermalReliefSpokeWidth = aOther.m_ThermalReliefSpokeWidth;
m_padConnection = aOther.m_padConnection;
m_cornerSmoothingType = aOther.m_cornerSmoothingType;
m_cornerRadius = aOther.m_cornerRadius;
m_isRuleArea = aOther.m_isRuleArea;
m_ruleAreaPlacementEnabled = aOther.m_ruleAreaPlacementEnabled;
m_ruleAreaPlacementSourceType = aOther.m_ruleAreaPlacementSourceType;
m_ruleAreaPlacementSource = aOther.m_ruleAreaPlacementSource;
m_keepoutDoNotAllowCopperPour = aOther.m_keepoutDoNotAllowCopperPour;
m_keepoutDoNotAllowVias = aOther.m_keepoutDoNotAllowVias;
m_keepoutDoNotAllowTracks = aOther.m_keepoutDoNotAllowTracks;
m_keepoutDoNotAllowPads = aOther.m_keepoutDoNotAllowPads;
m_keepoutDoNotAllowFootprints = aOther.m_keepoutDoNotAllowFootprints;
m_Locked = aOther.m_Locked;
m_removeIslands = aOther.m_removeIslands;
m_minIslandArea = aOther.m_minIslandArea;
// clang-format on
if( aCopyFull )
{
m_layerProperties.clear();
std::ranges::copy( aOther.m_layerProperties,
std::inserter( m_layerProperties, std::end( m_layerProperties ) ) );
m_TeardropType = aOther.m_TeardropType;
m_Layers = aOther.m_Layers;
}
}
void ZONE_SETTINGS::SetCornerRadius( int aRadius )
{

View File

@ -30,6 +30,8 @@
#ifndef ZONE_SETTINGS_H_
#define ZONE_SETTINGS_H_
#include <optional>
#include <map>
#include <layer_ids.h>
#include <lset.h>
#include <zones.h>
@ -44,6 +46,13 @@ enum class ZONE_FILL_MODE
HATCH_PATTERN = 1 // fill zone using a grid pattern
};
struct ZONE_LAYER_PROPERTIES
{
std::optional<VECTOR2I> hatching_offset;
bool operator==( const ZONE_LAYER_PROPERTIES& aOther ) const;
};
/// Zone border styles
enum class ZONE_BORDER_DISPLAY_STYLE
@ -120,6 +129,8 @@ public:
*/
TEARDROP_TYPE m_TeardropType;
std::map<PCB_LAYER_ID, ZONE_LAYER_PROPERTIES> m_layerProperties;
private:
int m_cornerSmoothingType; // Corner smoothing type
unsigned int m_cornerRadius; // Corner chamfer distance / fillet radius
@ -187,6 +198,19 @@ public:
*/
void ExportSetting( ZONE& aTarget, bool aFullExport = true ) const;
/**
* Function CopyFrom
* copy settings from a different ZONE_SETTINGS object
*
* @param aOther the other ZONE_SETTINGS
* @param aCopyFull if false: some parameters are not copied.
* This option is used specifically to copy zone settings from
* a zone to the default zone settings.
* There, the layer information is not needed, plus layer specific
* properties should not be overridden in the zone default settings.
*/
void CopyFrom( const ZONE_SETTINGS& aOther, bool aCopyFull = true );
void SetCornerSmoothingType( int aType) { m_cornerSmoothingType = aType; }
int GetCornerSmoothingType() const { return m_cornerSmoothingType; }

View File

LOADING design file

View File

LOADING design file

View File

@ -96,6 +96,7 @@ BOOST_AUTO_TEST_CASE( Issue19775_ZoneLayerWildcards )
BOOST_CHECK( z->GetLayerSet().Contains( F_Cu ) && z->GetLayerSet().Contains( B_Cu ) );
BOOST_CHECK( z->GetFilledPolysList( F_Cu )->TotalVertices() > 0 );
BOOST_CHECK( z->GetFilledPolysList( B_Cu )->TotalVertices() > 0 );
BOOST_CHECK( z->LayerProperties().contains( F_Cu ) );
}
}