Add ignore-line-widths mode to CONVERT_TOOL.

Fixes https://gitlab.com/kicad/code/kicad/issues/5911
This commit is contained in:
Jeff Young 2022-07-29 20:56:55 +01:00
parent 3245aec5b5
commit f0b9e67212
8 changed files with 407 additions and 109 deletions

View File

@ -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<VECTOR2I>& aPoints );

View File

@ -28,7 +28,6 @@
#include <pcb_edit_frame.h>
#include <pcbnew_settings.h>
#include <zones.h>
#include <bitmaps.h>
#include <widgets/unit_binder.h>
#include <zone.h>
#include <pad.h>
@ -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<EDA_PATTERN_MATCH>;
@ -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<wxString, int> m_netNameToNetCode;
std::vector<NETINFO_ITEM*> 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<wxString, int> m_netNameToNetCode;
std::vector<NETINFO_ITEM*> 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 <no net> will create an isolated copper island." ), wxICON_WARNING );
m_copperZoneInfo->ShowMessage( _( "<no net> 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();
}

View File

@ -28,6 +28,7 @@
#include <pcb_edit_frame.h>
#include <pcbnew_settings.h>
#include <widgets/unit_binder.h>
#include <wx/statbox.h>
#include <zones.h>
#include <dialog_non_copper_zones_properties_base.h>
@ -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

View File

@ -30,6 +30,7 @@
#include <zone_settings.h>
#include <dialog_rule_area_properties_base.h>
#include <widgets/unit_binder.h>
#include <wx/statbox.h>
#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() );

View File

@ -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,

View File

@ -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 <jon@craftyjon.com>
*
* This program is free software; you can redistribute it and/or
@ -23,6 +23,10 @@
*/
#include <bitmaps.h>
#include <dialog_shim.h>
#include <wx/statline.h>
#include <wx/checkbox.h>
#include <wx/button.h>
#include <board.h>
#include <board_commit.h>
#include <board_design_settings.h>
@ -33,7 +37,6 @@
#include <footprint_edit_frame.h>
#include <fp_shape.h>
#include <geometry/shape_compound.h>
#include <menus_helpers.h>
#include <pcb_edit_frame.h>
#include <pcb_shape.h>
#include <pcb_track.h>
@ -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<SHAPE_POLY_SET> 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<PCB_SHAPE*>( 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<SHAPE_POLY_SET> 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<EDA_ITEM
}
SHAPE_POLY_SET CONVERT_TOOL::makePolysFromGraphics( const std::deque<EDA_ITEM*>& aItems )
SHAPE_POLY_SET CONVERT_TOOL::makePolysFromGraphics( const std::deque<EDA_ITEM*>& 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<EDA_ITEM*>&
case PCB_SHAPE_T:
case PCB_FP_SHAPE_T:
{
PCB_SHAPE* graphic = static_cast<PCB_SHAPE*>( item );
PCB_SHAPE* temp = static_cast<PCB_SHAPE*>( 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<ZONE*>( item )->Outline() );
item->SetFlags( SKIP_STRUCT );
break;
default:

View File

@ -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<EDA_ITEM*>& aItems );
SHAPE_POLY_SET makePolysFromGraphics( const std::deque<EDA_ITEM*>& aItems,
bool aIgnoreLineWidths );
PCB_SELECTION_TOOL* m_selectionTool;
CONDITIONAL_MENU* m_menu;

View File

@ -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 <wx/translation.h>
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_