Move DRC dialog to new DRC engine.

This commit is contained in:
Jeff Young 2020-09-14 18:54:14 +01:00
parent 52d9a47d5b
commit 514da2f886
59 changed files with 1060 additions and 4286 deletions

View File

@ -43,13 +43,20 @@ void PROGRESS_REPORTER::BeginPhase( int aPhase )
} }
void PROGRESS_REPORTER::AdvancePhase( ) void PROGRESS_REPORTER::AdvancePhase()
{ {
m_phase.fetch_add( 1 ); m_phase.fetch_add( 1 );
m_progress.store( 0 ); m_progress.store( 0 );
} }
void PROGRESS_REPORTER::AdvancePhase( const wxString& aMessage )
{
AdvancePhase();
Report( aMessage );
}
void PROGRESS_REPORTER::Report( const wxString& aMessage ) void PROGRESS_REPORTER::Report( const wxString& aMessage )
{ {
std::lock_guard<std::mutex> guard( m_mutex ); std::lock_guard<std::mutex> guard( m_mutex );
@ -81,6 +88,12 @@ void PROGRESS_REPORTER::SetNumPhases( int aNumPhases )
} }
void PROGRESS_REPORTER::AddPhases( int aNumPhases )
{
m_numPhases += aNumPhases;
}
int PROGRESS_REPORTER::currentProgress() const int PROGRESS_REPORTER::currentProgress() const
{ {
double current = ( 1.0 / (double) m_numPhases ) * double current = ( 1.0 / (double) m_numPhases ) *

View File

@ -42,7 +42,7 @@
*/ */
class PROGRESS_REPORTER class PROGRESS_REPORTER
{ {
public: public:
PROGRESS_REPORTER( int aNumPhases ); PROGRESS_REPORTER( int aNumPhases );
PROGRESS_REPORTER( const PROGRESS_REPORTER& ) = delete; PROGRESS_REPORTER( const PROGRESS_REPORTER& ) = delete;
@ -55,21 +55,28 @@ class PROGRESS_REPORTER
* sets the number of phases * sets the number of phases
*/ */
void SetNumPhases( int aNumPhases ); void SetNumPhases( int aNumPhases );
void AddPhases( int aNumPhases );
/** /**
* initialize the aPhase virtual zone of the dialog progress bar * initialize the aPhase virtual zone of the dialog progress bar
*/ */
void BeginPhase( int aPhase ); virtual void BeginPhase( int aPhase );
/** /**
* Uses the next vailable virtual zone of the dialog progress bar * Uses the next vailable virtual zone of the dialog progress bar
*/ */
void AdvancePhase(); virtual void AdvancePhase();
/**
* Uses the next vailable virtual zone of the dialog progress bar and updates
* the message.
*/
virtual void AdvancePhase( const wxString& aMessage );
/** /**
* Display aMessage in the progress bar dialog * Display aMessage in the progress bar dialog
*/ */
void Report( const wxString& aMessage ); virtual void Report( const wxString& aMessage );
/** /**
* Set the progress value to aProgress (0..1) * Set the progress value to aProgress (0..1)
@ -102,7 +109,7 @@ class PROGRESS_REPORTER
bool IsCancelled() const { return m_cancelled.load(); } bool IsCancelled() const { return m_cancelled.load(); }
protected: protected:
int currentProgress() const; int currentProgress() const;

View File

@ -232,13 +232,7 @@ set( PCBNEW_MICROWAVE_SRCS
) )
set( PCBNEW_DRC_SRCS set( PCBNEW_DRC_SRCS
drc/drc_courtyard_tester.cpp
drc/drc_drilled_hole_tester.cpp
drc/drc_keepout_tester.cpp
drc/drc_textvar_tester.cpp
drc/footprint_tester.cpp
drc/drc.cpp drc/drc.cpp
drc/drc_clearance_test_functions.cpp
drc/drc_engine.cpp drc/drc_engine.cpp
drc/drc_rule_parser.cpp drc/drc_rule_parser.cpp
drc/drc_test_provider.cpp drc/drc_test_provider.cpp
@ -250,6 +244,7 @@ set( PCBNEW_DRC_SRCS
drc/drc_test_provider_edge_clearance.cpp drc/drc_test_provider_edge_clearance.cpp
drc/drc_test_provider_hole_clearance.cpp drc/drc_test_provider_hole_clearance.cpp
drc/drc_test_provider_hole_size.cpp drc/drc_test_provider_hole_size.cpp
drc/drc_test_provider_lvs.cpp
drc/drc_test_provider_misc.cpp drc/drc_test_provider_misc.cpp
drc/drc_test_provider_track_width.cpp drc/drc_test_provider_track_width.cpp
drc/drc_test_provider_via_diameter.cpp drc/drc_test_provider_via_diameter.cpp
@ -333,6 +328,7 @@ set( PCBNEW_CLASS_SRCS
tools/convert_tool.cpp tools/convert_tool.cpp
tools/drawing_tool.cpp tools/drawing_tool.cpp
tools/drc_tool.cpp
tools/edit_tool.cpp tools/edit_tool.cpp
tools/global_edit_tool.cpp tools/global_edit_tool.cpp
tools/footprint_editor_tools.cpp tools/footprint_editor_tools.cpp

View File

@ -1165,10 +1165,18 @@ void ZONE_CONTAINER::SwapData( BOARD_ITEM* aImage )
} }
void ZONE_CONTAINER::CacheTriangulation() void ZONE_CONTAINER::CacheTriangulation( PCB_LAYER_ID aLayer )
{ {
if( aLayer == UNDEFINED_LAYER )
{
for( std::pair<const PCB_LAYER_ID, SHAPE_POLY_SET>& pair : m_FilledPolysList ) for( std::pair<const PCB_LAYER_ID, SHAPE_POLY_SET>& pair : m_FilledPolysList )
pair.second.CacheTriangulation(); pair.second.CacheTriangulation();
}
else
{
if( m_FilledPolysList.count( aLayer ) )
m_FilledPolysList[ aLayer ].CacheTriangulation();
}
} }

View File

@ -620,7 +620,7 @@ public:
/** (re)create a list of triangles that "fill" the solid areas. /** (re)create a list of triangles that "fill" the solid areas.
* used for instance to draw these solid areas on opengl * used for instance to draw these solid areas on opengl
*/ */
void CacheTriangulation(); void CacheTriangulation( PCB_LAYER_ID aLayer = UNDEFINED_LAYER );
/** /**
* Function SetFilledPolysList * Function SetFilledPolysList

View File

@ -29,7 +29,6 @@
#include <tools/pcb_actions.h> #include <tools/pcb_actions.h>
#include <tracks_cleaner.h> #include <tracks_cleaner.h>
#include <drc/drc_item.h> #include <drc/drc_item.h>
#include <drc/drc_results_provider.h>
#include <tools/zone_filler_tool.h> #include <tools/zone_filler_tool.h>
DIALOG_CLEANUP_TRACKS_AND_VIAS::DIALOG_CLEANUP_TRACKS_AND_VIAS( PCB_EDIT_FRAME* aParentFrame ) : DIALOG_CLEANUP_TRACKS_AND_VIAS::DIALOG_CLEANUP_TRACKS_AND_VIAS( PCB_EDIT_FRAME* aParentFrame ) :

View File

@ -23,9 +23,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include <base_units.h>
#include <bitmaps.h> #include <bitmaps.h>
#include <collectors.h>
#include <confirm.h> #include <confirm.h>
#include <dialog_drc.h> #include <dialog_drc.h>
#include <fctsys.h> #include <fctsys.h>
@ -40,10 +38,41 @@
#include <wx/wupdlock.h> #include <wx/wupdlock.h>
#include <widgets/appearance_controls.h> #include <widgets/appearance_controls.h>
#include <widgets/ui_common.h> #include <widgets/ui_common.h>
#include <widgets/progress_reporter.h>
#include <drc/drc_engine.h>
#include <tools/drc_tool.h>
DIALOG_DRC::DIALOG_DRC( DRC* aTester, PCB_EDIT_FRAME* aEditorFrame, wxWindow* aParent ) : class DRC_PROGRESS_REPORTER : public WX_PROGRESS_REPORTER
{
public:
DRC_PROGRESS_REPORTER( wxWindow* aParent, wxTextCtrl* aAuxStageReporter ) :
WX_PROGRESS_REPORTER( aParent, _( "Test Progress" ), 1, true ),
m_auxStageReporter( aAuxStageReporter )
{ }
void AdvancePhase( const wxString& aMessage ) override
{
WX_PROGRESS_REPORTER::AdvancePhase( aMessage );
m_auxStageReporter->AppendText( aMessage + "\n" );
}
void SetCurrentProgress( double aProgress ) override
{
WX_PROGRESS_REPORTER::SetCurrentProgress( aProgress );
KeepRefreshing( false );
}
private:
wxTextCtrl* m_auxStageReporter;
};
DIALOG_DRC::DIALOG_DRC( PCB_EDIT_FRAME* aEditorFrame, wxWindow* aParent ) :
DIALOG_DRC_BASE( aParent ), DIALOG_DRC_BASE( aParent ),
m_drcRun( false ),
m_footprintTestsRun( false ),
m_trackMinWidth( aEditorFrame, m_MinWidthLabel, m_MinWidthCtrl, m_MinWidthUnits, true ), m_trackMinWidth( aEditorFrame, m_MinWidthLabel, m_MinWidthCtrl, m_MinWidthUnits, true ),
m_viaMinSize( aEditorFrame, m_ViaMinLabel, m_ViaMinCtrl, m_ViaMinUnits, true ), m_viaMinSize( aEditorFrame, m_ViaMinLabel, m_ViaMinCtrl, m_ViaMinUnits, true ),
m_uviaMinSize( aEditorFrame, m_uViaMinLabel, m_uViaMinCtrl, m_uViaMinUnits, true ), m_uviaMinSize( aEditorFrame, m_uViaMinLabel, m_uViaMinCtrl, m_uViaMinUnits, true ),
@ -57,7 +86,6 @@ DIALOG_DRC::DIALOG_DRC( DRC* aTester, PCB_EDIT_FRAME* aEditorFrame, wxWindow* aP
{ {
SetName( DIALOG_DRC_WINDOW_NAME ); // Set a window name to be able to find it SetName( DIALOG_DRC_WINDOW_NAME ); // Set a window name to be able to find it
m_tester = aTester;
m_brdEditor = aEditorFrame; m_brdEditor = aEditorFrame;
m_currentBoard = m_brdEditor->GetBoard(); m_currentBoard = m_brdEditor->GetBoard();
@ -105,13 +133,14 @@ void DIALOG_DRC::OnActivateDlg( wxActivateEvent& aEvent )
{ {
if( m_currentBoard != m_brdEditor->GetBoard() ) if( m_currentBoard != m_brdEditor->GetBoard() )
{ {
// If m_currentBoard is not the current parent board, // If m_currentBoard is not the current board, (for instance because a new board
// (for instance because a new board was loaded), // was loaded), close the dialog, because many pointers are now invalid in lists
// close the dialog, because many pointers are now invalid
// in lists
SetReturnCode( wxID_CANCEL ); SetReturnCode( wxID_CANCEL );
Close(); Close();
m_tester->DestroyDRCDialog( wxID_CANCEL );
DRC_TOOL* drcTool = m_brdEditor->GetToolManager()->GetTool<DRC_TOOL>();
drcTool->DestroyDRCDialog( wxID_CANCEL );
return; return;
} }
@ -183,22 +212,35 @@ void DIALOG_DRC::syncCheckboxes()
void DIALOG_DRC::OnRunDRCClick( wxCommandEvent& aEvent ) void DIALOG_DRC::OnRunDRCClick( wxCommandEvent& aEvent )
{ {
DRC_TOOL* drcTool = m_parentFrame->GetToolManager()->GetTool<DRC_TOOL>();
DRC_PROGRESS_REPORTER progressReporter( this, m_Messages );
bool testTracksAgainstZones = m_cbReportTracksToZonesErrors->GetValue();
bool refillZones = m_cbRefillZones->GetValue();
bool reportAllTrackErrors = m_cbReportAllTrackErrors->GetValue();
bool testFootprints = m_cbTestFootprints->GetValue();
setDRCParameters(); setDRCParameters();
m_tester->m_testTracksAgainstZones = m_cbReportTracksToZonesErrors->GetValue();
m_tester->m_refillZones = m_cbRefillZones->GetValue(); m_drcRun = false;
m_tester->m_reportAllTrackErrors = m_cbReportAllTrackErrors->GetValue(); m_footprintTestsRun = false;
m_tester->m_testFootprints = m_cbTestFootprints->GetValue();
m_brdEditor->RecordDRCExclusions(); m_brdEditor->RecordDRCExclusions();
deleteAllMarkers( true ); deleteAllMarkers( true );
wxBeginBusyCursor(); wxBeginBusyCursor();
wxWindowDisabler disabler; wxWindowDisabler disabler( &progressReporter );
Raise();
// run all the tests, with no UI at this time. // run all the tests, with no UI at this time.
m_Messages->Clear(); m_Messages->Clear();
wxSafeYield(); // Allows time slice to refresh the Messages wxYield(); // Allows time slice to refresh the Messages
m_tester->RunTests( m_Messages );
drcTool->RunTests( &progressReporter, testTracksAgainstZones, refillZones,
reportAllTrackErrors, testFootprints );
m_drcRun = true;
if( testFootprints )
m_footprintTestsRun = true;
m_Notebook->ChangeSelection( 0 ); // display the "Problems/Markers" tab m_Notebook->ChangeSelection( 0 ); // display the "Problems/Markers" tab
@ -206,7 +248,7 @@ void DIALOG_DRC::OnRunDRCClick( wxCommandEvent& aEvent )
refreshBoardEditor(); refreshBoardEditor();
wxSafeYield(); wxYield();
Raise(); Raise();
m_Notebook->GetPage( m_Notebook->GetSelection() )->SetFocus(); m_Notebook->GetPage( m_Notebook->GetSelection() )->SetFocus();
} }
@ -538,7 +580,8 @@ void DIALOG_DRC::OnCancelClick( wxCommandEvent& aEvent )
// The dialog can be modal or not modal. // The dialog can be modal or not modal.
// Leave the DRC caller destroy (or not) the dialog // Leave the DRC caller destroy (or not) the dialog
m_tester->DestroyDRCDialog( wxID_CANCEL ); DRC_TOOL* drcTool = m_brdEditor->GetToolManager()->GetTool<DRC_TOOL>();
drcTool->DestroyDRCDialog( wxID_CANCEL );
} }
@ -689,7 +732,7 @@ void DIALOG_DRC::updateDisplayedCounts()
// First the tab headers: // First the tab headers:
// //
if( m_tester->m_drcRun ) if( m_drcRun )
{ {
msg.sprintf( m_markersTitleTemplate, m_markerTreeModel->GetDRCItemCount() ); msg.sprintf( m_markersTitleTemplate, m_markerTreeModel->GetDRCItemCount() );
m_Notebook->SetPageText( 0, msg ); m_Notebook->SetPageText( 0, msg );
@ -697,7 +740,7 @@ void DIALOG_DRC::updateDisplayedCounts()
msg.sprintf( m_unconnectedTitleTemplate, m_unconnectedTreeModel->GetDRCItemCount() ); msg.sprintf( m_unconnectedTitleTemplate, m_unconnectedTreeModel->GetDRCItemCount() );
m_Notebook->SetPageText( 1, msg ); m_Notebook->SetPageText( 1, msg );
if( m_tester->m_footprintsTested ) if( m_footprintTestsRun )
msg.sprintf( m_footprintsTitleTemplate, m_footprintWarningsTreeModel->GetDRCItemCount() ); msg.sprintf( m_footprintsTitleTemplate, m_footprintWarningsTreeModel->GetDRCItemCount() );
else else
{ {

View File

@ -48,7 +48,7 @@ DIALOG_DRC: public DIALOG_DRC_BASE
{ {
public: public:
/// Constructors /// Constructors
DIALOG_DRC( DRC* aTester, PCB_EDIT_FRAME* aEditorFrame, wxWindow* aParent ); DIALOG_DRC( PCB_EDIT_FRAME* aEditorFrame, wxWindow* aParent );
~DIALOG_DRC(); ~DIALOG_DRC();
void SetMarkersProvider( RC_ITEMS_PROVIDER* aProvider ); void SetMarkersProvider( RC_ITEMS_PROVIDER* aProvider );
@ -95,8 +95,9 @@ private:
BOARD_DESIGN_SETTINGS& bds() { return m_currentBoard->GetDesignSettings(); } BOARD_DESIGN_SETTINGS& bds() { return m_currentBoard->GetDesignSettings(); }
BOARD* m_currentBoard; // the board currently on test BOARD* m_currentBoard; // the board currently on test
DRC* m_tester;
PCB_EDIT_FRAME* m_brdEditor; PCB_EDIT_FRAME* m_brdEditor;
bool m_drcRun;
bool m_footprintTestsRun;
wxString m_markersTitleTemplate; wxString m_markersTitleTemplate;
wxString m_unconnectedTitleTemplate; wxString m_unconnectedTitleTemplate;

View File

@ -31,9 +31,6 @@
#include <pcbnew_settings.h> #include <pcbnew_settings.h>
#include <reporter.h> #include <reporter.h>
#include <bitmaps.h> #include <bitmaps.h>
#include <drc/drc.h>
#include <drc/drc_item.h>
#include <drc/footprint_tester.h>
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
#include <tools/pcb_actions.h> #include <tools/pcb_actions.h>
#include <class_board.h> #include <class_board.h>
@ -174,33 +171,6 @@ void DIALOG_NETLIST::OnUpdatePCB( wxCommandEvent& event )
} }
void DIALOG_NETLIST::OnTestFootprintsClick( wxCommandEvent& event )
{
if( m_parent->GetBoard()->GetFirstModule() == nullptr )
{
DisplayInfoMessage( this, _( "No footprints." ) );
return;
}
wxString netlistFilename = m_NetlistFilenameCtrl->GetValue();
NETLIST netlist;
wxBusyCursor dummy; // Shows an hourglass while calculating.
if( !m_parent->ReadNetlistFromFile( netlistFilename, netlist, NULL_REPORTER::GetInstance() ) )
return;
HTML_MESSAGE_BOX dlg( this, _( "Check footprints" ) );
std::vector<std::shared_ptr<DRC_ITEM> > drcItems;
TestFootprints( netlist, m_parent->GetBoard(), drcItems );
for( auto item : drcItems )
dlg.AddHTML_Text( item->ShowHtml( m_parent ) );
dlg.ShowModal();
}
void DIALOG_NETLIST::OnFilenameKillFocus( wxFocusEvent& event ) void DIALOG_NETLIST::OnFilenameKillFocus( wxFocusEvent& event )
{ {
onFilenameChanged(); onFilenameChanged();
@ -254,12 +224,6 @@ void DIALOG_NETLIST::OnCompileRatsnestClick( wxCommandEvent& event )
} }
void DIALOG_NETLIST::OnUpdateUIValidNetlistFile( wxUpdateUIEvent& aEvent )
{
aEvent.Enable( !m_NetlistFilenameCtrl->GetValue().IsEmpty() );
}
void DIALOG_NETLIST::loadNetlist( bool aDryRun ) void DIALOG_NETLIST::loadNetlist( bool aDryRun )
{ {
wxString netlistFileName = m_NetlistFilenameCtrl->GetValue(); wxString netlistFileName = m_NetlistFilenameCtrl->GetValue();

View File

@ -64,9 +64,7 @@ private:
void OnFilenameKillFocus( wxFocusEvent& event ) override; void OnFilenameKillFocus( wxFocusEvent& event ) override;
void OnMatchChanged( wxCommandEvent& event ) override; void OnMatchChanged( wxCommandEvent& event ) override;
void OnOptionChanged( wxCommandEvent& event ) override; void OnOptionChanged( wxCommandEvent& event ) override;
void OnTestFootprintsClick( wxCommandEvent& event ) override;
void OnCompileRatsnestClick( wxCommandEvent& event ) override; void OnCompileRatsnestClick( wxCommandEvent& event ) override;
void OnUpdateUIValidNetlistFile( wxUpdateUIEvent& aEvent ) override;
}; };

View File

@ -86,11 +86,6 @@ DIALOG_NETLIST_BASE::DIALOG_NETLIST_BASE( wxWindow* parent, wxWindowID id, const
m_buttonsSizer = new wxBoxSizer( wxHORIZONTAL ); m_buttonsSizer = new wxBoxSizer( wxHORIZONTAL );
m_buttonFPTest = new wxButton( this, ID_TEST_NETLIST, _("Test Footprints"), wxDefaultPosition, wxDefaultSize, 0 );
m_buttonFPTest->SetToolTip( _("Read the current netlist file and list missing and extra footprints") );
m_buttonsSizer->Add( m_buttonFPTest, 0, wxEXPAND|wxLEFT|wxRIGHT, 10 );
m_sdbSizer1 = new wxStdDialogButtonSizer(); m_sdbSizer1 = new wxStdDialogButtonSizer();
m_sdbSizer1OK = new wxButton( this, wxID_OK ); m_sdbSizer1OK = new wxButton( this, wxID_OK );
m_sdbSizer1->AddButton( m_sdbSizer1OK ); m_sdbSizer1->AddButton( m_sdbSizer1OK );
@ -111,6 +106,7 @@ DIALOG_NETLIST_BASE::DIALOG_NETLIST_BASE( wxWindow* parent, wxWindowID id, const
bMainSizer->Fit( this ); bMainSizer->Fit( this );
// Connect Events // Connect Events
this->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_NETLIST_BASE::OnUpdateUIValidNetlistFile ) );
m_NetlistFilenameCtrl->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_NETLIST_BASE::OnFilenameKillFocus ), NULL, this ); m_NetlistFilenameCtrl->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_NETLIST_BASE::OnFilenameKillFocus ), NULL, this );
m_browseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOpenNetlistClick ), NULL, this ); m_browseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOpenNetlistClick ), NULL, this );
m_matchByTimestamp->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnMatchChanged ), NULL, this ); m_matchByTimestamp->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnMatchChanged ), NULL, this );
@ -119,8 +115,6 @@ DIALOG_NETLIST_BASE::DIALOG_NETLIST_BASE( wxWindow* parent, wxWindowID id, const
m_cbDeleteShortingTracks->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this ); m_cbDeleteShortingTracks->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this );
m_cbDeleteSinglePadNets->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this ); m_cbDeleteSinglePadNets->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this );
m_cbWarnNoNetPad->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this ); m_cbWarnNoNetPad->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this );
m_buttonFPTest->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnTestFootprintsClick ), NULL, this );
m_buttonFPTest->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_NETLIST_BASE::OnUpdateUIValidNetlistFile ), NULL, this );
m_sdbSizer1Apply->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnCompileRatsnestClick ), NULL, this ); m_sdbSizer1Apply->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnCompileRatsnestClick ), NULL, this );
m_sdbSizer1OK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnUpdatePCB ), NULL, this ); m_sdbSizer1OK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnUpdatePCB ), NULL, this );
} }
@ -128,6 +122,7 @@ DIALOG_NETLIST_BASE::DIALOG_NETLIST_BASE( wxWindow* parent, wxWindowID id, const
DIALOG_NETLIST_BASE::~DIALOG_NETLIST_BASE() DIALOG_NETLIST_BASE::~DIALOG_NETLIST_BASE()
{ {
// Disconnect Events // Disconnect Events
this->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_NETLIST_BASE::OnUpdateUIValidNetlistFile ) );
m_NetlistFilenameCtrl->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_NETLIST_BASE::OnFilenameKillFocus ), NULL, this ); m_NetlistFilenameCtrl->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_NETLIST_BASE::OnFilenameKillFocus ), NULL, this );
m_browseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOpenNetlistClick ), NULL, this ); m_browseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOpenNetlistClick ), NULL, this );
m_matchByTimestamp->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnMatchChanged ), NULL, this ); m_matchByTimestamp->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnMatchChanged ), NULL, this );
@ -136,8 +131,6 @@ DIALOG_NETLIST_BASE::~DIALOG_NETLIST_BASE()
m_cbDeleteShortingTracks->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this ); m_cbDeleteShortingTracks->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this );
m_cbDeleteSinglePadNets->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this ); m_cbDeleteSinglePadNets->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this );
m_cbWarnNoNetPad->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this ); m_cbWarnNoNetPad->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this );
m_buttonFPTest->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnTestFootprintsClick ), NULL, this );
m_buttonFPTest->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_NETLIST_BASE::OnUpdateUIValidNetlistFile ), NULL, this );
m_sdbSizer1Apply->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnCompileRatsnestClick ), NULL, this ); m_sdbSizer1Apply->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnCompileRatsnestClick ), NULL, this );
m_sdbSizer1OK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnUpdatePCB ), NULL, this ); m_sdbSizer1OK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnUpdatePCB ), NULL, this );

View File

@ -762,80 +762,6 @@
<property name="name">m_buttonsSizer</property> <property name="name">m_buttonsSizer</property>
<property name="orient">wxHORIZONTAL</property> <property name="orient">wxHORIZONTAL</property>
<property name="permission">protected</property> <property name="permission">protected</property>
<object class="sizeritem" expanded="0">
<property name="border">10</property>
<property name="flag">wxEXPAND|wxLEFT|wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxButton" 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="bitmap"></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="current"></property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="disabled"></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="focus"></property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">ID_TEST_NETLIST</property>
<property name="label">Test Footprints</property>
<property name="margins"></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">m_buttonFPTest</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="position"></property>
<property name="pressed"></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">Read the current netlist file and list missing and extra footprints</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>
<event name="OnButtonClick">OnTestFootprintsClick</event>
<event name="OnUpdateUI">OnUpdateUIValidNetlistFile</event>
</object>
</object>
<object class="sizeritem" expanded="1"> <object class="sizeritem" expanded="1">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxEXPAND</property> <property name="flag">wxEXPAND</property>

View File

@ -42,11 +42,6 @@ class DIALOG_NETLIST_BASE : public DIALOG_SHIM
private: private:
protected: protected:
enum
{
ID_TEST_NETLIST = 1000
};
wxTextCtrl* m_NetlistFilenameCtrl; wxTextCtrl* m_NetlistFilenameCtrl;
wxBitmapButton* m_browseButton; wxBitmapButton* m_browseButton;
wxRadioBox* m_matchByTimestamp; wxRadioBox* m_matchByTimestamp;
@ -57,19 +52,17 @@ class DIALOG_NETLIST_BASE : public DIALOG_SHIM
wxCheckBox* m_cbWarnNoNetPad; wxCheckBox* m_cbWarnNoNetPad;
WX_HTML_REPORT_PANEL* m_MessageWindow; WX_HTML_REPORT_PANEL* m_MessageWindow;
wxBoxSizer* m_buttonsSizer; wxBoxSizer* m_buttonsSizer;
wxButton* m_buttonFPTest;
wxStdDialogButtonSizer* m_sdbSizer1; wxStdDialogButtonSizer* m_sdbSizer1;
wxButton* m_sdbSizer1OK; wxButton* m_sdbSizer1OK;
wxButton* m_sdbSizer1Apply; wxButton* m_sdbSizer1Apply;
wxButton* m_sdbSizer1Cancel; wxButton* m_sdbSizer1Cancel;
// Virtual event handlers, overide them in your derived class // Virtual event handlers, overide them in your derived class
virtual void OnUpdateUIValidNetlistFile( wxUpdateUIEvent& event ) { event.Skip(); }
virtual void OnFilenameKillFocus( wxFocusEvent& event ) { event.Skip(); } virtual void OnFilenameKillFocus( wxFocusEvent& event ) { event.Skip(); }
virtual void OnOpenNetlistClick( wxCommandEvent& event ) { event.Skip(); } virtual void OnOpenNetlistClick( wxCommandEvent& event ) { event.Skip(); }
virtual void OnMatchChanged( wxCommandEvent& event ) { event.Skip(); } virtual void OnMatchChanged( wxCommandEvent& event ) { event.Skip(); }
virtual void OnOptionChanged( wxCommandEvent& event ) { event.Skip(); } virtual void OnOptionChanged( wxCommandEvent& event ) { event.Skip(); }
virtual void OnTestFootprintsClick( wxCommandEvent& event ) { event.Skip(); }
virtual void OnUpdateUIValidNetlistFile( wxUpdateUIEvent& event ) { event.Skip(); }
virtual void OnCompileRatsnestClick( wxCommandEvent& event ) { event.Skip(); } virtual void OnCompileRatsnestClick( wxCommandEvent& event ) { event.Skip(); }
virtual void OnUpdatePCB( wxCommandEvent& event ) { event.Skip(); } virtual void OnUpdatePCB( wxCommandEvent& event ) { event.Skip(); }

View File

@ -37,9 +37,9 @@
#include <dialog_plot.h> #include <dialog_plot.h>
#include <dialog_gendrill.h> #include <dialog_gendrill.h>
#include <wx_html_report_panel.h> #include <wx_html_report_panel.h>
#include <drc/drc.h>
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
#include <tools/zone_filler_tool.h> #include <tools/zone_filler_tool.h>
#include <tools/drc_tool.h>
#include <math/util.h> // for KiROUND #include <math/util.h> // for KiROUND
#include <macros.h> #include <macros.h>
@ -903,7 +903,7 @@ void DIALOG_PLOT::onRunDRC( wxCommandEvent& event )
if( parent ) if( parent )
{ {
DRC* drcTool = parent->GetToolManager()->GetTool<DRC>(); DRC_TOOL* drcTool = parent->GetToolManager()->GetTool<DRC_TOOL>();
// First close an existing dialog if open // First close an existing dialog if open
// (low probability, but can happen) // (low probability, but can happen)

File diff suppressed because it is too large Load Diff

View File

@ -36,67 +36,7 @@
#include <tools/pcb_tool_base.h> #include <tools/pcb_tool_base.h>
/// DRC error codes:
enum PCB_DRC_CODE {
DRCE_FIRST = 1,
DRCE_UNCONNECTED_ITEMS = DRCE_FIRST, // items are unconnected
DRCE_SHORTING_ITEMS, // items short two nets but are not a net-tie
DRCE_ALLOWED_ITEMS, // a disallowed item has been used
DRCE_CLEARANCE, // items are too close together
DRCE_TRACKS_CROSSING, // tracks are crossing
DRCE_COPPER_EDGE_CLEARANCE, // a copper item is too close to the board edge
DRCE_ZONES_INTERSECT, // copper area outlines intersect
DRCE_ZONE_HAS_EMPTY_NET, // copper area has a net but no pads in nets, which is suspicious
DRCE_DANGLING_VIA, // via which isn't connected to anything
DRCE_DANGLING_TRACK, // track with at least one end not connected to anything
DRCE_DRILLED_HOLES_TOO_CLOSE, // overlapping drilled holes break drill bits
DRCE_HOLE_CLEARANCE, //
DRCE_TRACK_WIDTH, // Track width is too small or too large
DRCE_TOO_SMALL_VIA, // Too small via size
DRCE_ANNULUS, // Via size and drill leave annulus too small or too large
DRCE_TOO_SMALL_DRILL, // Too small via or pad drill
DRCE_VIA_HOLE_BIGGER, // via's hole is bigger than its diameter
DRCE_VIA_DIAMETER, // Via diameter checks (min/max)
DRCE_PADSTACK, // something is wrong with a pad or via stackup
DRCE_TOO_SMALL_MICROVIA, // Too small micro via size
DRCE_TOO_SMALL_MICROVIA_DRILL, // Too small micro via drill
DRCE_KEEPOUT, // A disallowed object is inside a keepout
DRCE_OVERLAPPING_FOOTPRINTS, // footprint courtyards overlap
DRCE_MISSING_COURTYARD, // footprint has no courtyard defined
DRCE_MALFORMED_COURTYARD, // footprint has a courtyard but malformed
// (not convertible to a closed polygon with holes)
DRCE_PTH_IN_COURTYARD,
DRCE_NPTH_IN_COURTYARD,
DRCE_DISABLED_LAYER_ITEM, // item on a disabled layer
DRCE_INVALID_OUTLINE, // invalid board outline
DRCE_MISSING_FOOTPRINT, // footprint not found for netlist item
DRCE_DUPLICATE_FOOTPRINT, // more than one footprints found for netlist item
DRCE_EXTRA_FOOTPRINT, // netlist item not found for footprint
DRCE_NET_CONFLICT, // pad net doesn't match netlist
DRCE_UNRESOLVED_VARIABLE,
DRCE_LAST = DRCE_UNRESOLVED_VARIABLE
};
class PCB_EDIT_FRAME; class PCB_EDIT_FRAME;
class DIALOG_DRC;
class BOARD_ITEM;
class BOARD;
class D_PAD;
class ZONE_CONTAINER;
class TRACK;
class MARKER_PCB;
class DRC_ITEM;
class NETCLASS;
class EDA_TEXT;
class DRAWSEGMENT;
class NETLIST;
class wxWindow;
class wxString;
class wxTextCtrl;
/** /**
@ -109,8 +49,6 @@ class wxTextCtrl;
*/ */
class DRC : public PCB_TOOL_BASE class DRC : public PCB_TOOL_BASE
{ {
friend class DIALOG_DRC;
public: public:
DRC(); DRC();
~DRC(); ~DRC();
@ -119,179 +57,14 @@ public:
void Reset( RESET_REASON aReason ) override; void Reset( RESET_REASON aReason ) override;
private: private:
bool m_doUnconnectedTest; // enable unconnected tests
bool m_testTracksAgainstZones; // enable zone to items clearance tests
bool m_doKeepoutTest; // enable keepout areas to items clearance tests
bool m_refillZones; // refill zones if requested (by user).
bool m_reportAllTrackErrors; // Report all tracks errors (or only 4 first errors)
bool m_testFootprints; // Test footprints against schematic
PCB_EDIT_FRAME* m_editFrame; // The pcb frame editor which owns the board PCB_EDIT_FRAME* m_editFrame; // The pcb frame editor which owns the board
BOARD* m_pcb;
SHAPE_POLY_SET m_board_outlines; // The board outline including cutouts
bool m_board_outline_valid;
DIALOG_DRC* m_drcDialog;
std::vector<std::shared_ptr<DRC_ITEM> > m_unconnected; // list of unconnected pads
std::vector<std::shared_ptr<DRC_ITEM> > m_footprints; // list of footprint warnings
bool m_drcRun; // indicates DRC has been run at least once
bool m_footprintsTested; // indicates footprints were tested in last run
std::vector<DRC_RULE*> m_rules; std::vector<DRC_RULE*> m_rules;
// Temp variables for performance during a single DRC run
//
// wxString's c'tor is surprisingly expensive, and in the world of DRC everything matters
//
wxString m_msg;
wxString m_clearanceSource;
int m_largestClearance;
private:
///> Sets up handlers for various events.
void setTransitions() override;
/**
* Update needed pointers from the one pointer which is known not to change.
*/
void updatePointers();
EDA_UNITS userUnits() const { return m_editFrame->GetUserUnits(); }
/**
* Adds a DRC marker to the PCB through the COMMIT mechanism.
*/
void addMarkerToPcb( BOARD_COMMIT& aCommit, MARKER_PCB* aMarker );
//-----<categorical group tests>-----------------------------------------
/**
* Perform the DRC on all tracks.
*
* This test can take a while, a progress bar can be displayed
* @param aActiveWindow = the active window ued as parent for the progress bar
* @param aShowProgressBar = true to show a progress bar
* (Note: it is shown only if there are many tracks)
*/
void testTracks( BOARD_COMMIT& aCommit, wxWindow * aActiveWindow, bool aShowProgressBar );
void testPadClearances( BOARD_COMMIT& aCommit );
void testUnconnected();
void testZones( BOARD_COMMIT& aCommit );
void testCopperDrawItem( BOARD_COMMIT& aCommit, BOARD_ITEM* aDrawing );
void testCopperTextAndGraphics( BOARD_COMMIT& aCommit );
// Tests for items placed on disabled layers (causing false connections).
void testDisabledLayers( BOARD_COMMIT& aCommit );
/**
* Test that the board outline is contiguous and composed of valid elements
*/
void testOutline( BOARD_COMMIT& aCommit );
//-----<single "item" tests>-----------------------------------------
/**
* Test the clearance between aRefPad and other pads.
*
* The pad list must be sorted by x coordinate.
*
* @param aRefPad is the pad to test
* @param aStart is the first pad of the list to test against aRefPad
* @param aEnd is the end of the list and is not included
* @param x_limit is used to stop the test
* (i.e. when the current pad pos X in list exceeds this limit, because the list
* is sorted by X coordinate)
*/
bool doPadToPadsDrc( BOARD_COMMIT& aCommit, D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd,
int x_limit );
/**
* Test the current segment.
*
* @param aRefSeg The segment to test
* @param aStartIt the iterator to the first track to test
* @param aEndIt the marker for the iterator end
* @param aTestZones true if should do copper zones test. This can be very time consumming
* @param aLayer sets the layer to test against
* @return bool - true if no problems, else false and m_currentMarker is
* filled in with the problem information.
*/
void doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
TRACKS::iterator aEndIt, bool aTestZones, PCB_LAYER_ID aLayer );
/**
* Test a single via for DRC errors
*
* @param aCommit The board commit to add DRC errors
* @param aRefVia The via to test against design settings
*/
void doSingleViaDRC( BOARD_COMMIT& aCommit, VIA* aRefVia );
/**
* Test a single track segment for DRC errors
*
* @param aCommit The board commit to add DRC errors
* @param aRefSeg The track to test against design settings
*/
void doSingleTrackDRC( BOARD_COMMIT& aCommit, TRACK* aRefSeg );
public: public:
/** /**
* Load the DRC rules. Must be called after the netclasses have been read. * Load the DRC rules. Must be called after the netclasses have been read.
*/ */
bool LoadRules(); bool LoadRules();
/**
* Fetches a reasonable point for marking a violoation between two non-point objects.
*/
static wxPoint GetLocation( PCB_LAYER_ID aLayer, TRACK* aTrack, ZONE_CONTAINER* aZone );
static wxPoint GetLocation( TRACK* aTrack, const SEG& aSeg );
/**
* Open a dialog and prompts the user, then if a test run button is
* clicked, runs the test(s) and creates the MARKERS. The dialog is only
* created if it is not already in existence.
*
* @param aParent is the parent window for wxWidgets. Usually the PCB editor frame
* but can be another dialog
* if aParent == NULL (default), the parent will be the PCB editor frame
* and the dialog will be not modal (just float on parent
* if aParent is specified, the dialog will be modal.
* The modal mode is mandatory if the dialog is created from another dialog, not
* from the PCB editor frame
*/
void ShowDRCDialog( wxWindow* aParent );
int ShowDRCDialog( const TOOL_EVENT& aEvent );
/**
* Check to see if the DRC dialog is currently shown
*
* @return true if the dialog is shown
*/
bool IsDRCDialogShown();
/**
* Deletes this ui dialog box and zeros out its pointer to remember
* the state of the dialog's existence.
*
* @param aReason Indication of which button was clicked to cause the destruction.
* if aReason == wxID_OK, design parameters values which can be entered from the dialog
* will bbe saved in design parameters list
*/
void DestroyDRCDialog( int aReason );
/**
* Run all the tests specified with a previous call to
* SetSettings()
* @param aMessages = a wxTextControl where to display some activity messages. Can be NULL
*/
void RunTests( wxTextCtrl* aMessages = NULL );
}; };

View File

@ -1,546 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2004-2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2007 Dick Hollenbeck, dick@softplc.com
* 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
*/
#include <fctsys.h>
#include <trigo.h>
#include <drc/drc.h>
#include <class_board.h>
#include <class_track.h>
#include <class_drawsegment.h>
#include <class_marker_pcb.h>
#include <geometry/polygon_test_point_inside.h>
#include <geometry/shape_rect.h>
#include <geometry/shape_segment.h>
void DRC::doSingleViaDRC( BOARD_COMMIT& aCommit, VIA* aRefVia )
{
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
// test if the via size is smaller than minimum
if( aRefVia->GetViaType() == VIATYPE::MICROVIA )
{
if( aRefVia->GetWidth() < bds.m_MicroViasMinSize )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ANNULUS );
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
MessageTextFromValue( userUnits(), bds.m_MicroViasMinSize, true ),
MessageTextFromValue( userUnits(), aRefVia->GetWidth(), true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefVia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
}
else
{
if( aRefVia->GetWidth() < bds.m_ViasMinSize )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ANNULUS );
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
MessageTextFromValue( userUnits(), bds.m_ViasMinSize, true ),
MessageTextFromValue( userUnits(), aRefVia->GetWidth(), true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefVia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
}
// test if via's hole is bigger than its diameter
// This test is necessary since the via hole size and width can be modified
// and a default via hole can be bigger than some vias sizes
if( aRefVia->GetDrillValue() > aRefVia->GetWidth() )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_VIA_HOLE_BIGGER );
m_msg.Printf( drcItem->GetErrorText() + _( " (diameter %s; drill %s)" ),
MessageTextFromValue( userUnits(), aRefVia->GetWidth(), true ),
MessageTextFromValue( userUnits(), aRefVia->GetDrillValue(), true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefVia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
// test if the type of via is allowed due to design rules
if( aRefVia->GetViaType() == VIATYPE::MICROVIA && !bds.m_MicroViasAllowed )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ALLOWED_ITEMS );
m_msg.Printf( _( "Microvia not allowed (board design rule constraints)" ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefVia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
// test if the type of via is allowed due to design rules
if( aRefVia->GetViaType() == VIATYPE::BLIND_BURIED && !bds.m_BlindBuriedViaAllowed )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ALLOWED_ITEMS );
m_msg.Printf( _( "Blind/buried via not allowed (board design rule constraints)" ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefVia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
// For microvias: test if they are blind vias and only between 2 layers
// because they are used for very small drill size and are drill by laser
// and **only one layer** can be drilled
if( aRefVia->GetViaType() == VIATYPE::MICROVIA )
{
PCB_LAYER_ID layer1, layer2;
bool err = true;
aRefVia->LayerPair( &layer1, &layer2 );
if( layer1 > layer2 )
std::swap( layer1, layer2 );
if( layer2 == B_Cu && layer1 == bds.GetCopperLayerCount() - 2 )
err = false;
else if( layer1 == F_Cu && layer2 == In1_Cu )
err = false;
else if ( layer1 == layer2 - 1 )
err = false;
if( err )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_PADSTACK );
m_msg.Printf( _( "Microvia through too many layers (%s and %s not adjacent)" ),
m_pcb->GetLayerName( layer1 ),
m_pcb->GetLayerName( layer2 ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefVia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
}
}
void DRC::doSingleTrackDRC( BOARD_COMMIT& aCommit, TRACK* aRefSeg )
{
SHAPE_SEGMENT refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd(), aRefSeg->GetWidth() );
EDA_RECT refSegBB = aRefSeg->GetBoundingBox();
int refSegWidth = aRefSeg->GetWidth();
int minWidth, maxWidth;
aRefSeg->GetWidthConstraints( &minWidth, &maxWidth, &m_clearanceSource );
int errorCode = 0;
int constraintWidth;
if( refSegWidth < minWidth )
{
errorCode = DRCE_TRACK_WIDTH;
constraintWidth = minWidth;
}
else if( refSegWidth > maxWidth )
{
errorCode = DRCE_TRACK_WIDTH;
constraintWidth = maxWidth;
}
if( errorCode )
{
wxPoint refsegMiddle = ( aRefSeg->GetStart() + aRefSeg->GetEnd() ) / 2;
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( errorCode );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
m_clearanceSource,
MessageTextFromValue( userUnits(), constraintWidth, true ),
MessageTextFromValue( userUnits(), refSegWidth, true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefSeg );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refsegMiddle );
addMarkerToPcb( aCommit, marker );
}
}
void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
TRACKS::iterator aEndIt, bool aTestZones, PCB_LAYER_ID aLayer )
{
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
SHAPE_SEGMENT refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd(), aRefSeg->GetWidth() );
EDA_RECT refSegBB = aRefSeg->GetBoundingBox();
SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
int halfWidth = ( aRefSeg->GetWidth() + 1 ) / 2;
/******************************************/
/* Phase 0 : via DRC tests : */
/******************************************/
if( aRefSeg->Type() == PCB_VIA_T )
{
VIA* refvia = static_cast<VIA*>( aRefSeg );
int viaAnnulus = ( refvia->GetWidth() - refvia->GetDrill() ) / 2;
int minAnnulus = refvia->GetMinAnnulus( aLayer, &m_clearanceSource );
if( !refvia->IsPadOnLayer( aLayer ) )
{
halfWidth = ( refvia->GetDrillValue() + 1 ) / 2;
refSegBB = EDA_RECT( refvia->GetStart(),
wxSize( refvia->GetDrillValue(), refvia->GetDrillValue() ) );
}
// test if the via size is smaller than minimum
if( refvia->GetViaType() == VIATYPE::MICROVIA )
{
if( viaAnnulus < minAnnulus )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ANNULUS );
m_msg.Printf( _( "Via annulus too small (%s %s; actual %s)" ),
m_clearanceSource,
MessageTextFromValue( userUnits(), minAnnulus, true ),
MessageTextFromValue( userUnits(), viaAnnulus, true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
}
else
{
if( bds.m_ViasMinAnnulus > minAnnulus )
{
minAnnulus = bds.m_ViasMinAnnulus;
m_clearanceSource = _( "board minimum" );
}
if( viaAnnulus < minAnnulus )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ANNULUS );
m_msg.Printf( _( "Via annulus too small (%s %s; actual %s)" ),
m_clearanceSource,
MessageTextFromValue( userUnits(), minAnnulus, true ),
MessageTextFromValue( userUnits(), viaAnnulus, true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
}
}
/******************************************/
/* Phase 1 : test DRC track to pads : */
/******************************************/
// Compute the min distance to pads
for( MODULE* mod : m_pcb->Modules() )
{
// Don't preflight at the module level. Getting a module's bounding box goes
// through all its pads anyway (so it's no faster), and also all its drawings
// (so it's in fact slower).
for( D_PAD* pad : mod->Pads() )
{
// Preflight based on bounding boxes.
EDA_RECT inflatedBB = refSegBB;
inflatedBB.Inflate( pad->GetBoundingRadius() + m_largestClearance );
if( !inflatedBB.Contains( pad->GetPosition() ) )
continue;
if( !( pad->IsOnLayer( aLayer ) ) )
continue;
// No need to check pads with the same net as the refSeg.
if( pad->GetNetCode() && aRefSeg->GetNetCode() == pad->GetNetCode() )
continue;
if( pad->GetDrillSize().x > 0 )
{
const SHAPE_SEGMENT* slot = pad->GetEffectiveHoleShape();
const DRC_CONSTRAINT* constraint = GetConstraint( aRefSeg, pad,
DRC_CONSTRAINT_TYPE_CLEARANCE,
aLayer, &m_clearanceSource );
int minClearance;
int actual;
if( constraint )
{
m_clearanceSource = wxString::Format( _( "'%s' rule" ), m_clearanceSource );
minClearance = constraint->m_Value.Min();
}
else
{
minClearance = aRefSeg->GetClearance( aLayer, nullptr, &m_clearanceSource );
}
if( pad->GetAttribute() == PAD_ATTRIB_STANDARD )
minClearance += bds.GetHolePlatingThickness();
if( slot->Collide( &refSeg, minClearance + bds.GetDRCEpsilon(), &actual ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
m_clearanceSource,
MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefSeg, pad );
MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() );
addMarkerToPcb( aCommit, marker );
if( !m_reportAllTrackErrors )
return;
}
}
/// Skip checking pad copper when it has been removed
if( !pad->IsPadOnLayer( aLayer ) )
continue;
int minClearance = aRefSeg->GetClearance( aLayer, pad, &m_clearanceSource );
int actual;
if( pad->Collide( &refSeg, minClearance - bds.GetDRCEpsilon(), &actual ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
m_clearanceSource,
MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefSeg, pad );
MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() );
addMarkerToPcb( aCommit, marker );
if( !m_reportAllTrackErrors )
return;
}
}
}
/***********************************************/
/* Phase 2: test DRC with other track segments */
/***********************************************/
// Test the reference segment with other track segments
for( auto it = aStartIt; it != aEndIt; it++ )
{
TRACK* track = *it;
// No problem if segments have the same net code:
if( aRefSeg->GetNetCode() == track->GetNetCode() )
continue;
if( !track->GetLayerSet().test( aLayer ) )
continue;
// Preflight based on worst-case inflated bounding boxes:
EDA_RECT trackBB = track->GetBoundingBox();
trackBB.Inflate( m_largestClearance );
if( !trackBB.Intersects( refSegBB ) )
continue;
int minClearance = aRefSeg->GetClearance( aLayer, track, &m_clearanceSource );
int actual;
SHAPE_SEGMENT trackSeg( track->GetStart(), track->GetEnd(), track->GetWidth() );
/// Check to see if the via has a pad on this layer
if( track->Type() == PCB_VIA_T )
{
VIA* via = static_cast<VIA*>( track );
if( !via->IsPadOnLayer( aLayer ) )
trackSeg.SetWidth( via->GetDrillValue() );
}
// Check two tracks crossing first as it reports a DRCE without distances
if( OPT_VECTOR2I intersection = refSeg.GetSeg().Intersect( trackSeg.GetSeg() ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TRACKS_CROSSING );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefSeg, track );
MARKER_PCB* marker = new MARKER_PCB( drcItem, (wxPoint) intersection.get() );
addMarkerToPcb( aCommit, marker );
if( !m_reportAllTrackErrors )
return;
}
else if( refSeg.Collide( &trackSeg, minClearance - bds.GetDRCEpsilon(), &actual ) )
{
wxPoint pos = GetLocation( aRefSeg, trackSeg.GetSeg() );
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
m_clearanceSource,
MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefSeg, track );
MARKER_PCB* marker = new MARKER_PCB( drcItem, pos );
addMarkerToPcb( aCommit, marker );
if( !m_reportAllTrackErrors )
return;
}
}
/***************************************/
/* Phase 3: test DRC with copper zones */
/***************************************/
// Can be *very* time consumming.
if( aTestZones )
{
for( ZONE_CONTAINER* zone : m_pcb->Zones() )
{
if( !zone->GetLayerSet().test( aLayer ) || zone->GetIsKeepout() )
continue;
if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() )
continue;
if( zone->GetFilledPolysList( aLayer ).IsEmpty() )
continue;
int minClearance = aRefSeg->GetClearance( aLayer, zone, &m_clearanceSource );
int allowedDist = minClearance + halfWidth - bds.GetDRCEpsilon();
int actual;
if( zone->GetFilledPolysList( aLayer ).Collide( testSeg, allowedDist, &actual ) )
{
actual = std::max( 0, actual - halfWidth );
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
m_clearanceSource,
MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefSeg, zone );
MARKER_PCB* marker = new MARKER_PCB( drcItem, GetLocation( aLayer, aRefSeg, zone ) );
addMarkerToPcb( aCommit, marker );
}
}
}
/***********************************************/
/* Phase 4: test DRC with to board edge */
/***********************************************/
if( m_board_outline_valid )
{
int minClearance = bds.m_CopperEdgeClearance;
m_clearanceSource = _( "board edge" );
static DRAWSEGMENT dummyEdge;
dummyEdge.SetParent( m_pcb );
dummyEdge.SetLayer( Edge_Cuts );
aRefSeg->GetRuleClearance( &dummyEdge, aLayer, &minClearance, &m_clearanceSource );
int center2centerAllowed = minClearance + halfWidth - bds.GetDRCEpsilon();
for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ )
{
SEG::ecoord center2center_squared = testSeg.SquaredDistance( *it );
if( center2center_squared < SEG::Square( center2centerAllowed ) )
{
VECTOR2I pt = testSeg.NearestPoint( *it );
KICAD_T types[] = { PCB_LINE_T, EOT };
DRAWSEGMENT* edge = nullptr;
INSPECTOR_FUNC inspector =
[&] ( EDA_ITEM* item, void* testData )
{
DRAWSEGMENT* test_edge = dynamic_cast<DRAWSEGMENT*>( item );
if( !test_edge || test_edge->GetLayer() != Edge_Cuts )
return SEARCH_RESULT::CONTINUE;
if( test_edge->HitTest( (wxPoint) pt, minClearance + halfWidth ) )
{
edge = test_edge;
return SEARCH_RESULT::QUIT;
}
return SEARCH_RESULT::CONTINUE;
};
// Best-efforts search for edge segment
BOARD::IterateForward<BOARD_ITEM*>( m_pcb->Drawings(), inspector, nullptr, types );
int actual = std::max( 0.0, sqrt( center2center_squared ) - halfWidth );
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_COPPER_EDGE_CLEARANCE );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
m_clearanceSource,
MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefSeg, edge );
MARKER_PCB* marker = new MARKER_PCB( drcItem, (wxPoint) pt );
addMarkerToPcb( aCommit, marker );
}
}
}
}

View File

@ -1,189 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2010 Dick Hollenbeck, dick@softplc.com
* Copyright (C) 2004-2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2018-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 <drc/drc_courtyard_tester.h>
#include <class_module.h>
#include <drc/drc.h>
#include <widgets/ui_common.h>
#include <memory>
#include <drc/drc_item.h>
DRC_COURTYARD_TESTER::DRC_COURTYARD_TESTER( MARKER_HANDLER aMarkerHandler ) :
LEGACY_DRC_TEST_PROVIDER( std::move( aMarkerHandler ) )
{
}
bool DRC_COURTYARD_TESTER::RunDRC( EDA_UNITS aUnits, BOARD& aBoard )
{
// Detects missing (or malformed) footprint courtyards and courtyard incursions (for those
// with a courtyard).
wxString msg;
bool success = true;
// Update courtyard polygons, and test for missing courtyard definition:
for( MODULE* footprint : aBoard.Modules() )
{
if( footprint->BuildPolyCourtyard() )
{
if( !aBoard.GetDesignSettings().Ignore( DRCE_MISSING_COURTYARD )
&& footprint->GetPolyCourtyardFront().OutlineCount() == 0
&& footprint->GetPolyCourtyardBack().OutlineCount() == 0 )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MISSING_COURTYARD );
drcItem->SetItems( footprint );
HandleMarker( new MARKER_PCB( drcItem, footprint->GetPosition() ) );
success = false;
}
else
{
footprint->GetPolyCourtyardFront().BuildBBoxCaches();
footprint->GetPolyCourtyardBack().BuildBBoxCaches();
}
}
else
{
if( !aBoard.GetDesignSettings().Ignore( DRCE_MALFORMED_COURTYARD ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MALFORMED_COURTYARD );
msg.Printf( drcItem->GetErrorText() + _( " (not a closed shape)" ) );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( footprint );
HandleMarker( new MARKER_PCB( drcItem, footprint->GetPosition() ) );
success = false;
}
}
}
if( !aBoard.GetDesignSettings().Ignore( DRCE_OVERLAPPING_FOOTPRINTS ) )
{
for( auto it1 = aBoard.Modules().begin(); it1 != aBoard.Modules().end(); it1++ )
{
MODULE* footprint = *it1;
SHAPE_POLY_SET& footprintFront = footprint->GetPolyCourtyardFront();
SHAPE_POLY_SET& footprintBack = footprint->GetPolyCourtyardBack();
if( footprintFront.OutlineCount() == 0 && footprintBack.OutlineCount() == 0 )
continue; // No courtyards defined
for( auto it2 = it1 + 1; it2 != aBoard.Modules().end(); it2++ )
{
MODULE* test = *it2;
SHAPE_POLY_SET& testFront = test->GetPolyCourtyardFront();
SHAPE_POLY_SET& testBack = test->GetPolyCourtyardBack();
SHAPE_POLY_SET intersection;
bool overlap = false;
wxPoint pos;
if( footprintFront.OutlineCount() > 0 && testFront.OutlineCount() > 0
&& footprintFront.BBoxFromCaches().Intersects( testFront.BBoxFromCaches() ) )
{
intersection.RemoveAllContours();
intersection.Append( footprintFront );
// Build the common area between footprint and the test:
intersection.BooleanIntersection( testFront, SHAPE_POLY_SET::PM_FAST );
// If the intersection exists then they overlap
if( intersection.OutlineCount() > 0 )
{
overlap = true;
pos = (wxPoint) intersection.CVertex( 0, 0, -1 );
}
}
if( footprintBack.OutlineCount() > 0 && testBack.OutlineCount() > 0
&& footprintBack.BBoxFromCaches().Intersects( testBack.BBoxFromCaches() ) )
{
intersection.RemoveAllContours();
intersection.Append( footprintBack );
intersection.BooleanIntersection( testBack, SHAPE_POLY_SET::PM_FAST );
if( intersection.OutlineCount() > 0 )
{
overlap = true;
pos = (wxPoint) intersection.CVertex( 0, 0, -1 );
}
}
if( overlap )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_OVERLAPPING_FOOTPRINTS );
drcItem->SetItems( footprint, test );
HandleMarker( new MARKER_PCB( drcItem, pos ) );
success = false;
}
}
}
}
if( !aBoard.GetDesignSettings().Ignore( DRCE_PTH_IN_COURTYARD )
|| !aBoard.GetDesignSettings().Ignore( DRCE_NPTH_IN_COURTYARD ) )
{
for( MODULE* footprint : aBoard.Modules() )
{
SHAPE_POLY_SET& footprintFront = footprint->GetPolyCourtyardFront();
SHAPE_POLY_SET& footprintBack = footprint->GetPolyCourtyardBack();
if( footprintFront.OutlineCount() == 0 && footprintBack.OutlineCount() == 0 )
continue; // No courtyards defined
for( MODULE* candidate : aBoard.Modules() )
{
if( footprint == candidate )
continue;
for( D_PAD* pad : candidate->Pads() )
{
if( pad->GetDrillSize().x == 0 || pad->GetDrillSize().y == 0 )
continue;
wxPoint pos = pad->GetPosition();
if( footprintFront.Contains( pos, -1, 0, true /* use bbox caches */ )
|| footprintBack.Contains( pos, -1, 0, true /* use bbox caches */ ) )
{
int code = pad->GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED ?
DRCE_NPTH_IN_COURTYARD :
DRCE_PTH_IN_COURTYARD;
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( code );
drcItem->SetItems( footprint, pad );
HandleMarker( new MARKER_PCB( drcItem, pos ) );
success = false;
}
}
}
}
}
return success;
}

View File

@ -1,43 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 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
*/
#ifndef DRC_COURTYARD_OVERLAP__H
#define DRC_COURTYARD_OVERLAP__H
#include <drc/drc_results_provider.h>
class BOARD;
class DRC_COURTYARD_TESTER : public LEGACY_DRC_TEST_PROVIDER
{
public:
DRC_COURTYARD_TESTER( MARKER_HANDLER aMarkerHandler );
virtual ~DRC_COURTYARD_TESTER() {};
bool RunDRC( EDA_UNITS aUnits, BOARD& aBoard ) override;
};
#endif // DRC_COURTYARD_OVERLAP__H

View File

@ -1,307 +0,0 @@
/*
* 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 <drc/drc_drilled_hole_tester.h>
#include <class_module.h>
#include <drc/drc.h>
#include <widgets/ui_common.h>
DRC_DRILLED_HOLE_TESTER::DRC_DRILLED_HOLE_TESTER( MARKER_HANDLER aMarkerHandler ) :
LEGACY_DRC_TEST_PROVIDER( std::move( aMarkerHandler ) ),
m_units( EDA_UNITS::MILLIMETRES ),
m_board( nullptr ),
m_largestRadius( 0 )
{
}
bool DRC_DRILLED_HOLE_TESTER::RunDRC( EDA_UNITS aUnits, BOARD& aBoard )
{
bool success = true;
// Test drilled holes to minimize drill bit breakage.
//
// Check pad & std. via circular holes for hole-to-hole-min (non-circular holes are milled)
// Check pad & std. via holes for via-min-drill (minimum hole classification)
// Check uvia holes for uvia-min-drill (laser drill classification)
m_units = aUnits;
m_board = &aBoard;
m_holes.clear();
m_largestRadius = 0;
for( MODULE* mod : aBoard.Modules() )
{
for( D_PAD* pad : mod->Pads( ) )
success &= checkPad( pad );
}
for( TRACK* track : aBoard.Tracks() )
{
VIA* via = dynamic_cast<VIA*>( track );
if( via )
{
if( via->GetViaType() == VIATYPE::MICROVIA )
success &= checkMicroVia( via );
else
success &= checkVia( via );
}
}
success &= checkHoles();
return success;
}
bool DRC_DRILLED_HOLE_TESTER::checkPad( D_PAD* aPad )
{
bool success = true;
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
// drilled holes go all the way through, so which layer we use shouldn't matter
PCB_LAYER_ID layer = F_Cu;
int holeSize = std::min( aPad->GetDrillSize().x, aPad->GetDrillSize().y );
if( holeSize == 0 )
return true;
if( !bds.Ignore( DRCE_TOO_SMALL_DRILL ) )
{
int minHole;
const DRC_CONSTRAINT* constraint = GetConstraint( aPad, nullptr, DRC_CONSTRAINT_TYPE_HOLE_SIZE,
layer, &m_source );
if( constraint )
{
minHole = constraint->m_Value.Min();
m_source = wxString::Format( _( "'%s' rule" ), m_source );
}
else
{
minHole = bds.m_MinThroughDrill;
m_source = _( "board minimum" );
}
if( holeSize < minHole )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_DRILL );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
m_source,
MessageTextFromValue( m_units, minHole, true ),
MessageTextFromValue( m_units, holeSize, true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aPad );
HandleMarker( new MARKER_PCB( drcItem, aPad->GetPosition() ) );
success = false;
}
}
if( !bds.Ignore( DRCE_DRILLED_HOLES_TOO_CLOSE ) && bds.m_HoleToHoleMin != 0 )
{
if( aPad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
addHole( aPad->GetPosition(), aPad->GetDrillSize().x / 2, aPad );
}
return success;
}
bool DRC_DRILLED_HOLE_TESTER::checkVia( VIA* via )
{
bool success = true;
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
// drilled holes go all the way through, so which layer we use shouldn't matter
PCB_LAYER_ID layer = F_Cu;
if( !bds.Ignore( DRCE_TOO_SMALL_DRILL ) )
{
int minHole;
const DRC_CONSTRAINT* constraint = GetConstraint( via, nullptr, DRC_CONSTRAINT_TYPE_HOLE_SIZE,
layer, &m_source );
if( constraint )
{
minHole = constraint->m_Value.Min();
m_source = wxString::Format( _( "'%s' rule" ), m_source );
}
else
{
minHole = bds.m_MinThroughDrill;
m_source = _( "board minimum" );
}
if( via->GetDrillValue() < minHole )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_DRILL );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
m_source,
MessageTextFromValue( m_units, minHole, true ),
MessageTextFromValue( m_units, via->GetDrillValue(), true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( via );
HandleMarker( new MARKER_PCB( drcItem, via->GetPosition() ) );
success = false;
}
}
if( !bds.Ignore( DRCE_DRILLED_HOLES_TOO_CLOSE ) && bds.m_HoleToHoleMin != 0 )
{
addHole( via->GetPosition(), via->GetDrillValue() / 2, via );
}
return success;
}
bool DRC_DRILLED_HOLE_TESTER::checkMicroVia( VIA* via )
{
bool success = true;
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
// while microvia holes don't necessarily go all the way through, they can't be different
// sizes on different layers so we should still be safe enough using a fixed layer.
PCB_LAYER_ID layer = F_Cu;
if( !bds.Ignore( DRCE_TOO_SMALL_MICROVIA_DRILL ) )
{
int minHole;
const DRC_CONSTRAINT* constraint = GetConstraint( via, nullptr, DRC_CONSTRAINT_TYPE_HOLE_SIZE,
layer, &m_source );
if( constraint )
{
minHole = constraint->m_Value.Min();
m_source = wxString::Format( _( "'%s' rule" ), m_source );
}
else
{
minHole = bds.m_MicroViasMinDrill;
m_source = _( "board minimum" );
}
if( via->GetDrillValue() < minHole )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_MICROVIA_DRILL );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
m_source,
MessageTextFromValue( m_units, minHole, true ),
MessageTextFromValue( m_units, via->GetDrillValue(), true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( via );
HandleMarker( new MARKER_PCB( drcItem, via->GetPosition() ) );
success = false;
}
}
return success;
}
void DRC_DRILLED_HOLE_TESTER::addHole( const wxPoint& aLocation, int aRadius, BOARD_ITEM* aOwner )
{
DRILLED_HOLE hole;
hole.m_location = aLocation;
hole.m_drillRadius = aRadius;
hole.m_owner = aOwner;
m_largestRadius = std::max( m_largestRadius, aRadius );
m_holes.push_back( hole );
}
bool DRC_DRILLED_HOLE_TESTER::checkHoles()
{
bool success = true;
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
// No need to check if we're ignoring DRCE_DRILLED_HOLES_TOO_CLOSE; if we are then we
// won't have collected any holes to test.
// Sort holes by X for performance. In the nested iteration we then need to look at
// following holes only while they are within the refHole's neighborhood as defined by
// the refHole radius + the minimum hole-to-hole clearance + the largest radius any of
// the following holes can have.
std::sort( m_holes.begin(), m_holes.end(),
[]( const DRILLED_HOLE& a, const DRILLED_HOLE& b )
{
if( a.m_location.x == b.m_location.x )
return a.m_location.y < b.m_location.y;
else
return a.m_location.x < b.m_location.x;
} );
for( size_t ii = 0; ii < m_holes.size(); ++ii )
{
const DRILLED_HOLE& refHole = m_holes[ ii ];
int neighborhood = refHole.m_drillRadius + bds.m_HoleToHoleMin + m_largestRadius;
for( size_t jj = ii + 1; jj < m_holes.size(); ++jj )
{
const DRILLED_HOLE& checkHole = m_holes[ jj ];
if( refHole.m_location.x + neighborhood < checkHole.m_location.x )
break;
// Holes with identical locations are allowable
if( checkHole.m_location == refHole.m_location )
continue;
int actual = KiROUND( GetLineLength( checkHole.m_location, refHole.m_location ) );
actual = std::max( 0, actual - checkHole.m_drillRadius - refHole.m_drillRadius );
if( actual < bds.m_HoleToHoleMin )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_DRILLED_HOLES_TOO_CLOSE );
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
MessageTextFromValue( m_units, bds.m_HoleToHoleMin, true ),
MessageTextFromValue( m_units, actual, true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refHole.m_owner, checkHole.m_owner );
HandleMarker( new MARKER_PCB( drcItem, refHole.m_location ) );
success = false;
}
}
}
return success;
}

View File

@ -1,69 +0,0 @@
/*
* 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
*/
#ifndef DRC_DRILLED_HOLE_TESTER__H
#define DRC_DRILLED_HOLE_TESTER__H
#include <drc/drc_results_provider.h>
class BOARD;
class BOARD_ITEM;
class DRC_DRILLED_HOLE_TESTER : public LEGACY_DRC_TEST_PROVIDER
{
public:
DRC_DRILLED_HOLE_TESTER( MARKER_HANDLER aMarkerHandler );
virtual ~DRC_DRILLED_HOLE_TESTER() {};
bool RunDRC( EDA_UNITS aUnits, BOARD& aBoard ) override;
private:
bool checkPad( D_PAD* aPad );
bool checkVia( VIA* aVia );
bool checkMicroVia( VIA* aVia );
void addHole( const wxPoint& aLocation, int aRadius, BOARD_ITEM* aOwner );
bool checkHoles();
private:
struct DRILLED_HOLE
{
wxPoint m_location;
int m_drillRadius = 0;
BOARD_ITEM* m_owner = nullptr;
};
EDA_UNITS m_units;
BOARD* m_board;
std::vector<DRILLED_HOLE> m_holes;
int m_largestRadius;
wxString m_source; // Construct only once for performance
wxString m_msg; // Construct only once for performance
};
#endif // DRC_DRILLED_HOLE_TESTER__H

View File

@ -87,7 +87,7 @@ void DRC_ENGINE::loadImplicitRules()
// 1) global defaults // 1) global defaults
DRC_RULE* rule = createImplicitRule( _( "board setup > design rules > constraints" )); DRC_RULE* rule = createImplicitRule( _( "board setup constraints" ));
DRC_CONSTRAINT clearanceConstraint( DRC_CONSTRAINT_TYPE_CLEARANCE ); DRC_CONSTRAINT clearanceConstraint( DRC_CONSTRAINT_TYPE_CLEARANCE );
clearanceConstraint.Value().SetMin( bds.m_MinClearance ); clearanceConstraint.Value().SetMin( bds.m_MinClearance );
@ -123,7 +123,7 @@ void DRC_ENGINE::loadImplicitRules()
// 2) micro-via specific defaults (new DRC doesn't treat microvias in any special way) // 2) micro-via specific defaults (new DRC doesn't treat microvias in any special way)
DRC_RULE* uViaRule = createImplicitRule( _( "board setup > design rules > constraints" )); DRC_RULE* uViaRule = createImplicitRule( _( "board setup constraints" ));
uViaRule->m_Condition = new DRC_RULE_CONDITION ( "A.Via_Type == 'micro_via'" ); uViaRule->m_Condition = new DRC_RULE_CONDITION ( "A.Via_Type == 'micro_via'" );
@ -144,7 +144,7 @@ void DRC_ENGINE::loadImplicitRules()
if( !bds.m_BlindBuriedViaAllowed ) if( !bds.m_BlindBuriedViaAllowed )
{ {
DRC_RULE* bbViaRule = createImplicitRule( _( "board setup > design rules > constraints" )); DRC_RULE* bbViaRule = createImplicitRule( _( "board setup constraints" ));
bbViaRule->m_Condition = new DRC_RULE_CONDITION ( "A.Via_Type == 'buried_via'" ); bbViaRule->m_Condition = new DRC_RULE_CONDITION ( "A.Via_Type == 'buried_via'" );
@ -188,13 +188,6 @@ void DRC_ENGINE::loadImplicitRules()
ncClearanceConstraint.Value().SetMin( nc->GetClearance() ); ncClearanceConstraint.Value().SetMin( nc->GetClearance() );
netclassRule->AddConstraint( ncClearanceConstraint ); netclassRule->AddConstraint( ncClearanceConstraint );
} }
if( nc->GetTrackWidth() > bds.m_TrackMinWidth )
{
DRC_CONSTRAINT ncWidthConstraint( DRC_CONSTRAINT_TYPE_TRACK_WIDTH );
ncWidthConstraint.Value().SetMin( nc->GetTrackWidth() );
netclassRule->AddConstraint( ncWidthConstraint );
}
} }
} }
@ -302,23 +295,21 @@ bool DRC_ENGINE::CompileRules()
for( DRC_TEST_PROVIDER* provider : m_testProviders ) for( DRC_TEST_PROVIDER* provider : m_testProviders )
{ {
ReportAux( wxString::Format( "- Provider: '%s': ", provider->GetName() ) ); ReportAux( wxString::Format( "- Provider: '%s': ", provider->GetName() ) );
drc_dbg(7, "do prov %s", provider->GetName() ); drc_dbg( 7, "do prov %s", provider->GetName() );
for ( DRC_CONSTRAINT_TYPE_T id : provider->GetConstraintTypes() ) for( DRC_CONSTRAINT_TYPE_T id : provider->GetConstraintTypes() )
{ {
drc_dbg( 7, "do id %d", id ); drc_dbg( 7, "do id %d", id );
if( m_constraintMap.find( id ) == m_constraintMap.end() ) if( m_constraintMap.find( id ) == m_constraintMap.end() )
m_constraintMap[ id ] = new CONSTRAINT_SET; m_constraintMap[ id ] = new std::vector<CONSTRAINT_WITH_CONDITIONS*>();
m_constraintMap[ id ]->provider = provider;
for( DRC_RULE* rule : m_rules ) for( DRC_RULE* rule : m_rules )
{ {
DRC_RULE_CONDITION* condition = nullptr; DRC_RULE_CONDITION* condition = nullptr;
bool compileOk = false; bool compileOk = false;
std::vector<DRC_CONSTRAINT> matchingConstraints; std::vector<DRC_CONSTRAINT> matchingConstraints;
drc_dbg(7, "Scan provider %s, rule %s", provider->GetName(), rule->m_Name ); drc_dbg( 7, "Scan provider %s, rule %s", provider->GetName(), rule->m_Name );
if( rule->m_Condition && !rule->m_Condition->GetExpression().IsEmpty() ) if( rule->m_Condition && !rule->m_Condition->GetExpression().IsEmpty() )
{ {
@ -342,7 +333,7 @@ bool DRC_ENGINE::CompileRules()
rcons->constraint = constraint; rcons->constraint = constraint;
rcons->parentRule = rule; rcons->parentRule = rule;
m_constraintMap[ id ]->sortedConstraints.push_back( rcons ); m_constraintMap[ id ]->push_back( rcons );
} }
if( !matchingConstraints.empty() ) if( !matchingConstraints.empty() )
@ -391,9 +382,22 @@ void DRC_ENGINE::InitEngine( const wxFileName& aRulePath )
} }
void DRC_ENGINE::RunTests( DRC_VIOLATION_HANDLER aViolationHandler ) void DRC_ENGINE::RunTests( EDA_UNITS aUnits, bool aTestTracksAgainstZones,
bool aReportAllTrackErrors, bool aTestFootprints )
{ {
m_violationHandler = std::move( aViolationHandler ); m_userUnits = aUnits;
// Note: set these first. The phase counts may be dependent on some of them.
m_testTracksAgainstZones = aTestTracksAgainstZones;
m_reportAllTrackErrors = aReportAllTrackErrors;
m_testFootprints = aTestFootprints;
int phases = 0;
for( DRC_TEST_PROVIDER* provider : m_testProviders )
phases += provider->GetNumPhases();
m_progressReporter->AddPhases( phases );
for( int ii = DRCE_FIRST; ii < DRCE_LAST; ++ii ) for( int ii = DRCE_FIRST; ii < DRCE_LAST; ++ii )
{ {
@ -405,27 +409,8 @@ void DRC_ENGINE::RunTests( DRC_VIOLATION_HANDLER aViolationHandler )
for( DRC_TEST_PROVIDER* provider : m_testProviders ) for( DRC_TEST_PROVIDER* provider : m_testProviders )
{ {
bool skipProvider = false; drc_dbg( 0, "Running test provider: '%s'\n", provider->GetName() );
auto providedConstraints = provider->GetConstraintTypes();
if( providedConstraints.size() )
{
for( DRC_CONSTRAINT_TYPE_T constraintType : providedConstraints )
{
if( !HasRulesForConstraintType( constraintType ) )
{
ReportAux( wxString::Format( "DRC provider '%s' has no rules provided. Skipping run.",
provider->GetName() ) );
skipProvider = true;
break;
}
}
}
if( skipProvider )
continue;
drc_dbg(0, "Running test provider: '%s'\n", provider->GetName() );
ReportAux( wxString::Format( "Run DRC provider: '%s'", provider->GetName() ) ); ReportAux( wxString::Format( "Run DRC provider: '%s'", provider->GetName() ) );
provider->Run(); provider->Run();
} }
@ -438,39 +423,33 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRulesForItems( DRC_CONSTRAINT_TYPE_T aConstraintI
{ {
#define REPORT( s ) { if( aReporter ) { aReporter->Report( s ); } } #define REPORT( s ) { if( aReporter ) { aReporter->Report( s ); } }
auto* connectedA = a && a->IsConnected() ? static_cast<BOARD_CONNECTED_ITEM*>( a ) : nullptr;
auto* connectedB = b && b->IsConnected() ? static_cast<BOARD_CONNECTED_ITEM*>( b ) : nullptr;
// Local overrides take precedence // Local overrides take precedence
if( aConstraintId == DRC_CONSTRAINT_TYPE_CLEARANCE ) if( aConstraintId == DRC_CONSTRAINT_TYPE_CLEARANCE )
{ {
BOARD_CONNECTED_ITEM* ac = a->IsConnected() ? static_cast<BOARD_CONNECTED_ITEM*>( a )
: nullptr;
BOARD_CONNECTED_ITEM* bc = b->IsConnected() ? static_cast<BOARD_CONNECTED_ITEM*>( b )
: nullptr;
int overrideA = 0; int overrideA = 0;
int overrideB = 0; int overrideB = 0;
if( ac && ac->GetLocalClearanceOverrides( nullptr ) > 0 ) if( connectedA && connectedA->GetLocalClearanceOverrides( nullptr ) > 0 )
{ {
overrideA = ac->GetLocalClearanceOverrides( &m_msg ); overrideA = connectedA->GetLocalClearanceOverrides( &m_msg );
REPORT( "" )
REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ), REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
a->GetSelectMenuText( aReporter->GetUnits() ), a->GetSelectMenuText( aReporter->GetUnits() ),
StringFromValue( aReporter->GetUnits(), overrideA, true ) ) ) StringFromValue( aReporter->GetUnits(), overrideA, true ) ) )
} }
if( bc && bc->GetLocalClearanceOverrides( nullptr ) > 0 ) if( connectedB && connectedB->GetLocalClearanceOverrides( nullptr ) > 0 )
{ {
overrideB = bc->GetLocalClearanceOverrides( &m_msg ); overrideB = connectedB->GetLocalClearanceOverrides( &m_msg );
REPORT( "" )
REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ), REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
b->GetSelectMenuText( aReporter->GetUnits() ), b->GetSelectMenuText( aReporter->GetUnits() ),
StringFromValue( aReporter->GetUnits(), overrideB, true ) ) ) StringFromValue( aReporter->GetUnits(), overrideB, true ) ) )
// If both overridden, report on which wins
if( overrideA )
{
REPORT( wxString::Format( _( "Clearance: %s." ),
std::max( overrideA, overrideB ) ) )
}
} }
if( overrideA || overrideB ) if( overrideA || overrideB )
@ -481,17 +460,34 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRulesForItems( DRC_CONSTRAINT_TYPE_T aConstraintI
} }
} }
CONSTRAINT_SET* ruleset = m_constraintMap[ aConstraintId ]; std::vector<CONSTRAINT_WITH_CONDITIONS*>* ruleset = m_constraintMap[ aConstraintId ];
for( ssize_t ii = ruleset->sortedConstraints.size() - 1; ii >= 0; --ii ) const DRC_CONSTRAINT* constraintRef = nullptr;
bool implicit = false;
// Last matching rule wins, so process in reverse order
for( int ii = (int) ruleset->size() - 1; ii >= 0; --ii )
{ {
const CONSTRAINT_WITH_CONDITIONS* rcons = ruleset->sortedConstraints[ ii ]; const CONSTRAINT_WITH_CONDITIONS* rcons = ruleset->at( ii );
bool implicit = rcons->parentRule && rcons->parentRule->m_Implicit; implicit = rcons->parentRule && rcons->parentRule->m_Implicit;
if( implicit ) REPORT( "" )
REPORT( wxString::Format( _( "Checking %s." ), rcons->parentRule->m_Name ) )
if( aConstraintId == DRC_CONSTRAINT_TYPE_CLEARANCE )
{
int clearance = rcons->constraint.m_Value.Min();
REPORT( wxString::Format( _( "Checking %s %s; clearance: %s." ),
implicit ? _( "" ) : _( "rule" ),
rcons->parentRule->m_Name,
StringFromValue( aReporter->GetUnits(), clearance, true ) ) )
}
else else
REPORT( wxString::Format( _( "Checking rule %s." ), rcons->parentRule->m_Name ) ) {
REPORT( wxString::Format( _( "Checking %s %s." ),
implicit ? _( "" ) : _( "rule" ),
rcons->parentRule->m_Name ) )
}
if( aLayer != UNDEFINED_LAYER && !rcons->layerTest.test( aLayer ) ) if( aLayer != UNDEFINED_LAYER && !rcons->layerTest.test( aLayer ) )
{ {
REPORT( wxString::Format( _( "Rule layer \"%s\" not matched." ), REPORT( wxString::Format( _( "Rule layer \"%s\" not matched." ),
@ -501,50 +497,103 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRulesForItems( DRC_CONSTRAINT_TYPE_T aConstraintI
continue; continue;
} }
const wxString& expression = rcons->condition->GetExpression(); if( !rcons->condition || rcons->condition->GetExpression().IsEmpty() )
if( expression.IsEmpty() )
{ {
REPORT( implicit ? _( "Unconditional constraint applied." ) REPORT( implicit ? _( "Unconditional constraint applied." )
: _( "Unconditional rule applied." ) ) : _( "Unconditional rule applied." ) )
return rcons->constraint; constraintRef = &rcons->constraint;
break;
} }
else else
{ {
// Don't report on implicit rule conditions; they're stuff we made up. // Don't report on implicit rule conditions; they're synthetic.
if( !implicit ) if( !implicit )
REPORT( _( "Checking rule condition \"" + expression + "\"." ) ) {
REPORT( wxString::Format( _( "Checking rule condition \"%s\"." ),
rcons->condition->GetExpression() ) )
}
if( rcons->condition->EvaluateFor( a, b, aLayer, aReporter ) ) if( rcons->condition->EvaluateFor( a, b, aLayer, aReporter ) )
{ {
REPORT( implicit ? _( "Constraint applied." ) REPORT( implicit ? _( "Constraint applicable." )
: _( "Rule applied." ) ) : _( "Rule applied." ) )
return rcons->constraint; constraintRef = &rcons->constraint;
break;
} }
else else
{ {
REPORT( implicit ? _( "Membership not satisfied; constraint not applied." ) REPORT( implicit ? _( "Membership not satisfied; constraint not applicable." )
: _( "Condition not satisfied; rule not applied." ) ) : _( "Condition not satisfied; rule not applied." ) )
REPORT( "" )
} }
} }
} }
// Unfortunately implicit rules don't work for local clearances (such as zones) because
// they have to be max'ed with netclass values (which are already implicit rules), and our
// rule selection paradigm is "winner takes all".
if( aConstraintId == DRC_CONSTRAINT_TYPE_CLEARANCE && implicit )
{
int global = constraintRef->m_Value.Min();
int localA = connectedA ? connectedA->GetLocalClearance( nullptr ) : 0;
int localB = connectedB ? connectedB->GetLocalClearance( nullptr ) : 0;
int clearance = global;
if( localA > 0 )
{
REPORT( "" )
REPORT( wxString::Format( _( "Local clearance on %s; clearance: %s." ),
a->GetSelectMenuText( aReporter->GetUnits() ),
StringFromValue( aReporter->GetUnits(), localA, true ) ) )
if( localA > clearance )
clearance = connectedA->GetLocalClearance( &m_msg );
}
if( localB > 0 )
{
REPORT( "" )
REPORT( wxString::Format( _( "Local clearance on %s; clearance: %s." ),
b->GetSelectMenuText( aReporter->GetUnits() ),
StringFromValue( aReporter->GetUnits(), localB, true ) ) )
if( localB > clearance )
clearance = connectedB->GetLocalClearance( &m_msg );
}
if( localA > global || localB > global )
{
DRC_CONSTRAINT constraint( DRC_CONSTRAINT_TYPE_CLEARANCE, m_msg );
constraint.m_Value.SetMin( clearance );
return constraint;
}
}
// fixme: return optional<drc_constraint>, let the particular test decide what to do if no matching constraint // fixme: return optional<drc_constraint>, let the particular test decide what to do if no matching constraint
// is found // is found
static DRC_CONSTRAINT nullConstraint; static DRC_CONSTRAINT nullConstraint;
nullConstraint.m_DisallowFlags = 0; nullConstraint.m_DisallowFlags = 0;
return nullConstraint; return constraintRef ? *constraintRef : nullConstraint;
#undef REPORT #undef REPORT
} }
bool DRC_ENGINE::IsErrorLimitExceeded( int error_code )
{
return m_errorLimits[ error_code ] <= 0;
}
void DRC_ENGINE::ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos ) void DRC_ENGINE::ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos )
{ {
m_errorLimits[ aItem->GetErrorCode() ] -= 1;
if( m_violationHandler )
m_violationHandler( aItem, aPos );
if( m_reporter ) if( m_reporter )
{ {
wxString msg = wxString::Format( "Test '%s': %s (code %d)", wxString msg = wxString::Format( "Test '%s': %s (code %d)",
@ -565,8 +614,6 @@ void DRC_ENGINE::ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, wxPoin
aPos.x, aPos.x,
aPos.y ) ); aPos.y ) );
} }
m_violationHandler( aItem, aPos );
} }
void DRC_ENGINE::ReportAux ( const wxString& aStr ) void DRC_ENGINE::ReportAux ( const wxString& aStr )
@ -587,14 +634,12 @@ void DRC_ENGINE::ReportProgress( double aProgress )
} }
void DRC_ENGINE::ReportStage ( const wxString& aStageName, int index, int total ) void DRC_ENGINE::ReportStage ( const wxString& aStageName )
{ {
if( !m_progressReporter ) if( !m_progressReporter )
return; return;
m_progressReporter->SetNumPhases( total ); m_progressReporter->AdvancePhase( aStageName );
m_progressReporter->BeginPhase( index ); // fixme: coalesce all stages/test providers
m_progressReporter->Report( aStageName );
} }
@ -623,8 +668,8 @@ std::vector<DRC_CONSTRAINT> DRC_ENGINE::QueryConstraintsById( DRC_CONSTRAINT_TYP
{ {
std::vector<DRC_CONSTRAINT> rv; std::vector<DRC_CONSTRAINT> rv;
for ( CONSTRAINT_WITH_CONDITIONS* c : m_constraintMap[constraintID]->sortedConstraints ) for ( CONSTRAINT_WITH_CONDITIONS* c : *m_constraintMap[constraintID] )
rv.push_back(c->constraint); rv.push_back( c->constraint );
return rv; return rv;
} }
@ -633,7 +678,7 @@ std::vector<DRC_CONSTRAINT> DRC_ENGINE::QueryConstraintsById( DRC_CONSTRAINT_TYP
bool DRC_ENGINE::HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_T constraintID ) bool DRC_ENGINE::HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_T constraintID )
{ {
//drc_dbg(10,"hascorrect id %d size %d\n", ruleID, m_ruleMap[ruleID]->sortedRules.size( ) ); //drc_dbg(10,"hascorrect id %d size %d\n", ruleID, m_ruleMap[ruleID]->sortedRules.size( ) );
return m_constraintMap[constraintID]->sortedConstraints.size() != 0; return m_constraintMap[constraintID]->size() != 0;
} }

View File

@ -79,7 +79,6 @@ std::function<void( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos )> DRC_
*/ */
class DRC_ENGINE class DRC_ENGINE
{ {
public: public:
DRC_ENGINE( BOARD* aBoard, BOARD_DESIGN_SETTINGS* aSettings ); DRC_ENGINE( BOARD* aBoard, BOARD_DESIGN_SETTINGS* aSettings );
~DRC_ENGINE(); ~DRC_ENGINE();
@ -87,31 +86,42 @@ public:
void SetSchematicNetlist( NETLIST* aNetlist ) { m_schematicNetlist = aNetlist; } void SetSchematicNetlist( NETLIST* aNetlist ) { m_schematicNetlist = aNetlist; }
NETLIST* GetSchematicNetlist() const { return m_schematicNetlist; } NETLIST* GetSchematicNetlist() const { return m_schematicNetlist; }
// JEY TODO: why isn't this called?
void SetWorksheet( KIGFX::WS_PROXY_VIEW_ITEM* aWorksheet ) { m_worksheet = aWorksheet; } void SetWorksheet( KIGFX::WS_PROXY_VIEW_ITEM* aWorksheet ) { m_worksheet = aWorksheet; }
KIGFX::WS_PROXY_VIEW_ITEM* GetWorksheet() const { return m_worksheet; } KIGFX::WS_PROXY_VIEW_ITEM* GetWorksheet() const { return m_worksheet; }
// JEY TODO: rationalize old progress report style with new... /*
* Receives DRC violation reports (a DRC_ITEM and a position).
*/
void SetViolationHandler( DRC_VIOLATION_HANDLER aHandler )
{
m_violationHandler = std::move( aHandler );
}
/*
* Receives progress information to show the user.
*/
void SetProgressReporter( PROGRESS_REPORTER* aProgRep ) { m_progressReporter = aProgRep; } void SetProgressReporter( PROGRESS_REPORTER* aProgRep ) { m_progressReporter = aProgRep; }
/*
* Receives debug information for a developer.
*/
void SetLogReporter( REPORTER* aReporter ) { m_reporter = aReporter; } void SetLogReporter( REPORTER* aReporter ) { m_reporter = aReporter; }
/*
* Loads and parses a rule set from an sexpr text file.
*/
bool LoadRules( const wxFileName& aPath ); bool LoadRules( const wxFileName& aPath );
void InitEngine( const wxFileName& aRulePath ); void InitEngine( const wxFileName& aRulePath );
void RunTests( DRC_VIOLATION_HANDLER aDRCItemHandler ); void RunTests( EDA_UNITS aUnits = EDA_UNITS::MILLIMETRES, bool aTestTracksAgainstZones = true,
bool aReportAllTrackErrors = true, bool aTestFootprints = true );
BOARD_DESIGN_SETTINGS* GetDesignSettings() const { return m_designSettings; } BOARD_DESIGN_SETTINGS* GetDesignSettings() const { return m_designSettings; }
BOARD* GetBoard() const { return m_board; } BOARD* GetBoard() const { return m_board; }
bool IsErrorLimitExceeded( int error_code ) bool IsErrorLimitExceeded( int error_code );
{
m_errorLimits[ error_code ] -= 1;
return m_errorLimits[ error_code ] <= 0;
}
DRC_CONSTRAINT EvalRulesForItems( DRC_CONSTRAINT_TYPE_T ruleID, BOARD_ITEM* a, DRC_CONSTRAINT EvalRulesForItems( DRC_CONSTRAINT_TYPE_T ruleID, BOARD_ITEM* a,
BOARD_ITEM* b = nullptr, BOARD_ITEM* b = nullptr,
@ -122,23 +132,16 @@ public:
bool HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_T constraintID ); bool HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_T constraintID );
EDA_UNITS UserUnits() const EDA_UNITS UserUnits() const { return m_userUnits; }
{ bool GetTestTracksAgainstZones() const { return m_testTracksAgainstZones; }
// JEY TODO bool GetReportAllTrackErrors() const { return m_reportAllTrackErrors; }
return EDA_UNITS::MILLIMETRES; bool GetTestFootprints() const { return m_testFootprints; }
}
bool GetTestTracksAgainstZones() const
{
// JEY TODO
return true;
}
bool CompileRules(); bool CompileRules();
void ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos ); void ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos );
void ReportProgress( double aProgress ); void ReportProgress( double aProgress );
void ReportStage ( const wxString& aStageName, int index, int total ); void ReportStage( const wxString& aStageName );
void ReportAux( const wxString& aStr ); void ReportAux( const wxString& aStr );
bool QueryWorstConstraint( DRC_CONSTRAINT_TYPE_T aRuleId, DRC_CONSTRAINT& aConstraint, bool QueryWorstConstraint( DRC_CONSTRAINT_TYPE_T aRuleId, DRC_CONSTRAINT& aConstraint,
@ -160,12 +163,6 @@ private:
DRC_CONSTRAINT constraint; DRC_CONSTRAINT constraint;
}; };
struct CONSTRAINT_SET
{
std::vector<CONSTRAINT_WITH_CONDITIONS*> sortedConstraints;
DRC_TEST_PROVIDER* provider;
};
void loadImplicitRules(); void loadImplicitRules();
void loadTestProviders(); void loadTestProviders();
DRC_RULE* createImplicitRule( const wxString& name ); DRC_RULE* createImplicitRule( const wxString& name );
@ -179,10 +176,16 @@ protected:
std::vector<DRC_RULE_CONDITION*> m_ruleConditions; std::vector<DRC_RULE_CONDITION*> m_ruleConditions;
std::vector<DRC_RULE*> m_rules; std::vector<DRC_RULE*> m_rules;
std::vector<DRC_TEST_PROVIDER*> m_testProviders; std::vector<DRC_TEST_PROVIDER*> m_testProviders;
EDA_UNITS m_userUnits;
std::vector<int> m_errorLimits; std::vector<int> m_errorLimits;
bool m_testTracksAgainstZones;
bool m_reportAllTrackErrors;
bool m_testFootprints;
// constraint -> rule -> provider // constraint -> rule -> provider
std::unordered_map<DRC_CONSTRAINT_TYPE_T, CONSTRAINT_SET*> m_constraintMap; std::unordered_map< DRC_CONSTRAINT_TYPE_T,
std::vector<CONSTRAINT_WITH_CONDITIONS*>* > m_constraintMap;
DRC_VIOLATION_HANDLER m_violationHandler; DRC_VIOLATION_HANDLER m_violationHandler;
REPORTER* m_reporter; REPORTER* m_reporter;

View File

@ -31,6 +31,50 @@ class PCB_BASE_FRAME;
class DRC_RULE; class DRC_RULE;
class DRC_TEST_PROVIDER; class DRC_TEST_PROVIDER;
enum PCB_DRC_CODE {
DRCE_FIRST = 1,
DRCE_UNCONNECTED_ITEMS = DRCE_FIRST, // items are unconnected
DRCE_SHORTING_ITEMS, // items short two nets but are not a net-tie
DRCE_ALLOWED_ITEMS, // a disallowed item has been used
DRCE_CLEARANCE, // items are too close together
DRCE_TRACKS_CROSSING, // tracks are crossing
DRCE_COPPER_EDGE_CLEARANCE, // a copper item is too close to the board edge
DRCE_ZONES_INTERSECT, // copper area outlines intersect
DRCE_ZONE_HAS_EMPTY_NET, // copper area has a net but no pads in nets, which is suspicious
DRCE_DANGLING_VIA, // via which isn't connected to anything
DRCE_DANGLING_TRACK, // track with at least one end not connected to anything
DRCE_DRILLED_HOLES_TOO_CLOSE, // overlapping drilled holes break drill bits
DRCE_HOLE_CLEARANCE, //
DRCE_TRACK_WIDTH, // Track width is too small or too large
DRCE_TOO_SMALL_VIA, // Too small via size
DRCE_ANNULUS, // Via size and drill leave annulus too small or too large
DRCE_TOO_SMALL_DRILL, // Too small via or pad drill
DRCE_VIA_HOLE_BIGGER, // via's hole is bigger than its diameter
DRCE_VIA_DIAMETER, // Via diameter checks (min/max)
DRCE_PADSTACK, // something is wrong with a pad or via stackup
DRCE_TOO_SMALL_MICROVIA, // Too small micro via size
DRCE_TOO_SMALL_MICROVIA_DRILL, // Too small micro via drill
DRCE_KEEPOUT, // A disallowed object is inside a keepout
DRCE_OVERLAPPING_FOOTPRINTS, // footprint courtyards overlap
DRCE_MISSING_COURTYARD, // footprint has no courtyard defined
DRCE_MALFORMED_COURTYARD, // footprint has a courtyard but malformed
// (not convertible to a closed polygon with holes)
DRCE_PTH_IN_COURTYARD,
DRCE_NPTH_IN_COURTYARD,
DRCE_DISABLED_LAYER_ITEM, // item on a disabled layer
DRCE_INVALID_OUTLINE, // invalid board outline
DRCE_MISSING_FOOTPRINT, // footprint not found for netlist item
DRCE_DUPLICATE_FOOTPRINT, // more than one footprints found for netlist item
DRCE_EXTRA_FOOTPRINT, // netlist item not found for footprint
DRCE_NET_CONFLICT, // pad net doesn't match netlist
DRCE_UNRESOLVED_VARIABLE,
DRCE_LAST = DRCE_UNRESOLVED_VARIABLE
};
class DRC_ITEM : public RC_ITEM class DRC_ITEM : public RC_ITEM
{ {
public: public:

View File

@ -1,328 +0,0 @@
/*
* 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 <drc/drc_keepout_tester.h>
#include <geometry/shape_segment.h>
#include <class_module.h>
#include <drc/drc.h>
#include <drc/drc_item.h>
DRC_KEEPOUT_TESTER::DRC_KEEPOUT_TESTER( MARKER_HANDLER aMarkerHandler ) :
LEGACY_DRC_TEST_PROVIDER( std::move( aMarkerHandler ) ),
m_units( EDA_UNITS::MILLIMETRES ),
m_board( nullptr ),
m_zone( nullptr ),
m_keepoutFlags( 0 )
{
}
bool DRC_KEEPOUT_TESTER::RunDRC( EDA_UNITS aUnits, BOARD& aBoard )
{
bool success = true;
m_units = aUnits;
m_board = &aBoard;
// Get a list of all zones to inspect, from both board and footprints
std::list<ZONE_CONTAINER*> areasToInspect = m_board->GetZoneList( true );
// Test keepout areas for vias, tracks and pads inside keepout areas
for( ZONE_CONTAINER* area : areasToInspect )
{
// JEY TODO: our existing keepout strategy needs a work-over for rules....
m_keepoutFlags = area->GetKeepouts( F_Cu, &m_sources );
if( m_keepoutFlags > 0 )
{
m_zone = area;
m_zoneBBox = area->GetBoundingBox();
success &= checkTracksAndVias();
success &= checkFootprints();
success &= checkDrawings();
}
}
return success;
}
bool DRC_KEEPOUT_TESTER::checkTracksAndVias()
{
constexpr int VIA_MASK = DRC_DISALLOW_VIAS | DRC_DISALLOW_MICRO_VIAS | DRC_DISALLOW_BB_VIAS;
constexpr int CHECK_VIAS_MASK = VIA_MASK | DRC_DISALLOW_HOLES;
constexpr int CHECK_TRACKS_AND_VIAS_MASK = CHECK_VIAS_MASK | DRC_DISALLOW_TRACKS;
if(( m_keepoutFlags & CHECK_TRACKS_AND_VIAS_MASK ) == 0 )
return true;
bool success = true;
for( TRACK* segm : m_board->Tracks() )
{
if( !m_zoneBBox.Intersects( segm->GetBoundingBox() ) )
continue;
if( segm->Type() == PCB_TRACE_T && ( m_keepoutFlags & DRC_DISALLOW_TRACKS ) != 0 )
{
// Ignore if the keepout zone is not on the same layer
PCB_LAYER_ID layer = segm->GetLayer();
if( !m_zone->IsOnLayer( layer ) )
continue;
SEG trackSeg( segm->GetStart(), segm->GetEnd() );
if( m_zone->Outline()->Collide( trackSeg, segm->GetWidth() / 2 ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_KEEPOUT );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s)" ),
m_sources.at( DRC_DISALLOW_TRACKS ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( segm, m_zone );
HandleMarker( new MARKER_PCB( drcItem, DRC::GetLocation( layer, segm, m_zone ) ) );
success = false;
}
}
else if( segm->Type() == PCB_VIA_T && ( m_keepoutFlags & CHECK_VIAS_MASK ) != 0 )
{
VIA* via = static_cast<VIA*>( segm );
SEG seg( via->GetPosition(), via->GetPosition() );
int test = 0;
int clearance = via->GetWidth() / 2;
if( ( m_keepoutFlags & DRC_DISALLOW_VIAS ) > 0 )
{
test = DRC_DISALLOW_VIAS;
}
else if( via->GetViaType() == VIATYPE::MICROVIA
&& ( m_keepoutFlags & DRC_DISALLOW_MICRO_VIAS ) > 0 )
{
test = DRC_DISALLOW_MICRO_VIAS;
}
else if( via->GetViaType() == VIATYPE::BLIND_BURIED
&& ( m_keepoutFlags & DRC_DISALLOW_BB_VIAS ) > 0 )
{
test = DRC_DISALLOW_BB_VIAS;
}
else if( ( m_keepoutFlags & DRC_DISALLOW_HOLES ) > 0 )
{
test = DRC_DISALLOW_HOLES;
clearance = via->GetDrillValue() / 2;
}
else
continue;
if( m_zone->Outline()->Collide( seg, clearance ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_KEEPOUT );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s)" ), m_sources.at( test ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( segm, m_zone );
HandleMarker( new MARKER_PCB( drcItem, via->GetPosition() ) );
success = false;
}
}
}
return success;
}
bool DRC_KEEPOUT_TESTER::checkFootprints()
{
constexpr int CHECK_PADS_MASK = DRC_DISALLOW_PADS | DRC_DISALLOW_HOLES;
constexpr int CHECK_FOOTPRINTS_MASK = CHECK_PADS_MASK | DRC_DISALLOW_FOOTPRINTS;
if(( m_keepoutFlags & CHECK_FOOTPRINTS_MASK ) == 0 )
return true;
bool success = true;
for( MODULE* fp : m_board->Modules() )
{
if( m_zone->GetParent() == fp )
continue;
if( !m_zoneBBox.Intersects( fp->GetBoundingBox() ) )
continue;
if( ( m_keepoutFlags & DRC_DISALLOW_FOOTPRINTS ) > 0
&& ( fp->IsFlipped() ? m_zone->CommonLayerExists( LSET::BackMask() )
: m_zone->CommonLayerExists( LSET::FrontMask() ) ) )
{
SHAPE_POLY_SET poly;
if( fp->BuildPolyCourtyard() )
poly = fp->IsFlipped() ? fp->GetPolyCourtyardBack() : fp->GetPolyCourtyardFront();
if( poly.OutlineCount() == 0 )
poly = fp->GetBoundingPoly();
// Build the common area between footprint and the keepout area:
poly.BooleanIntersection( *m_zone->Outline(), SHAPE_POLY_SET::PM_FAST );
// If it's not empty then we have a violation
if( poly.OutlineCount() )
{
const VECTOR2I& pt = poly.CVertex( 0, 0, -1 );
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_KEEPOUT );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s)" ),
m_sources.at( DRC_DISALLOW_FOOTPRINTS ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( fp, m_zone );
HandleMarker( new MARKER_PCB( drcItem, (wxPoint) pt ) );
success = false;
}
}
if( ( m_keepoutFlags & CHECK_PADS_MASK ) > 0 )
{
success &= checkPads( fp );
}
}
return success;
}
bool DRC_KEEPOUT_TESTER::checkPads( MODULE* aModule )
{
bool success = true;
for( D_PAD* pad : aModule->Pads() )
{
if( !m_zone->CommonLayerExists( pad->GetLayerSet() ) )
continue;
// Fast test to detect a pad inside the keepout area bounding box.
EDA_RECT padBBox( pad->GetPosition(), wxSize() );
padBBox.Inflate( pad->GetBoundingRadius() );
if( !m_zoneBBox.Intersects( padBBox ) )
continue;
if( ( m_keepoutFlags & DRC_DISALLOW_PADS ) > 0 )
{
SHAPE_POLY_SET outline = *pad->GetEffectivePolygon();
// Build the common area between pad and the keepout area:
outline.BooleanIntersection( *m_zone->Outline(), SHAPE_POLY_SET::PM_FAST );
// If it's not empty then we have a violation
if( outline.OutlineCount() )
{
const VECTOR2I& pt = outline.CVertex( 0, 0, -1 );
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_KEEPOUT );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s)" ),
m_sources.at( DRC_DISALLOW_PADS ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( pad, m_zone );
HandleMarker( new MARKER_PCB( drcItem, (wxPoint) pt ) );
success = false;
}
}
else if( ( m_keepoutFlags & DRC_DISALLOW_HOLES ) > 0 )
{
const SHAPE_SEGMENT* slot = pad->GetEffectiveHoleShape();
if( m_zone->Outline()->Collide( slot->GetSeg(), slot->GetWidth() / 2 ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_KEEPOUT );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s)" ),
m_sources.at( DRC_DISALLOW_HOLES ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( pad, m_zone );
HandleMarker( new MARKER_PCB( drcItem, pad->GetPosition() ) );
success = false;
}
}
}
return success;
}
bool DRC_KEEPOUT_TESTER::checkDrawings()
{
constexpr int CHECK_DRAWINGS_MASK = DRC_DISALLOW_TEXTS | DRC_DISALLOW_GRAPHICS;
constexpr KICAD_T graphicTypes[] = { PCB_LINE_T, PCB_DIMENSION_T, PCB_TARGET_T, EOT };
if(( m_keepoutFlags & CHECK_DRAWINGS_MASK ) == 0 )
return true;
bool success = true;
for( BOARD_ITEM* drawing : m_board->Drawings() )
{
if( !m_zoneBBox.Intersects( drawing->GetBoundingBox() ) )
continue;
int sourceId = 0;
if( drawing->IsType( graphicTypes ) && ( m_keepoutFlags & DRC_DISALLOW_GRAPHICS ) > 0 )
sourceId = DRC_DISALLOW_GRAPHICS;
else if( drawing->Type() == PCB_TEXT_T && ( m_keepoutFlags & DRC_DISALLOW_TEXTS ) > 0 )
sourceId = DRC_DISALLOW_TEXTS;
else
continue;
SHAPE_POLY_SET poly;
drawing->TransformShapeWithClearanceToPolygon( poly, drawing->GetLayer(), 0 );
// Build the common area between footprint and the keepout area:
poly.BooleanIntersection( *m_zone->Outline(), SHAPE_POLY_SET::PM_FAST );
// If it's not empty then we have a violation
if( poly.OutlineCount() )
{
const VECTOR2I& pt = poly.CVertex( 0, 0, -1 );
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_KEEPOUT );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s)" ), m_sources.at( sourceId ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( drawing, m_zone );
HandleMarker( new MARKER_PCB( drcItem, (wxPoint) pt ) );
success = false;
}
}
return success;
}

View File

@ -1,61 +0,0 @@
/*
* 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
*/
#ifndef DRC_KEEPOUT_TESTER__H
#define DRC_KEEPOUT_TESTER__H
#include <drc/drc_results_provider.h>
class BOARD;
class DRC_KEEPOUT_TESTER : public LEGACY_DRC_TEST_PROVIDER
{
public:
DRC_KEEPOUT_TESTER( MARKER_HANDLER aMarkerHandler );
virtual ~DRC_KEEPOUT_TESTER() {};
bool RunDRC( EDA_UNITS aUnits, BOARD& aBoard ) override;
private:
bool checkTracksAndVias();
bool checkFootprints();
bool checkPads( MODULE* aModule );
bool checkDrawings();
private:
EDA_UNITS m_units;
BOARD* m_board;
// Temp variables for use while testing:
ZONE_CONTAINER* m_zone;
EDA_RECT m_zoneBBox;
int m_keepoutFlags; // bitset of DISALLOW_* flags
std::map<int, wxString> m_sources; // map of DISALLOW_* flag to source
wxString m_msg; // avoid lots of calls to wxString's c'tor.
};
#endif // DRC_KEEPOUT_TESTER__H

View File

@ -1,7 +1,7 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2018 KiCad Developers, see change_log.txt for contributors. * Copyright (C) 2018-2020 KiCad Developers, see change_log.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -28,58 +28,11 @@
#include <class_board.h> #include <class_board.h>
#include <class_marker_pcb.h> #include <class_marker_pcb.h>
#include <pcb_base_frame.h> #include <pcb_base_frame.h>
#include <drc/drc.h>
#include <drc/drc_item.h> #include <drc/drc_item.h>
#include <widgets/ui_common.h> #include <widgets/ui_common.h>
#include <functional> #include <functional>
/**
* LEGACY_DRC_TEST_PROVIDER
* is a base class that represents a DRC "provider" which runs some DRC functions over a
* #BOARD and spits out #PCB_MARKERs as needed.
*
* JEY TODO: to remove
*
*/
class LEGACY_DRC_TEST_PROVIDER
{
public:
/**
* A callable that can handle a single generated PCB_MARKER
*/
using MARKER_HANDLER = std::function<void( MARKER_PCB* )>;
/**
* Runs this provider against the given PCB with configured options (if any).
*
* Note: Board is non-const, as some DRC functions modify the board (e.g. zone fill
* or polygon coalescing)
*/
virtual bool RunDRC( EDA_UNITS aUnits, BOARD& aBoard ) = 0;
virtual ~LEGACY_DRC_TEST_PROVIDER() {}
protected:
LEGACY_DRC_TEST_PROVIDER( MARKER_HANDLER aMarkerHandler ) :
m_marker_handler( std::move( aMarkerHandler ) )
{
}
/**
* Pass a given marker to the marker handler
*/
void HandleMarker( MARKER_PCB* aMarker ) const
{
m_marker_handler( aMarker );
}
private:
/// The handler for any generated markers
MARKER_HANDLER m_marker_handler;
};
/** /**
* BOARD_DRC_ITEMS_PROVIDER * BOARD_DRC_ITEMS_PROVIDER
* is an implementation of the RC_ITEMS_PROVIDER interface which uses a BOARD instance * is an implementation of the RC_ITEMS_PROVIDER interface which uses a BOARD instance

View File

@ -39,27 +39,27 @@ const wxString DRC_TEST_PROVIDER::GetName() const { return "<no name test>"; }
const wxString DRC_TEST_PROVIDER::GetDescription() const { return ""; } const wxString DRC_TEST_PROVIDER::GetDescription() const { return ""; }
void DRC_TEST_PROVIDER::ReportViolation( std::shared_ptr<DRC_ITEM> aItem, wxPoint aPos ) void DRC_TEST_PROVIDER::reportViolation( std::shared_ptr<DRC_ITEM> item, wxPoint aMarkerPos )
{ {
aItem->SetViolatingTest( this ); item->SetViolatingTest( this );
m_drcEngine->ReportViolation( aItem, aPos ); m_drcEngine->ReportViolation( item, aMarkerPos );
} }
void DRC_TEST_PROVIDER::ReportProgress( double aProgress ) void DRC_TEST_PROVIDER::reportProgress( double aProgress )
{ {
m_drcEngine->ReportProgress( aProgress ); m_drcEngine->ReportProgress( aProgress );
} }
void DRC_TEST_PROVIDER::ReportStage ( const wxString& aStageName, int index, int total ) void DRC_TEST_PROVIDER::reportStage( const wxString& aStageName )
{ {
m_drcEngine->ReportStage( aStageName, index, total ); m_drcEngine->ReportStage( aStageName );
ReportAux( aStageName ); reportAux( aStageName );
} }
void DRC_TEST_PROVIDER::ReportAux( wxString fmt, ... ) void DRC_TEST_PROVIDER::reportAux( wxString fmt, ... )
{ {
va_list vargs; va_list vargs;
va_start( vargs, fmt ); va_start( vargs, fmt );
@ -83,7 +83,7 @@ void DRC_TEST_PROVIDER::accountCheck( const DRC_RULE* ruleToTest )
if( it == m_stats.end() ) if( it == m_stats.end() )
m_stats[ ruleToTest ] = 1; m_stats[ ruleToTest ] = 1;
else else
it->second++; m_stats[ ruleToTest ] += 1;
} }
@ -98,14 +98,17 @@ void DRC_TEST_PROVIDER::reportRuleStatistics()
if( !m_isRuleDriven ) if( !m_isRuleDriven )
return; return;
m_drcEngine->ReportAux("Rule hit statistics: "); m_drcEngine->ReportAux( "Rule hit statistics: " );
for( const std::pair<const DRC_RULE* const, int>& stat : m_stats ) for( const std::pair<const DRC_RULE* const, int>& stat : m_stats )
{
if( stat.first )
{ {
m_drcEngine->ReportAux( wxString::Format( " - rule '%s': %d hits ", m_drcEngine->ReportAux( wxString::Format( " - rule '%s': %d hits ",
stat.first->m_Name, stat.first->m_Name,
stat.second ) ); stat.second ) );
} }
}
} }

View File

@ -67,7 +67,7 @@ public:
/** /**
* DRC_TEST_PROVIDER * DRC_TEST_PROVIDER
* is a base class that represents a DRC "provider" which runs some DRC functions over a * is a base class that represents a DRC "provider" which runs some DRC functions over a
* #BOARD and spits out #PCB_MARKERs as needed. * #BOARD and spits out #DRC_ITEMs and positions as needed.
*/ */
class DRC_TEST_PROVIDER class DRC_TEST_PROVIDER
{ {
@ -82,23 +82,16 @@ public:
/** /**
* Runs this provider against the given PCB with configured options (if any). * Runs this provider against the given PCB with configured options (if any).
*
* Note: Board is non-const, as some DRC functions modify the board (e.g. zone fill
* or polygon coalescing)
*/ */
virtual bool Run() = 0; virtual bool Run() = 0;
virtual const wxString GetName() const; virtual const wxString GetName() const;
virtual const wxString GetDescription() const; virtual const wxString GetDescription() const;
virtual void ReportAux( wxString fmt, ... );
virtual void ReportViolation( std::shared_ptr<DRC_ITEM> item, wxPoint aMarkerPos );
virtual void ReportProgress( double aProgress );
virtual void ReportStage ( const wxString& aStageName, int index, int total );
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const = 0; virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const = 0;
virtual int GetNumPhases() const = 0;
virtual bool IsRuleDriven() const virtual bool IsRuleDriven() const
{ {
return m_isRuleDriven; return m_isRuleDriven;
@ -108,6 +101,11 @@ protected:
int forEachGeometryItem( const std::vector<KICAD_T>& aTypes, LSET aLayers, int forEachGeometryItem( const std::vector<KICAD_T>& aTypes, LSET aLayers,
const std::function<bool(BOARD_ITEM*)>& aFunc ); const std::function<bool(BOARD_ITEM*)>& aFunc );
virtual void reportAux( wxString fmt, ... );
virtual void reportViolation( std::shared_ptr<DRC_ITEM> item, wxPoint aMarkerPos );
virtual void reportProgress( double aProgress );
virtual void reportStage( const wxString& aStageName );
virtual void reportRuleStatistics(); virtual void reportRuleStatistics();
virtual void accountCheck( const DRC_RULE* ruleToTest ); virtual void accountCheck( const DRC_RULE* ruleToTest );
virtual void accountCheck( const DRC_CONSTRAINT& constraintToTest ); virtual void accountCheck( const DRC_CONSTRAINT& constraintToTest );

View File

@ -63,6 +63,8 @@ public:
} }
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
}; };
@ -70,11 +72,11 @@ bool DRC_TEST_PROVIDER_ANNULUS::Run()
{ {
if( !m_drcEngine->HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_ANNULUS_WIDTH ) ) if( !m_drcEngine->HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_ANNULUS_WIDTH ) )
{ {
ReportAux( "No annulus constraints found. Skipping check." ); reportAux( "No annulus constraints found. Skipping check." );
return false; return false;
} }
ReportStage( _( "Testing via annular rings" ), 0, 2 ); reportStage( _( "Via annular rings..." ));
auto checkAnnulus = auto checkAnnulus =
[&]( BOARD_ITEM* item ) -> bool [&]( BOARD_ITEM* item ) -> bool
@ -117,7 +119,7 @@ bool DRC_TEST_PROVIDER_ANNULUS::Run()
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s annulus %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s annulus %s; actual %s)" ),
constraint.GetName(), constraint.GetName(),
fail_min ? _( "minimum" ) : _( "maximum" ), fail_min ? _( "min" ) : _( "max" ),
MessageTextFromValue( userUnits(), annulus, true ), MessageTextFromValue( userUnits(), annulus, true ),
MessageTextFromValue( userUnits(), fail_min ? v_min : v_max, true ) ); MessageTextFromValue( userUnits(), fail_min ? v_min : v_max, true ) );
@ -125,7 +127,7 @@ bool DRC_TEST_PROVIDER_ANNULUS::Run()
drcItem->SetItems( item ); drcItem->SetItems( item );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportViolation( drcItem, via->GetPosition() ); reportViolation( drcItem, via->GetPosition());
} }
return true; return true;
@ -139,6 +141,12 @@ bool DRC_TEST_PROVIDER_ANNULUS::Run()
} }
int DRC_TEST_PROVIDER_ANNULUS::GetNumPhases() const
{
return 1;
}
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_ANNULUS::GetConstraintTypes() const std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_ANNULUS::GetConstraintTypes() const
{ {
return { DRC_CONSTRAINT_TYPE_ANNULUS_WIDTH }; return { DRC_CONSTRAINT_TYPE_ANNULUS_WIDTH };

View File

@ -66,12 +66,14 @@ public:
} }
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
}; };
bool DRC_TEST_PROVIDER_CONNECTIVITY::Run() bool DRC_TEST_PROVIDER_CONNECTIVITY::Run()
{ {
ReportStage( _( "Testing dangling pads/vias" ), 0, 2 ); reportStage( _( "Dangling pads/vias..." ));
BOARD* board = m_drcEngine->GetBoard(); BOARD* board = m_drcEngine->GetBoard();
@ -100,11 +102,11 @@ bool DRC_TEST_PROVIDER_CONNECTIVITY::Run()
{ {
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( code ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( code );
drcItem->SetItems( track ); drcItem->SetItems( track );
ReportViolation( drcItem, pos ); reportViolation( drcItem, pos );
} }
} }
ReportStage( _( "Testing starved zones" ), 0, 2 ); reportStage( _( "Starved zones..." ));
/* test starved zones */ /* test starved zones */
for( ZONE_CONTAINER* zone : board->Zones() ) for( ZONE_CONTAINER* zone : board->Zones() )
@ -125,11 +127,11 @@ bool DRC_TEST_PROVIDER_CONNECTIVITY::Run()
{ {
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ZONE_HAS_EMPTY_NET ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ZONE_HAS_EMPTY_NET );
drcItem->SetItems( zone ); drcItem->SetItems( zone );
ReportViolation( drcItem, zone->GetPosition() ); reportViolation( drcItem, zone->GetPosition());
} }
} }
ReportStage( _( "Testing unconnected nets" ), 0, 2 ); reportStage( _( "Unconnected nets..." ));
connectivity->RecalculateRatsnest(); connectivity->RecalculateRatsnest();
std::vector<CN_EDGE> edges; std::vector<CN_EDGE> edges;
@ -142,7 +144,7 @@ bool DRC_TEST_PROVIDER_CONNECTIVITY::Run()
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNCONNECTED_ITEMS ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNCONNECTED_ITEMS );
drcItem->SetItems( edge.GetSourceNode()->Parent(), edge.GetTargetNode()->Parent() ); drcItem->SetItems( edge.GetSourceNode()->Parent(), edge.GetTargetNode()->Parent() );
ReportViolation( drcItem, (wxPoint) edge.GetSourceNode()->Pos() ); reportViolation( drcItem, (wxPoint) edge.GetSourceNode()->Pos());
} }
reportRuleStatistics(); reportRuleStatistics();
@ -151,6 +153,12 @@ bool DRC_TEST_PROVIDER_CONNECTIVITY::Run()
} }
int DRC_TEST_PROVIDER_CONNECTIVITY::GetNumPhases() const
{
return 3;
}
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_CONNECTIVITY::GetConstraintTypes() const std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_CONNECTIVITY::GetConstraintTypes() const
{ {
return {}; return {};

View File

@ -75,10 +75,12 @@ public:
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
private: private:
void testPadClearances(); void testPadClearances();
void testTrackClearances( bool aTestZones ); void testTrackClearances();
void testCopperTextAndGraphics(); void testCopperTextAndGraphics();
@ -87,7 +89,7 @@ private:
void testCopperDrawItem( BOARD_ITEM* aItem ); void testCopperDrawItem( BOARD_ITEM* aItem );
void doTrackDrc( TRACK* aRefSeg, PCB_LAYER_ID aLayer, TRACKS::iterator aStartIt, void doTrackDrc( TRACK* aRefSeg, PCB_LAYER_ID aLayer, TRACKS::iterator aStartIt,
TRACKS::iterator aEndIt, bool aTestZones ); TRACKS::iterator aEndIt );
void doPadToPadsDrc( D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd, int x_limit ); void doPadToPadsDrc( D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd, int x_limit );
}; };
@ -105,22 +107,22 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::Run()
} }
else else
{ {
ReportAux( "No Clearance constraints found..." ); reportAux( "No Clearance constraints found..." );
return false; return false;
} }
ReportAux( "Worst clearance : %d nm", m_largestClearance ); reportAux( "Worst clearance : %d nm", m_largestClearance );
ReportStage( _( "Testing pad copper clerances" ), 0, 2 ); reportStage( _( "Pad clerances..." ));
testPadClearances(); testPadClearances();
ReportStage( _( "Testing track/via copper clerances" ), 1, 2 ); reportStage( _( "Track/via clerances..." ));
testTrackClearances( m_drcEngine->GetTestTracksAgainstZones() ); testTrackClearances();
ReportStage( _( "Testing copper drawing/text clerances" ), 1, 2 ); reportStage( _( "Copper drawing/text clerances..." ));
testCopperTextAndGraphics(); testCopperTextAndGraphics();
ReportStage( _( "Testing copper zone clearances" ), 1, 2 ); reportStage( _( "Zone clearances..." ));
testZones(); testZones();
reportRuleStatistics(); reportRuleStatistics();
@ -230,7 +232,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* aItem )
drcItem->SetItems( track, aItem ); drcItem->SetItems( track, aItem );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportViolation( drcItem, pos ); reportViolation( drcItem, pos );
} }
} }
@ -253,7 +255,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* aItem )
// Fast test to detect a pad candidate inside the text bounding box // Fast test to detect a pad candidate inside the text bounding box
// Finer test (time consumming) is made only for pads near the text. // Finer test (time consuming) is made only for pads near the text.
int bb_radius = pad->GetBoundingRadius() + minClearance; int bb_radius = pad->GetBoundingRadius() + minClearance;
if( !bboxShape.Collide( SEG( pad->GetPosition(), pad->GetPosition() ), bb_radius ) ) if( !bboxShape.Collide( SEG( pad->GetPosition(), pad->GetPosition() ), bb_radius ) )
@ -273,39 +275,39 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* aItem )
drcItem->SetItems( pad, aItem ); drcItem->SetItems( pad, aItem );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportViolation( drcItem, pad->GetPosition() ); reportViolation( drcItem, pad->GetPosition());
} }
} }
void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances( bool aTestZones ) void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
{ {
const int delta = 500; // This is the number of tests between 2 calls to the progress bar const int delta = 500; // This is the number of tests between 2 calls to the progress bar
int count = m_board->Tracks().size(); int count = m_board->Tracks().size();
ReportProgress( 0.0 ); reportProgress( 0.0 );
ReportAux( "Testing %d tracks...", count ); reportAux( "Testing %d tracks...", count );
int ii = 0; int ii = 0;
for( auto seg_it = m_board->Tracks().begin(); seg_it != m_board->Tracks().end(); seg_it++ ) for( auto seg_it = m_board->Tracks().begin(); seg_it != m_board->Tracks().end(); seg_it++ )
{ {
if( (ii % delta) == 0) if( (ii % delta) == 0)
ReportProgress( (double) ii / (double) m_board->Tracks().size() ); reportProgress((double) ii / (double) m_board->Tracks().size());
ii++; ii++;
// Test segment against tracks and pads, optionally against copper zones // Test segment against tracks and pads, optionally against copper zones
for( PCB_LAYER_ID layer : (*seg_it)->GetLayerSet().Seq() ) for( PCB_LAYER_ID layer : (*seg_it)->GetLayerSet().Seq() )
{ {
doTrackDrc( *seg_it, layer, seg_it + 1, m_board->Tracks().end(), aTestZones ); doTrackDrc( *seg_it, layer, seg_it + 1, m_board->Tracks().end() );
} }
} }
} }
void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_ID aLayer, void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_ID aLayer,
TRACKS::iterator aStartIt, TRACKS::iterator aStartIt,
TRACKS::iterator aEndIt, bool aTestZones ) TRACKS::iterator aEndIt )
{ {
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
@ -369,7 +371,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_I
drcItem->SetItems( aRefSeg, pad ); drcItem->SetItems( aRefSeg, pad );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportViolation( drcItem, pad->GetPosition() ); reportViolation( drcItem, pad->GetPosition());
} }
} }
} }
@ -424,7 +426,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_I
drcItem->SetItems( aRefSeg, track ); drcItem->SetItems( aRefSeg, track );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportViolation( drcItem, (wxPoint) intersection.get() ); reportViolation( drcItem, (wxPoint) intersection.get());
} }
else if( refSeg.Collide( &trackSeg, minClearance - bds.GetDRCEpsilon(), &actual ) ) else if( refSeg.Collide( &trackSeg, minClearance - bds.GetDRCEpsilon(), &actual ) )
{ {
@ -440,16 +442,19 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_I
drcItem->SetItems( aRefSeg, track ); drcItem->SetItems( aRefSeg, track );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportViolation( drcItem, pos ); reportViolation( drcItem, pos );
if( !m_drcEngine->GetReportAllTrackErrors() )
break;
} }
} }
/***************************************/ /***************************************/
/* Phase 3: test DRC with copper zones */ /* Phase 3: test DRC with copper zones */
/***************************************/ /***************************************/
// Can be *very* time consumming. // Can be *very* time consuming.
if( aTestZones ) if( m_drcEngine->GetTestTracksAgainstZones() )
{ {
SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() ); SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
@ -490,7 +495,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_I
drcItem->SetItems( aRefSeg, zone ); drcItem->SetItems( aRefSeg, zone );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportViolation( drcItem, getLocation( aLayer, aRefSeg, zone ) ); reportViolation( drcItem, getLocation( aLayer, aRefSeg, zone ));
} }
} }
} }
@ -503,7 +508,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( )
m_board->GetSortedPadListByXthenYCoord( sortedPads ); m_board->GetSortedPadListByXthenYCoord( sortedPads );
ReportAux( "Testing %d pads...", sortedPads.size() ); reportAux( "Testing %d pads...", sortedPads.size());
if( sortedPads.empty() ) if( sortedPads.empty() )
return; return;
@ -533,7 +538,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( )
for( D_PAD* pad : sortedPads ) for( D_PAD* pad : sortedPads )
{ {
if( ii % 100 == 0 ) if( ii % 100 == 0 )
ReportProgress( (double) ii / (double) sortedPads.size() ); reportProgress((double) ii / (double) sortedPads.size());
ii++; ii++;
int x_limit = pad->GetPosition().x + pad->GetBoundingRadius() + max_size; int x_limit = pad->GetPosition().x + pad->GetBoundingRadius() + max_size;
@ -589,7 +594,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doPadToPadsDrc( D_PAD* aRefPad, D_PAD**
drcItem->SetErrorMessage( m_msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( pad, aRefPad ); drcItem->SetItems( pad, aRefPad );
ReportViolation( drcItem, aRefPad->GetPosition() ); reportViolation( drcItem, aRefPad->GetPosition());
} }
continue; continue;
@ -630,7 +635,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doPadToPadsDrc( D_PAD* aRefPad, D_PAD**
drcItem->SetItems( aRefPad, pad ); drcItem->SetItems( aRefPad, pad );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportViolation( drcItem, aRefPad->GetPosition() ); reportViolation( drcItem, aRefPad->GetPosition());
break; break;
} }
} }
@ -711,7 +716,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZones()
drcItem->SetItems( zoneRef, zoneToTest ); drcItem->SetItems( zoneRef, zoneToTest );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportViolation( drcItem, pt ); reportViolation( drcItem, pt );
} }
} }
@ -727,7 +732,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZones()
drcItem->SetItems( zoneToTest, zoneRef ); drcItem->SetItems( zoneToTest, zoneRef );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportViolation( drcItem, pt ); reportViolation( drcItem, pt );
} }
} }
@ -799,13 +804,19 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZones()
drcItem->SetItems( zoneRef, zoneToTest ); drcItem->SetItems( zoneRef, zoneToTest );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportViolation( drcItem, conflict.first ); reportViolation( drcItem, conflict.first );
} }
} }
} }
} }
int DRC_TEST_PROVIDER_COPPER_CLEARANCE::GetNumPhases() const
{
return 4;
}
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_COPPER_CLEARANCE::GetConstraintTypes() const std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_COPPER_CLEARANCE::GetConstraintTypes() const
{ {
return { DRC_CONSTRAINT_TYPE_CLEARANCE }; return { DRC_CONSTRAINT_TYPE_CLEARANCE };

View File

@ -65,6 +65,8 @@ public:
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
private: private:
void testFootprintCourtyardDefinitions(); void testFootprintCourtyardDefinitions();
@ -75,7 +77,7 @@ private:
void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions() void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions()
{ {
// Detects missing (or malformed) footprint courtyards // Detects missing (or malformed) footprint courtyards
ReportStage( _( "Testing component courtyard definitions" ), 0, 2 ); reportStage( _( "Footprint courtyard definitions..." ));
for( MODULE* footprint : m_board->Modules() ) for( MODULE* footprint : m_board->Modules() )
{ {
@ -89,7 +91,7 @@ void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions()
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MISSING_COURTYARD ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MISSING_COURTYARD );
drcItem->SetItems( footprint ); drcItem->SetItems( footprint );
ReportViolation( drcItem, footprint->GetPosition() ); reportViolation( drcItem, footprint->GetPosition());
} }
else else
{ {
@ -108,7 +110,7 @@ void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions()
drcItem->SetErrorMessage( m_msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( footprint ); drcItem->SetItems( footprint );
ReportViolation( drcItem, footprint->GetPosition() ); reportViolation( drcItem, footprint->GetPosition());
} }
} }
} }
@ -116,7 +118,7 @@ void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions()
void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testOverlappingComponentCourtyards() void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testOverlappingComponentCourtyards()
{ {
ReportStage( _( "Testing component courtyard overlap" ), 0, 2 ); reportStage( _( "Footprint courtyard overlap..." ));
for( auto it1 = m_board->Modules().begin(); it1 != m_board->Modules().end(); it1++ ) for( auto it1 = m_board->Modules().begin(); it1 != m_board->Modules().end(); it1++ )
{ {
@ -175,7 +177,7 @@ void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testOverlappingComponentCourtyards()
{ {
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_OVERLAPPING_FOOTPRINTS ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_OVERLAPPING_FOOTPRINTS );
drcItem->SetItems( footprint, test ); drcItem->SetItems( footprint, test );
ReportViolation( drcItem, pos ); reportViolation( drcItem, pos );
} }
} }
} }
@ -198,6 +200,12 @@ bool DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::Run()
} }
int DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::GetNumPhases() const
{
return 2;
}
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::GetConstraintTypes() const std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::GetConstraintTypes() const
{ {
return { DRC_CONSTRAINT_TYPE_COURTYARD_CLEARANCE }; return { DRC_CONSTRAINT_TYPE_COURTYARD_CLEARANCE };

View File

@ -21,11 +21,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
//#include <class_board.h>
#include <common.h> #include <common.h>
//#include <geometry/shape.h>
#include <drc/drc_engine.h> #include <drc/drc_engine.h>
#include <drc/drc.h> #include <drc/drc.h>
#include <drc/drc_item.h> #include <drc/drc_item.h>
@ -62,18 +58,20 @@ public:
} }
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
}; };
bool DRC_TEST_PROVIDER_DISALLOW::Run() bool DRC_TEST_PROVIDER_DISALLOW::Run()
{ {
if( !m_drcEngine->HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_DISALLOW ) ) if( !m_drcEngine->HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_DISALLOW ) )
{ {
ReportAux( "No disallow constraints found. Skipping check." ); reportAux( "No disallow constraints found. Skipping check." );
return false; return false;
} }
ReportStage( _( "Testing disallow constraints" ), 0, 2 ); reportStage( _( "Keepouts & disallow constraints..." ));
auto checkItem = [&]( BOARD_ITEM *item ) -> bool auto checkItem = [&]( BOARD_ITEM *item ) -> bool
{ {
@ -93,7 +91,7 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run()
drcItem->SetItems( item ); drcItem->SetItems( item );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportViolation( drcItem, item->GetPosition() ); reportViolation( drcItem, item->GetPosition());
} }
return true; return true;
@ -107,6 +105,12 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run()
} }
int DRC_TEST_PROVIDER_DISALLOW::GetNumPhases() const
{
return 1;
}
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_DISALLOW::GetConstraintTypes() const std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_DISALLOW::GetConstraintTypes() const
{ {
return { DRC_CONSTRAINT_TYPE_DISALLOW }; return { DRC_CONSTRAINT_TYPE_DISALLOW };

View File

@ -66,6 +66,8 @@ public:
} }
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
}; };
@ -82,13 +84,13 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
} }
else else
{ {
ReportAux("No Clearance constraints found..."); reportAux( "No Clearance constraints found..." );
return false; return false;
} }
ReportAux( "Worst clearance : %d nm", m_largestClearance ); reportAux( "Worst clearance : %d nm", m_largestClearance );
ReportStage( _( "Testing all items <> Board Edge clearance" ), 0, 2 ); reportStage( _( "Board edge clearances..." ));
std::vector<DRAWSEGMENT*> boardOutline; std::vector<DRAWSEGMENT*> boardOutline;
std::vector<BOARD_ITEM*> boardItems; std::vector<BOARD_ITEM*> boardItems;
@ -108,12 +110,13 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
}; };
forEachGeometryItem( { PCB_LINE_T }, LSET( Edge_Cuts ), queryBoardOutlineItems ); forEachGeometryItem( { PCB_LINE_T }, LSET( Edge_Cuts ), queryBoardOutlineItems );
forEachGeometryItem( {}, LSET::AllTechMask() | LSET::AllCuMask(), queryBoardGeometryItems ); forEachGeometryItem( {}, LSET::AllCuMask(), queryBoardGeometryItems );
wxString val; wxString val;
wxGetEnv( "WXTRACE", &val); wxGetEnv( "WXTRACE", &val);
drc_dbg( 2,"outline: %d items, board: %d items\n", boardOutline.size(), boardItems.size() ); drc_dbg( 2, "outline: %d items, board: %d items\n",
(int) boardOutline.size(), (int) boardItems.size() );
for( DRAWSEGMENT* outlineItem : boardOutline ) for( DRAWSEGMENT* outlineItem : boardOutline )
{ {
@ -154,7 +157,7 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
drcItem->SetItems( outlineItem, boardItem ); drcItem->SetItems( outlineItem, boardItem );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportViolation( drcItem, (wxPoint) refShape->Centre() ); reportViolation( drcItem, (wxPoint) refShape->Centre());
} }
} }
} }
@ -165,6 +168,12 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
} }
int DRC_TEST_PROVIDER_EDGE_CLEARANCE::GetNumPhases() const
{
return 1;
}
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_EDGE_CLEARANCE::GetConstraintTypes() const std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_EDGE_CLEARANCE::GetConstraintTypes() const
{ {
return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE }; return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE };

View File

@ -67,6 +67,8 @@ public:
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
private: private:
void addHole( const VECTOR2I& aLocation, int aRadius, BOARD_ITEM* aOwner ); void addHole( const VECTOR2I& aLocation, int aRadius, BOARD_ITEM* aOwner );
@ -103,21 +105,20 @@ bool DRC_TEST_PROVIDER_HOLE_CLEARANCE::Run()
worstClearanceConstraint, DRCCQ_LARGEST_MINIMUM ) ) worstClearanceConstraint, DRCCQ_LARGEST_MINIMUM ) )
{ {
m_largestClearance = worstClearanceConstraint.GetValue().Min(); m_largestClearance = worstClearanceConstraint.GetValue().Min();
reportAux( "Worst hole clearance : %d nm", m_largestClearance );
} }
else else
{ {
ReportAux( "No Clearance constraints found..." ); reportAux( "No hole clearance constraints found..." );
return false; return false;
} }
ReportAux( "Worst hole clearance : %d nm", m_largestClearance );
buildDrilledHoleList(); buildDrilledHoleList();
ReportStage( _( "Testing hole<->pad clearances" ), 0, 2 ); reportStage( _( "Hole to pad clearances..." ));
testPads2Holes(); testPads2Holes();
ReportStage( _( "Testing hole<->hole clearances" ), 0, 2 ); reportStage( _( "Hole to hole clearances..." ));
testHoles2Holes(); testHoles2Holes();
reportRuleStatistics(); reportRuleStatistics();
@ -155,7 +156,7 @@ void DRC_TEST_PROVIDER_HOLE_CLEARANCE::buildDrilledHoleList()
} }
} }
ReportAux( "Total drilled holes : %d", m_drilledHoles.size() ); reportAux( "Total drilled holes : %d", m_drilledHoles.size());
} }
void DRC_TEST_PROVIDER_HOLE_CLEARANCE::testPads2Holes() void DRC_TEST_PROVIDER_HOLE_CLEARANCE::testPads2Holes()
@ -277,7 +278,7 @@ bool DRC_TEST_PROVIDER_HOLE_CLEARANCE::doPadToPadHoleDrc( D_PAD* aRefPad, D_PAD
drcItem->SetItems( pad, aRefPad ); drcItem->SetItems( pad, aRefPad );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportViolation( drcItem, pad->GetPosition() ); reportViolation( drcItem, pad->GetPosition());
return false; return false;
} }
} }
@ -310,7 +311,7 @@ bool DRC_TEST_PROVIDER_HOLE_CLEARANCE::doPadToPadHoleDrc( D_PAD* aRefPad, D_PAD
drcItem->SetItems( aRefPad, pad ); drcItem->SetItems( aRefPad, pad );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportViolation( drcItem, pad->GetPosition() ); reportViolation( drcItem, pad->GetPosition());
return false; return false;
} }
} }
@ -395,13 +396,19 @@ void DRC_TEST_PROVIDER_HOLE_CLEARANCE::testHoles2Holes()
drcItem->SetItems( refHole.m_owner, checkHole.m_owner ); drcItem->SetItems( refHole.m_owner, checkHole.m_owner );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportViolation( drcItem, (wxPoint) refHole.m_location ); reportViolation( drcItem, (wxPoint) refHole.m_location );
} }
} }
} }
} }
int DRC_TEST_PROVIDER_HOLE_CLEARANCE::GetNumPhases() const
{
return 2;
}
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_HOLE_CLEARANCE::GetConstraintTypes() const std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_HOLE_CLEARANCE::GetConstraintTypes() const
{ {
return { DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE }; return { DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE };

View File

@ -64,6 +64,8 @@ public:
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
private: private:
void checkVia( VIA* via, bool aExceedMicro, bool aExceedStd ); void checkVia( VIA* via, bool aExceedMicro, bool aExceedStd );
void checkPad( D_PAD* aPad ); void checkPad( D_PAD* aPad );
@ -74,7 +76,7 @@ private:
bool DRC_TEST_PROVIDER_HOLE_SIZE::Run() bool DRC_TEST_PROVIDER_HOLE_SIZE::Run()
{ {
ReportStage( _( "Testing pad holes" ), 0, 2 ); reportStage( _( "Pad holes..." ));
m_board = m_drcEngine->GetBoard(); m_board = m_drcEngine->GetBoard();
@ -92,7 +94,7 @@ bool DRC_TEST_PROVIDER_HOLE_SIZE::Run()
} }
} }
ReportStage( _( "Testing via/microvia holes" ), 0, 2 ); reportStage( _( "Via holes..." ));
std::vector<VIA*> vias; std::vector<VIA*> vias;
@ -145,7 +147,7 @@ void DRC_TEST_PROVIDER_HOLE_SIZE::checkPad( D_PAD* aPad )
drcItem->SetItems( aPad ); drcItem->SetItems( aPad );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportViolation( drcItem, aPad->GetPosition() ); reportViolation( drcItem, aPad->GetPosition());
} }
} }
@ -187,11 +189,17 @@ void DRC_TEST_PROVIDER_HOLE_SIZE::checkVia( VIA* via, bool aExceedMicro, bool aE
drcItem->SetItems( via ); drcItem->SetItems( via );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportViolation( drcItem, via->GetPosition() ); reportViolation( drcItem, via->GetPosition());
} }
} }
int DRC_TEST_PROVIDER_HOLE_SIZE::GetNumPhases() const
{
return 2;
}
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_HOLE_SIZE::GetConstraintTypes() const std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_HOLE_SIZE::GetConstraintTypes() const
{ {
return { DRC_CONSTRAINT_TYPE_HOLE_SIZE }; return { DRC_CONSTRAINT_TYPE_HOLE_SIZE };

View File

@ -70,9 +70,9 @@ public:
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
private: int GetNumPhases() const override;
bool fetchNetlistFromSchematic( NETLIST& aNetlist ); private:
void testFootprints( NETLIST& aNetlist ); void testFootprints( NETLIST& aNetlist );
}; };
@ -101,7 +101,7 @@ void DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist )
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_DUPLICATE_FOOTPRINT ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_DUPLICATE_FOOTPRINT );
drcItem->SetItems( mod, *ins.first ); drcItem->SetItems( mod, *ins.first );
ReportViolation( drcItem, mod->GetPosition() ); reportViolation( drcItem, mod->GetPosition());
} }
} }
@ -123,7 +123,7 @@ void DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist )
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MISSING_FOOTPRINT ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MISSING_FOOTPRINT );
drcItem->SetErrorMessage( m_msg ); drcItem->SetErrorMessage( m_msg );
ReportViolation( drcItem, wxPoint() ); reportViolation( drcItem, wxPoint());
} }
else else
{ {
@ -142,7 +142,7 @@ void DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist )
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
drcItem->SetErrorMessage( m_msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( pad ); drcItem->SetItems( pad );
ReportViolation( drcItem, module->GetPosition() ); reportViolation( drcItem, module->GetPosition());
} }
else if( pcb_netname.IsEmpty() && !sch_net.GetNetName().IsEmpty() ) else if( pcb_netname.IsEmpty() && !sch_net.GetNetName().IsEmpty() )
{ {
@ -152,7 +152,7 @@ void DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist )
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
drcItem->SetErrorMessage( m_msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( pad ); drcItem->SetItems( pad );
ReportViolation( drcItem, module->GetPosition() ); reportViolation( drcItem, module->GetPosition());
} }
else if( pcb_netname != sch_net.GetNetName() ) else if( pcb_netname != sch_net.GetNetName() )
{ {
@ -163,7 +163,7 @@ void DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist )
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
drcItem->SetErrorMessage( m_msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( pad ); drcItem->SetItems( pad );
ReportViolation( drcItem, module->GetPosition() ); reportViolation( drcItem, module->GetPosition());
} }
} }
@ -182,7 +182,7 @@ void DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist )
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
drcItem->SetErrorMessage( m_msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( module ); drcItem->SetItems( module );
ReportViolation( drcItem, module->GetPosition() ); reportViolation( drcItem, module->GetPosition());
} }
} }
} }
@ -199,63 +199,33 @@ void DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist )
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_EXTRA_FOOTPRINT ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_EXTRA_FOOTPRINT );
drcItem->SetItems( module ); drcItem->SetItems( module );
ReportViolation( drcItem, module->GetPosition() ); reportViolation( drcItem, module->GetPosition());
} }
} }
} }
bool DRC_TEST_PROVIDER_LVS::fetchNetlistFromSchematic( NETLIST& aNetlist )
{
// fixme: make it work without dependency on EDIT_FRAME/kiway
#if 0
std::string payload;
Kiway().ExpressMail( FRAME_SCH, MAIL_SCH_GET_NETLIST, payload, nullptr );
try
{
auto lineReader = new STRING_LINE_READER( payload, _( "Eeschema netlist" ) );
KICAD_NETLIST_READER netlistReader( lineReader, &aNetlist );
netlistReader.LoadNetlist();
}
catch( const IO_ERROR& )
{
assert( false ); // should never happen
return false;
}
#endif
return false;
}
bool DRC_TEST_PROVIDER_LVS::Run() bool DRC_TEST_PROVIDER_LVS::Run()
{ {
ReportStage( _( "Layout-vs-Schematic checks..." ), 0, 2 ); if( m_drcEngine->GetTestFootprints() )
#if 0
if ( !Kiface().IsSingle() )
{ {
NETLIST netlist; // fixme: fetch from schematic without referring directly to the FRAME reportStage( _( "Layout-vs-Schematic checks..." ));
if( ! fetchNetlistFromSchematic( netlist ) ) testFootprints( *m_drcEngine->GetSchematicNetlist() );
{
ReportAux( _( "Unable to fetch the schematic netlist. Skipping LVS checks. ") );
return true;
}
testFootprints( netlist );
}
#endif
reportRuleStatistics(); reportRuleStatistics();
}
return true; return true;
} }
int DRC_TEST_PROVIDER_LVS::GetNumPhases() const
{
return m_drcEngine->GetTestFootprints() ? 1 : 0;
}
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_LVS::GetConstraintTypes() const std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_LVS::GetConstraintTypes() const
{ {
return {}; return {};

View File

@ -68,6 +68,8 @@ public:
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
private: private:
void testOutline(); void testOutline();
void testDisabledLayers(); void testDisabledLayers();
@ -93,7 +95,7 @@ void DRC_TEST_PROVIDER_MISC::testOutline()
drcItem->SetErrorMessage( m_msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( m_board ); drcItem->SetItems( m_board );
ReportViolation( drcItem, error_loc ); reportViolation( drcItem, error_loc );
} }
@ -119,7 +121,7 @@ void DRC_TEST_PROVIDER_MISC::testDisabledLayers()
drcItem->SetErrorMessage( m_msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( item ); drcItem->SetItems( item );
ReportViolation( drcItem, item->GetPosition() ); reportViolation( drcItem, item->GetPosition());
} }
return true; return true;
}; };
@ -144,7 +146,7 @@ void DRC_TEST_PROVIDER_MISC::testTextVars()
std::shared_ptr<DRC_ITEM>drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE ); std::shared_ptr<DRC_ITEM>drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE );
drcItem->SetItems( item ); drcItem->SetItems( item );
ReportViolation( drcItem, item->GetPosition() ); reportViolation( drcItem, item->GetPosition());
} }
return true; return true;
}; };
@ -179,7 +181,7 @@ void DRC_TEST_PROVIDER_MISC::testTextVars()
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE );
drcItem->SetItems( text ); drcItem->SetItems( text );
ReportViolation( drcItem, text->GetPosition() ); reportViolation( drcItem, text->GetPosition());
} }
} }
} }
@ -189,19 +191,25 @@ bool DRC_TEST_PROVIDER_MISC::Run()
{ {
m_board = m_drcEngine->GetBoard(); m_board = m_drcEngine->GetBoard();
ReportStage( _( "Test board outline" ), 0, 3 ); reportStage( _( "Board outline..." ));
testOutline(); testOutline();
ReportStage( _( "Test disabled layers" ), 1, 3 ); reportStage( _( "Disabled layers..." ));
testDisabledLayers(); testDisabledLayers();
ReportStage( _( "Test text variables" ), 2, 3 ); reportStage( _( "Text variables..." ));
testTextVars(); testTextVars();
return true; return true;
} }
int DRC_TEST_PROVIDER_MISC::GetNumPhases() const
{
return 3;
}
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_MISC::GetConstraintTypes() const std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_MISC::GetConstraintTypes() const
{ {
return {}; return {};

View File

@ -60,6 +60,8 @@ public:
} }
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
}; };
@ -67,11 +69,11 @@ bool DRC_TEST_PROVIDER_TRACK_WIDTH::Run()
{ {
if( !m_drcEngine->HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_TRACK_WIDTH ) ) if( !m_drcEngine->HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_TRACK_WIDTH ) )
{ {
ReportAux( "No track width constraints found. Skipping check." ); reportAux( "No track width constraints found. Skipping check." );
return false; return false;
} }
ReportStage( _( "Testing track widths" ), 0, 2 ); reportStage( _( "Track widths..." ));
auto checkTrackWidth = auto checkTrackWidth =
[&]( BOARD_ITEM* item ) -> bool [&]( BOARD_ITEM* item ) -> bool
@ -117,15 +119,15 @@ bool DRC_TEST_PROVIDER_TRACK_WIDTH::Run()
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s width %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s width %s; actual %s)" ),
constraint.GetName(), constraint.GetName(),
fail_min ? _( "minimum" ) : _( "maximum" ), fail_min ? _( "min" ) : _( "max" ),
MessageTextFromValue( userUnits(), constraintWidth, true ) ); MessageTextFromValue( userUnits(), constraintWidth, true ),
MessageTextFromValue( userUnits(), actual, true ), MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( m_msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( item ); drcItem->SetItems( item );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportViolation( drcItem, p0 ); reportViolation( drcItem, p0 );
} }
return true; return true;
@ -139,6 +141,12 @@ bool DRC_TEST_PROVIDER_TRACK_WIDTH::Run()
} }
int DRC_TEST_PROVIDER_TRACK_WIDTH::GetNumPhases() const
{
return 1;
}
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_TRACK_WIDTH::GetConstraintTypes() const std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_TRACK_WIDTH::GetConstraintTypes() const
{ {
return { DRC_CONSTRAINT_TYPE_TRACK_WIDTH }; return { DRC_CONSTRAINT_TYPE_TRACK_WIDTH };

View File

@ -61,6 +61,8 @@ public:
} }
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
}; };
@ -68,11 +70,11 @@ bool DRC_TEST_PROVIDER_VIA_DIAMETER::Run()
{ {
if( !m_drcEngine->HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_VIA_DIAMETER ) ) if( !m_drcEngine->HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_VIA_DIAMETER ) )
{ {
ReportAux( "No diameter constraints found. Skipping check." ); reportAux( "No diameter constraints found. Skipping check." );
return false; return false;
} }
ReportStage( ( "Testing via diameters" ), 0, 2 ); reportStage(( "Via diameters..." ));
auto checkViaDiameter = auto checkViaDiameter =
[&]( BOARD_ITEM* item ) -> bool [&]( BOARD_ITEM* item ) -> bool
@ -111,7 +113,7 @@ bool DRC_TEST_PROVIDER_VIA_DIAMETER::Run()
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s diameter %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s diameter %s; actual %s)" ),
constraint.GetName(), constraint.GetName(),
fail_min ? _( "minimum" ) : _( "maximum" ), fail_min ? _( "min" ) : _( "max" ),
MessageTextFromValue( userUnits(), constraintDiameter, true ) ); MessageTextFromValue( userUnits(), constraintDiameter, true ) );
MessageTextFromValue( userUnits(), actual, true ), MessageTextFromValue( userUnits(), actual, true ),
@ -119,7 +121,7 @@ bool DRC_TEST_PROVIDER_VIA_DIAMETER::Run()
drcItem->SetItems( item ); drcItem->SetItems( item );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportViolation( drcItem, via->GetPosition() ); reportViolation( drcItem, via->GetPosition());
} }
return true; return true;
@ -133,6 +135,12 @@ bool DRC_TEST_PROVIDER_VIA_DIAMETER::Run()
} }
int DRC_TEST_PROVIDER_VIA_DIAMETER::GetNumPhases() const
{
return 1;
}
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_VIA_DIAMETER::GetConstraintTypes() const std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_VIA_DIAMETER::GetConstraintTypes() const
{ {
return { DRC_CONSTRAINT_TYPE_VIA_DIAMETER }; return { DRC_CONSTRAINT_TYPE_VIA_DIAMETER };

View File

@ -1,120 +0,0 @@
/*
* 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 <drc/drc_textvar_tester.h>
#include <class_module.h>
#include <class_pcb_text.h>
#include <ws_draw_item.h>
#include <ws_proxy_view_item.h>
DRC_TEXTVAR_TESTER::DRC_TEXTVAR_TESTER( MARKER_HANDLER aMarkerHandler,
KIGFX::WS_PROXY_VIEW_ITEM* aWorksheet ) :
LEGACY_DRC_TEST_PROVIDER( std::move( aMarkerHandler ) ),
m_units( EDA_UNITS::MILLIMETRES ),
m_board( nullptr ),
m_worksheet( aWorksheet )
{
}
bool DRC_TEXTVAR_TESTER::RunDRC( EDA_UNITS aUnits, BOARD& aBoard )
{
bool success = true;
m_units = aUnits;
m_board = &aBoard;
for( MODULE* module : m_board->Modules() )
{
module->RunOnChildren(
[&]( BOARD_ITEM* child )
{
if( child->Type() == PCB_MODULE_TEXT_T )
{
TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( child );
if( text->GetShownText().Matches( wxT( "*${*}*" ) ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE );
drcItem->SetItems( text );
HandleMarker( new MARKER_PCB( drcItem, text->GetPosition() ) );
success = false;
}
}
} );
}
for( BOARD_ITEM* drawing : m_board->Drawings() )
{
if( drawing->Type() == PCB_TEXT_T )
{
TEXTE_PCB* text = static_cast<TEXTE_PCB*>( drawing );
if( text->GetShownText().Matches( wxT( "*${*}*" ) ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE );
drcItem->SetItems( text );
HandleMarker( new MARKER_PCB( drcItem, text->GetPosition() ) );
success = false;
}
}
}
WS_DRAW_ITEM_LIST wsItems;
if( m_worksheet )
{
wsItems.SetMilsToIUfactor( IU_PER_MILS );
wsItems.SetSheetNumber( 1 );
wsItems.SetSheetCount( 1 );
wsItems.SetFileName( "dummyFilename" );
wsItems.SetSheetName( "dummySheet" );
wsItems.SetSheetLayer( "dummyLayer" );
wsItems.SetProject( m_board->GetProject() );
wsItems.BuildWorkSheetGraphicList( m_worksheet->GetPageInfo(),
m_worksheet->GetTitleBlock() );
for( WS_DRAW_ITEM_BASE* item = wsItems.GetFirst(); item; item = wsItems.GetNext() )
{
if( WS_DRAW_ITEM_TEXT* text = dynamic_cast<WS_DRAW_ITEM_TEXT*>( item ) )
{
if( text->GetShownText().Matches( wxT( "*${*}*" ) ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE );
drcItem->SetErrorMessage( _( "Unresolved text variable in worksheet." ) );
HandleMarker( new MARKER_PCB( drcItem, text->GetPosition() ) );
success = false;
}
}
}
}
return success;
}

View File

@ -1,49 +0,0 @@
/*
* 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
*/
#ifndef DRC_TEXTVAR_TESTER__H
#define DRC_TEXTVAR_TESTER__H
#include <drc/drc_results_provider.h>
class BOARD;
class DRC_TEXTVAR_TESTER : public LEGACY_DRC_TEST_PROVIDER
{
public:
DRC_TEXTVAR_TESTER( MARKER_HANDLER aMarkerHandler, KIGFX::WS_PROXY_VIEW_ITEM* aWorksheet );
virtual ~DRC_TEXTVAR_TESTER() {};
bool RunDRC( EDA_UNITS aUnits, BOARD& aBoard ) override;
private:
EDA_UNITS m_units;
BOARD* m_board;
KIGFX::WS_PROXY_VIEW_ITEM* m_worksheet;
};
#endif // DRC_TEXTVAR_TESTER__H

View File

@ -1,149 +0,0 @@
/*
* 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 <netlist_reader/pcb_netlist.h>
#include <drc/footprint_tester.h>
#include <drc/drc_item.h>
void TestFootprints( NETLIST& aNetlist, BOARD* aBoard, std::vector<std::shared_ptr<DRC_ITEM> >& aDRCList )
{
wxString msg;
auto comp = []( const MODULE* x, const MODULE* y )
{
return x->GetReference().CmpNoCase( y->GetReference() ) < 0;
};
auto mods = std::set<MODULE*, decltype( comp )>( comp );
if( !aBoard->GetDesignSettings().Ignore( DRCE_DUPLICATE_FOOTPRINT ) )
{
// Search for duplicate footprints on the board
for( MODULE* mod : aBoard->Modules() )
{
auto ins = mods.insert( mod );
if( !ins.second )
{
std::shared_ptr<DRC_ITEM> item = DRC_ITEM::Create( DRCE_DUPLICATE_FOOTPRINT );
item->SetItems( mod, *ins.first );
aDRCList.push_back( item );
}
}
}
// Search for component footprints in the netlist but not on the board.
for( unsigned ii = 0; ii < aNetlist.GetCount(); ii++ )
{
COMPONENT* component = aNetlist.GetComponent( ii );
MODULE* module = aBoard->FindModuleByReference( component->GetReference() );
if( module == nullptr )
{
if( !aBoard->GetDesignSettings().Ignore( DRCE_MISSING_FOOTPRINT ) && module == NULL )
{
msg.Printf( _( "Missing footprint %s (%s)" ),
component->GetReference(),
component->GetValue() );
std::shared_ptr<DRC_ITEM> item = DRC_ITEM::Create( DRCE_MISSING_FOOTPRINT );
item->SetErrorMessage( msg );
aDRCList.push_back( item );
}
}
else
{
if( !aBoard->GetDesignSettings().Ignore( DRCE_NET_CONFLICT ) )
{
for( D_PAD* pad : module->Pads() )
{
const COMPONENT_NET& sch_net = component->GetNet( pad->GetName() );
const wxString& pcb_netname = pad->GetNetname();
if( !pcb_netname.IsEmpty() && sch_net.GetPinName().IsEmpty() )
{
msg.Printf( _( "No corresponding pin found in schematic." ) );
std::shared_ptr<DRC_ITEM> item = DRC_ITEM::Create( DRCE_NET_CONFLICT );
item->SetErrorMessage( msg );
item->SetItems( pad );
aDRCList.push_back( item );
}
else if( pcb_netname.IsEmpty() && !sch_net.GetNetName().IsEmpty() )
{
msg.Printf( _( "Pad missing net given by schematic (%s)." ),
sch_net.GetNetName() );
std::shared_ptr<DRC_ITEM> item = DRC_ITEM::Create( DRCE_NET_CONFLICT );
item->SetErrorMessage( msg );
item->SetItems( pad );
aDRCList.push_back( item );
}
else if( pcb_netname != sch_net.GetNetName() )
{
msg.Printf( _( "Pad net (%s) doesn't match net given by schematic (%s)." ),
pcb_netname,
sch_net.GetNetName() );
std::shared_ptr<DRC_ITEM> item = DRC_ITEM::Create( DRCE_NET_CONFLICT );
item->SetErrorMessage( msg );
item->SetItems( pad );
aDRCList.push_back( item );
}
}
for( unsigned jj = 0; jj < component->GetNetCount(); ++jj )
{
const COMPONENT_NET& sch_net = component->GetNet( jj );
if( !module->FindPadByName( sch_net.GetPinName() ) )
{
msg.Printf( _( "No pad found for pin %s in schematic." ),
sch_net.GetPinName() );
std::shared_ptr<DRC_ITEM> item = DRC_ITEM::Create( DRCE_NET_CONFLICT );
item->SetErrorMessage( msg );
item->SetItems( module );
aDRCList.push_back( item );
}
}
}
}
}
if( !aBoard->GetDesignSettings().Ignore( DRCE_EXTRA_FOOTPRINT ) )
{
// Search for component footprints found on board but not in netlist.
for( MODULE* module : aBoard->Modules() )
{
COMPONENT* component = aNetlist.GetComponentByReference( module->GetReference() );
if( component == NULL )
{
std::shared_ptr<DRC_ITEM> item = DRC_ITEM::Create( DRCE_EXTRA_FOOTPRINT );
item->SetItems( module );
aDRCList.push_back( item );
}
}
}
}

View File

@ -1,34 +0,0 @@
/*
* 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
*/
#ifndef FOOTPRINT_TESTER_H
#define FOOTPRINT_TESTER_H
#include <drc/drc.h>
class BOARD;
void TestFootprints( NETLIST& aNetlist, BOARD* aBoard, std::vector<std::shared_ptr<DRC_ITEM> >& aDRCList );
#endif // FOOTPRINT_TESTER_H

View File

@ -64,6 +64,7 @@
#include <tools/pcbnew_picker_tool.h> #include <tools/pcbnew_picker_tool.h>
#include <tools/point_editor.h> #include <tools/point_editor.h>
#include <tools/edit_tool.h> #include <tools/edit_tool.h>
#include <tools/drc_tool.h>
#include <tools/global_edit_tool.h> #include <tools/global_edit_tool.h>
#include <tools/convert_tool.h> #include <tools/convert_tool.h>
#include <tools/drawing_tool.h> #include <tools/drawing_tool.h>
@ -504,6 +505,7 @@ void PCB_EDIT_FRAME::setupTools()
m_toolManager->RegisterTool( new ZONE_FILLER_TOOL ); m_toolManager->RegisterTool( new ZONE_FILLER_TOOL );
m_toolManager->RegisterTool( new AUTOPLACE_TOOL ); m_toolManager->RegisterTool( new AUTOPLACE_TOOL );
m_toolManager->RegisterTool( new DRC ); m_toolManager->RegisterTool( new DRC );
m_toolManager->RegisterTool( new DRC_TOOL );
m_toolManager->RegisterTool( new PCB_VIEWER_TOOLS ); m_toolManager->RegisterTool( new PCB_VIEWER_TOOLS );
m_toolManager->RegisterTool( new CONVERT_TOOL ); m_toolManager->RegisterTool( new CONVERT_TOOL );
m_toolManager->InitTools(); m_toolManager->InitTools();
@ -573,7 +575,7 @@ void PCB_EDIT_FRAME::setupUIConditions()
auto enableBoardSetupCondition = auto enableBoardSetupCondition =
[this] ( const SELECTION& ) [this] ( const SELECTION& )
{ {
if( DRC* tool = m_toolManager->GetTool<DRC>() ) if( DRC_TOOL* tool = m_toolManager->GetTool<DRC_TOOL>() )
return !tool->IsDRCDialogShown(); return !tool->IsDRCDialogShown();
return true; return true;

224
pcbnew/tools/drc_tool.cpp Normal file
View File

@ -0,0 +1,224 @@
/*
* 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 <pcb_edit_frame.h>
#include <bitmaps.h>
#include <tool/tool_manager.h>
#include <tools/pcb_actions.h>
#include <tools/pcb_tool_base.h>
#include <tools/zone_filler_tool.h>
#include <tools/drc_tool.h>
#include <kiface_i.h>
#include <dialog_drc.h>
#include <board_commit.h>
#include <widgets/progress_reporter.h>
#include <drc/drc_engine.h>
#include <drc/drc_results_provider.h>
#include <netlist_reader/pcb_netlist.h>
DRC_TOOL::DRC_TOOL() :
PCB_TOOL_BASE( "pcbnew.DRCTool" ),
m_editFrame( nullptr ),
m_pcb( nullptr ),
m_drcDialog( nullptr )
{
}
DRC_TOOL::~DRC_TOOL()
{
}
void DRC_TOOL::Reset( RESET_REASON aReason )
{
m_editFrame = getEditFrame<PCB_EDIT_FRAME>();
if( m_pcb != m_editFrame->GetBoard() )
{
if( m_drcDialog )
DestroyDRCDialog( wxID_OK );
m_pcb = m_editFrame->GetBoard();
}
}
void DRC_TOOL::ShowDRCDialog( wxWindow* aParent )
{
bool show_dlg_modal = true;
// the dialog needs a parent frame. if it is not specified, this is the PCB editor frame
// specified in DRC_TOOL class.
if( !aParent )
{
// if any parent is specified, the dialog is modal.
// if this is the default PCB editor frame, it is not modal
show_dlg_modal = false;
aParent = m_editFrame;
}
Activate();
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
if( !m_drcDialog )
{
m_drcDialog = new DIALOG_DRC( m_editFrame, aParent );
updatePointers();
if( show_dlg_modal )
m_drcDialog->ShowModal();
else
m_drcDialog->Show( true );
}
else // The dialog is just not visible (because the user has double clicked on an error item)
{
updatePointers();
m_drcDialog->Show( true );
}
}
int DRC_TOOL::ShowDRCDialog( const TOOL_EVENT& aEvent )
{
ShowDRCDialog( nullptr );
return 0;
}
bool DRC_TOOL::IsDRCDialogShown()
{
if( m_drcDialog )
return m_drcDialog->IsShown();
return false;
}
void DRC_TOOL::DestroyDRCDialog( int aReason )
{
if( m_drcDialog )
{
m_drcDialog->Destroy();
m_drcDialog = nullptr;
}
}
void DRC_TOOL::RunTests( WX_PROGRESS_REPORTER* aProgressReporter, bool aTestTracksAgainstZones,
bool aRefillZones, bool aReportAllTrackErrors, bool aTestFootprints )
{
ZONE_FILLER_TOOL* zoneFiller = m_toolMgr->GetTool<ZONE_FILLER_TOOL>();
BOARD_COMMIT commit( m_editFrame );
DRC_ENGINE drcEngine( m_pcb, &m_pcb->GetDesignSettings() );
NETLIST netlist;
if( aRefillZones )
{
aProgressReporter->AdvancePhase( _( "Refilling all zones..." ) );
zoneFiller->FillAllZones( aProgressReporter->GetParent(), aProgressReporter );
}
else
{
aProgressReporter->AdvancePhase( _( "Checking zone fills..." ) );
zoneFiller->CheckAllZones( aProgressReporter->GetParent(), aProgressReporter );
}
drcEngine.InitEngine( m_editFrame->Prj().AbsolutePath( "drc-rules" ) );
drcEngine.SetWorksheet( m_editFrame->GetCanvas()->GetWorksheet() );
if( aTestFootprints && !Kiface().IsSingle() )
{
m_editFrame->FetchNetlistFromSchematic( netlist, PCB_EDIT_FRAME::ANNOTATION_DIALOG );
if( m_drcDialog )
m_drcDialog->Raise();
drcEngine.SetSchematicNetlist( &netlist );
}
drcEngine.SetProgressReporter( aProgressReporter );
drcEngine.SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos )
{
if( aItem->GetErrorCode() == DRCE_MISSING_FOOTPRINT
|| aItem->GetErrorCode() == DRCE_DUPLICATE_FOOTPRINT
|| aItem->GetErrorCode() == DRCE_EXTRA_FOOTPRINT
|| aItem->GetErrorCode() == DRCE_NET_CONFLICT )
{
m_footprints.push_back( aItem );
}
else if( aItem->GetErrorCode() == DRCE_UNCONNECTED_ITEMS )
{
m_unconnected.push_back( aItem );
}
else
{
MARKER_PCB* marker = new MARKER_PCB( aItem, aPos );
commit.Add( marker );
}
} );
drcEngine.RunTests( m_editFrame->GetUserUnits(), aTestTracksAgainstZones,
aReportAllTrackErrors, aTestFootprints );
commit.Push( _( "DRC" ), false );
// update the m_drcDialog listboxes
updatePointers();
aProgressReporter->AdvancePhase( _( "Done." ) );
}
void DRC_TOOL::updatePointers()
{
// update my pointers, m_editFrame is the only unchangeable one
m_pcb = m_editFrame->GetBoard();
m_editFrame->ResolveDRCExclusions();
if( m_drcDialog ) // Use diag list boxes only in DRC_TOOL dialog
{
m_drcDialog->SetMarkersProvider( new BOARD_DRC_ITEMS_PROVIDER( m_pcb ) );
m_drcDialog->SetUnconnectedProvider( new RATSNEST_DRC_ITEMS_PROVIDER( m_editFrame,
&m_unconnected ) );
m_drcDialog->SetFootprintsProvider( new VECTOR_DRC_ITEMS_PROVIDER( m_editFrame,
&m_footprints ) );
}
}
void DRC_TOOL::setTransitions()
{
Go( &DRC_TOOL::ShowDRCDialog, PCB_ACTIONS::runDRC.MakeEvent() );
}

119
pcbnew/tools/drc_tool.h Normal file
View File

@ -0,0 +1,119 @@
/*
* 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
*/
#ifndef DRC_TOOL_H
#define DRC_TOOL_H
#include <board_commit.h>
#include <class_board.h>
#include <class_track.h>
#include <class_marker_pcb.h>
#include <geometry/seg.h>
#include <geometry/shape_poly_set.h>
#include <memory>
#include <vector>
#include <tools/pcb_tool_base.h>
class PCB_EDIT_FRAME;
class DIALOG_DRC;
class DRC_ITEM;
class WX_PROGRESS_REPORTER;
class DRC_TOOL : public PCB_TOOL_BASE
{
friend class DIALOG_DRC;
public:
DRC_TOOL();
~DRC_TOOL();
/// @copydoc TOOL_INTERACTIVE::Reset()
void Reset( RESET_REASON aReason ) override;
private:
PCB_EDIT_FRAME* m_editFrame; // The pcb frame editor which owns the board
BOARD* m_pcb;
DIALOG_DRC* m_drcDialog;
std::vector<std::shared_ptr<DRC_ITEM>> m_unconnected; // list of unconnected pads
std::vector<std::shared_ptr<DRC_ITEM>> m_footprints; // list of footprint warnings
private:
///> Sets up handlers for various events.
void setTransitions() override;
/**
* Update needed pointers from the one pointer which is known not to change.
*/
void updatePointers();
EDA_UNITS userUnits() const { return m_editFrame->GetUserUnits(); }
public:
/**
* Open a dialog and prompts the user, then if a test run button is
* clicked, runs the test(s) and creates the MARKERS. The dialog is only
* created if it is not already in existence.
*
* @param aParent is the parent window for wxWidgets. Usually the PCB editor frame
* but can be another dialog
* if aParent == NULL (default), the parent will be the PCB editor frame
* and the dialog will be not modal (just float on parent
* if aParent is specified, the dialog will be modal.
* The modal mode is mandatory if the dialog is created from another dialog, not
* from the PCB editor frame
*/
void ShowDRCDialog( wxWindow* aParent );
int ShowDRCDialog( const TOOL_EVENT& aEvent );
/**
* Check to see if the DRC_TOOL dialog is currently shown
*
* @return true if the dialog is shown
*/
bool IsDRCDialogShown();
/**
* Deletes this ui dialog box and zeros out its pointer to remember
* the state of the dialog's existence.
*
* @param aReason Indication of which button was clicked to cause the destruction.
* if aReason == wxID_OK, design parameters values which can be entered from the dialog
* will bbe saved in design parameters list
*/
void DestroyDRCDialog( int aReason );
/**
* Run all the tests specified with a previous call to
* SetSettings()
* @param aMessages = a wxTextControl where to display some activity messages. Can be NULL
*/
void RunTests( WX_PROGRESS_REPORTER* aProgressReporter, bool aTestTracksAgainstZones,
bool aRefillZones, bool aReportAllTrackErrors, bool aTestFootprints );
};
#endif // DRC_TOOL_H

View File

@ -194,6 +194,8 @@ void PCB_INSPECTION_TOOL::reportCopperClearance( PCB_LAYER_ID aLayer, BOARD_CONN
if( r ) if( r )
{ {
wxString clearance = StringFromValue( r->GetUnits(), constraint.m_Value.Min(), true ); wxString clearance = StringFromValue( r->GetUnits(), constraint.m_Value.Min(), true );
r->Report( "" );
r->Report( wxString::Format( _( "Clearance: %s." ), clearance ) ); r->Report( wxString::Format( _( "Clearance: %s." ), clearance ) );
} }

View File

@ -30,9 +30,7 @@
#include <widgets/progress_reporter.h> #include <widgets/progress_reporter.h>
#include <wx/event.h> #include <wx/event.h>
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
#include <bitmaps.h>
#include "pcb_actions.h" #include "pcb_actions.h"
#include "selection_tool.h"
#include "zone_filler_tool.h" #include "zone_filler_tool.h"
#include "zone_filler.h" #include "zone_filler.h"
@ -53,7 +51,7 @@ void ZONE_FILLER_TOOL::Reset( RESET_REASON aReason )
} }
void ZONE_FILLER_TOOL::CheckAllZones( wxWindow* aCaller ) void ZONE_FILLER_TOOL::CheckAllZones( wxWindow* aCaller, WX_PROGRESS_REPORTER* aReporter )
{ {
if( !getEditFrame<PCB_EDIT_FRAME>()->m_ZoneFillsDirty ) if( !getEditFrame<PCB_EDIT_FRAME>()->m_ZoneFillsDirty )
return; return;
@ -66,6 +64,10 @@ void ZONE_FILLER_TOOL::CheckAllZones( wxWindow* aCaller )
BOARD_COMMIT commit( this ); BOARD_COMMIT commit( this );
ZONE_FILLER filler( frame()->GetBoard(), &commit ); ZONE_FILLER filler( frame()->GetBoard(), &commit );
if( aReporter )
filler.SetProgressReporter( aReporter );
else
filler.InstallNewProgressReporter( aCaller, _( "Checking Zones" ), 4 ); filler.InstallNewProgressReporter( aCaller, _( "Checking Zones" ), 4 );
if( filler.Fill( toFill, true ) ) if( filler.Fill( toFill, true ) )
@ -89,7 +91,7 @@ void ZONE_FILLER_TOOL::singleShotRefocus( wxIdleEvent& )
} }
void ZONE_FILLER_TOOL::FillAllZones( wxWindow* aCaller ) void ZONE_FILLER_TOOL::FillAllZones( wxWindow* aCaller, WX_PROGRESS_REPORTER* aReporter )
{ {
std::vector<ZONE_CONTAINER*> toFill; std::vector<ZONE_CONTAINER*> toFill;
@ -99,6 +101,10 @@ void ZONE_FILLER_TOOL::FillAllZones( wxWindow* aCaller )
toFill.push_back(zone); toFill.push_back(zone);
ZONE_FILLER filler( board(), &commit ); ZONE_FILLER filler( board(), &commit );
if( aReporter )
filler.SetProgressReporter( aReporter );
else
filler.InstallNewProgressReporter( aCaller, _( "Fill All Zones" ), 4 ); filler.InstallNewProgressReporter( aCaller, _( "Fill All Zones" ), 4 );
if( filler.Fill( toFill ) ) if( filler.Fill( toFill ) )

View File

@ -29,6 +29,8 @@
class PCB_EDIT_FRAME; class PCB_EDIT_FRAME;
class WX_PROGRESS_REPORTER;
/** /**
* ZONE_FILLER_TOOL * ZONE_FILLER_TOOL
@ -44,8 +46,8 @@ public:
/// @copydoc TOOL_INTERACTIVE::Reset() /// @copydoc TOOL_INTERACTIVE::Reset()
void Reset( RESET_REASON aReason ) override; void Reset( RESET_REASON aReason ) override;
void CheckAllZones( wxWindow* aCaller ); void CheckAllZones( wxWindow* aCaller, WX_PROGRESS_REPORTER* aReporter = nullptr );
void FillAllZones( wxWindow* aCaller ); void FillAllZones( wxWindow* aCaller, WX_PROGRESS_REPORTER* aReporter = nullptr );
int ZoneFill( const TOOL_EVENT& aEvent ); int ZoneFill( const TOOL_EVENT& aEvent );
int ZoneFillAll( const TOOL_EVENT& aEvent ); int ZoneFillAll( const TOOL_EVENT& aEvent );

View File

@ -96,7 +96,13 @@ void ZONE_FILLER::InstallNewProgressReporter( wxWindow* aParent, const wxString&
int aNumPhases ) int aNumPhases )
{ {
m_uniqueReporter = std::make_unique<WX_PROGRESS_REPORTER>( aParent, aTitle, aNumPhases ); m_uniqueReporter = std::make_unique<WX_PROGRESS_REPORTER>( aParent, aTitle, aNumPhases );
m_progressReporter = m_uniqueReporter.get(); SetProgressReporter( m_uniqueReporter.get() );
}
void ZONE_FILLER::SetProgressReporter( WX_PROGRESS_REPORTER* aReporter )
{
m_progressReporter = aReporter;
} }
@ -118,6 +124,7 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
m_progressReporter->Report( aCheck ? _( "Checking zone fills..." ) m_progressReporter->Report( aCheck ? _( "Checking zone fills..." )
: _( "Building zone fills..." ) ); : _( "Building zone fills..." ) );
m_progressReporter->SetMaxProgress( aZones.size() ); m_progressReporter->SetMaxProgress( aZones.size() );
m_progressReporter->KeepRefreshing();
} }
// The board outlines is used to clip solid areas inside the board (when outlines are valid) // The board outlines is used to clip solid areas inside the board (when outlines are valid)
@ -125,9 +132,9 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
m_brdOutlinesValid = m_board->GetBoardPolygonOutlines( m_boardOutline ); m_brdOutlinesValid = m_board->GetBoardPolygonOutlines( m_boardOutline );
// Update the bounding box shape caches in the pads to prevent multi-threaded rebuilds // Update the bounding box shape caches in the pads to prevent multi-threaded rebuilds
for( auto module : m_board->Modules() ) for( MODULE* module : m_board->Modules() )
{ {
for( auto pad : module->Pads() ) for( D_PAD* pad : module->Pads() )
{ {
if( pad->IsDirty() ) if( pad->IsDirty() )
pad->BuildEffectiveShapes( UNDEFINED_LAYER ); pad->BuildEffectiveShapes( UNDEFINED_LAYER );
@ -263,8 +270,6 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
} }
// Now remove insulated copper islands and islands outside the board edge // Now remove insulated copper islands and islands outside the board edge
bool outOfDate = false;
for( auto& zone : islandsList ) for( auto& zone : islandsList )
{ {
for( PCB_LAYER_ID layer : zone.m_zone->GetLayerSet().Seq() ) for( PCB_LAYER_ID layer : zone.m_zone->GetLayerSet().Seq() )
@ -322,15 +327,34 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
zone.m_zone->SetFilledPolysList( layer, poly ); zone.m_zone->SetFilledPolysList( layer, poly );
zone.m_zone->CalculateFilledArea(); zone.m_zone->CalculateFilledArea();
if( aCheck && zone.m_zone->GetHashValue( layer ) != poly.GetHash() )
outOfDate = true;
if( m_progressReporter && m_progressReporter->IsCancelled() ) if( m_progressReporter && m_progressReporter->IsCancelled() )
return false; return false;
} }
} }
if( aCheck && outOfDate ) if( aCheck )
{
bool outOfDate = false;
for( ZONE_CONTAINER* zone : aZones )
{
// Keepout zones are not filled
if( zone->GetIsKeepout() )
continue;
for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
{
MD5_HASH was = zone->GetHashValue( layer );
zone->CacheTriangulation( layer );
zone->BuildHashValue( layer );
MD5_HASH is = zone->GetHashValue( layer );
if( is != was )
outOfDate = true;
}
}
if( outOfDate )
{ {
PROGRESS_REPORTER_HIDER raii( m_progressReporter ); PROGRESS_REPORTER_HIDER raii( m_progressReporter );
KIDIALOG dlg( m_progressReporter->GetParent(), KIDIALOG dlg( m_progressReporter->GetParent(),
@ -342,6 +366,7 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
if( dlg.ShowModal() == wxID_CANCEL ) if( dlg.ShowModal() == wxID_CANCEL )
return false; return false;
} }
}
if( m_progressReporter ) if( m_progressReporter )
{ {
@ -406,7 +431,6 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
return false; return false;
m_progressReporter->AdvancePhase(); m_progressReporter->AdvancePhase();
m_progressReporter->Report( _( "Committing changes..." ) );
m_progressReporter->KeepRefreshing(); m_progressReporter->KeepRefreshing();
} }

View File

@ -42,6 +42,7 @@ public:
ZONE_FILLER( BOARD* aBoard, COMMIT* aCommit ); ZONE_FILLER( BOARD* aBoard, COMMIT* aCommit );
~ZONE_FILLER(); ~ZONE_FILLER();
void SetProgressReporter( WX_PROGRESS_REPORTER* aReporter );
void InstallNewProgressReporter( wxWindow* aParent, const wxString& aTitle, int aNumPhases ); void InstallNewProgressReporter( wxWindow* aParent, const wxString& aTitle, int aNumPhases );
bool Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck = false ); bool Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck = false );
@ -108,11 +109,11 @@ private:
SHAPE_POLY_SET& aRawPolys ); SHAPE_POLY_SET& aRawPolys );
BOARD* m_board; BOARD* m_board;
SHAPE_POLY_SET m_boardOutline; // The board outlines, if exists SHAPE_POLY_SET m_boardOutline; // the board outlines, if exists
bool m_brdOutlinesValid; // true if m_boardOutline can be calculated bool m_brdOutlinesValid; // true if m_boardOutline is well-formed
// false if not (not closed outlines for instance)
COMMIT* m_commit; COMMIT* m_commit;
WX_PROGRESS_REPORTER* m_progressReporter; WX_PROGRESS_REPORTER* m_progressReporter;
std::unique_ptr<WX_PROGRESS_REPORTER> m_uniqueReporter; std::unique_ptr<WX_PROGRESS_REPORTER> m_uniqueReporter;
int m_maxError; int m_maxError;

View File

@ -236,6 +236,12 @@ int main( int argc, char *argv[] )
drcEngine.SetLogReporter( new CONSOLE_MSG_REPORTER ( &consoleLog ) ); drcEngine.SetLogReporter( new CONSOLE_MSG_REPORTER ( &consoleLog ) );
drcEngine.SetProgressReporter( new CONSOLE_PROGRESS_REPORTER ( &consoleLog ) ); drcEngine.SetProgressReporter( new CONSOLE_PROGRESS_REPORTER ( &consoleLog ) );
drcEngine.SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos )
{
// fixme
} );
wxString rulesFilepath; wxString rulesFilepath;
if( argc > 2 ) if( argc > 2 )
@ -245,10 +251,7 @@ int main( int argc, char *argv[] )
drcEngine.InitEngine( rulesFilepath ); drcEngine.InitEngine( rulesFilepath );
drcEngine.RunTests( drcEngine.RunTests();
[&]( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos )
{
} );
return 0; return 0;
} }

View File

@ -50,7 +50,7 @@
namespace test { namespace test {
class DRC_TEST_PROVIDER_SILK_TO_PAD : public DRC_TEST_PROVIDER class DRC_TEST_PROVIDER_SILK_TO_PAD : public ::DRC_TEST_PROVIDER
{ {
public: public:
DRC_TEST_PROVIDER_SILK_TO_PAD () DRC_TEST_PROVIDER_SILK_TO_PAD ()
@ -94,8 +94,8 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_PAD::Run()
m_largestClearance = worstClearanceConstraint.m_Value.Min(); m_largestClearance = worstClearanceConstraint.m_Value.Min();
} }
ReportAux( "Worst clearance : %d nm", m_largestClearance ); reportAux( "Worst clearance : %d nm", m_largestClearance );
ReportStage( ("Testing pads vs silkscreen clearance"), 0, 2 ); reportStage(( "Pad to silkscreen clearances..." ));
std::vector<DRAWSEGMENT*> boardOutline; std::vector<DRAWSEGMENT*> boardOutline;
std::vector<BOARD_ITEM*> boardItems; std::vector<BOARD_ITEM*> boardItems;
@ -116,7 +116,7 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_PAD::Run()
forEachGeometryItem( {}, LSET::AllTechMask() | LSET::AllCuMask(), queryBoardGeometryItems ); forEachGeometryItem( {}, LSET::AllTechMask() | LSET::AllCuMask(), queryBoardGeometryItems );
drc_dbg(2,"outline: %d items, board: %d items\n", boardOutline.size(), boardItems.size() ); drc_dbg( 2, "outline: %d items, board: %d items\n", boardOutline.size(), boardItems.size() );
for( auto outlineItem : boardOutline ) for( auto outlineItem : boardOutline )
{ {
@ -129,13 +129,14 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_PAD::Run()
auto shape = boardItem->GetEffectiveShape(); auto shape = boardItem->GetEffectiveShape();
test::DRC_RULE* rule = m_drcEngine->EvalRulesForItems( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE, outlineItem, boardItem ); auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE,
int minClearance = rule->GetConstraint().GetValue().Min(); outlineItem, boardItem );
int minClearance = constraint.GetValue().Min();
int actual; int actual;
if( refShape->Collide( shape.get(), minClearance, &actual ) ) if( refShape->Collide( shape.get(), minClearance, &actual ) )
{ {
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_COPPER_EDGE_CLEARANCE ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_COPPER_EDGE_CLEARANCE );
wxString msg; wxString msg;
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
@ -147,7 +148,7 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_PAD::Run()
drcItem->SetItems( outlineItem, boardItem ); drcItem->SetItems( outlineItem, boardItem );
drcItem->SetViolatingRule( rule ); drcItem->SetViolatingRule( rule );
ReportViolation( drcItem, refShape->Centre() ); reportViolation( drcItem, refShape->Centre());
} }
} }
} }
@ -156,13 +157,13 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_PAD::Run()
} }
std::set<DRC_CONSTRAINT_TYPE_T> test::DRC_TEST_PROVIDER_EDGE_CLEARANCE::GetMatchingConstraintIds() const std::set<DRC_CONSTRAINT_TYPE_T> test::DRC_TEST_PROVIDER_SILK_TO_PAD::GetConstraintTypes() const
{ {
return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE }; return { DRC_CONSTRAINT_TYPE_CLEARANCE };
} }
namespace detail namespace detail
{ {
static DRC_REGISTER_TEST_PROVIDER<test::DRC_TEST_PROVIDER_EDGE_CLEARANCE> dummy; static DRC_REGISTER_TEST_PROVIDER<test::DRC_TEST_PROVIDER_SILK_TO_PAD> dummy;
} }

View File

@ -25,11 +25,11 @@
#include <pcbnew_utils/board_construction_utils.h> #include <pcbnew_utils/board_construction_utils.h>
#include <pcbnew_utils/board_file_utils.h> #include <pcbnew_utils/board_file_utils.h>
#include <class_board.h>
#include <class_module.h> #include <class_module.h>
#include <drc/drc.h> #include <class_marker_pcb.h>
#include <drc/drc_engine.h>
#include <drc/drc_item.h> #include <drc/drc_item.h>
#include <drc/drc_courtyard_tester.h>
#include <widgets/ui_common.h> #include <widgets/ui_common.h>
#include "../board_test_utils.h" #include "../board_test_utils.h"
@ -294,13 +294,21 @@ void DoCourtyardInvalidTest( const COURTYARD_INVALID_CASE& aCase,
// list of markers to collect // list of markers to collect
std::vector<std::unique_ptr<MARKER_PCB>> markers; std::vector<std::unique_ptr<MARKER_PCB>> markers;
DRC_COURTYARD_TESTER drc_overlap( DRC_ENGINE drcEngine( board.get(), &board->GetDesignSettings() );
[&]( MARKER_PCB* aMarker )
drcEngine.InitEngine( wxFileName() );
drcEngine.SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos )
{ {
markers.push_back( std::unique_ptr<MARKER_PCB>( aMarker ) ); if( aItem->GetErrorCode() == DRCE_OVERLAPPING_FOOTPRINTS
|| aItem->GetErrorCode() == DRCE_MISSING_COURTYARD )
{
markers.push_back( std::make_unique<MARKER_PCB>( aItem, aPos ) );
}
} ); } );
drc_overlap.RunDRC( EDA_UNITS::MILLIMETRES, *board ); drcEngine.RunTests();
CheckInvalidsMatchExpected( *board, markers, aCase.m_exp_errors ); CheckInvalidsMatchExpected( *board, markers, aCase.m_exp_errors );
} }

View File

@ -25,11 +25,11 @@
#include <pcbnew_utils/board_construction_utils.h> #include <pcbnew_utils/board_construction_utils.h>
#include <pcbnew_utils/board_file_utils.h> #include <pcbnew_utils/board_file_utils.h>
#include <class_board.h>
#include <class_module.h> #include <class_module.h>
#include <drc/drc.h> #include <class_marker_pcb.h>
#include <drc/drc_item.h> #include <drc/drc_item.h>
#include <drc/drc_courtyard_tester.h> #include <drc/drc_engine.h>
#include <widgets/ui_common.h> #include <widgets/ui_common.h>
#include "../board_test_utils.h" #include "../board_test_utils.h"
@ -463,13 +463,21 @@ static void DoCourtyardOverlapTest( const COURTYARD_OVERLAP_TEST_CASE& aCase,
// list of markers to collect // list of markers to collect
std::vector<std::unique_ptr<MARKER_PCB>> markers; std::vector<std::unique_ptr<MARKER_PCB>> markers;
DRC_COURTYARD_TESTER drc_overlap( DRC_ENGINE drcEngine( board.get(), &board->GetDesignSettings() );
[&]( MARKER_PCB* aMarker )
drcEngine.InitEngine( wxFileName() );
drcEngine.SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos )
{ {
markers.push_back( std::unique_ptr<MARKER_PCB>( aMarker ) ); if( aItem->GetErrorCode() == DRCE_OVERLAPPING_FOOTPRINTS
|| aItem->GetErrorCode() == DRCE_MISSING_COURTYARD )
{
markers.push_back( std::make_unique<MARKER_PCB>( aItem, aPos ) );
}
} ); } );
drc_overlap.RunDRC( EDA_UNITS::MILLIMETRES, *board ); drcEngine.RunTests();
CheckCollisionsMatchExpected( *board, markers, aCase.m_collisions ); CheckCollisionsMatchExpected( *board, markers, aCase.m_collisions );
} }

View File

@ -29,8 +29,6 @@ add_executable( qa_pcbnew_tools
# The main entry point # The main entry point
pcbnew_tools.cpp pcbnew_tools.cpp
tools/drc_tool/drc_tool.cpp
tools/pcb_parser/pcb_parser_tool.cpp tools/pcb_parser/pcb_parser_tool.cpp
tools/polygon_generator/polygon_generator.cpp tools/polygon_generator/polygon_generator.cpp

View File

@ -1,332 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018-2020 KiCad Developers, see CHANGELOG.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 <string>
#include <common.h>
#include <profile.h>
#include <wx/cmdline.h>
#include <pcbnew_utils/board_file_utils.h>
#include <widgets/ui_common.h>
#include <pcbnew/drc/drc.h>
#include <drc/drc_courtyard_tester.h>
#include <qa_utils/utility_registry.h>
using DRC_DURATION = std::chrono::microseconds;
/**
* DRC runner: provides a simple framework to run some DRC checks on #BOARDS.
* The DRC_RUNNER can be set up as needed to instantiate a #DRC_TEST_PROVIDER to
* perform the desired DRC on the #BOARD and provide some basic information
* about what happened.
*/
class DRC_RUNNER
{
public:
/**
* How the DRC runner behaves (e.g. what is printed and how)
*/
struct EXECUTION_CONTEXT
{
bool m_verbose;
bool m_print_times;
bool m_print_markers;
};
DRC_RUNNER( const EXECUTION_CONTEXT& aExecCtx ) : m_exec_context( aExecCtx )
{
}
virtual ~DRC_RUNNER()
{
}
void Execute( BOARD& aBoard )
{
if( m_exec_context.m_verbose )
std::cout << "Running DRC check: " << getRunnerIntro() << std::endl;
setDesignSettings( aBoard.GetDesignSettings() );
std::vector<std::unique_ptr<MARKER_PCB>> markers;
auto marker_handler = [&]( MARKER_PCB* aMarker )
{
markers.push_back( std::unique_ptr<MARKER_PCB>( aMarker ) );
};
std::unique_ptr<LEGACY_DRC_TEST_PROVIDER> drc_prov = createDrcProvider( aBoard, marker_handler );
DRC_DURATION duration;
{
SCOPED_PROF_COUNTER<DRC_DURATION> timer( duration );
drc_prov->RunDRC( EDA_UNITS::MILLIMETRES, aBoard );
}
// report results
if( m_exec_context.m_print_times )
reportDuration( duration );
if( m_exec_context.m_print_markers )
reportMarkers( aBoard, markers );
}
private:
/**
* Get the introduction text for this DRC runner
*/
virtual std::string getRunnerIntro() const = 0;
/**
* Set suitable design settings for this DRC runner
* @param aSettings is a reference to the design settings object of the board under test
*/
virtual void setDesignSettings( BOARD_DESIGN_SETTINGS& aSettings ) const = 0;
virtual std::unique_ptr<LEGACY_DRC_TEST_PROVIDER> createDrcProvider(
BOARD& aBoard, LEGACY_DRC_TEST_PROVIDER::MARKER_HANDLER aHandler ) = 0;
void reportDuration( const DRC_DURATION& aDuration ) const
{
std::cout << "Took: " << aDuration.count() << "us" << std::endl;
}
void reportMarkers( BOARD& aBoard,
const std::vector<std::unique_ptr<MARKER_PCB>>& aMarkers ) const
{
std::map<KIID, EDA_ITEM*> itemMap;
aBoard.FillItemMap( itemMap );
std::cout << "DRC markers: " << aMarkers.size() << std::endl;
int index = 0;
for( const auto& m : aMarkers )
{
std::cout << index++ << ": " ;
std::cout << m->GetRCItem()->ShowReport( EDA_UNITS::MILLIMETRES, itemMap );
}
if( index )
std::cout << std::endl;
}
const EXECUTION_CONTEXT m_exec_context;
};
/**
* DRC runner to run only DRC courtyard-overlap checks
*/
class DRC_COURTYARD_OVERLAP_RUNNER : public DRC_RUNNER
{
public:
DRC_COURTYARD_OVERLAP_RUNNER( const EXECUTION_CONTEXT& aCtx ) : DRC_RUNNER( aCtx )
{
}
virtual ~DRC_COURTYARD_OVERLAP_RUNNER()
{
}
private:
std::string getRunnerIntro() const override
{
return "Courtyard overlap";
}
void setDesignSettings( BOARD_DESIGN_SETTINGS& aSettings ) const override
{
aSettings.m_DRCSeverities[ DRCE_MISSING_COURTYARD ] = RPT_SEVERITY_IGNORE;
aSettings.m_DRCSeverities[ DRCE_OVERLAPPING_FOOTPRINTS ] = RPT_SEVERITY_ERROR;
}
std::unique_ptr<LEGACY_DRC_TEST_PROVIDER> createDrcProvider(
BOARD& aBoard, LEGACY_DRC_TEST_PROVIDER::MARKER_HANDLER aHandler ) override
{
return std::make_unique<DRC_COURTYARD_TESTER>( aHandler );
}
};
/**
* DRC runner to run only DRC courtyard-missing checks
*/
class DRC_COURTYARD_MISSING_RUNNER : public DRC_RUNNER
{
public:
DRC_COURTYARD_MISSING_RUNNER( const EXECUTION_CONTEXT& aCtx ) : DRC_RUNNER( aCtx )
{
}
virtual ~DRC_COURTYARD_MISSING_RUNNER()
{
}
private:
std::string getRunnerIntro() const override
{
return "Courtyard missing";
}
void setDesignSettings( BOARD_DESIGN_SETTINGS& aSettings ) const override
{
aSettings.m_DRCSeverities[ DRCE_MISSING_COURTYARD ] = RPT_SEVERITY_ERROR;
aSettings.m_DRCSeverities[ DRCE_OVERLAPPING_FOOTPRINTS ] = RPT_SEVERITY_IGNORE;
}
std::unique_ptr<LEGACY_DRC_TEST_PROVIDER> createDrcProvider(
BOARD& aBoard, LEGACY_DRC_TEST_PROVIDER::MARKER_HANDLER aHandler ) override
{
return std::make_unique<DRC_COURTYARD_TESTER>( aHandler );
}
};
static const wxCmdLineEntryDesc g_cmdLineDesc[] = {
{
wxCMD_LINE_SWITCH,
"h",
"help",
_( "displays help on the command line parameters" ).mb_str(),
wxCMD_LINE_VAL_NONE,
wxCMD_LINE_OPTION_HELP,
},
{
wxCMD_LINE_SWITCH,
"v",
"verbose",
_( "print parsing information" ).mb_str(),
},
{
wxCMD_LINE_SWITCH,
"t",
"timings",
_( "print DRC timings" ).mb_str(),
},
{
wxCMD_LINE_SWITCH,
"m",
"print-markers",
_( "print DRC marker information" ).mb_str(),
},
{
wxCMD_LINE_SWITCH,
"A",
"all-checks",
_( "perform all available DRC checks" ).mb_str(),
},
{
wxCMD_LINE_SWITCH,
"C",
"courtyard-overlap",
_( "perform courtyard-overlap (and malformation) checking" ).mb_str(),
},
{
wxCMD_LINE_SWITCH,
"c",
"courtyard-missing",
_( "perform courtyard-missing checking" ).mb_str(),
},
{
wxCMD_LINE_PARAM,
nullptr,
nullptr,
_( "input file" ).mb_str(),
wxCMD_LINE_VAL_STRING,
wxCMD_LINE_PARAM_OPTIONAL,
},
{ wxCMD_LINE_NONE }
};
/**
* Tool=specific return codes
*/
enum PARSER_RET_CODES
{
PARSE_FAILED = KI_TEST::RET_CODES::TOOL_SPECIFIC,
};
int drc_main_func( int argc, char** argv )
{
#ifdef __AFL_COMPILER
__AFL_INIT();
#endif
wxMessageOutput::Set( new wxMessageOutputStderr );
wxCmdLineParser cl_parser( argc, argv );
cl_parser.SetDesc( g_cmdLineDesc );
cl_parser.AddUsageText(
_( "This program runs DRC tools on given PCB files. "
"This can be used for debugging, fuzz testing or development, etc." ) );
int cmd_parsed_ok = cl_parser.Parse();
if( cmd_parsed_ok != 0 )
{
// Help and invalid input both stop here
return ( cmd_parsed_ok == -1 ) ? KI_TEST::RET_CODES::OK : KI_TEST::RET_CODES::BAD_CMDLINE;
}
const bool verbose = cl_parser.Found( "verbose" );
std::string filename;
if( cl_parser.GetParamCount() )
filename = cl_parser.GetParam( 0 ).ToStdString();
std::unique_ptr<BOARD> board = KI_TEST::ReadBoardFromFileOrStream( filename );
if( !board )
return PARSER_RET_CODES::PARSE_FAILED;
DRC_RUNNER::EXECUTION_CONTEXT exec_context{
verbose,
cl_parser.Found( "timings" ),
cl_parser.Found( "print-markers" ),
};
const bool all = cl_parser.Found( "all-checks" );
// Run the DRC on the board
if( all || cl_parser.Found( "courtyard-overlap" ) )
{
DRC_COURTYARD_OVERLAP_RUNNER runner( exec_context );
runner.Execute( *board );
}
if( all || cl_parser.Found( "courtyard-missing" ) )
{
DRC_COURTYARD_MISSING_RUNNER runner( exec_context );
runner.Execute( *board );
}
return KI_TEST::RET_CODES::OK;
}
static bool registered = UTILITY_REGISTRY::Register(
{ "drc", "Run selected DRC function on a PCB", drc_main_func } );