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:
parent
b0eef3ee28
commit
27edf0b949
api/proto/board
common
include/project
pcbnew
edit_zone_helpers.cpp
pcb_io/kicad_sexpr
tools
zone.cppzone.hzone_filler.cppzone_manager
zone_settings.cppzone_settings.hqa
data/pcbnew
tests/pcbnew/pcb_io/kicad_sexpr
@ -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
|
||||
|
@ -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
|
||||
|
@ -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, "" ) );
|
||||
|
@ -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
|
||||
|
@ -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 );
|
||||
|
@ -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 ),
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
||||
/**
|
||||
|
@ -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 );
|
||||
|
||||
|
@ -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 );
|
||||
|
@ -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
|
||||
|
@ -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" ) );
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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 )
|
||||
{
|
||||
|
@ -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; }
|
||||
|
||||
|
LOADING design file
LOADING design 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 ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user