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.
This commit is contained in:
Jeff Young 2020-06-17 13:46:50 +01:00
parent a3cab09fb4
commit a7703d1207
37 changed files with 1558 additions and 250 deletions

View File

@ -108,6 +108,8 @@ KIID RC_TREE_MODEL::ToUUID( wxDataViewItem aItem )
case RC_TREE_NODE::MAIN_ITEM: return rc_item->GetMainItemID();
case RC_TREE_NODE::AUX_ITEM: return rc_item->GetAuxItemID();
case RC_TREE_NODE::AUX_ITEM2: return rc_item->GetAuxItem2ID();
case RC_TREE_NODE::AUX_ITEM3: return rc_item->GetAuxItem3ID();
}
}
@ -162,16 +164,22 @@ void RC_TREE_MODEL::rebuildModel( RC_ITEMS_PROVIDER* aProvider, int aSeverities
for( int i = 0; m_rcItemsProvider && i < m_rcItemsProvider->GetCount(); ++i )
{
RC_ITEM* drcItem = m_rcItemsProvider->GetItem( i );
RC_ITEM* rcItem = m_rcItemsProvider->GetItem( i );
m_tree.push_back( new RC_TREE_NODE( nullptr, drcItem, RC_TREE_NODE::MARKER ) );
m_tree.push_back( new RC_TREE_NODE( nullptr, rcItem, RC_TREE_NODE::MARKER ) );
RC_TREE_NODE* n = m_tree.back();
if( drcItem->GetMainItemID() != niluuid )
n->m_Children.push_back( new RC_TREE_NODE( n, drcItem, RC_TREE_NODE::MAIN_ITEM ) );
if( rcItem->GetMainItemID() != niluuid )
n->m_Children.push_back( new RC_TREE_NODE( n, rcItem, RC_TREE_NODE::MAIN_ITEM ) );
if( drcItem->GetAuxItemID() != niluuid )
n->m_Children.push_back( new RC_TREE_NODE( n, drcItem, RC_TREE_NODE::AUX_ITEM ) );
if( rcItem->GetAuxItemID() != niluuid )
n->m_Children.push_back( new RC_TREE_NODE( n, rcItem, RC_TREE_NODE::AUX_ITEM ) );
if( rcItem->GetAuxItem2ID() != niluuid )
n->m_Children.push_back( new RC_TREE_NODE( n, rcItem, RC_TREE_NODE::AUX_ITEM2 ) );
if( rcItem->GetAuxItem3ID() != niluuid )
n->m_Children.push_back( new RC_TREE_NODE( n, rcItem, RC_TREE_NODE::AUX_ITEM3 ) );
}
// Must be called after a significant change of items to force the
@ -256,11 +264,16 @@ void RC_TREE_MODEL::GetValue( wxVariant& aVariant,
{
case RC_TREE_NODE::MARKER:
{
bool excluded = rcItem->GetParent() && rcItem->GetParent()->IsExcluded();
bool error = m_editFrame->GetSeverity( rcItem->GetErrorCode() ) == RPT_SEVERITY_ERROR;
wxString prefix = wxString::Format( wxT( "%s%s" ),
excluded ? _( "Excluded " ) : wxString( "" ),
error ? _( "Error: " ) : _( "Warning: " ) );
wxString prefix;
if( rcItem->GetParent() && rcItem->GetParent()->IsExcluded() )
prefix = _( "Excluded " );
switch( m_editFrame->GetSeverity( rcItem->GetErrorCode() ) )
{
case RPT_SEVERITY_ERROR: prefix += _( "Error: " ); break;
case RPT_SEVERITY_WARNING: prefix += _( "Warning: " ); break;
}
aVariant = prefix + rcItem->GetErrorMessage();
}
@ -269,22 +282,28 @@ void RC_TREE_MODEL::GetValue( wxVariant& aVariant,
case RC_TREE_NODE::MAIN_ITEM:
{
EDA_ITEM* item = m_editFrame->GetItem( rcItem->GetMainItemID() );
if( item )
aVariant = item->GetSelectMenuText( m_editFrame->GetUserUnits() );
else
aVariant = _( "item not found (Please, rerun ERC)" );
}
break;
case RC_TREE_NODE::AUX_ITEM:
{
EDA_ITEM* item = m_editFrame->GetItem( rcItem->GetAuxItemID() );
if( item )
aVariant = item->GetSelectMenuText( m_editFrame->GetUserUnits() );
else
aVariant = _( "item not found (Please, rerun ERC)" );
}
break;
case RC_TREE_NODE::AUX_ITEM2:
{
EDA_ITEM* item = m_editFrame->GetItem( rcItem->GetAuxItem2ID() );
aVariant = item->GetSelectMenuText( m_editFrame->GetUserUnits() );
}
break;
case RC_TREE_NODE::AUX_ITEM3:
{
EDA_ITEM* item = m_editFrame->GetItem( rcItem->GetAuxItem3ID() );
aVariant = item->GetSelectMenuText( m_editFrame->GetUserUnits() );
}
break;
}

View File

@ -82,6 +82,8 @@ protected:
MARKER_BASE* m_parent; // The marker this item belongs to, if any
KIID m_mainItemUuid;
KIID m_auxItemUuid;
KIID m_auxItem2Uuid;
KIID m_auxItem3Uuid;
public:
@ -91,6 +93,8 @@ public:
m_parent = nullptr;
m_mainItemUuid = niluuid;
m_auxItemUuid = niluuid;
m_auxItem2Uuid = niluuid;
m_auxItem3Uuid = niluuid;
}
RC_ITEM( RC_ITEM* aItem )
@ -100,28 +104,42 @@ public:
m_parent = aItem->m_parent;
m_mainItemUuid = aItem->m_mainItemUuid;
m_auxItemUuid = aItem->m_auxItemUuid;
m_auxItem2Uuid = aItem->m_auxItem2Uuid;
m_auxItem3Uuid = aItem->m_auxItem3Uuid;
}
virtual ~RC_ITEM() { }
void SetErrorMessage( const wxString& aMessage ) { m_errorMessage = aMessage; }
void SetItems( EDA_ITEM* aItem, EDA_ITEM* bItem = nullptr )
void SetItems( EDA_ITEM* aItem, EDA_ITEM* bItem = nullptr, EDA_ITEM* cItem = nullptr,
EDA_ITEM* dItem = nullptr )
{
m_mainItemUuid = aItem->m_Uuid;
if( bItem )
m_auxItemUuid = bItem->m_Uuid;
if( cItem )
m_auxItem2Uuid = cItem->m_Uuid;
if( dItem )
m_auxItem3Uuid = dItem->m_Uuid;
}
void SetItems( const KIID& aItem, const KIID& bItem = niluuid )
void SetItems( const KIID& aItem, const KIID& bItem = niluuid, const KIID& cItem = niluuid,
const KIID& dItem = niluuid )
{
m_mainItemUuid = aItem;
m_auxItemUuid = bItem;
m_auxItem2Uuid = cItem;
m_auxItem3Uuid = dItem;
}
KIID GetMainItemID() const { return m_mainItemUuid; }
KIID GetAuxItemID() const { return m_auxItemUuid; }
KIID GetAuxItem2ID() const { return m_auxItem2Uuid; }
KIID GetAuxItem3ID() const { return m_auxItem3Uuid; }
void SetParent( MARKER_BASE* aMarker ) { m_parent = aMarker; }
MARKER_BASE* GetParent() const { return m_parent; }
@ -161,7 +179,7 @@ public:
class RC_TREE_NODE
{
public:
enum NODE_TYPE { MARKER, MAIN_ITEM, AUX_ITEM };
enum NODE_TYPE { MARKER, MAIN_ITEM, AUX_ITEM, AUX_ITEM2, AUX_ITEM3 };
RC_TREE_NODE( RC_TREE_NODE* aParent, RC_ITEM* aRcItem, NODE_TYPE aType ) :
m_Type( aType ),

View File

@ -41,6 +41,44 @@
#include <wx/filename.h>
#include "erc_item.h"
/**
* A singleton item of this class is returned for a weak reference that no longer exists.
* Its sole purpose is to flag the item as having been deleted.
*/
class DELETED_SHEET_ITEM : public SCH_ITEM
{
public:
DELETED_SHEET_ITEM() :
SCH_ITEM( nullptr, NOT_USED )
{}
wxString GetSelectMenuText( EDA_UNITS aUnits ) const override
{
return _( "(Deleted Item)" );
}
wxString GetClass() const override
{
return wxT( "DELETED_SHEET_ITEM" );
}
// pure virtuals:
void SetPosition( const wxPoint& ) override {}
void Print( RENDER_SETTINGS* aSettings, const wxPoint& aOffset ) override {}
void Move( const wxPoint& aMoveVector ) override {}
void MirrorY( int aYaxis_position ) override {}
void MirrorX( int aXaxis_position ) override {}
void Rotate( wxPoint aPosition ) override {}
#if defined(DEBUG)
void Show( int , std::ostream& ) const override {}
#endif
};
DELETED_SHEET_ITEM* g_DeletedItem = nullptr;
namespace std
{
size_t hash<SCH_SHEET_PATH>::operator()( const SCH_SHEET_PATH& path ) const
@ -491,7 +529,11 @@ SCH_ITEM* SCH_SHEET_LIST::GetItem( const KIID& aID, SCH_SHEET_PATH* aPathOut )
}
}
return nullptr;
// Not found; weak reference has been deleted.
if( !g_DeletedItem )
g_DeletedItem = new DELETED_SHEET_ITEM();
return g_DeletedItem;
}

View File

@ -362,24 +362,18 @@ public:
virtual void SwitchLayer( wxDC* DC, PCB_LAYER_ID layer );
/**
* Function SetActiveLayer
* will change the currently active layer to \a aLayer.
*/
virtual void SetActiveLayer( PCB_LAYER_ID aLayer )
{
GetScreen()->m_Active_Layer = aLayer;
}
/**
* Function GetActiveLayer
* returns the active layer
*/
virtual PCB_LAYER_ID GetActiveLayer() const
{
return GetScreen()->m_Active_Layer;
}
int GetSeverity( int aErrorCode ) const override;
void LoadSettings( APP_SETTINGS_BASE* aCfg ) override;
void SaveSettings( APP_SETTINGS_BASE* aCfg ) override;

View File

@ -55,6 +55,8 @@ set( PCBNEW_DIALOGS
dialogs/dialog_board_statistics.cpp
dialogs/dialog_board_statistics_base.cpp
dialogs/dialog_choose_footprint.cpp
dialogs/dialog_cleanup_graphics.cpp
dialogs/dialog_cleanup_graphics_base.cpp
dialogs/dialog_cleanup_tracks_and_vias.cpp
dialogs/dialog_cleanup_tracks_and_vias_base.cpp
dialogs/dialog_copper_zones.cpp
@ -262,6 +264,7 @@ set( PCBNEW_CLASS_SRCS
array_creator.cpp
array_pad_name_provider.cpp
build_BOM_from_board.cpp
cleanup_item.cpp
cross-probing.cpp
edit.cpp
edit_track_width.cpp
@ -276,6 +279,7 @@ set( PCBNEW_CLASS_SRCS
footprint_viewer_frame.cpp
fp_tree_model_adapter.cpp
generate_footprint_info.cpp
graphics_cleaner.cpp
grid_layer_box_helpers.cpp
grid_layer_box_helpers.h
initpcb.cpp

View File

@ -93,15 +93,6 @@ public:
bds.m_DRCSeverities[ DRCE_OVERLAPPING_FOOTPRINTS ] = RPT_SEVERITY_IGNORE;
}
bds.m_DRCSeverities[ CLEANUP_SHORT ] = RPT_SEVERITY_ACTION;
bds.m_DRCSeverities[ CLEANUP_REDUNDANT_VIA ] = RPT_SEVERITY_ACTION;
bds.m_DRCSeverities[ CLEANUP_DUPLICATE_TRACK ] = RPT_SEVERITY_ACTION;
bds.m_DRCSeverities[ CLEANUP_MERGE_TRACKS ] = RPT_SEVERITY_ACTION;
bds.m_DRCSeverities[ CLEANUP_DANGLING_TRACK ] = RPT_SEVERITY_ACTION;
bds.m_DRCSeverities[ CLEANUP_DANGLING_VIA ] = RPT_SEVERITY_ACTION;
bds.m_DRCSeverities[ CLEANUP_ZERO_LENGTH_TRACK ] = RPT_SEVERITY_ACTION;
bds.m_DRCSeverities[ CLEANUP_TRACK_IN_PAD ] = RPT_SEVERITY_ACTION;
DRC_ITEM drc( 0 );
wxString severity;

View File

@ -29,6 +29,7 @@
#include <msgpanel.h>
#include <bitmaps.h>
#include <base_units.h>
#include <pcb_base_frame.h>
#include <class_board.h>
#include <class_board_item.h>
#include <class_marker_pcb.h>

72
pcbnew/cleanup_item.cpp Normal file
View File

@ -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;
}

124
pcbnew/cleanup_item.h Normal file
View File

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

View File

@ -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 );
}
}

View File

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

View File

@ -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 );
}

View File

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

View File

@ -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();
};

View File

@ -20,14 +20,11 @@
* 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 <board_commit.h>
#include <wx/wx.h>
#include <dialog_cleanup_tracks_and_vias.h>
#include <kiface_i.h>
#include <pcb_edit_frame.h>
#include <pcbnew_settings.h>
#include <reporter.h>
#include <tool/tool_manager.h>
#include <tools/pcb_actions.h>
#include <tracks_cleaner.h>
@ -71,7 +68,7 @@ DIALOG_CLEANUP_TRACKS_AND_VIAS::~DIALOG_CLEANUP_TRACKS_AND_VIAS()
cfg->m_Cleanup.cleanup_short_circuits = m_cleanShortCircuitOpt->GetValue();
cfg->m_Cleanup.cleanup_tracks_in_pad = m_deleteTracksInPadsOpt->GetValue();
for( DRC_ITEM* item : m_items )
for( CLEANUP_ITEM* item : m_items )
delete item;
m_changesTreeModel->DecRef();
@ -104,7 +101,7 @@ void DIALOG_CLEANUP_TRACKS_AND_VIAS::doCleanup( bool aDryRun )
{
wxBusyCursor busy;
BOARD_COMMIT commit( m_parentFrame );
TRACKS_CLEANER cleaner( m_parentFrame->GetUserUnits(), m_parentFrame->GetBoard(), commit );
TRACKS_CLEANER cleaner( m_parentFrame->GetBoard(), commit );
if( !aDryRun )
{
@ -115,7 +112,7 @@ void DIALOG_CLEANUP_TRACKS_AND_VIAS::doCleanup( bool aDryRun )
m_changesTreeModel->SetProvider( nullptr );
}
for( DRC_ITEM* item : m_items )
for( CLEANUP_ITEM* item : m_items )
delete item;
m_items.clear();
@ -123,8 +120,7 @@ void DIALOG_CLEANUP_TRACKS_AND_VIAS::doCleanup( bool aDryRun )
// Old model has to be refreshed, GAL normally does not keep updating it
m_parentFrame->Compile_Ratsnest( false );
bool modified = cleaner.CleanupBoard( aDryRun, &m_items,
m_cleanShortCircuitOpt->GetValue(),
cleaner.CleanupBoard( aDryRun, &m_items, m_cleanShortCircuitOpt->GetValue(),
m_cleanViasOpt->GetValue(),
m_mergeSegmOpt->GetValue(),
m_deleteUnconnectedOpt->GetValue(),
@ -132,10 +128,10 @@ void DIALOG_CLEANUP_TRACKS_AND_VIAS::doCleanup( bool aDryRun )
if( aDryRun )
{
RC_ITEMS_PROVIDER* provider = new VECTOR_DRC_ITEMS_PROVIDER( m_parentFrame, &m_items );
RC_ITEMS_PROVIDER* provider = new VECTOR_CLEANUP_ITEMS_PROVIDER( &m_items );
m_changesTreeModel->SetProvider( provider );
}
else if( modified )
else if( !commit.Empty() )
{
// Clear undo and redo lists to avoid inconsistencies between lists
commit.Push( _( "Board cleanup" ) );

View File

@ -26,18 +26,16 @@
#define DIALOG_CLEANUP_TRACKS_AND_VIAS_H_
#include <dialog_cleanup_tracks_and_vias_base.h>
#include <drc/drc.h>
#include <cleanup_item.h>
class PCB_EDIT_FRAME;
class DRC_TREE_MODEL;
class DIALOG_CLEANUP_TRACKS_AND_VIAS: public DIALOG_CLEANUP_TRACKS_AND_VIAS_BASE
{
PCB_EDIT_FRAME* m_parentFrame;
std::vector<DRC_ITEM*> m_items;
std::vector<CLEANUP_ITEM*> m_items;
RC_TREE_MODEL* m_changesTreeModel;
void doCleanup( bool aDryRun );

View File

@ -58,11 +58,11 @@
<property name="name">bSizerMain</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<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="0">
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizerUpper</property>
<property name="orient">wxVERTICAL</property>
@ -295,7 +295,7 @@
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Delete &amp;dangling tracks</property>
<property name="label">Delete tracks unconnected at one end</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
@ -360,7 +360,7 @@
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Delete Tracks in Pads</property>
<property name="label">Delete tracks fully inside pads</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>

View File

@ -106,17 +106,7 @@ enum PCB_DRC_CODE {
DRCE_UNRESOLVED_VARIABLE,
DRCE_LAST = DRCE_UNRESOLVED_VARIABLE,
// These are actually Cleanup Tracks and Vias actions, not DRCE errors
CLEANUP_SHORT,
CLEANUP_REDUNDANT_VIA,
CLEANUP_DUPLICATE_TRACK,
CLEANUP_MERGE_TRACKS,
CLEANUP_DANGLING_TRACK,
CLEANUP_DANGLING_VIA,
CLEANUP_ZERO_LENGTH_TRACK,
CLEANUP_TRACK_IN_PAD
DRCE_LAST = DRCE_UNRESOLVED_VARIABLE
};

View File

@ -129,16 +129,6 @@ wxString DRC_ITEM::GetErrorText( int aCode, bool aTranslate ) const
case DRCE_MISSING_FOOTPRINT: msg = _HKI( "Missing footprint" ); break;
case DRCE_EXTRA_FOOTPRINT: msg = _HKI( "Extra footprint" ); break;
// 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;
case DRCE_UNRESOLVED_VARIABLE: msg = _HKI( "Unresolved text variable" ); break;
default:

View File

@ -25,13 +25,9 @@
#ifndef DRC_ITEM_H
#define DRC_ITEM_H
#include <macros.h>
#include <base_struct.h>
#include <rc_item.h>
#include <marker_base.h>
#include <class_board.h>
#include <pcb_base_frame.h>
#include "drc.h"
class PCB_BASE_FRAME;
class DRC_ITEM : public RC_ITEM
{

View File

@ -27,7 +27,9 @@
#include <class_board.h>
#include <class_marker_pcb.h>
#include <pcb_base_frame.h>
#include <drc/drc.h>
#include <widgets/ui_common.h>
#include <functional>

View File

@ -27,6 +27,8 @@
#include <settings/settings_manager.h>
#include <wx/config.h>
#include <base_units.h>
#include <drc/drc.h>
#include <widgets/ui_common.h>
extern const char* traceSettings;

347
pcbnew/graphics_cleaner.cpp Normal file
View File

@ -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 );
}
}

65
pcbnew/graphics_cleaner.h Normal file
View File

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

View File

@ -137,6 +137,9 @@ void FOOTPRINT_EDIT_FRAME::ReCreateMenuBar()
editMenu->AddItem( PCB_ACTIONS::footprintProperties, haveFootprintCondition );
editMenu->AddItem( PCB_ACTIONS::defaultPadProperties, SELECTION_CONDITIONS::ShowAlways );
editMenu->AddSeparator();
editMenu->AddItem( PCB_ACTIONS::cleanupGraphics, haveFootprintCondition );
editMenu->Resolve();
//-- View menu -------------------------------------------------------

View File

@ -251,6 +251,7 @@ void PCB_EDIT_FRAME::ReCreateMenuBar()
editMenu->AddItem( ACTIONS::deleteTool, SELECTION_CONDITIONS::ShowAlways );
editMenu->AddItem( PCB_ACTIONS::globalDeletions, SELECTION_CONDITIONS::ShowAlways );
editMenu->AddItem( PCB_ACTIONS::cleanupTracksAndVias, SELECTION_CONDITIONS::ShowAlways );
editMenu->AddItem( PCB_ACTIONS::cleanupGraphics, SELECTION_CONDITIONS::ShowAlways );
editMenu->Resolve();

View File

@ -51,6 +51,7 @@
#include <tool/tool_dispatcher.h>
#include <tools/pcb_actions.h>
#include <tool/grid_menu.h>
#include "cleanup_item.h"
wxDEFINE_EVENT( BOARD_CHANGED, wxCommandEvent );
@ -662,6 +663,17 @@ void PCB_BASE_FRAME::LoadSettings( APP_SETTINGS_BASE* aCfg )
}
int PCB_BASE_FRAME::GetSeverity( int aErrorCode ) const
{
if( aErrorCode >= CLEANUP_FIRST )
return RPT_SEVERITY_ACTION;
BOARD_DESIGN_SETTINGS& bds = GetBoard()->GetDesignSettings();
return bds.m_DRCSeverities[ aErrorCode ];
}
void PCB_BASE_FRAME::SaveSettings( APP_SETTINGS_BASE* aCfg )
{
EDA_DRAW_FRAME::SaveSettings( aCfg );

View File

@ -370,14 +370,6 @@ BOARD_ITEM_CONTAINER* PCB_EDIT_FRAME::GetModel() const
}
int PCB_EDIT_FRAME::GetSeverity( int aErrorCode ) const
{
BOARD_DESIGN_SETTINGS& bds = GetBoard()->GetDesignSettings();
return bds.m_DRCSeverities[ aErrorCode ];
}
void PCB_EDIT_FRAME::SetPageSettings( const PAGE_INFO& aPageSettings )
{
PCB_BASE_FRAME::SetPageSettings( aPageSettings );

View File

@ -672,9 +672,6 @@ public:
///> @copydoc PCB_BASE_FRAME::GetModel()
BOARD_ITEM_CONTAINER* GetModel() const override;
///> @copydoc EDA_BASE_FRAME::GetSeverity()
int GetSeverity( int aErrorCode ) const override;
///> @copydoc PCB_BASE_FRAME::SetPageSettings()
void SetPageSettings( const PAGE_INFO& aPageSettings ) override;

View File

@ -27,32 +27,21 @@
#include <pad_naming.h>
#include "kicad_clipboard.h"
#include "selection_tool.h"
#include "pcb_actions.h"
#include <core/optional.h>
#include <tool/tool_manager.h>
#include <class_draw_panel_gal.h>
#include <tools/pcb_actions.h>
#include <view/view_controls.h>
#include <view/view_group.h>
#include <pcb_painter.h>
#include <origin_viewitem.h>
#include <status_popup.h>
#include <footprint_edit_frame.h>
#include <kicad_plugin.h>
#include <pcbnew_id.h>
#include <collectors.h>
#include <confirm.h>
#include <bitmaps.h>
#include <pcb_edit_frame.h>
#include <class_board.h>
#include <class_module.h>
#include <class_edge_mod.h>
#include <board_commit.h>
#include <project.h>
#include <tools/tool_event_utils.h>
#include <fp_lib_table.h>
#include <functional>
using namespace std::placeholders;
#include <wx/defs.h>
#include <dialogs/dialog_cleanup_graphics.h>
FOOTPRINT_EDITOR_TOOLS::FOOTPRINT_EDITOR_TOOLS() :
@ -605,6 +594,17 @@ int FOOTPRINT_EDITOR_TOOLS::CreatePadFromShapes( const TOOL_EVENT& aEvent )
return 0;
}
int FOOTPRINT_EDITOR_TOOLS::CleanupGraphics( const TOOL_EVENT& aEvent )
{
FOOTPRINT_EDIT_FRAME* editFrame = getEditFrame<FOOTPRINT_EDIT_FRAME>();
DIALOG_CLEANUP_GRAPHICS dlg( editFrame, true );
dlg.ShowModal();
return 0;
}
void FOOTPRINT_EDITOR_TOOLS::setTransitions()
{
Go( &FOOTPRINT_EDITOR_TOOLS::NewFootprint, PCB_ACTIONS::newFootprint.MakeEvent() );
@ -625,6 +625,8 @@ void FOOTPRINT_EDITOR_TOOLS::setTransitions()
Go( &FOOTPRINT_EDITOR_TOOLS::ImportFootprint, PCB_ACTIONS::importFootprint.MakeEvent() );
Go( &FOOTPRINT_EDITOR_TOOLS::ExportFootprint, PCB_ACTIONS::exportFootprint.MakeEvent() );
Go( &FOOTPRINT_EDITOR_TOOLS::CleanupGraphics, PCB_ACTIONS::cleanupGraphics.MakeEvent() );
Go( &FOOTPRINT_EDITOR_TOOLS::PinLibrary, ACTIONS::pinLibrary.MakeEvent() );
Go( &FOOTPRINT_EDITOR_TOOLS::UnpinLibrary, ACTIONS::unpinLibrary.MakeEvent() );
Go( &FOOTPRINT_EDITOR_TOOLS::ToggleFootprintTree, PCB_ACTIONS::toggleFootprintTree.MakeEvent() );

View File

@ -67,6 +67,8 @@ public:
int ToggleFootprintTree( const TOOL_EVENT& aEvent );
int Properties( const TOOL_EVENT& aEvent );
int CleanupGraphics( const TOOL_EVENT& aEvent );
/**
* Edit the properties used for new pad creation.
*/

View File

@ -21,21 +21,16 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <bitmaps.h>
#include <class_track.h>
#include <class_zone.h>
#include <tool/tool_manager.h>
#include <tools/pcb_actions.h>
#include <tools/selection_tool.h>
#include <tools/edit_tool.h>
#include <dialogs/dialog_track_via_properties.h>
#include <dialogs/dialog_exchange_footprints.h>
#include <dialogs/dialog_cleanup_tracks_and_vias.h>
#include <dialogs/dialog_swap_layers.h>
#include <tools/global_edit_tool.h>
#include <board_commit.h>
#include <memory>
#include <dialogs/dialog_cleanup_graphics.h>
GLOBAL_EDIT_TOOL::GLOBAL_EDIT_TOOL() :
PCB_TOOL_BASE( "pcbnew.GlobalEdit" ),
@ -175,6 +170,26 @@ int GLOBAL_EDIT_TOOL::SwapLayers( const TOOL_EVENT& aEvent )
}
int GLOBAL_EDIT_TOOL::CleanupTracksAndVias( const TOOL_EVENT& aEvent )
{
PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
DIALOG_CLEANUP_TRACKS_AND_VIAS dlg( editFrame );
dlg.ShowModal();
return 0;
}
int GLOBAL_EDIT_TOOL::CleanupGraphics( const TOOL_EVENT& aEvent )
{
PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
DIALOG_CLEANUP_GRAPHICS dlg( editFrame, false );
dlg.ShowModal();
return 0;
}
void GLOBAL_EDIT_TOOL::setTransitions()
{
Go( &GLOBAL_EDIT_TOOL::ExchangeFootprints, PCB_ACTIONS::updateFootprint.MakeEvent() );
@ -188,6 +203,7 @@ void GLOBAL_EDIT_TOOL::setTransitions()
Go( &GLOBAL_EDIT_TOOL::EditTextAndGraphics, PCB_ACTIONS::editTextAndGraphics.MakeEvent() );
Go( &GLOBAL_EDIT_TOOL::GlobalDeletions, PCB_ACTIONS::globalDeletions.MakeEvent() );
Go( &GLOBAL_EDIT_TOOL::CleanupTracksAndVias, PCB_ACTIONS::cleanupTracksAndVias.MakeEvent() );
Go( &GLOBAL_EDIT_TOOL::CleanupGraphics, PCB_ACTIONS::cleanupGraphics.MakeEvent() );
}

View File

@ -60,6 +60,7 @@ public:
int EditTextAndGraphics( const TOOL_EVENT& aEvent );
int GlobalDeletions( const TOOL_EVENT& aEvent );
int CleanupTracksAndVias( const TOOL_EVENT& aEvent );
int CleanupGraphics( const TOOL_EVENT& aEvent );
private:
bool swapBoardItem( BOARD_ITEM* aItem, PCB_LAYER_ID* new_layer );

View File

@ -405,9 +405,14 @@ TOOL_ACTION PCB_ACTIONS::globalDeletions( "pcbnew.GlobalEdit.globalDeletions",
TOOL_ACTION PCB_ACTIONS::cleanupTracksAndVias( "pcbnew.GlobalEdit.cleanupTracksAndVias",
AS_GLOBAL, 0, "",
_( "Cleanup Tracks & Vias..." ),
_( "Clean stubs, vias, delete break points or unconnected tracks" ),
_( "Cleanup redundant items, shorting items, etc." ),
delete_xpm );
TOOL_ACTION PCB_ACTIONS::cleanupGraphics( "pcbnew.GlobalEdit.cleanupGraphics",
AS_GLOBAL, 0, "",
_( "Cleanup Graphics..." ),
_( "Cleanup redundant items, etc." ),
delete_xpm );
// MICROWAVE_TOOL
//

View File

@ -297,6 +297,7 @@ public:
static TOOL_ACTION editTextAndGraphics;
static TOOL_ACTION globalDeletions;
static TOOL_ACTION cleanupTracksAndVias;
static TOOL_ACTION cleanupGraphics;
static TOOL_ACTION updateFootprint;
static TOOL_ACTION updateFootprints;
static TOOL_ACTION changeFootprint;

View File

@ -24,14 +24,9 @@
*/
#include <fctsys.h>
#include <pcb_edit_frame.h>
#include <pcbnew.h>
#include <class_board.h>
#include <class_track.h>
#include <dialog_cleanup_tracks_and_vias.h>
#include <reporter.h>
#include <board_commit.h>
#include <drc/drc_item.h>
#include <cleanup_item.h>
#include <connectivity/connectivity_algo.h>
#include <connectivity/connectivity_data.h>
#include <tool/tool_manager.h>
@ -40,20 +35,8 @@
#include <tracks_cleaner.h>
/* Install the cleanup dialog frame to know what should be cleaned
*/
int GLOBAL_EDIT_TOOL::CleanupTracksAndVias( const TOOL_EVENT& aEvent )
{
PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
DIALOG_CLEANUP_TRACKS_AND_VIAS dlg( editFrame );
dlg.ShowModal();
return 0;
}
TRACKS_CLEANER::TRACKS_CLEANER( EDA_UNITS aUnits, BOARD* aPcb, BOARD_COMMIT& aCommit )
: m_brd( aPcb ),
TRACKS_CLEANER::TRACKS_CLEANER( BOARD* aPcb, BOARD_COMMIT& aCommit ) :
m_brd( aPcb ),
m_commit( aCommit ),
m_dryRun( true ),
m_itemsList( nullptr )
@ -67,42 +50,39 @@ TRACKS_CLEANER::TRACKS_CLEANER( EDA_UNITS aUnits, BOARD* aPcb, BOARD_COMMIT& aCo
* - vias on pad
* - null length segments
*/
bool TRACKS_CLEANER::CleanupBoard( bool aDryRun, std::vector<DRC_ITEM*>* aItemsList,
void TRACKS_CLEANER::CleanupBoard( bool aDryRun, std::vector<CLEANUP_ITEM*>* aItemsList,
bool aRemoveMisConnected, bool aCleanVias, bool aMergeSegments,
bool aDeleteUnconnected, bool aDeleteTracksinPad )
{
m_dryRun = aDryRun;
m_itemsList = aItemsList;
bool modified = false;
// Clear the flag used to mark some segments as deleted, in dry run:
for( auto segment : m_brd->Tracks() )
for( TRACK* segment : m_brd->Tracks() )
segment->ClearFlags( IS_DELETED );
// delete redundant vias
if( aCleanVias )
modified |= cleanupVias();
cleanupVias();
// Remove null segments and intermediate points on aligned segments
// If not asked, remove null segments only if remove misconnected is asked
if( aMergeSegments )
modified |= cleanupSegments();
cleanupSegments();
else if( aRemoveMisConnected )
modified |= deleteNullSegments( m_brd->Tracks() );
deleteNullSegments( m_brd->Tracks() );
if( aRemoveMisConnected )
modified |= removeBadTrackSegments();
removeBadTrackSegments();
if( aDeleteTracksinPad )
modified |= deleteTracksInPads();
deleteTracksInPads();
// Delete dangling tracks
if( aDeleteUnconnected )
{
if( deleteDanglingTracks() )
{
modified = true;
// Removed tracks can leave aligned segments
// (when a T was formed by tracks and the "vertical" segment is removed)
if( aMergeSegments )
@ -111,20 +91,18 @@ bool TRACKS_CLEANER::CleanupBoard( bool aDryRun, std::vector<DRC_ITEM*>* aItemsL
}
// Clear the flag used to mark some segments:
for( auto segment : m_brd->Tracks() )
for( TRACK* segment : m_brd->Tracks() )
segment->ClearFlags( IS_DELETED );
return modified;
}
bool TRACKS_CLEANER::removeBadTrackSegments()
void TRACKS_CLEANER::removeBadTrackSegments()
{
auto connectivity = m_brd->GetConnectivity();
std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_brd->GetConnectivity();
std::set<BOARD_ITEM *> toRemove;
for( auto segment : m_brd->Tracks() )
for( TRACK* segment : m_brd->Tracks() )
{
segment->SetState( FLAG0, false );
@ -132,7 +110,7 @@ bool TRACKS_CLEANER::removeBadTrackSegments()
{
if( segment->GetNetCode() != testedPad->GetNetCode() )
{
DRC_ITEM* item = new DRC_ITEM( CLEANUP_SHORT );
CLEANUP_ITEM* item = new CLEANUP_ITEM( CLEANUP_SHORT );
item->SetItems( segment );
m_itemsList->push_back( item );
@ -140,11 +118,11 @@ bool TRACKS_CLEANER::removeBadTrackSegments()
}
}
for( auto testedTrack : connectivity->GetConnectedTracks( segment ) )
for( TRACK* testedTrack : connectivity->GetConnectedTracks( segment ) )
{
if( segment->GetNetCode() != testedTrack->GetNetCode() && !testedTrack->GetState( FLAG0 ) )
{
DRC_ITEM* item = new DRC_ITEM( CLEANUP_SHORT );
CLEANUP_ITEM* item = new CLEANUP_ITEM( CLEANUP_SHORT );
item->SetItems( segment );
m_itemsList->push_back( item );
@ -153,16 +131,17 @@ bool TRACKS_CLEANER::removeBadTrackSegments()
}
}
return removeItems( toRemove );
if( !m_dryRun )
removeItems( toRemove );
}
bool TRACKS_CLEANER::cleanupVias()
void TRACKS_CLEANER::cleanupVias()
{
std::set<BOARD_ITEM*> toRemove;
std::vector<VIA*> vias;
for( auto track : m_brd->Tracks() )
for( TRACK* track : m_brd->Tracks() )
{
if( auto via = dyn_cast<VIA*>( track ) )
vias.push_back( via );
@ -170,7 +149,7 @@ bool TRACKS_CLEANER::cleanupVias()
for( auto via1_it = vias.begin(); via1_it != vias.end(); via1_it++ )
{
auto via1 = *via1_it;
VIA* via1 = *via1_it;
if( via1->IsLocked() )
continue;
@ -182,14 +161,15 @@ bool TRACKS_CLEANER::cleanupVias()
// Examine the list of connected pads:
// if a through pad is found, the via can be removed
const auto pads = m_brd->GetConnectivity()->GetConnectedPads( via1 );
for( const auto pad : pads )
const std::vector<D_PAD*> pads = m_brd->GetConnectivity()->GetConnectedPads( via1 );
for( D_PAD* pad : pads )
{
const LSET all_cu = LSET::AllCuMask();
if( ( pad->GetLayerSet() & all_cu ) == all_cu )
{
DRC_ITEM* item = new DRC_ITEM( CLEANUP_REDUNDANT_VIA );
CLEANUP_ITEM* item = new CLEANUP_ITEM( CLEANUP_REDUNDANT_VIA );
item->SetItems( via1, pad );
m_itemsList->push_back( item );
@ -201,14 +181,14 @@ bool TRACKS_CLEANER::cleanupVias()
for( auto via2_it = via1_it + 1; via2_it != vias.end(); via2_it++ )
{
auto via2 = *via2_it;
VIA* via2 = *via2_it;
if( via1->GetPosition() != via2->GetPosition() || via2->IsLocked() )
continue;
if( via1->GetViaType() == via2->GetViaType() )
{
DRC_ITEM* item = new DRC_ITEM( CLEANUP_REDUNDANT_VIA );
CLEANUP_ITEM* item = new CLEANUP_ITEM( CLEANUP_REDUNDANT_VIA );
item->SetItems( via1, via2 );
m_itemsList->push_back( item );
@ -218,8 +198,8 @@ bool TRACKS_CLEANER::cleanupVias()
}
}
return removeItems( toRemove );
if( !m_dryRun )
removeItems( toRemove );
}
@ -282,7 +262,7 @@ bool TRACKS_CLEANER::deleteDanglingTracks()
if( flag_erase )
{
int errorCode = track->IsTrack() ? CLEANUP_DANGLING_TRACK : CLEANUP_DANGLING_VIA;
DRC_ITEM* item = new DRC_ITEM( errorCode );
CLEANUP_ITEM* item = new CLEANUP_ITEM( errorCode );
item->SetItems( track );
m_itemsList->push_back( item );
@ -307,15 +287,15 @@ bool TRACKS_CLEANER::deleteDanglingTracks()
// Delete null length track segments
bool TRACKS_CLEANER::deleteNullSegments( TRACKS& aTracks )
void TRACKS_CLEANER::deleteNullSegments( TRACKS& aTracks )
{
std::set<BOARD_ITEM *> toRemove;
for( auto segment : aTracks )
for( TRACK* segment : aTracks )
{
if( segment->IsNull() && segment->Type() == PCB_TRACE_T && !segment->IsLocked() )
{
DRC_ITEM* item = new DRC_ITEM( CLEANUP_ZERO_LENGTH_TRACK );
CLEANUP_ITEM* item = new CLEANUP_ITEM( CLEANUP_ZERO_LENGTH_TRACK );
item->SetItems( segment );
m_itemsList->push_back( item );
@ -323,25 +303,26 @@ bool TRACKS_CLEANER::deleteNullSegments( TRACKS& aTracks )
}
}
return removeItems( toRemove );
if( !m_dryRun )
removeItems( toRemove );
}
bool TRACKS_CLEANER::deleteTracksInPads()
void TRACKS_CLEANER::deleteTracksInPads()
{
std::set<BOARD_ITEM*> toRemove;
// Delete tracks that start and end on the same pad
auto connectivity = m_brd->GetConnectivity();
std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_brd->GetConnectivity();
for( auto track : m_brd->Tracks() )
for( TRACK* track : m_brd->Tracks() )
{
// Mark track if connected to pads
for( auto pad : connectivity->GetConnectedPads( track ) )
for( D_PAD* pad : connectivity->GetConnectedPads( track ) )
{
if( pad->HitTest( track->GetStart() ) && pad->HitTest( track->GetEnd() ) )
{
DRC_ITEM* item = new DRC_ITEM( CLEANUP_TRACK_IN_PAD );
CLEANUP_ITEM* item = new CLEANUP_ITEM( CLEANUP_TRACK_IN_PAD );
item->SetItems( track );
m_itemsList->push_back( item );
@ -350,31 +331,30 @@ bool TRACKS_CLEANER::deleteTracksInPads()
}
}
return removeItems( toRemove );
if( !m_dryRun )
removeItems( toRemove );
}
// Delete null length segments, and intermediate points ..
bool TRACKS_CLEANER::cleanupSegments()
void TRACKS_CLEANER::cleanupSegments()
{
bool modified = false;
// Easy things first
modified |= deleteNullSegments( m_brd->Tracks() );
deleteNullSegments( m_brd->Tracks() );
std::set<BOARD_ITEM*> toRemove;
// Remove duplicate segments (2 superimposed identical segments):
for( auto it = m_brd->Tracks().begin(); it != m_brd->Tracks().end(); it++ )
{
auto track1 = *it;
TRACK* track1 = *it;
if( track1->Type() != PCB_TRACE_T || track1->HasFlag( IS_DELETED ) || track1->IsLocked() )
continue;
for( auto it2 = it + 1; it2 != m_brd->Tracks().end(); it2++ )
{
auto track2 = *it2;
TRACK* track2 = *it2;
if( track2->HasFlag( IS_DELETED ) )
continue;
@ -384,7 +364,7 @@ bool TRACKS_CLEANER::cleanupSegments()
&& track1->GetWidth() == track2->GetWidth()
&& track1->GetLayer() == track2->GetLayer() )
{
DRC_ITEM* item = new DRC_ITEM( CLEANUP_DUPLICATE_TRACK );
CLEANUP_ITEM* item = new CLEANUP_ITEM( CLEANUP_DUPLICATE_TRACK );
item->SetItems( track2 );
m_itemsList->push_back( item );
@ -394,7 +374,8 @@ bool TRACKS_CLEANER::cleanupSegments()
}
}
modified |= removeItems( toRemove );
if( !m_dryRun )
removeItems( toRemove );
// Keep a duplicate deque to all deleting in the primary
std::deque<TRACK*> temp_segments( m_brd->Tracks() );
@ -412,9 +393,9 @@ bool TRACKS_CLEANER::cleanupSegments()
auto& entry = connectivity->GetConnectivityAlgo()->ItemEntry( segment );
for( auto citem : entry.GetItems() )
for( CN_ITEM* citem : entry.GetItems() )
{
for( auto connected : citem->ConnectedItems() )
for( CN_ITEM* connected : citem->ConnectedItems() )
{
if( !connected->Valid() )
continue;
@ -431,20 +412,18 @@ bool TRACKS_CLEANER::cleanupSegments()
continue;
if( segment->ApproxCollinear( *candidateSegment ) )
modified |= mergeCollinearSegments( segment, candidateSegment );
mergeCollinearSegments( segment, candidateSegment );
}
}
}
}
}
return modified;
}
bool TRACKS_CLEANER::mergeCollinearSegments( TRACK* aSeg1, TRACK* aSeg2 )
void TRACKS_CLEANER::mergeCollinearSegments( TRACK* aSeg1, TRACK* aSeg2 )
{
if( aSeg1->IsLocked() || aSeg2->IsLocked() )
return false;
return;
auto connectivity = m_brd->GetConnectivity();
@ -478,16 +457,16 @@ bool TRACKS_CLEANER::mergeCollinearSegments( TRACK* aSeg1, TRACK* aSeg2 )
if( aSeg1->GetStart() != dummy_seg.GetStart() && aSeg1->GetStart() != dummy_seg.GetEnd() )
{
if( testTrackEndpointIsNode( aSeg1, true ) )
return false;
return;
}
if( aSeg1->GetEnd() != dummy_seg.GetStart() && aSeg1->GetEnd() != dummy_seg.GetEnd() )
{
if( testTrackEndpointIsNode( aSeg1, false ) )
return false;
return;
}
DRC_ITEM* item = new DRC_ITEM( CLEANUP_MERGE_TRACKS );
CLEANUP_ITEM* item = new CLEANUP_ITEM( CLEANUP_MERGE_TRACKS );
item->SetItems( aSeg1, aSeg2 );
m_itemsList->push_back( item );
@ -511,21 +490,14 @@ bool TRACKS_CLEANER::mergeCollinearSegments( TRACK* aSeg1, TRACK* aSeg2 )
m_brd->Remove( aSeg2 );
m_commit.Removed( aSeg2 );
}
return true;
}
bool TRACKS_CLEANER::removeItems( std::set<BOARD_ITEM*>& aItems )
void TRACKS_CLEANER::removeItems( std::set<BOARD_ITEM*>& aItems )
{
if( m_dryRun )
return false;
for( auto item : aItems )
{
m_brd->Remove( item );
m_commit.Removed( item );
}
return !aItems.empty();
}

View File

@ -25,60 +25,52 @@
#define KICAD_TRACKS_CLEANER_H
#include <class_track.h>
#include <class_board.h>
class BOARD;
class BOARD_COMMIT;
class CLEANUP_ITEM;
// Helper class used to clean tracks and vias
class TRACKS_CLEANER
{
public:
TRACKS_CLEANER( EDA_UNITS aUnits, BOARD* aPcb, BOARD_COMMIT& aCommit );
TRACKS_CLEANER( BOARD* aPcb, BOARD_COMMIT& aCommit );
/**
* the cleanup function.
* return true if some item was modified
* @param aCleanVias = true to remove superimposed vias
* @param aRemoveMisConnected = true to remove segments connecting 2 different nets
* (short circuits)
* @param aMergeSegments = true to merge collinear segmenst and remove 0 len segm
* @param aDeleteUnconnected = true to remove dangling tracks
* @param aDeleteTracksinPad = true to remove tracks fully inside pads
* (short circuits)
*/
bool CleanupBoard( bool aDryRun, std::vector<DRC_ITEM*>* aItemsList, bool aCleanVias,
void CleanupBoard( bool aDryRun, std::vector<CLEANUP_ITEM*>* aItemsList, bool aCleanVias,
bool aRemoveMisConnected, bool aMergeSegments, bool aDeleteUnconnected,
bool aDeleteTracksinPad );
private:
/* finds and remove all track segments which are connected to more than one net.
* (short circuits)
/*
* Removes track segments which are connected to more than one net (short circuits).
*/
bool removeBadTrackSegments();
void removeBadTrackSegments();
/**
* Removes redundant vias like vias at same location
* or on pad through
* Removes redundant vias like vias at same location or on pad through.
*/
bool cleanupVias();
void cleanupVias();
/**
* Removes dangling tracks
*/
bool deleteDanglingTracks();
/**
* Removes tracks that are fully inside pads
*/
bool deleteTracksInPads();
void deleteTracksInPads();
/// Delete null length track segments
bool deleteNullSegments( TRACKS& aTracks );
void deleteNullSegments( TRACKS& aTracks );
/**
* Merge collinear segments and remove duplicated and null len segments
* Merge collinear segments and remove duplicated and null length segments.
*/
bool cleanupSegments();
void cleanupSegments();
/**
* helper function
@ -88,23 +80,23 @@ private:
* @param aSeg1 is the reference
* @param aSeg2 is the candidate, and after merging, the removed segment
*/
bool mergeCollinearSegments( TRACK* aSeg1, TRACK* aSeg2 );
void mergeCollinearSegments( TRACK* aSeg1, TRACK* aSeg2 );
/**
* @return true if a track end position is a node, i.e. a end connected
* to more than one item.
* @param aTrack is the track to test.
* @param aTstStart = true ot test the start point of the track, and false to
* test the end point
* @param aTstStart = true ot test the start point of the track or false for end point
*/
bool testTrackEndpointIsNode( TRACK* aTrack, bool aTstStart );
void removeItems( std::set<BOARD_ITEM*>& aItems );
private:
BOARD* m_brd;
BOARD_COMMIT& m_commit;
bool m_dryRun;
std::vector<DRC_ITEM*>* m_itemsList;
bool removeItems( std::set<BOARD_ITEM*>& aItems );
std::vector<CLEANUP_ITEM*>* m_itemsList;
};