Browse Source
Cleanup Graphics to parallel Cleanup Tracks & Vias.
Cleanup Graphics to parallel Cleanup Tracks & Vias.
This also allows for easier migration to DRAWSEGMENT::S_RECTs by auto-converting 4 rectilinear lines to a rectangle.pull/16/head
37 changed files with 1558 additions and 250 deletions
-
59common/rc_item.cpp
-
24common/rc_item.h
-
44eeschema/sch_sheet_path.cpp
-
10include/pcb_base_frame.h
-
4pcbnew/CMakeLists.txt
-
9pcbnew/board_design_settings.cpp
-
1pcbnew/class_marker_pcb.cpp
-
72pcbnew/cleanup_item.cpp
-
124pcbnew/cleanup_item.h
-
149pcbnew/dialogs/dialog_cleanup_graphics.cpp
-
56pcbnew/dialogs/dialog_cleanup_graphics.h
-
76pcbnew/dialogs/dialog_cleanup_graphics_base.cpp
-
323pcbnew/dialogs/dialog_cleanup_graphics_base.fbp
-
57pcbnew/dialogs/dialog_cleanup_graphics_base.h
-
30pcbnew/dialogs/dialog_cleanup_tracks_and_vias.cpp
-
10pcbnew/dialogs/dialog_cleanup_tracks_and_vias.h
-
8pcbnew/dialogs/dialog_cleanup_tracks_and_vias_base.fbp
-
12pcbnew/drc/drc.h
-
10pcbnew/drc/drc_item.cpp
-
8pcbnew/drc/drc_item.h
-
4pcbnew/drc/drc_provider.h
-
2pcbnew/footprint_editor_settings.cpp
-
347pcbnew/graphics_cleaner.cpp
-
65pcbnew/graphics_cleaner.h
-
3pcbnew/menubar_footprint_editor.cpp
-
1pcbnew/menubar_pcb_editor.cpp
-
12pcbnew/pcb_base_frame.cpp
-
8pcbnew/pcb_edit_frame.cpp
-
3pcbnew/pcb_edit_frame.h
-
28pcbnew/tools/footprint_editor_tools.cpp
-
2pcbnew/tools/footprint_editor_tools.h
-
30pcbnew/tools/global_edit_tool.cpp
-
1pcbnew/tools/global_edit_tool.h
-
7pcbnew/tools/pcb_actions.cpp
-
1pcbnew/tools/pcb_actions.h
-
152pcbnew/tracks_cleaner.cpp
-
56pcbnew/tracks_cleaner.h
@ -0,0 +1,72 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2020 KiCad Developers, see change_log.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 |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
|
|||
#include <fctsys.h>
|
|||
#include <cleanup_item.h>
|
|||
#include <pcb_base_frame.h>
|
|||
|
|||
|
|||
CLEANUP_ITEM::CLEANUP_ITEM( int aErrorCode ) |
|||
{ |
|||
m_errorCode = aErrorCode; |
|||
} |
|||
|
|||
|
|||
wxString CLEANUP_ITEM::GetErrorText( int aCode, bool aTranslate ) const |
|||
{ |
|||
wxString msg; |
|||
|
|||
if( aCode < 0 ) |
|||
aCode = m_errorCode; |
|||
|
|||
switch( aCode ) |
|||
{ |
|||
// For cleanup tracks and vias:
|
|||
case CLEANUP_SHORT: msg = _HKI( "Remove track shorting two nets" ); break; |
|||
case CLEANUP_REDUNDANT_VIA: msg = _HKI( "Remove redundant via" ); break; |
|||
case CLEANUP_DUPLICATE_TRACK: msg = _HKI( "Remove duplicate track" ); break; |
|||
case CLEANUP_MERGE_TRACKS: msg = _HKI( "Merge co-linear tracks" ); break; |
|||
case CLEANUP_DANGLING_TRACK: msg = _HKI( "Remove dangling track" ); break; |
|||
case CLEANUP_DANGLING_VIA: msg = _HKI( "Remove dangling via" ); break; |
|||
case CLEANUP_ZERO_LENGTH_TRACK: msg = _HKI( "Remove zero-length track" ); break; |
|||
case CLEANUP_TRACK_IN_PAD: msg = _HKI( "Remove track inside pad" ); break; |
|||
|
|||
// For cleanup graphics:
|
|||
case CLEANUP_NULL_GRAPHIC: msg = _HKI( "Remove zero-size graphic" ); break; |
|||
case CLEANUP_DUPLICATE_GRAPHIC: msg = _HKI( "Remove duplicated graphic" ); break; |
|||
case CLEANUP_LINES_TO_RECT: msg = _HKI( "Convert lines to rectangle" ); break; |
|||
|
|||
default: |
|||
wxFAIL_MSG( "Missing cleanup item description" ); |
|||
msg = _HKI( "Unknown cleanup action" ); |
|||
break; |
|||
} |
|||
|
|||
if( aTranslate ) |
|||
return wxGetTranslation( msg ); |
|||
else |
|||
return msg; |
|||
} |
|||
|
|||
|
|||
@ -0,0 +1,124 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2020 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 |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
|||
* or you may search the http://www.gnu.org website for the version 2 license, |
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
#ifndef CLEANUP_ITEM_H |
|||
#define CLEANUP_ITEM_H |
|||
|
|||
#include <rc_item.h> |
|||
#include <drc/drc.h> |
|||
|
|||
class PCB_BASE_FRAME; |
|||
|
|||
|
|||
enum CLEANUP_RC_CODE { |
|||
CLEANUP_FIRST = DRCE_LAST + 1, |
|||
CLEANUP_SHORT = CLEANUP_FIRST, |
|||
CLEANUP_REDUNDANT_VIA, |
|||
CLEANUP_DUPLICATE_TRACK, |
|||
CLEANUP_MERGE_TRACKS, |
|||
CLEANUP_DANGLING_TRACK, |
|||
CLEANUP_DANGLING_VIA, |
|||
CLEANUP_ZERO_LENGTH_TRACK, |
|||
CLEANUP_TRACK_IN_PAD, |
|||
CLEANUP_NULL_GRAPHIC, |
|||
CLEANUP_DUPLICATE_GRAPHIC, |
|||
CLEANUP_LINES_TO_RECT |
|||
}; |
|||
|
|||
class CLEANUP_ITEM : public RC_ITEM |
|||
{ |
|||
public: |
|||
CLEANUP_ITEM( int aErrorCode ); |
|||
|
|||
/** |
|||
* Function GetErrorText |
|||
* returns the string form of a drc error code. |
|||
*/ |
|||
wxString GetErrorText( int aErrorCode = -1, bool aTranslate = true ) const override; |
|||
|
|||
/** |
|||
* Function ShowHtml |
|||
* translates this object into a fragment of HTML suitable for the wxHtmlListBox class. |
|||
* @return wxString - the html text. |
|||
*/ |
|||
wxString ShowHtml( PCB_BASE_FRAME* aFrame ) const; |
|||
}; |
|||
|
|||
|
|||
/** |
|||
* VECTOR_CLEANUP_ITEMS_PROVIDER |
|||
* is an implementation of the interface named RC_ITEMS_PROVIDER which uses a vector |
|||
* of pointers to CLEANUP_ITEMs to fulfill the interface. No ownership is taken of the |
|||
* vector. |
|||
*/ |
|||
class VECTOR_CLEANUP_ITEMS_PROVIDER : public RC_ITEMS_PROVIDER |
|||
{ |
|||
std::vector<CLEANUP_ITEM*>* m_sourceVector; // owns its CLEANUP_ITEMs |
|||
|
|||
public: |
|||
|
|||
VECTOR_CLEANUP_ITEMS_PROVIDER( std::vector<CLEANUP_ITEM*>* aList ) : |
|||
m_sourceVector( aList ) |
|||
{ |
|||
} |
|||
|
|||
void SetSeverities( int aSeverities ) override |
|||
{ |
|||
} |
|||
|
|||
int GetCount( int aSeverity = -1 ) override |
|||
{ |
|||
return m_sourceVector->size(); |
|||
} |
|||
|
|||
CLEANUP_ITEM* GetItem( int aIndex ) override |
|||
{ |
|||
return m_sourceVector->at( aIndex ); |
|||
} |
|||
|
|||
void DeleteItem( int aIndex, bool aDeep ) override |
|||
{ |
|||
if( aDeep ) |
|||
{ |
|||
CLEANUP_ITEM* item = m_sourceVector->at( aIndex ); |
|||
delete item; |
|||
|
|||
m_sourceVector->erase( m_sourceVector->begin() + aIndex ); |
|||
} |
|||
} |
|||
|
|||
void DeleteAllItems() override |
|||
{ |
|||
if( m_sourceVector ) |
|||
{ |
|||
for( CLEANUP_ITEM* item : *m_sourceVector ) |
|||
delete item; |
|||
|
|||
m_sourceVector->clear(); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
|
|||
|
|||
#endif // CLEANUP_ITEM_H |
|||
@ -0,0 +1,149 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2020 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 |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
#include <wx/wx.h>
|
|||
#include <dialog_cleanup_graphics.h>
|
|||
#include <tool/tool_manager.h>
|
|||
#include <tools/pcb_actions.h>
|
|||
#include <graphics_cleaner.h>
|
|||
|
|||
|
|||
DIALOG_CLEANUP_GRAPHICS::DIALOG_CLEANUP_GRAPHICS( PCB_BASE_FRAME* aParent, bool isModEdit ) : |
|||
DIALOG_CLEANUP_GRAPHICS_BASE( aParent ), |
|||
m_parentFrame( aParent ), |
|||
m_isModEdit( isModEdit ) |
|||
{ |
|||
m_changesTreeModel = new RC_TREE_MODEL( m_parentFrame, m_changesDataView ); |
|||
m_changesDataView->AssociateModel( m_changesTreeModel ); |
|||
|
|||
m_changesTreeModel->SetSeverities( RPT_SEVERITY_ACTION ); |
|||
|
|||
// We use a sdbSizer to get platform-dependent ordering of the action buttons, but
|
|||
// that requires us to correct the button labels here.
|
|||
m_sdbSizerOK->SetLabel( isModEdit ? _( "Update Footprint" ) : _( "Update PCB" ) ); |
|||
|
|||
m_sdbSizerOK->SetDefault(); |
|||
GetSizer()->SetSizeHints(this); |
|||
Centre(); |
|||
} |
|||
|
|||
|
|||
DIALOG_CLEANUP_GRAPHICS::~DIALOG_CLEANUP_GRAPHICS() |
|||
{ |
|||
for( CLEANUP_ITEM* item : m_items ) |
|||
delete item; |
|||
|
|||
m_changesTreeModel->DecRef(); |
|||
} |
|||
|
|||
|
|||
void DIALOG_CLEANUP_GRAPHICS::OnCheckBox( wxCommandEvent& anEvent ) |
|||
{ |
|||
doCleanup( true ); |
|||
} |
|||
|
|||
|
|||
bool DIALOG_CLEANUP_GRAPHICS::TransferDataToWindow() |
|||
{ |
|||
doCleanup( true ); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
bool DIALOG_CLEANUP_GRAPHICS::TransferDataFromWindow() |
|||
{ |
|||
doCleanup( false ); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
void DIALOG_CLEANUP_GRAPHICS::doCleanup( bool aDryRun ) |
|||
{ |
|||
wxBusyCursor busy; |
|||
|
|||
BOARD_COMMIT commit( m_parentFrame ); |
|||
BOARD* board = m_parentFrame->GetBoard(); |
|||
MODULE* fp = m_isModEdit ? board->GetFirstModule() : nullptr; |
|||
GRAPHICS_CLEANER cleaner( fp ? fp->GraphicalItems() : board->Drawings(), fp, commit ); |
|||
|
|||
if( !aDryRun ) |
|||
{ |
|||
// Clear current selection list to avoid selection of deleted items
|
|||
m_parentFrame->GetToolManager()->RunAction( PCB_ACTIONS::selectionClear, true ); |
|||
|
|||
// ... and to keep the treeModel from trying to refresh a deleted item
|
|||
m_changesTreeModel->SetProvider( nullptr ); |
|||
} |
|||
|
|||
for( CLEANUP_ITEM* item : m_items ) |
|||
delete item; |
|||
|
|||
m_items.clear(); |
|||
|
|||
// Old model has to be refreshed, GAL normally does not keep updating it
|
|||
m_parentFrame->Compile_Ratsnest( false ); |
|||
|
|||
cleaner.CleanupBoard( aDryRun, &m_items, m_createRectanglesOpt->GetValue(), |
|||
m_deleteRedundantOpt->GetValue() ); |
|||
|
|||
if( aDryRun ) |
|||
{ |
|||
RC_ITEMS_PROVIDER* provider = new VECTOR_CLEANUP_ITEMS_PROVIDER( &m_items ); |
|||
m_changesTreeModel->SetProvider( provider ); |
|||
} |
|||
else if( !commit.Empty() ) |
|||
{ |
|||
// Clear undo and redo lists to avoid inconsistencies between lists
|
|||
commit.Push( _( "Graphics cleanup" ) ); |
|||
m_parentFrame->GetCanvas()->Refresh( true ); |
|||
} |
|||
} |
|||
|
|||
|
|||
void DIALOG_CLEANUP_GRAPHICS::OnSelectItem( wxDataViewEvent& aEvent ) |
|||
{ |
|||
const KIID& itemID = RC_TREE_MODEL::ToUUID( aEvent.GetItem() ); |
|||
BOARD_ITEM* item = m_parentFrame->GetBoard()->GetItem( itemID ); |
|||
WINDOW_THAWER thawer( m_parentFrame ); |
|||
|
|||
m_parentFrame->FocusOnItem( item ); |
|||
m_parentFrame->GetCanvas()->Refresh(); |
|||
|
|||
aEvent.Skip(); |
|||
} |
|||
|
|||
|
|||
void DIALOG_CLEANUP_GRAPHICS::OnLeftDClickItem( wxMouseEvent& event ) |
|||
{ |
|||
event.Skip(); |
|||
|
|||
if( m_changesDataView->GetCurrentItem().IsOk() ) |
|||
{ |
|||
if( !IsModal() ) |
|||
Show( false ); |
|||
} |
|||
} |
|||
|
|||
|
|||
@ -0,0 +1,56 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2010-2014 Jean-Pierre Charras, jean-pierre.charras at wanadoo.fr |
|||
* Copyright (C) 1992-2019 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 |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
|||
* or you may search the http://www.gnu.org website for the version 2 license, |
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
#ifndef DIALOG_CLEANUP_GRAPHICS_H_ |
|||
#define DIALOG_CLEANUP_GRAPHICS_H_ |
|||
|
|||
#include <dialog_cleanup_graphics_base.h> |
|||
#include <cleanup_item.h> |
|||
|
|||
|
|||
class PCB_BASE_FRAME; |
|||
|
|||
|
|||
class DIALOG_CLEANUP_GRAPHICS: public DIALOG_CLEANUP_GRAPHICS_BASE |
|||
{ |
|||
PCB_BASE_FRAME* m_parentFrame; |
|||
bool m_isModEdit; |
|||
std::vector<CLEANUP_ITEM*> m_items; |
|||
RC_TREE_MODEL* m_changesTreeModel; |
|||
|
|||
void doCleanup( bool aDryRun ); |
|||
|
|||
void OnCheckBox( wxCommandEvent& anEvent ) override; |
|||
void OnSelectItem( wxDataViewEvent& event ) override; |
|||
void OnLeftDClickItem( wxMouseEvent& event ) override; |
|||
|
|||
bool TransferDataToWindow() override; |
|||
bool TransferDataFromWindow() override; |
|||
|
|||
public: |
|||
DIALOG_CLEANUP_GRAPHICS( PCB_BASE_FRAME* aParent, bool isModEdit ); |
|||
~DIALOG_CLEANUP_GRAPHICS(); |
|||
}; |
|||
|
|||
#endif // DIALOG_CLEANUP_GRAPHICS_H_ |
|||
@ -0,0 +1,76 @@ |
|||
///////////////////////////////////////////////////////////////////////////
|
|||
// C++ code generated with wxFormBuilder (version Oct 26 2018)
|
|||
// http://www.wxformbuilder.org/
|
|||
//
|
|||
// PLEASE DO *NOT* EDIT THIS FILE!
|
|||
///////////////////////////////////////////////////////////////////////////
|
|||
|
|||
#include "dialog_cleanup_graphics_base.h"
|
|||
|
|||
///////////////////////////////////////////////////////////////////////////
|
|||
|
|||
DIALOG_CLEANUP_GRAPHICS_BASE::DIALOG_CLEANUP_GRAPHICS_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style ) |
|||
{ |
|||
this->SetSizeHints( wxDefaultSize, wxDefaultSize ); |
|||
|
|||
wxBoxSizer* bSizerMain; |
|||
bSizerMain = new wxBoxSizer( wxVERTICAL ); |
|||
|
|||
wxBoxSizer* bSizerUpper; |
|||
bSizerUpper = new wxBoxSizer( wxVERTICAL ); |
|||
|
|||
m_createRectanglesOpt = new wxCheckBox( this, wxID_ANY, _("Merge lines into rectangles"), wxDefaultPosition, wxDefaultSize, 0 ); |
|||
m_createRectanglesOpt->SetToolTip( _("remove track segments connecting nodes belonging to different nets (short circuit)") ); |
|||
|
|||
bSizerUpper->Add( m_createRectanglesOpt, 0, wxALL, 5 ); |
|||
|
|||
m_deleteRedundantOpt = new wxCheckBox( this, wxID_ANY, _("Delete redundant graphics"), wxDefaultPosition, wxDefaultSize, 0 ); |
|||
bSizerUpper->Add( m_deleteRedundantOpt, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); |
|||
|
|||
|
|||
bSizerMain->Add( bSizerUpper, 0, wxEXPAND|wxALL, 5 ); |
|||
|
|||
wxBoxSizer* bLowerSizer; |
|||
bLowerSizer = new wxBoxSizer( wxVERTICAL ); |
|||
|
|||
bLowerSizer->SetMinSize( wxSize( 660,250 ) ); |
|||
staticChangesLabel = new wxStaticText( this, wxID_ANY, _("Changes To Be Applied:"), wxDefaultPosition, wxDefaultSize, 0 ); |
|||
staticChangesLabel->Wrap( -1 ); |
|||
bLowerSizer->Add( staticChangesLabel, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); |
|||
|
|||
m_changesDataView = new wxDataViewCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxDV_NO_HEADER ); |
|||
bLowerSizer->Add( m_changesDataView, 1, wxALL|wxEXPAND, 5 ); |
|||
|
|||
|
|||
bSizerMain->Add( bLowerSizer, 1, wxEXPAND|wxRIGHT|wxLEFT, 5 ); |
|||
|
|||
m_sdbSizer = new wxStdDialogButtonSizer(); |
|||
m_sdbSizerOK = new wxButton( this, wxID_OK ); |
|||
m_sdbSizer->AddButton( m_sdbSizerOK ); |
|||
m_sdbSizerCancel = new wxButton( this, wxID_CANCEL ); |
|||
m_sdbSizer->AddButton( m_sdbSizerCancel ); |
|||
m_sdbSizer->Realize(); |
|||
|
|||
bSizerMain->Add( m_sdbSizer, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 ); |
|||
|
|||
|
|||
this->SetSizer( bSizerMain ); |
|||
this->Layout(); |
|||
bSizerMain->Fit( this ); |
|||
|
|||
this->Centre( wxBOTH ); |
|||
|
|||
// Connect Events
|
|||
m_createRectanglesOpt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_CLEANUP_GRAPHICS_BASE::OnCheckBox ), NULL, this ); |
|||
m_changesDataView->Connect( wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED, wxDataViewEventHandler( DIALOG_CLEANUP_GRAPHICS_BASE::OnSelectItem ), NULL, this ); |
|||
m_changesDataView->Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( DIALOG_CLEANUP_GRAPHICS_BASE::OnLeftDClickItem ), NULL, this ); |
|||
} |
|||
|
|||
DIALOG_CLEANUP_GRAPHICS_BASE::~DIALOG_CLEANUP_GRAPHICS_BASE() |
|||
{ |
|||
// Disconnect Events
|
|||
m_createRectanglesOpt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_CLEANUP_GRAPHICS_BASE::OnCheckBox ), NULL, this ); |
|||
m_changesDataView->Disconnect( wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED, wxDataViewEventHandler( DIALOG_CLEANUP_GRAPHICS_BASE::OnSelectItem ), NULL, this ); |
|||
m_changesDataView->Disconnect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( DIALOG_CLEANUP_GRAPHICS_BASE::OnLeftDClickItem ), NULL, this ); |
|||
|
|||
} |
|||
@ -0,0 +1,323 @@ |
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> |
|||
<wxFormBuilder_Project> |
|||
<FileVersion major="1" minor="15" /> |
|||
<object class="Project" expanded="1"> |
|||
<property name="class_decoration"></property> |
|||
<property name="code_generation">C++</property> |
|||
<property name="disconnect_events">1</property> |
|||
<property name="disconnect_mode">source_name</property> |
|||
<property name="disconnect_php_events">0</property> |
|||
<property name="disconnect_python_events">0</property> |
|||
<property name="embedded_files_path">res</property> |
|||
<property name="encoding">UTF-8</property> |
|||
<property name="event_generation">connect</property> |
|||
<property name="file">dialog_cleanup_graphics_base</property> |
|||
<property name="first_id">1000</property> |
|||
<property name="help_provider">none</property> |
|||
<property name="indent_with_spaces"></property> |
|||
<property name="internationalize">1</property> |
|||
<property name="name">dialog_cleanup_graphics</property> |
|||
<property name="namespace"></property> |
|||
<property name="path">.</property> |
|||
<property name="precompiled_header"></property> |
|||
<property name="relative_path">1</property> |
|||
<property name="skip_lua_events">1</property> |
|||
<property name="skip_php_events">1</property> |
|||
<property name="skip_python_events">1</property> |
|||
<property name="ui_table">UI</property> |
|||
<property name="use_enum">0</property> |
|||
<property name="use_microsoft_bom">0</property> |
|||
<object class="Dialog" expanded="1"> |
|||
<property name="aui_managed">0</property> |
|||
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property> |
|||
<property name="bg"></property> |
|||
<property name="center">wxBOTH</property> |
|||
<property name="context_help"></property> |
|||
<property name="context_menu">1</property> |
|||
<property name="enabled">1</property> |
|||
<property name="event_handler">impl_virtual</property> |
|||
<property name="extra_style"></property> |
|||
<property name="fg"></property> |
|||
<property name="font"></property> |
|||
<property name="hidden">0</property> |
|||
<property name="id">wxID_ANY</property> |
|||
<property name="maximum_size"></property> |
|||
<property name="minimum_size"></property> |
|||
<property name="name">DIALOG_CLEANUP_GRAPHICS_BASE</property> |
|||
<property name="pos"></property> |
|||
<property name="size">-1,-1</property> |
|||
<property name="style">wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</property> |
|||
<property name="subclass">DIALOG_SHIM; dialog_shim.h</property> |
|||
<property name="title">Cleanup Graphics</property> |
|||
<property name="tooltip"></property> |
|||
<property name="window_extra_style"></property> |
|||
<property name="window_name"></property> |
|||
<property name="window_style"></property> |
|||
<object class="wxBoxSizer" expanded="1"> |
|||
<property name="minimum_size"></property> |
|||
<property name="name">bSizerMain</property> |
|||
<property name="orient">wxVERTICAL</property> |
|||
<property name="permission">none</property> |
|||
<object class="sizeritem" expanded="1"> |
|||
<property name="border">5</property> |
|||
<property name="flag">wxEXPAND|wxALL</property> |
|||
<property name="proportion">0</property> |
|||
<object class="wxBoxSizer" expanded="1"> |
|||
<property name="minimum_size"></property> |
|||
<property name="name">bSizerUpper</property> |
|||
<property name="orient">wxVERTICAL</property> |
|||
<property name="permission">none</property> |
|||
<object class="sizeritem" expanded="0"> |
|||
<property name="border">5</property> |
|||
<property name="flag">wxALL</property> |
|||
<property name="proportion">0</property> |
|||
<object class="wxCheckBox" expanded="0"> |
|||
<property name="BottomDockable">1</property> |
|||
<property name="LeftDockable">1</property> |
|||
<property name="RightDockable">1</property> |
|||
<property name="TopDockable">1</property> |
|||
<property name="aui_layer"></property> |
|||
<property name="aui_name"></property> |
|||
<property name="aui_position"></property> |
|||
<property name="aui_row"></property> |
|||
<property name="best_size"></property> |
|||
<property name="bg"></property> |
|||
<property name="caption"></property> |
|||
<property name="caption_visible">1</property> |
|||
<property name="center_pane">0</property> |
|||
<property name="checked">0</property> |
|||
<property name="close_button">1</property> |
|||
<property name="context_help"></property> |
|||
<property name="context_menu">1</property> |
|||
<property name="default_pane">0</property> |
|||
<property name="dock">Dock</property> |
|||
<property name="dock_fixed">0</property> |
|||
<property name="docking">Left</property> |
|||
<property name="enabled">1</property> |
|||
<property name="fg"></property> |
|||
<property name="floatable">1</property> |
|||
<property name="font"></property> |
|||
<property name="gripper">0</property> |
|||
<property name="hidden">0</property> |
|||
<property name="id">wxID_ANY</property> |
|||
<property name="label">Merge lines into rectangles</property> |
|||
<property name="max_size"></property> |
|||
<property name="maximize_button">0</property> |
|||
<property name="maximum_size"></property> |
|||
<property name="min_size"></property> |
|||
<property name="minimize_button">0</property> |
|||
<property name="minimum_size"></property> |
|||
<property name="moveable">1</property> |
|||
<property name="name">m_createRectanglesOpt</property> |
|||
<property name="pane_border">1</property> |
|||
<property name="pane_position"></property> |
|||
<property name="pane_size"></property> |
|||
<property name="permission">protected</property> |
|||
<property name="pin_button">1</property> |
|||
<property name="pos"></property> |
|||
<property name="resize">Resizable</property> |
|||
<property name="show">1</property> |
|||
<property name="size"></property> |
|||
<property name="style"></property> |
|||
<property name="subclass"></property> |
|||
<property name="toolbar_pane">0</property> |
|||
<property name="tooltip">remove track segments connecting nodes belonging to different nets (short circuit)</property> |
|||
<property name="validator_data_type"></property> |
|||
<property name="validator_style">wxFILTER_NUMERIC</property> |
|||
<property name="validator_type">wxDefaultValidator</property> |
|||
<property name="validator_variable"></property> |
|||
<property name="window_extra_style"></property> |
|||
<property name="window_name"></property> |
|||
<property name="window_style"></property> |
|||
<event name="OnCheckBox">OnCheckBox</event> |
|||
</object> |
|||
</object> |
|||
<object class="sizeritem" expanded="1"> |
|||
<property name="border">5</property> |
|||
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property> |
|||
<property name="proportion">0</property> |
|||
<object class="wxCheckBox" expanded="1"> |
|||
<property name="BottomDockable">1</property> |
|||
<property name="LeftDockable">1</property> |
|||
<property name="RightDockable">1</property> |
|||
<property name="TopDockable">1</property> |
|||
<property name="aui_layer"></property> |
|||
<property name="aui_name"></property> |
|||
<property name="aui_position"></property> |
|||
<property name="aui_row"></property> |
|||
<property name="best_size"></property> |
|||
<property name="bg"></property> |
|||
<property name="caption"></property> |
|||
<property name="caption_visible">1</property> |
|||
<property name="center_pane">0</property> |
|||
<property name="checked">0</property> |
|||
<property name="close_button">1</property> |
|||
<property name="context_help"></property> |
|||
<property name="context_menu">1</property> |
|||
<property name="default_pane">0</property> |
|||
<property name="dock">Dock</property> |
|||
<property name="dock_fixed">0</property> |
|||
<property name="docking">Left</property> |
|||
<property name="enabled">1</property> |
|||
<property name="fg"></property> |
|||
<property name="floatable">1</property> |
|||
<property name="font"></property> |
|||
<property name="gripper">0</property> |
|||
<property name="hidden">0</property> |
|||
<property name="id">wxID_ANY</property> |
|||
<property name="label">Delete redundant graphics</property> |
|||
<property name="max_size"></property> |
|||
<property name="maximize_button">0</property> |
|||
<property name="maximum_size"></property> |
|||
<property name="min_size"></property> |
|||
<property name="minimize_button">0</property> |
|||
<property name="minimum_size"></property> |
|||
<property name="moveable">1</property> |
|||
<property name="name">m_deleteRedundantOpt</property> |
|||
<property name="pane_border">1</property> |
|||
<property name="pane_position"></property> |
|||
<property name="pane_size"></property> |
|||
<property name="permission">protected</property> |
|||
<property name="pin_button">1</property> |
|||
<property name="pos"></property> |
|||
<property name="resize">Resizable</property> |
|||
<property name="show">1</property> |
|||
<property name="size"></property> |
|||
<property name="style"></property> |
|||
<property name="subclass">; ; forward_declare</property> |
|||
<property name="toolbar_pane">0</property> |
|||
<property name="tooltip"></property> |
|||
<property name="validator_data_type"></property> |
|||
<property name="validator_style">wxFILTER_NONE</property> |
|||
<property name="validator_type">wxDefaultValidator</property> |
|||
<property name="validator_variable"></property> |
|||
<property name="window_extra_style"></property> |
|||
<property name="window_name"></property> |
|||
<property name="window_style"></property> |
|||
</object> |
|||
</object> |
|||
</object> |
|||
</object> |
|||
<object class="sizeritem" expanded="1"> |
|||
<property name="border">5</property> |
|||
<property name="flag">wxEXPAND|wxRIGHT|wxLEFT</property> |
|||
<property name="proportion">1</property> |
|||
<object class="wxBoxSizer" expanded="1"> |
|||
<property name="minimum_size">660,250</property> |
|||
<property name="name">bLowerSizer</property> |
|||
<property name="orient">wxVERTICAL</property> |
|||
<property name="permission">none</property> |
|||
<object class="sizeritem" expanded="0"> |
|||
<property name="border">5</property> |
|||
<property name="flag">wxTOP|wxRIGHT|wxLEFT</property> |
|||
<property name="proportion">0</property> |
|||
<object class="wxStaticText" expanded="0"> |
|||
<property name="BottomDockable">1</property> |
|||
<property name="LeftDockable">1</property> |
|||
<property name="RightDockable">1</property> |
|||
<property name="TopDockable">1</property> |
|||
<property name="aui_layer"></property> |
|||
<property name="aui_name"></property> |
|||
<property name="aui_position"></property> |
|||
<property name="aui_row"></property> |
|||
<property name="best_size"></property> |
|||
<property name="bg"></property> |
|||
<property name="caption"></property> |
|||
<property name="caption_visible">1</property> |
|||
<property name="center_pane">0</property> |
|||
<property name="close_button">1</property> |
|||
<property name="context_help"></property> |
|||
<property name="context_menu">1</property> |
|||
<property name="default_pane">0</property> |
|||
<property name="dock">Dock</property> |
|||
<property name="dock_fixed">0</property> |
|||
<property name="docking">Left</property> |
|||
<property name="enabled">1</property> |
|||
<property name="fg"></property> |
|||
<property name="floatable">1</property> |
|||
<property name="font"></property> |
|||
<property name="gripper">0</property> |
|||
<property name="hidden">0</property> |
|||
<property name="id">wxID_ANY</property> |
|||
<property name="label">Changes To Be Applied:</property> |
|||
<property name="markup">0</property> |
|||
<property name="max_size"></property> |
|||
<property name="maximize_button">0</property> |
|||
<property name="maximum_size"></property> |
|||
<property name="min_size"></property> |
|||
<property name="minimize_button">0</property> |
|||
<property name="minimum_size"></property> |
|||
<property name="moveable">1</property> |
|||
<property name="name">staticChangesLabel</property> |
|||
<property name="pane_border">1</property> |
|||
<property name="pane_position"></property> |
|||
<property name="pane_size"></property> |
|||
<property name="permission">protected</property> |
|||
<property name="pin_button">1</property> |
|||
<property name="pos"></property> |
|||
<property name="resize">Resizable</property> |
|||
<property name="show">1</property> |
|||
<property name="size"></property> |
|||
<property name="style"></property> |
|||
<property name="subclass">; forward_declare</property> |
|||
<property name="toolbar_pane">0</property> |
|||
<property name="tooltip"></property> |
|||
<property name="window_extra_style"></property> |
|||
<property name="window_name"></property> |
|||
<property name="window_style"></property> |
|||
<property name="wrap">-1</property> |
|||
</object> |
|||
</object> |
|||
<object class="sizeritem" expanded="1"> |
|||
<property name="border">5</property> |
|||
<property name="flag">wxALL|wxEXPAND</property> |
|||
<property name="proportion">1</property> |
|||
<object class="wxDataViewCtrl" expanded="1"> |
|||
<property name="bg"></property> |
|||
<property name="context_help"></property> |
|||
<property name="context_menu">1</property> |
|||
<property name="enabled">1</property> |
|||
<property name="fg"></property> |
|||
<property name="font"></property> |
|||
<property name="hidden">0</property> |
|||
<property name="id">wxID_ANY</property> |
|||
<property name="maximum_size"></property> |
|||
<property name="minimum_size"></property> |
|||
<property name="name">m_changesDataView</property> |
|||
<property name="permission">protected</property> |
|||
<property name="pos"></property> |
|||
<property name="size"></property> |
|||
<property name="style">wxDV_NO_HEADER</property> |
|||
<property name="subclass">; ; forward_declare</property> |
|||
<property name="tooltip"></property> |
|||
<property name="window_extra_style"></property> |
|||
<property name="window_name"></property> |
|||
<property name="window_style"></property> |
|||
<event name="OnDataViewCtrlSelectionChanged">OnSelectItem</event> |
|||
<event name="OnLeftDClick">OnLeftDClickItem</event> |
|||
</object> |
|||
</object> |
|||
</object> |
|||
</object> |
|||
<object class="sizeritem" expanded="0"> |
|||
<property name="border">5</property> |
|||
<property name="flag">wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT</property> |
|||
<property name="proportion">0</property> |
|||
<object class="wxStdDialogButtonSizer" expanded="0"> |
|||
<property name="Apply">0</property> |
|||
<property name="Cancel">1</property> |
|||
<property name="ContextHelp">0</property> |
|||
<property name="Help">0</property> |
|||
<property name="No">0</property> |
|||
<property name="OK">1</property> |
|||
<property name="Save">0</property> |
|||
<property name="Yes">0</property> |
|||
<property name="minimum_size"></property> |
|||
<property name="name">m_sdbSizer</property> |
|||
<property name="permission">protected</property> |
|||
</object> |
|||
</object> |
|||
</object> |
|||
</object> |
|||
</object> |
|||
</wxFormBuilder_Project> |
|||
@ -0,0 +1,57 @@ |
|||
/////////////////////////////////////////////////////////////////////////// |
|||
// C++ code generated with wxFormBuilder (version Oct 26 2018) |
|||
// http://www.wxformbuilder.org/ |
|||
// |
|||
// PLEASE DO *NOT* EDIT THIS FILE! |
|||
/////////////////////////////////////////////////////////////////////////// |
|||
|
|||
#pragma once |
|||
|
|||
#include <wx/artprov.h> |
|||
#include <wx/xrc/xmlres.h> |
|||
#include <wx/intl.h> |
|||
#include "dialog_shim.h" |
|||
#include <wx/string.h> |
|||
#include <wx/checkbox.h> |
|||
#include <wx/gdicmn.h> |
|||
#include <wx/font.h> |
|||
#include <wx/colour.h> |
|||
#include <wx/settings.h> |
|||
#include <wx/sizer.h> |
|||
#include <wx/stattext.h> |
|||
#include <wx/dataview.h> |
|||
#include <wx/button.h> |
|||
#include <wx/dialog.h> |
|||
|
|||
/////////////////////////////////////////////////////////////////////////// |
|||
|
|||
|
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
/// Class DIALOG_CLEANUP_GRAPHICS_BASE |
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
class DIALOG_CLEANUP_GRAPHICS_BASE : public DIALOG_SHIM |
|||
{ |
|||
private: |
|||
|
|||
protected: |
|||
wxCheckBox* m_createRectanglesOpt; |
|||
wxCheckBox* m_deleteRedundantOpt; |
|||
wxStaticText* staticChangesLabel; |
|||
wxDataViewCtrl* m_changesDataView; |
|||
wxStdDialogButtonSizer* m_sdbSizer; |
|||
wxButton* m_sdbSizerOK; |
|||
wxButton* m_sdbSizerCancel; |
|||
|
|||
// Virtual event handlers, overide them in your derived class |
|||
virtual void OnCheckBox( wxCommandEvent& event ) { event.Skip(); } |
|||
virtual void OnSelectItem( wxDataViewEvent& event ) { event.Skip(); } |
|||
virtual void OnLeftDClickItem( wxMouseEvent& event ) { event.Skip(); } |
|||
|
|||
|
|||
public: |
|||
|
|||
DIALOG_CLEANUP_GRAPHICS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Cleanup Graphics"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); |
|||
~DIALOG_CLEANUP_GRAPHICS_BASE(); |
|||
|
|||
}; |
|||
|
|||
@ -0,0 +1,347 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2004-2018 Jean-Pierre Charras, jp.charras at wanadoo.fr |
|||
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net> |
|||
* Copyright (C) 1992-2020 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 |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
#include <fctsys.h>
|
|||
#include <reporter.h>
|
|||
#include <board_commit.h>
|
|||
#include <cleanup_item.h>
|
|||
#include <class_drawsegment.h>
|
|||
#include <class_edge_mod.h>
|
|||
#include <graphics_cleaner.h>
|
|||
|
|||
|
|||
GRAPHICS_CLEANER::GRAPHICS_CLEANER( DRAWINGS& aDrawings, MODULE* aParentModule, |
|||
BOARD_COMMIT& aCommit ) : |
|||
m_drawings( aDrawings ), |
|||
m_parentModule( aParentModule ), |
|||
m_commit( aCommit ), |
|||
m_dryRun( true ), |
|||
m_itemsList( nullptr ) |
|||
{ |
|||
} |
|||
|
|||
|
|||
void GRAPHICS_CLEANER::CleanupBoard( bool aDryRun, std::vector<CLEANUP_ITEM*>* aItemsList, |
|||
bool aMergeRects, bool aDeleteRedundant ) |
|||
{ |
|||
m_dryRun = aDryRun; |
|||
m_itemsList = aItemsList; |
|||
|
|||
// Clear the flag used to mark some segments as deleted, in dry run:
|
|||
for( BOARD_ITEM* drawing : m_drawings ) |
|||
drawing->ClearFlags( IS_DELETED ); |
|||
|
|||
if( aDeleteRedundant ) |
|||
cleanupSegments(); |
|||
|
|||
if( aMergeRects ) |
|||
mergeRects(); |
|||
|
|||
// Clear the flag used to mark some segments:
|
|||
for( BOARD_ITEM* drawing : m_drawings ) |
|||
drawing->ClearFlags( IS_DELETED ); |
|||
} |
|||
|
|||
|
|||
bool GRAPHICS_CLEANER::isNullSegment( DRAWSEGMENT* aSegment ) |
|||
{ |
|||
switch( aSegment->GetShape() ) |
|||
{ |
|||
case S_SEGMENT: |
|||
case S_RECT: |
|||
return aSegment->GetStart() == aSegment->GetEnd(); |
|||
|
|||
case S_CIRCLE: |
|||
return aSegment->GetRadius() == 0; |
|||
|
|||
case S_ARC: |
|||
return aSegment->GetCenter().x == aSegment->GetArcStart().x |
|||
&& aSegment->GetCenter().y == aSegment->GetArcStart().y; |
|||
|
|||
case S_POLYGON: |
|||
return aSegment->GetPointCount() == 0; |
|||
|
|||
case S_CURVE: |
|||
aSegment->RebuildBezierToSegmentsPointsList( aSegment->GetWidth() ); |
|||
return aSegment->GetBezierPoints().empty(); |
|||
|
|||
default: |
|||
wxFAIL_MSG( wxString::Format( "unknown DRAWSEGMENT shape: %d", aSegment->GetShape() ) ); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
|
|||
bool GRAPHICS_CLEANER::areEquivalent( DRAWSEGMENT* aSegment1, DRAWSEGMENT* aSegment2 ) |
|||
{ |
|||
if( aSegment1->GetShape() != aSegment2->GetShape() |
|||
|| aSegment1->GetLayer() != aSegment2->GetLayer() |
|||
|| aSegment1->GetWidth() != aSegment2->GetWidth() ) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
switch( aSegment1->GetShape() ) |
|||
{ |
|||
case S_SEGMENT: |
|||
case S_RECT: |
|||
case S_CIRCLE: |
|||
return aSegment1->GetStart() == aSegment2->GetStart() |
|||
&& aSegment1->GetEnd() == aSegment2->GetEnd(); |
|||
|
|||
case S_ARC: |
|||
return aSegment1->GetCenter() == aSegment2->GetCenter() |
|||
&& aSegment1->GetArcStart() == aSegment2->GetArcStart() |
|||
&& aSegment1->GetAngle() == aSegment2->GetAngle(); |
|||
|
|||
case S_POLYGON: |
|||
// TODO
|
|||
return false; |
|||
|
|||
case S_CURVE: |
|||
return aSegment1->GetBezControl1() == aSegment2->GetBezControl1() |
|||
&& aSegment1->GetBezControl2() == aSegment2->GetBezControl2() |
|||
&& aSegment1->GetBezierPoints() == aSegment2->GetBezierPoints(); |
|||
|
|||
default: |
|||
wxFAIL_MSG( wxString::Format( "unknown DRAWSEGMENT shape: %d", aSegment1->GetShape() ) ); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
|
|||
void GRAPHICS_CLEANER::cleanupSegments() |
|||
{ |
|||
std::set<BOARD_ITEM*> toRemove; |
|||
|
|||
// Remove duplicate segments (2 superimposed identical segments):
|
|||
for( auto it = m_drawings.begin(); it != m_drawings.end(); it++ ) |
|||
{ |
|||
DRAWSEGMENT* segment = dynamic_cast<DRAWSEGMENT*>( *it ); |
|||
|
|||
if( !segment || segment->GetShape() != S_SEGMENT || segment->HasFlag( IS_DELETED ) ) |
|||
continue; |
|||
|
|||
if( isNullSegment( segment ) ) |
|||
{ |
|||
CLEANUP_ITEM* item = new CLEANUP_ITEM( CLEANUP_NULL_GRAPHIC ); |
|||
item->SetItems( segment ); |
|||
m_itemsList->push_back( item ); |
|||
|
|||
toRemove.insert( segment ); |
|||
continue; |
|||
} |
|||
|
|||
for( auto it2 = it + 1; it2 != m_drawings.end(); it2++ ) |
|||
{ |
|||
DRAWSEGMENT* segment2 = dynamic_cast<DRAWSEGMENT*>( *it2 ); |
|||
|
|||
if( !segment2 || segment2->HasFlag( IS_DELETED ) ) |
|||
continue; |
|||
|
|||
if( areEquivalent( segment, segment2 ) ) |
|||
{ |
|||
CLEANUP_ITEM* item = new CLEANUP_ITEM( CLEANUP_DUPLICATE_GRAPHIC ); |
|||
item->SetItems( segment2 ); |
|||
m_itemsList->push_back( item ); |
|||
|
|||
segment2->SetFlags( IS_DELETED ); |
|||
toRemove.insert( segment2 ); |
|||
} |
|||
} |
|||
} |
|||
|
|||
if( !m_dryRun ) |
|||
removeItems( toRemove ); |
|||
} |
|||
|
|||
|
|||
void GRAPHICS_CLEANER::mergeRects() |
|||
{ |
|||
struct SIDE_CANDIDATE |
|||
{ |
|||
SIDE_CANDIDATE( DRAWSEGMENT* aSeg ) : |
|||
start( aSeg->GetStart() ), |
|||
end( aSeg->GetEnd() ), |
|||
seg( aSeg ) |
|||
{ |
|||
if( start.x > end.x || start.y > end.y ) |
|||
std::swap( start, end ); |
|||
} |
|||
|
|||
wxPoint start; |
|||
wxPoint end; |
|||
DRAWSEGMENT* seg; |
|||
}; |
|||
|
|||
std::set<BOARD_ITEM*> toRemove; |
|||
|
|||
auto markForRemoval = [&]( SIDE_CANDIDATE* aSide ) |
|||
{ |
|||
toRemove.insert( aSide->seg ); |
|||
aSide->seg->SetFlags( IS_DELETED ); |
|||
}; |
|||
|
|||
std::vector<SIDE_CANDIDATE*> sides; |
|||
std::map<wxPoint, std::vector<SIDE_CANDIDATE*>> ptMap; |
|||
|
|||
// First load all the candidates into the side vector and layer maps
|
|||
for( BOARD_ITEM* item : m_drawings ) |
|||
{ |
|||
DRAWSEGMENT* seg = dynamic_cast<DRAWSEGMENT*>( item ); |
|||
|
|||
if( !seg || seg->GetShape() != S_SEGMENT ) |
|||
continue; |
|||
|
|||
if( seg->GetStart().x == seg->GetEnd().x || seg->GetStart().y == seg->GetEnd().y ) |
|||
{ |
|||
sides.emplace_back( new SIDE_CANDIDATE( seg ) ); |
|||
ptMap[ sides.back()->start ].push_back( sides.back() ); |
|||
} |
|||
} |
|||
|
|||
// Now go through the sides and try and match lines into rectangles
|
|||
for( SIDE_CANDIDATE* side : sides ) |
|||
{ |
|||
if( side->seg->HasFlag( IS_DELETED ) ) |
|||
continue; |
|||
|
|||
SIDE_CANDIDATE* left = nullptr; |
|||
SIDE_CANDIDATE* top = nullptr; |
|||
SIDE_CANDIDATE* right = nullptr; |
|||
SIDE_CANDIDATE* bottom = nullptr; |
|||
|
|||
auto viable = [&]( SIDE_CANDIDATE* aCandidate ) -> bool |
|||
{ |
|||
return aCandidate->seg->GetLayer() == side->seg->GetLayer() |
|||
&& aCandidate->seg->GetWidth() == side->seg->GetWidth() |
|||
&& !aCandidate->seg->HasFlag( IS_DELETED ); |
|||
}; |
|||
|
|||
if( side->start.x == side->end.x ) |
|||
{ |
|||
// We've found a possible left; see if we have a top
|
|||
//
|
|||
left = side; |
|||
|
|||
for( SIDE_CANDIDATE* candidate : ptMap[ left->start ] ) |
|||
{ |
|||
if( candidate != left && viable( candidate ) ) |
|||
{ |
|||
top = candidate; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
else if( side->start.y == side->end.y ) |
|||
{ |
|||
// We've found a possible top; see if we have a left
|
|||
//
|
|||
top = side; |
|||
|
|||
for( SIDE_CANDIDATE* candidate : ptMap[ top->start ] ) |
|||
{ |
|||
if( candidate != top && viable( candidate ) ) |
|||
{ |
|||
left = candidate; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
if( top && left ) |
|||
{ |
|||
// See if we can fill in the other two sides
|
|||
//
|
|||
for( SIDE_CANDIDATE* candidate : ptMap[ top->end ] ) |
|||
{ |
|||
if( candidate != top && viable( candidate ) ) |
|||
{ |
|||
right = candidate; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
for( SIDE_CANDIDATE* candidate : ptMap[ left->end ] ) |
|||
{ |
|||
if( candidate != left && viable( candidate ) ) |
|||
{ |
|||
bottom = candidate; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if( right && bottom ) |
|||
{ |
|||
markForRemoval( left ); |
|||
markForRemoval( top ); |
|||
markForRemoval( right ); |
|||
markForRemoval( bottom ); |
|||
|
|||
CLEANUP_ITEM* item = new CLEANUP_ITEM( CLEANUP_LINES_TO_RECT ); |
|||
item->SetItems( left->seg, top->seg, right->seg, bottom->seg ); |
|||
m_itemsList->push_back( item ); |
|||
|
|||
if( !m_dryRun ) |
|||
{ |
|||
DRAWSEGMENT* rect; |
|||
|
|||
if( m_parentModule ) |
|||
rect = new EDGE_MODULE( m_parentModule ); |
|||
else |
|||
rect = new DRAWSEGMENT(); |
|||
|
|||
rect->SetShape( S_RECT ); |
|||
rect->SetStart( top->start ); |
|||
rect->SetEnd( bottom->end ); |
|||
rect->SetLayer( top->seg->GetLayer() ); |
|||
rect->SetWidth( top->seg->GetWidth() ); |
|||
|
|||
m_commit.Add( rect ); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
if( !m_dryRun ) |
|||
removeItems( toRemove ); |
|||
|
|||
for( SIDE_CANDIDATE* side : sides ) |
|||
delete side; |
|||
} |
|||
|
|||
|
|||
void GRAPHICS_CLEANER::removeItems( std::set<BOARD_ITEM*>& aItems ) |
|||
{ |
|||
for( BOARD_ITEM* item : aItems ) |
|||
{ |
|||
if( m_parentModule ) |
|||
m_parentModule->Remove( item ); |
|||
else |
|||
item->GetParent()->Remove( item ); |
|||
|
|||
m_commit.Removed( item ); |
|||
} |
|||
} |
|||
@ -0,0 +1,65 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2019 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 |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
|||
* or you may search the http://www.gnu.org website for the version 2 license, |
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
#ifndef KICAD_GRAPHICS_CLEANER_H |
|||
#define KICAD_GRAPHICS_CLEANER_H |
|||
|
|||
#include <class_board.h> |
|||
|
|||
class MODULE; |
|||
class BOARD_COMMIT; |
|||
class CLEANUP_ITEM; |
|||
|
|||
|
|||
// Helper class used to clean tracks and vias |
|||
class GRAPHICS_CLEANER |
|||
{ |
|||
public: |
|||
GRAPHICS_CLEANER( DRAWINGS& aDrawings, MODULE* aParentModule, BOARD_COMMIT& aCommit ); |
|||
|
|||
/** |
|||
* the cleanup function. |
|||
* @param aMergeRects = merge for segments forming a rectangle into a rect |
|||
* @param aDeleteRedundant = true to delete null graphics and duplicated graphics |
|||
*/ |
|||
void CleanupBoard( bool aDryRun, std::vector<CLEANUP_ITEM*>* aItemsList, bool aMergeRects, |
|||
bool aDeleteRedundant ); |
|||
|
|||
private: |
|||
bool isNullSegment( DRAWSEGMENT* aSegment ); |
|||
bool areEquivalent( DRAWSEGMENT* aSegment1, DRAWSEGMENT* aSegment2 ); |
|||
|
|||
void cleanupSegments(); |
|||
void mergeRects(); |
|||
void removeItems( std::set<BOARD_ITEM*>& aItems ); |
|||
|
|||
private: |
|||
DRAWINGS& m_drawings; |
|||
MODULE* m_parentModule; // nullptr if not in ModEdit |
|||
BOARD_COMMIT& m_commit; |
|||
bool m_dryRun; |
|||
std::vector<CLEANUP_ITEM*>* m_itemsList; |
|||
}; |
|||
|
|||
|
|||
#endif //KICAD_GRAPHICS_CLEANER_H |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue