From f0b9e67212a4a7a7ce1fd5730c21a3856b134055 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Fri, 29 Jul 2022 20:56:55 +0100 Subject: [PATCH] Add ignore-line-widths mode to CONVERT_TOOL. Fixes https://gitlab.com/kicad/code/kicad/issues/5911 --- include/eda_shape.h | 14 +- pcbnew/dialogs/dialog_copper_zones.cpp | 125 +++++++---- .../dialog_non_copper_zones_properties.cpp | 81 +++++-- .../dialogs/dialog_rule_area_properties.cpp | 70 ++++-- pcbnew/pcbnew_settings.h | 9 + pcbnew/tools/convert_tool.cpp | 201 +++++++++++++++--- pcbnew/tools/convert_tool.h | 3 +- pcbnew/zones.h | 13 +- 8 files changed, 407 insertions(+), 109 deletions(-) diff --git a/include/eda_shape.h b/include/eda_shape.h index 54304cb6c5..d6c73f577d 100644 --- a/include/eda_shape.h +++ b/include/eda_shape.h @@ -247,7 +247,19 @@ public: */ bool IsPolyShapeValid() const; - void SetPolyShape( const SHAPE_POLY_SET& aShape ) { m_poly = aShape; } + void SetPolyShape( const SHAPE_POLY_SET& aShape ) + { + m_poly = aShape; + + for( int ii = 0; ii < m_poly.OutlineCount(); ++ii ) + { + if( m_poly.HoleCount( ii ) ) + { + m_poly.Fracture( SHAPE_POLY_SET::PM_FAST ); + break; + } + } + } void SetPolyPoints( const std::vector& aPoints ); diff --git a/pcbnew/dialogs/dialog_copper_zones.cpp b/pcbnew/dialogs/dialog_copper_zones.cpp index 23597b00cf..fe919197d5 100644 --- a/pcbnew/dialogs/dialog_copper_zones.cpp +++ b/pcbnew/dialogs/dialog_copper_zones.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -43,7 +42,8 @@ class DIALOG_COPPER_ZONE : public DIALOG_COPPER_ZONE_BASE { public: - DIALOG_COPPER_ZONE( PCB_BASE_FRAME* aParent, ZONE_SETTINGS* aSettings ); + DIALOG_COPPER_ZONE( PCB_BASE_FRAME* aParent, ZONE_SETTINGS* aSettings, + CONVERT_SETTINGS* aConvertSettings ); private: using NET_FILTER = std::unique_ptr; @@ -56,36 +56,6 @@ private: static constexpr int HIDE_ANONYMOUS_NETS{ 1 << 0 }; static constexpr int SORT_BY_PAD_COUNT{ 1 << 1 }; - PCB_BASE_FRAME* m_Parent; - - bool m_settingsExported; // settings will be written to all other zones - - ZONE_SETTINGS m_settings; - ZONE_SETTINGS* m_ptr; - bool m_netSortingByPadCount; - NET_FILTER_LIST m_showNetsFilter; - - int m_cornerSmoothingType; - int m_maxNetCode; - int m_currentlySelectedNetcode; - UNIT_BINDER m_outlineHatchPitch; - - UNIT_BINDER m_cornerRadius; - UNIT_BINDER m_clearance; - UNIT_BINDER m_minWidth; - UNIT_BINDER m_antipadClearance; - UNIT_BINDER m_spokeWidth; - - UNIT_BINDER m_gridStyleRotation; - UNIT_BINDER m_gridStyleThickness; - UNIT_BINDER m_gridStyleGap; - UNIT_BINDER m_islandThreshold; - bool m_hideAutoGeneratedNets; - bool m_isTeardrop; - - std::map m_netNameToNetCode; - std::vector m_netInfoItemList; - bool TransferDataToWindow() override; bool TransferDataFromWindow() override; @@ -127,12 +97,48 @@ private: void handleRemoveIslandsSelection(); void storePersistentNetSortConfigurations(); void loadPersistentNetSortConfigurations(); + +private: + PCB_BASE_FRAME* m_Parent; + + bool m_settingsExported; // settings will be written to all other zones + + ZONE_SETTINGS m_settings; + ZONE_SETTINGS* m_ptr; + bool m_netSortingByPadCount; + NET_FILTER_LIST m_showNetsFilter; + + int m_cornerSmoothingType; + int m_maxNetCode; + int m_currentlySelectedNetcode; + UNIT_BINDER m_outlineHatchPitch; + + UNIT_BINDER m_cornerRadius; + UNIT_BINDER m_clearance; + UNIT_BINDER m_minWidth; + UNIT_BINDER m_antipadClearance; + UNIT_BINDER m_spokeWidth; + + UNIT_BINDER m_gridStyleRotation; + UNIT_BINDER m_gridStyleThickness; + UNIT_BINDER m_gridStyleGap; + UNIT_BINDER m_islandThreshold; + bool m_hideAutoGeneratedNets; + bool m_isTeardrop; + + std::map m_netNameToNetCode; + std::vector m_netInfoItemList; + + CONVERT_SETTINGS* m_convertSettings; + wxCheckBox* m_cbIgnoreLineWidths; + wxCheckBox* m_cbDeleteOriginals; }; -int InvokeCopperZonesEditor( PCB_BASE_FRAME* aCaller, ZONE_SETTINGS* aSettings ) +int InvokeCopperZonesEditor( PCB_BASE_FRAME* aCaller, ZONE_SETTINGS* aSettings, + CONVERT_SETTINGS* aConvertSettings ) { - DIALOG_COPPER_ZONE dlg( aCaller, aSettings ); + DIALOG_COPPER_ZONE dlg( aCaller, aSettings, aConvertSettings ); return dlg.ShowQuasiModal(); } @@ -164,7 +170,8 @@ static bool sortNetsByNames( const NETINFO_ITEM* a, const NETINFO_ITEM* b ) } -DIALOG_COPPER_ZONE::DIALOG_COPPER_ZONE( PCB_BASE_FRAME* aParent, ZONE_SETTINGS* aSettings ) : +DIALOG_COPPER_ZONE::DIALOG_COPPER_ZONE( PCB_BASE_FRAME* aParent, ZONE_SETTINGS* aSettings, + CONVERT_SETTINGS* aConvertSettings ) : DIALOG_COPPER_ZONE_BASE( aParent ), m_cornerSmoothingType( ZONE_SETTINGS::SMOOTHING_UNDEFINED ), m_outlineHatchPitch( aParent, m_stBorderHatchPitchText, @@ -181,7 +188,8 @@ DIALOG_COPPER_ZONE::DIALOG_COPPER_ZONE( PCB_BASE_FRAME* aParent, ZONE_SETTINGS* m_gridStyleGap( aParent, m_staticTextGridGap, m_tcGridStyleGap, m_GridStyleGapUnits ), m_islandThreshold( aParent, m_islandThresholdLabel, m_tcIslandThreshold, m_islandThresholdUnits ), - m_hideAutoGeneratedNets{ false } + m_hideAutoGeneratedNets{ false }, + m_convertSettings( aConvertSettings ) { m_Parent = aParent; @@ -211,6 +219,29 @@ DIALOG_COPPER_ZONE::DIALOG_COPPER_ZONE( PCB_BASE_FRAME* aParent, ZONE_SETTINGS* break; } + if( aConvertSettings ) + { + wxStaticBox* bConvertBox = new wxStaticBox( this, wxID_ANY, + _( "Conversion Settings" ) ); + wxStaticBoxSizer* bConvertSizer = new wxStaticBoxSizer( bConvertBox, wxVERTICAL ); + + m_cbIgnoreLineWidths = new wxCheckBox( this, wxID_ANY, + _( "Ignore source object line widths" ) ); + bConvertSizer->Add( m_cbIgnoreLineWidths, 0, wxLEFT|wxRIGHT, 5 ); + + m_cbDeleteOriginals = new wxCheckBox( this, wxID_ANY, + _( "Delete source objects after conversion" ) ); + bConvertSizer->Add( m_cbDeleteOriginals, 0, wxALL, 5 ); + + GetSizer()->Insert( 0, bConvertSizer, 0, wxALL|wxEXPAND, 10 ); + + wxStaticLine* line = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, + wxLI_HORIZONTAL ); + GetSizer()->Insert( 1, line, 0, wxLEFT|wxRIGHT|wxEXPAND, 10 ); + + SetTitle( _( "Convert to Copper Zone" ) ); + } + m_settingsExported = false; m_currentlySelectedNetcode = INVALID_NET_CODE; m_maxNetCode = INVALID_NET_CODE; @@ -238,6 +269,12 @@ DIALOG_COPPER_ZONE::DIALOG_COPPER_ZONE( PCB_BASE_FRAME* aParent, ZONE_SETTINGS* bool DIALOG_COPPER_ZONE::TransferDataToWindow() { + if( m_convertSettings ) + { + m_cbIgnoreLineWidths->SetValue( m_convertSettings->m_IgnoreLineWidths ); + m_cbDeleteOriginals->SetValue( m_convertSettings->m_DeleteOriginals ); + } + m_cbLocked->SetValue( m_settings.m_Locked ); m_cornerSmoothingChoice->SetSelection( m_settings.GetCornerSmoothingType() ); m_cornerRadius.SetValue( m_settings.GetCornerRadius() ); @@ -461,6 +498,12 @@ bool DIALOG_COPPER_ZONE::TransferDataFromWindow() if( !AcceptOptions() ) return false; + if( m_convertSettings ) + { + m_convertSettings->m_IgnoreLineWidths = m_cbIgnoreLineWidths->GetValue(); + m_convertSettings->m_DeleteOriginals = m_cbDeleteOriginals->GetValue(); + } + m_settings.m_HatchOrientation = m_gridStyleRotation.GetAngleValue(); m_settings.m_HatchThickness = m_gridStyleThickness.GetValue(); m_settings.m_HatchGap = m_gridStyleGap.GetValue(); @@ -917,12 +960,14 @@ wxString DIALOG_COPPER_ZONE::getUnescapedNetName( const NETINFO_ITEM* net ) void DIALOG_COPPER_ZONE::updateInfoBar() { - if( m_currentlySelectedNetcode <= INVALID_NET_CODE && !m_copperZoneInfo->IsShown() ) + if( m_currentlySelectedNetcode <= INVALID_NET_CODE + && !m_copperZoneInfo->IsShown() + && !m_convertSettings ) { - m_copperZoneInfo->ShowMessage( - _( "Selecting will create an isolated copper island." ), wxICON_WARNING ); + m_copperZoneInfo->ShowMessage( _( " will result in an isolated copper island." ), + wxICON_WARNING ); } - else if( m_currentlySelectedNetcode > INVALID_NET_CODE && m_copperZoneInfo->IsShown() ) + else if( m_copperZoneInfo->IsShown() ) { m_copperZoneInfo->Dismiss(); } diff --git a/pcbnew/dialogs/dialog_non_copper_zones_properties.cpp b/pcbnew/dialogs/dialog_non_copper_zones_properties.cpp index f82eb6dddc..ee8a8ed225 100644 --- a/pcbnew/dialogs/dialog_non_copper_zones_properties.cpp +++ b/pcbnew/dialogs/dialog_non_copper_zones_properties.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -35,18 +36,11 @@ class DIALOG_NON_COPPER_ZONES_EDITOR : public DIALOG_NONCOPPER_ZONES_PROPERTIES_BASE { -private: - PCB_BASE_FRAME* m_parent; - ZONE_SETTINGS* m_ptr; - ZONE_SETTINGS m_settings; // working copy of zone settings - UNIT_BINDER m_outlineHatchPitch; - UNIT_BINDER m_minWidth; - UNIT_BINDER m_hatchRotation; - UNIT_BINDER m_hatchWidth; - UNIT_BINDER m_hatchGap; - int m_cornerSmoothingType; - UNIT_BINDER m_cornerRadius; +public: + DIALOG_NON_COPPER_ZONES_EDITOR( PCB_BASE_FRAME* aParent, ZONE_SETTINGS* aSettings, + CONVERT_SETTINGS* aConvertSettings ); +private: bool TransferDataToWindow() override; bool TransferDataFromWindow() override; @@ -54,14 +48,28 @@ private: void OnLayerSelection( wxDataViewEvent& event ) override; void OnUpdateUI( wxUpdateUIEvent& ) override; -public: - DIALOG_NON_COPPER_ZONES_EDITOR( PCB_BASE_FRAME* aParent, ZONE_SETTINGS* aSettings ); +private: + PCB_BASE_FRAME* m_parent; + ZONE_SETTINGS* m_ptr; + ZONE_SETTINGS m_settings; // working copy of zone settings + UNIT_BINDER m_outlineHatchPitch; + UNIT_BINDER m_minWidth; + UNIT_BINDER m_hatchRotation; + UNIT_BINDER m_hatchWidth; + UNIT_BINDER m_hatchGap; + int m_cornerSmoothingType; + UNIT_BINDER m_cornerRadius; + + CONVERT_SETTINGS* m_convertSettings; + wxCheckBox* m_cbIgnoreLineWidths; + wxCheckBox* m_cbDeleteOriginals; }; -int InvokeNonCopperZonesEditor( PCB_BASE_FRAME* aParent, ZONE_SETTINGS* aSettings ) +int InvokeNonCopperZonesEditor( PCB_BASE_FRAME* aParent, ZONE_SETTINGS* aSettings, + CONVERT_SETTINGS* aConvertSettings ) { - DIALOG_NON_COPPER_ZONES_EDITOR dlg( aParent, aSettings ); + DIALOG_NON_COPPER_ZONES_EDITOR dlg( aParent, aSettings, aConvertSettings ); return dlg.ShowQuasiModal(); } @@ -69,7 +77,8 @@ int InvokeNonCopperZonesEditor( PCB_BASE_FRAME* aParent, ZONE_SETTINGS* aSetting #define MIN_THICKNESS 10*IU_PER_MILS DIALOG_NON_COPPER_ZONES_EDITOR::DIALOG_NON_COPPER_ZONES_EDITOR( PCB_BASE_FRAME* aParent, - ZONE_SETTINGS* aSettings ) : + ZONE_SETTINGS* aSettings, + CONVERT_SETTINGS* aConvertSettings ) : DIALOG_NONCOPPER_ZONES_PROPERTIES_BASE( aParent ), m_outlineHatchPitch( aParent, m_stBorderHatchPitchText, m_outlineHatchPitchCtrl, m_outlineHatchUnits ), @@ -78,15 +87,41 @@ DIALOG_NON_COPPER_ZONES_EDITOR::DIALOG_NON_COPPER_ZONES_EDITOR( PCB_BASE_FRAME* m_hatchWidth( aParent, m_hatchWidthLabel, m_hatchWidthCtrl, m_hatchWidthUnits), m_hatchGap( aParent, m_hatchGapLabel, m_hatchGapCtrl, m_hatchGapUnits ), m_cornerSmoothingType( ZONE_SETTINGS::SMOOTHING_UNDEFINED ), - m_cornerRadius( aParent, m_cornerRadiusLabel, m_cornerRadiusCtrl, m_cornerRadiusUnits ) + m_cornerRadius( aParent, m_cornerRadiusLabel, m_cornerRadiusCtrl, m_cornerRadiusUnits ), + m_convertSettings( aConvertSettings ) { m_parent = aParent; m_ptr = aSettings; m_settings = *aSettings; + if( aConvertSettings ) + { + wxStaticBox* bConvertBox = new wxStaticBox( this, wxID_ANY, + _( "Conversion Settings" ) ); + wxStaticBoxSizer* bConvertSizer = new wxStaticBoxSizer( bConvertBox, wxVERTICAL ); + + m_cbIgnoreLineWidths = new wxCheckBox( this, wxID_ANY, + _( "Ignore source object line widths" ) ); + bConvertSizer->Add( m_cbIgnoreLineWidths, 0, wxLEFT|wxRIGHT, 5 ); + + m_cbDeleteOriginals = new wxCheckBox( this, wxID_ANY, + _( "Delete source objects after conversion" ) ); + bConvertSizer->Add( m_cbDeleteOriginals, 0, wxALL, 5 ); + + GetSizer()->Insert( 0, bConvertSizer, 0, wxALL|wxEXPAND, 10 ); + + wxStaticLine* line = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, + wxLI_HORIZONTAL ); + GetSizer()->Insert( 1, line, 0, wxLEFT|wxRIGHT|wxEXPAND, 10 ); + + SetTitle( _( "Convert to Non Copper Zone" ) ); + } + bool fpEditorMode = m_parent->IsType( FRAME_FOOTPRINT_EDITOR ); + m_staticTextLayerSelection->SetFont( KIUI::GetInfoFont( this ) ); + m_settings.SetupLayersList( m_layers, m_parent, LSET::AllNonCuMask(), fpEditorMode ); SetupStandardButtons(); @@ -113,6 +148,12 @@ void DIALOG_NON_COPPER_ZONES_EDITOR::OnUpdateUI( wxUpdateUIEvent& ) bool DIALOG_NON_COPPER_ZONES_EDITOR::TransferDataToWindow() { + if( m_convertSettings ) + { + m_cbIgnoreLineWidths->SetValue( m_convertSettings->m_IgnoreLineWidths ); + m_cbDeleteOriginals->SetValue( m_convertSettings->m_DeleteOriginals ); + } + m_cornerSmoothingChoice->SetSelection( m_settings.GetCornerSmoothingType() ); m_cornerRadius.SetValue( m_settings.GetCornerRadius() ); @@ -199,6 +240,12 @@ void DIALOG_NON_COPPER_ZONES_EDITOR::OnLayerSelection( wxDataViewEvent& event ) bool DIALOG_NON_COPPER_ZONES_EDITOR::TransferDataFromWindow() { + if( m_convertSettings ) + { + m_convertSettings->m_IgnoreLineWidths = m_cbIgnoreLineWidths->GetValue(); + m_convertSettings->m_DeleteOriginals = m_cbDeleteOriginals->GetValue(); + } + m_settings.SetCornerSmoothingType( m_cornerSmoothingChoice->GetSelection() ); m_settings.SetCornerRadius( m_settings.GetCornerSmoothingType() == ZONE_SETTINGS::SMOOTHING_NONE diff --git a/pcbnew/dialogs/dialog_rule_area_properties.cpp b/pcbnew/dialogs/dialog_rule_area_properties.cpp index aaf2024466..945f70f5b6 100644 --- a/pcbnew/dialogs/dialog_rule_area_properties.cpp +++ b/pcbnew/dialogs/dialog_rule_area_properties.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #define LAYER_LIST_COLUMN_CHECK 0 #define LAYER_LIST_COLUMN_ICON 1 @@ -40,36 +41,44 @@ class DIALOG_RULE_AREA_PROPERTIES : public DIALOG_RULE_AREA_PROPERTIES_BASE { public: - DIALOG_RULE_AREA_PROPERTIES( PCB_BASE_FRAME* aParent, ZONE_SETTINGS* aSettings ); + DIALOG_RULE_AREA_PROPERTIES( PCB_BASE_FRAME* aParent, ZONE_SETTINGS* aSettings, + CONVERT_SETTINGS* aConvertSettings ); private: - UNIT_BINDER m_outlineHatchPitch; - PCB_BASE_FRAME* m_parent; - ZONE_SETTINGS m_zonesettings; ///< the working copy of zone settings - ZONE_SETTINGS* m_ptr; ///< the pointer to the zone settings - ///< of the zone to edit - bool m_isFpEditor; - bool TransferDataToWindow() override; bool TransferDataFromWindow() override; void OnLayerSelection( wxDataViewEvent& event ) override; + +private: + UNIT_BINDER m_outlineHatchPitch; + PCB_BASE_FRAME* m_parent; + ZONE_SETTINGS m_zonesettings; ///< the working copy of zone settings + ZONE_SETTINGS* m_ptr; ///< the pointer to the zone settings of the zone to edit + bool m_isFpEditor; + + CONVERT_SETTINGS* m_convertSettings; + wxCheckBox* m_cbIgnoreLineWidths; + wxCheckBox* m_cbDeleteOriginals; }; -int InvokeRuleAreaEditor( PCB_BASE_FRAME* aCaller, ZONE_SETTINGS* aSettings ) +int InvokeRuleAreaEditor( PCB_BASE_FRAME* aCaller, ZONE_SETTINGS* aZoneSettings, + CONVERT_SETTINGS* aConvertSettings ) { - DIALOG_RULE_AREA_PROPERTIES dlg( aCaller, aSettings ); + DIALOG_RULE_AREA_PROPERTIES dlg( aCaller, aZoneSettings, aConvertSettings ); return dlg.ShowModal(); } DIALOG_RULE_AREA_PROPERTIES::DIALOG_RULE_AREA_PROPERTIES( PCB_BASE_FRAME* aParent, - ZONE_SETTINGS* aSettings ) : + ZONE_SETTINGS* aSettings, + CONVERT_SETTINGS* aConvertSettings ) : DIALOG_RULE_AREA_PROPERTIES_BASE( aParent ), m_outlineHatchPitch( aParent, m_stBorderHatchPitchText, - m_outlineHatchPitchCtrl, m_outlineHatchUnits ) + m_outlineHatchPitchCtrl, m_outlineHatchUnits ), + m_convertSettings( aConvertSettings ) { m_parent = aParent; @@ -77,6 +86,31 @@ DIALOG_RULE_AREA_PROPERTIES::DIALOG_RULE_AREA_PROPERTIES( PCB_BASE_FRAME* aParen m_ptr = aSettings; m_zonesettings = *aSettings; + if( aConvertSettings ) + { + wxBoxSizer* bConvertSizer = new wxBoxSizer( wxVERTICAL ); + + wxStaticText* conversionSettingsLabel = new wxStaticText( this, wxID_ANY, + _( "Conversion settings:" ) ); + bConvertSizer->Add( conversionSettingsLabel, 0, wxLEFT|wxRIGHT|wxEXPAND, 5 ); + + m_cbIgnoreLineWidths = new wxCheckBox( this, wxID_ANY, + _( "Ignore source object line widths" ) ); + bConvertSizer->Add( m_cbIgnoreLineWidths, 0, wxLEFT|wxRIGHT|wxTOP, 5 ); + + m_cbDeleteOriginals = new wxCheckBox( this, wxID_ANY, + _( "Delete source objects after conversion" ) ); + bConvertSizer->Add( m_cbDeleteOriginals, 0, wxALL, 5 ); + + GetSizer()->Insert( 0, bConvertSizer, 0, wxALL|wxEXPAND, 10 ); + + wxStaticLine* line = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, + wxLI_HORIZONTAL ); + GetSizer()->Insert( 1, line, 0, wxLEFT|wxRIGHT|wxEXPAND, 10 ); + + SetTitle( _( "Convert to Rule Area" ) ); + } + m_isFpEditor = m_parent->IsType( FRAME_FOOTPRINT_EDITOR ); BOARD* board = m_parent->GetBoard(); @@ -92,6 +126,12 @@ DIALOG_RULE_AREA_PROPERTIES::DIALOG_RULE_AREA_PROPERTIES( PCB_BASE_FRAME* aParen bool DIALOG_RULE_AREA_PROPERTIES::TransferDataToWindow() { + if( m_convertSettings ) + { + m_cbIgnoreLineWidths->SetValue( m_convertSettings->m_IgnoreLineWidths ); + m_cbDeleteOriginals->SetValue( m_convertSettings->m_DeleteOriginals ); + } + // Init keepout parameters: m_cbTracksCtrl->SetValue( m_zonesettings.GetDoNotAllowTracks() ); m_cbViasCtrl->SetValue( m_zonesettings.GetDoNotAllowVias() ); @@ -147,6 +187,12 @@ void DIALOG_RULE_AREA_PROPERTIES::OnLayerSelection( wxDataViewEvent& event ) bool DIALOG_RULE_AREA_PROPERTIES::TransferDataFromWindow() { + if( m_convertSettings ) + { + m_convertSettings->m_IgnoreLineWidths = m_cbIgnoreLineWidths->GetValue(); + m_convertSettings->m_DeleteOriginals = m_cbDeleteOriginals->GetValue(); + } + // Init keepout parameters: m_zonesettings.SetIsRuleArea( true ); m_zonesettings.SetDoNotAllowTracks( m_cbTracksCtrl->GetValue() ); diff --git a/pcbnew/pcbnew_settings.h b/pcbnew/pcbnew_settings.h index 2aa8d880f8..68c855ceb3 100644 --- a/pcbnew/pcbnew_settings.h +++ b/pcbnew/pcbnew_settings.h @@ -31,6 +31,15 @@ namespace PNS } +// Settings for the CONVERT_TOOL. +struct CONVERT_SETTINGS +{ + bool m_IgnoreLineWidths; + bool m_DeleteOriginals; +}; + + + enum class MAGNETIC_OPTIONS { NO_EFFECT = 0, diff --git a/pcbnew/tools/convert_tool.cpp b/pcbnew/tools/convert_tool.cpp index 234b432d36..fcddf58319 100644 --- a/pcbnew/tools/convert_tool.cpp +++ b/pcbnew/tools/convert_tool.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors. * @author Jon Evans * * This program is free software; you can redistribute it and/or @@ -23,6 +23,10 @@ */ #include +#include +#include +#include +#include #include #include #include @@ -33,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -47,6 +50,75 @@ #include "convert_tool.h" +class CONVERT_SETTINGS_DIALOG : public DIALOG_SHIM +{ +public: + CONVERT_SETTINGS_DIALOG( wxWindow* aParent, CONVERT_SETTINGS* aSettings ) : + DIALOG_SHIM( aParent, wxID_ANY, _( "Conversion Settings" ), wxDefaultPosition, + wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ), + m_settings( aSettings ) + { + wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL ); + wxBoxSizer* topSizer = new wxBoxSizer( wxVERTICAL ); + SetSizer( mainSizer ); + + m_cbIgnoreLineWidths = new wxCheckBox( this, wxID_ANY, + _( "Ignore source object line widths" ) ); + topSizer->Add( m_cbIgnoreLineWidths, 0, wxLEFT|wxRIGHT, 5 ); + + m_cbDeleteOriginals = new wxCheckBox( this, wxID_ANY, + _( "Delete source objects after conversion" ) ); + topSizer->Add( m_cbDeleteOriginals, 0, wxALL, 5 ); + + wxStaticLine* line = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, + wxLI_HORIZONTAL ); + topSizer->Add( line, 0, wxLEFT|wxRIGHT|wxTOP|wxEXPAND, 5 ); + + mainSizer->Add( topSizer, 1, wxALL|wxEXPAND, 10 ); + + wxBoxSizer* buttonsSizer = new wxBoxSizer( wxHORIZONTAL ); + buttonsSizer->AddStretchSpacer(); + + wxStdDialogButtonSizer* sdbSizer = new wxStdDialogButtonSizer(); + wxButton* sdbSizerOK = new wxButton( this, wxID_OK ); + sdbSizer->AddButton( sdbSizerOK ); + wxButton* sdbSizerCancel = new wxButton( this, wxID_CANCEL ); + sdbSizer->AddButton( sdbSizerCancel ); + sdbSizer->Realize(); + + buttonsSizer->Add( sdbSizer, 1, 0, 5 ); + mainSizer->Add( buttonsSizer, 0, wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND, 5 ); + + SetupStandardButtons(); + + finishDialogSettings(); + } + + ~CONVERT_SETTINGS_DIALOG() + {}; + +protected: + bool TransferDataToWindow() override + { + m_cbIgnoreLineWidths->SetValue( m_settings->m_IgnoreLineWidths ); + m_cbDeleteOriginals->SetValue( m_settings->m_DeleteOriginals ); + return true; + } + + bool TransferDataFromWindow() override + { + m_settings->m_IgnoreLineWidths = m_cbIgnoreLineWidths->GetValue(); + m_settings->m_DeleteOriginals = m_cbDeleteOriginals->GetValue(); + return true; + } + +private: + CONVERT_SETTINGS* m_settings; + wxCheckBox* m_cbIgnoreLineWidths; + wxCheckBox* m_cbDeleteOriginals; +}; + + CONVERT_TOOL::CONVERT_TOOL() : TOOL_INTERACTIVE( "pcbnew.Convert" ), m_selectionTool( nullptr ), @@ -123,7 +195,12 @@ bool CONVERT_TOOL::Init() int CONVERT_TOOL::CreatePolys( const TOOL_EVENT& aEvent ) { - FOOTPRINT* parentFootprint = nullptr; + std::vector polys; + CONVERT_SETTINGS convertSettings; + PCB_LAYER_ID destLayer = m_frame->GetActiveLayer(); + FOOTPRINT* parentFootprint = nullptr; + bool foundChainedSegs = false; + bool foundFilledShape = false; PCB_SELECTION& selection = m_selectionTool->RequestSelection( []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool ) @@ -133,18 +210,57 @@ int CONVERT_TOOL::CreatePolys( const TOOL_EVENT& aEvent ) if( selection.Empty() ) return 0; - PCB_LAYER_ID destLayer = m_frame->GetActiveLayer(); - SHAPE_POLY_SET polySet; + auto getPolys = + [&]() + { + polys.clear(); - if( !IsCopperLayer( destLayer ) ) - polySet = makePolysFromChainedSegs( selection.GetItems() ); + for( EDA_ITEM* item : selection ) + { + item->ClearTempFlags(); - polySet.Append( makePolysFromGraphics( selection.GetItems() ) ); + if( item->Type() == PCB_SHAPE_T || item->Type() == PCB_FP_SHAPE_T ) + foundFilledShape = static_cast( item )->IsFilled(); + } - if( polySet.IsEmpty() ) + SHAPE_POLY_SET polySet; + + if( convertSettings.m_IgnoreLineWidths ) + { + polySet.Append( makePolysFromChainedSegs( selection.GetItems() ) ); + foundChainedSegs = polySet.OutlineCount() > 0; + } + + polySet.Append( makePolysFromGraphics( selection.GetItems(), + convertSettings.m_IgnoreLineWidths ) ); + + if( polySet.IsEmpty() ) + return false; + + polySet.Simplify( SHAPE_POLY_SET::PM_FAST ); + + for( int ii = 0; ii < polySet.OutlineCount(); ++ii ) + { + polys.emplace_back( SHAPE_POLY_SET( polySet.COutline( ii ) ) ); + + for( int jj = 0; jj < polySet.HoleCount( ii ); ++jj ) + polys.back().AddHole( polySet.Hole( ii, jj ) ); + } + + return true; + }; + + // Pre-flight getPolys(). If we find any chained segments then we default m_IgnoreLineWidths + // to true. + // We also use the pre-flight to keep from putting up any of the dialogs if there's nothing + // to convert. + convertSettings.m_IgnoreLineWidths = true; + convertSettings.m_DeleteOriginals = false; + + if( !getPolys() ) return 0; - polySet.Simplify( SHAPE_POLY_SET::PM_FAST ); + convertSettings.m_IgnoreLineWidths = foundChainedSegs; bool isFootprint = m_frame->IsType( FRAME_FOOTPRINT_EDITOR ); @@ -160,33 +276,28 @@ int CONVERT_TOOL::CreatePolys( const TOOL_EVENT& aEvent ) BOARD_COMMIT commit( m_frame ); - // For now, we convert each outline in the returned shape to its own polygon - std::vector polys; - - for( int ii = 0; ii < polySet.OutlineCount(); ++ii ) - { - polys.emplace_back( SHAPE_POLY_SET( polySet.COutline( ii ) ) ); - - for( int jj = 0; jj < polySet.HoleCount( ii ); ++jj ) - polys.back().AddHole( polySet.Hole( ii, jj ) ); - } - if( aEvent.IsAction( &PCB_ACTIONS::convertToPoly ) ) { + CONVERT_SETTINGS_DIALOG dlg( m_frame, &convertSettings ); + + if( dlg.ShowModal() != wxID_OK ) + return 0; + + if( !getPolys() ) + return 0; + for( const SHAPE_POLY_SET& poly : polys ) { PCB_SHAPE* graphic = isFootprint ? new FP_SHAPE( parentFootprint ) : new PCB_SHAPE; graphic->SetShape( SHAPE_T::POLY ); - graphic->SetFilled( false ); - graphic->SetStroke( STROKE_PARAMS( poly.Outline( 0 ).Width() ) ); + graphic->SetFilled( !convertSettings.m_IgnoreLineWidths || foundFilledShape ); + graphic->SetStroke( STROKE_PARAMS( 0, PLOT_DASH_TYPE::SOLID, COLOR4D::UNSPECIFIED ) ); graphic->SetLayer( destLayer ); graphic->SetPolyShape( poly ); commit.Add( graphic ); } - - commit.Push( _( "Convert shapes to polygon" ) ); } else { @@ -204,22 +315,25 @@ int CONVERT_TOOL::CreatePolys( const TOOL_EVENT& aEvent ) if( aEvent.IsAction( &PCB_ACTIONS::convertToKeepout ) ) { zoneInfo.SetIsRuleArea( true ); - ret = InvokeRuleAreaEditor( frame, &zoneInfo ); + ret = InvokeRuleAreaEditor( frame, &zoneInfo, &convertSettings ); } else if( nonCopper ) { zoneInfo.SetIsRuleArea( false ); - ret = InvokeNonCopperZonesEditor( frame, &zoneInfo ); + ret = InvokeNonCopperZonesEditor( frame, &zoneInfo, &convertSettings ); } else { zoneInfo.SetIsRuleArea( false ); - ret = InvokeCopperZonesEditor( frame, &zoneInfo ); + ret = InvokeCopperZonesEditor( frame, &zoneInfo, &convertSettings ); } if( ret == wxID_CANCEL ) return 0; + if( !getPolys() ) + return 0; + for( const SHAPE_POLY_SET& poly : polys ) { ZONE* zone = isFootprint ? new FP_ZONE( parent ) : new ZONE( parent ); @@ -231,10 +345,22 @@ int CONVERT_TOOL::CreatePolys( const TOOL_EVENT& aEvent ) commit.Add( zone ); } - - commit.Push( _( "Convert shapes to zone" ) ); } + if( convertSettings.m_DeleteOriginals ) + { + for( EDA_ITEM* item : selection ) + { + if( item->GetFlags() & SKIP_STRUCT ) + commit.Remove( item ); + } + } + + if( aEvent.IsAction( &PCB_ACTIONS::convertToPoly ) ) + commit.Push( _( "Convert shapes to polygon" ) ); + else + commit.Push( _( "Convert shapes to zone" ) ); + return 0; } @@ -410,7 +536,8 @@ SHAPE_POLY_SET CONVERT_TOOL::makePolysFromChainedSegs( const std::deque& aItems ) +SHAPE_POLY_SET CONVERT_TOOL::makePolysFromGraphics( const std::deque& aItems, + bool aIgnoreLineWidths ) { BOARD_DESIGN_SETTINGS& bds = m_frame->GetBoard()->GetDesignSettings(); SHAPE_POLY_SET poly; @@ -425,16 +552,22 @@ SHAPE_POLY_SET CONVERT_TOOL::makePolysFromGraphics( const std::deque& case PCB_SHAPE_T: case PCB_FP_SHAPE_T: { - PCB_SHAPE* graphic = static_cast( item ); + PCB_SHAPE* temp = static_cast( item->Clone() ); - graphic->TransformShapeWithClearanceToPolygon( poly, UNDEFINED_LAYER, 0, - bds.m_MaxError, ERROR_INSIDE ); + if( aIgnoreLineWidths ) + temp->SetFilled( true ); + + temp->TransformShapeWithClearanceToPolygon( poly, UNDEFINED_LAYER, 0, + bds.m_MaxError, ERROR_INSIDE, + aIgnoreLineWidths ); + item->SetFlags( SKIP_STRUCT ); break; } case PCB_ZONE_T: case PCB_FP_ZONE_T: poly.Append( *static_cast( item )->Outline() ); + item->SetFlags( SKIP_STRUCT ); break; default: diff --git a/pcbnew/tools/convert_tool.h b/pcbnew/tools/convert_tool.h index 0b19896cf2..ce3c895a34 100644 --- a/pcbnew/tools/convert_tool.h +++ b/pcbnew/tools/convert_tool.h @@ -90,7 +90,8 @@ private: * @param aItems is a list of items to process. * @return a #SHAPE_POLY_SET containing any polygons that were created. */ - SHAPE_POLY_SET makePolysFromGraphics( const std::deque& aItems ); + SHAPE_POLY_SET makePolysFromGraphics( const std::deque& aItems, + bool aIgnoreLineWidths ); PCB_SELECTION_TOOL* m_selectionTool; CONDITIONAL_MENU* m_menu; diff --git a/pcbnew/zones.h b/pcbnew/zones.h index 8023eca8d3..f2d52015ac 100644 --- a/pcbnew/zones.h +++ b/pcbnew/zones.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2008-2014 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -27,6 +27,8 @@ #include +struct CONVERT_SETTINGS; + // Default values in mils for parameters in ZONE #define ZONE_THERMAL_RELIEF_GAP_MIL 20 // default value for ZONE_SETTINGS::m_ThermalReliefGap #define ZONE_THERMAL_RELIEF_COPPER_WIDTH_MIL 20 // default value for ZONE_SETTINGS::m_ThermalReliefCopperBridge @@ -81,7 +83,8 @@ class PCB_BASE_FRAME; * @param aSettings points to the ZONE_SETTINGS to edit. * @return int - tells if user aborted, changed only one zone, or all of them. */ -int InvokeNonCopperZonesEditor( PCB_BASE_FRAME* aParent, ZONE_SETTINGS* aSettings ); +int InvokeNonCopperZonesEditor( PCB_BASE_FRAME* aParent, ZONE_SETTINGS* aSettings, + CONVERT_SETTINGS* aConvertSettings = nullptr ); /** * Function InvokeCopperZonesEditor @@ -92,7 +95,8 @@ int InvokeNonCopperZonesEditor( PCB_BASE_FRAME* aParent, ZONE_SETTINGS* aSetting * @param aSettings points to the ZONE_SETTINGS to edit. * @return int - tells if user aborted, changed only one zone, or all of them. */ -int InvokeCopperZonesEditor( PCB_BASE_FRAME* aCaller, ZONE_SETTINGS* aSettings ); +int InvokeCopperZonesEditor( PCB_BASE_FRAME* aCaller, ZONE_SETTINGS* aSettings, + CONVERT_SETTINGS* aConvertSettings = nullptr ); /** * Function InvokeRuleAreaEditor @@ -103,6 +107,7 @@ int InvokeCopperZonesEditor( PCB_BASE_FRAME* aCaller, ZONE_SETTINGS* aSettings ) * @param aSettings points to the ZONE_SETTINGS to edit. * @return int - tells if user aborted, changed only one zone, or all of them. */ -int InvokeRuleAreaEditor( PCB_BASE_FRAME* aCaller, ZONE_SETTINGS* aSettings ); +int InvokeRuleAreaEditor( PCB_BASE_FRAME* aCaller, ZONE_SETTINGS* aSettings, + CONVERT_SETTINGS* aConvertSettings = nullptr ); #endif // ZONES_H_