From 514da2f8865d645ac9e12726b08952a7e1682f3b Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Mon, 14 Sep 2020 18:54:14 +0100 Subject: [PATCH] Move DRC dialog to new DRC engine. --- common/widgets/progress_reporter.cpp | 15 +- include/widgets/progress_reporter.h | 121 +- pcbnew/CMakeLists.txt | 8 +- pcbnew/class_zone.cpp | 14 +- pcbnew/class_zone.h | 2 +- .../dialog_cleanup_tracks_and_vias.cpp | 1 - pcbnew/dialogs/dialog_drc.cpp | 83 +- pcbnew/dialogs/dialog_drc.h | 5 +- pcbnew/dialogs/dialog_netlist.cpp | 36 - pcbnew/dialogs/dialog_netlist.h | 2 - pcbnew/dialogs/dialog_netlist_base.cpp | 11 +- pcbnew/dialogs/dialog_netlist_base.fbp | 74 - pcbnew/dialogs/dialog_netlist_base.h | 9 +- pcbnew/dialogs/dialog_plot.cpp | 4 +- pcbnew/drc/drc.cpp | 1228 +---------------- pcbnew/drc/drc.h | 227 --- pcbnew/drc/drc_clearance_test_functions.cpp | 546 -------- pcbnew/drc/drc_courtyard_tester.cpp | 189 --- pcbnew/drc/drc_courtyard_tester.h | 43 - pcbnew/drc/drc_drilled_hole_tester.cpp | 307 ----- pcbnew/drc/drc_drilled_hole_tester.h | 69 - pcbnew/drc/drc_engine.cpp | 213 +-- pcbnew/drc/drc_engine.h | 61 +- pcbnew/drc/drc_item.h | 44 + pcbnew/drc/drc_keepout_tester.cpp | 328 ----- pcbnew/drc/drc_keepout_tester.h | 61 - pcbnew/drc/drc_results_provider.h | 49 +- pcbnew/drc/drc_test_provider.cpp | 29 +- pcbnew/drc/drc_test_provider.h | 18 +- pcbnew/drc/drc_test_provider_annulus.cpp | 16 +- pcbnew/drc/drc_test_provider_connectivity.cpp | 20 +- .../drc_test_provider_copper_clearance.cpp | 73 +- .../drc_test_provider_courtyard_clearance.cpp | 18 +- pcbnew/drc/drc_test_provider_disallow.cpp | 20 +- .../drc/drc_test_provider_edge_clearance.cpp | 21 +- .../drc/drc_test_provider_hole_clearance.cpp | 25 +- pcbnew/drc/drc_test_provider_hole_size.cpp | 16 +- pcbnew/drc/drc_test_provider_lvs.cpp | 70 +- pcbnew/drc/drc_test_provider_misc.cpp | 22 +- pcbnew/drc/drc_test_provider_track_width.cpp | 20 +- pcbnew/drc/drc_test_provider_via_diameter.cpp | 16 +- pcbnew/drc/drc_textvar_tester.cpp | 120 -- pcbnew/drc/drc_textvar_tester.h | 49 - pcbnew/drc/footprint_tester.cpp | 149 -- pcbnew/drc/footprint_tester.h | 34 - pcbnew/pcb_edit_frame.cpp | 4 +- pcbnew/tools/drc_tool.cpp | 224 +++ pcbnew/tools/drc_tool.h | 119 ++ pcbnew/tools/pcb_inspection_tool.cpp | 2 + pcbnew/tools/zone_filler_tool.cpp | 18 +- pcbnew/tools/zone_filler_tool.h | 6 +- pcbnew/zone_filler.cpp | 60 +- pcbnew/zone_filler.h | 13 +- qa/drc_proto/drc_proto_test.cpp | 11 +- .../drc_test_provider_silk_to_pad.cpp | 25 +- qa/pcbnew/drc/test_drc_courtyard_invalid.cpp | 22 +- qa/pcbnew/drc/test_drc_courtyard_overlap.cpp | 22 +- qa/pcbnew_tools/CMakeLists.txt | 2 - qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp | 332 ----- 59 files changed, 1060 insertions(+), 4286 deletions(-) delete mode 100644 pcbnew/drc/drc_clearance_test_functions.cpp delete mode 100644 pcbnew/drc/drc_courtyard_tester.cpp delete mode 100644 pcbnew/drc/drc_courtyard_tester.h delete mode 100644 pcbnew/drc/drc_drilled_hole_tester.cpp delete mode 100644 pcbnew/drc/drc_drilled_hole_tester.h delete mode 100644 pcbnew/drc/drc_keepout_tester.cpp delete mode 100644 pcbnew/drc/drc_keepout_tester.h delete mode 100644 pcbnew/drc/drc_textvar_tester.cpp delete mode 100644 pcbnew/drc/drc_textvar_tester.h delete mode 100644 pcbnew/drc/footprint_tester.cpp delete mode 100644 pcbnew/drc/footprint_tester.h create mode 100644 pcbnew/tools/drc_tool.cpp create mode 100644 pcbnew/tools/drc_tool.h delete mode 100644 qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp diff --git a/common/widgets/progress_reporter.cpp b/common/widgets/progress_reporter.cpp index aa937db019..08f42e7027 100644 --- a/common/widgets/progress_reporter.cpp +++ b/common/widgets/progress_reporter.cpp @@ -43,13 +43,20 @@ void PROGRESS_REPORTER::BeginPhase( int aPhase ) } -void PROGRESS_REPORTER::AdvancePhase( ) +void PROGRESS_REPORTER::AdvancePhase() { m_phase.fetch_add( 1 ); m_progress.store( 0 ); } +void PROGRESS_REPORTER::AdvancePhase( const wxString& aMessage ) +{ + AdvancePhase(); + Report( aMessage ); +} + + void PROGRESS_REPORTER::Report( const wxString& aMessage ) { std::lock_guard 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 { double current = ( 1.0 / (double) m_numPhases ) * diff --git a/include/widgets/progress_reporter.h b/include/widgets/progress_reporter.h index e304485b02..f29a19a384 100644 --- a/include/widgets/progress_reporter.h +++ b/include/widgets/progress_reporter.h @@ -42,79 +42,86 @@ */ class PROGRESS_REPORTER { - public: +public: - PROGRESS_REPORTER( int aNumPhases ); - PROGRESS_REPORTER( const PROGRESS_REPORTER& ) = delete; + PROGRESS_REPORTER( int aNumPhases ); + PROGRESS_REPORTER( const PROGRESS_REPORTER& ) = delete; - virtual ~PROGRESS_REPORTER() - { - } + virtual ~PROGRESS_REPORTER() + { + } - /** - * sets the number of phases - */ - void SetNumPhases( int aNumPhases ); + /** + * sets the number of phases + */ + void SetNumPhases( int aNumPhases ); + void AddPhases( int aNumPhases ); - /** - * initialize the aPhase virtual zone of the dialog progress bar - */ - void BeginPhase( int aPhase ); + /** + * initialize the aPhase virtual zone of the dialog progress bar + */ + virtual void BeginPhase( int aPhase ); - /** - * Uses the next vailable virtual zone of the dialog progress bar - */ - void AdvancePhase(); + /** + * Uses the next vailable virtual zone of the dialog progress bar + */ + virtual void AdvancePhase(); - /** - * Display aMessage in the progress bar dialog - */ - void Report( const wxString& aMessage ); + /** + * Uses the next vailable virtual zone of the dialog progress bar and updates + * the message. + */ + virtual void AdvancePhase( const wxString& aMessage ); - /** - * Set the progress value to aProgress (0..1) - */ - virtual void SetCurrentProgress( double aProgress ); + /** + * Display aMessage in the progress bar dialog + */ + virtual void Report( const wxString& aMessage ); - /** - * Fix the value thar gives the 100 precent progress bar length - * (inside the current virtual zone) - */ - void SetMaxProgress( int aMaxProgress ); + /** + * Set the progress value to aProgress (0..1) + */ + virtual void SetCurrentProgress( double aProgress ); - /** - * Increment the progress bar length (inside the current virtual zone) - */ - void AdvanceProgress(); + /** + * Fix the value thar gives the 100 precent progress bar length + * (inside the current virtual zone) + */ + void SetMaxProgress( int aMaxProgress ); - /** - * Update the UI dialog. *MUST* only be called from the main thread. - * Returns false if the user clicked Cancel. - */ - bool KeepRefreshing( bool aWait = false ); + /** + * Increment the progress bar length (inside the current virtual zone) + */ + void AdvanceProgress(); - /** change the title displayed on the window caption - * *MUST* only be called from the main thread. - * Has meaning only for some reporters. - * Do nothing for others - */ - virtual void SetTitle( const wxString& aTitle ) {} + /** + * Update the UI dialog. *MUST* only be called from the main thread. + * Returns false if the user clicked Cancel. + */ + bool KeepRefreshing( bool aWait = false ); - bool IsCancelled() const { return m_cancelled.load(); } + /** change the title displayed on the window caption + * *MUST* only be called from the main thread. + * Has meaning only for some reporters. + * Do nothing for others + */ + virtual void SetTitle( const wxString& aTitle ) {} - protected: + bool IsCancelled() const { return m_cancelled.load(); } - int currentProgress() const; +protected: - virtual bool updateUI() = 0; + int currentProgress() const; - wxString m_rptMessage; - mutable std::mutex m_mutex; - std::atomic_int m_phase; - std::atomic_int m_numPhases; - std::atomic_int m_progress; - std::atomic_int m_maxProgress; - std::atomic_bool m_cancelled; + virtual bool updateUI() = 0; + + wxString m_rptMessage; + mutable std::mutex m_mutex; + std::atomic_int m_phase; + std::atomic_int m_numPhases; + std::atomic_int m_progress; + std::atomic_int m_maxProgress; + std::atomic_bool m_cancelled; }; /** diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 2b8c94ff7d..24c15da175 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -232,13 +232,7 @@ set( PCBNEW_MICROWAVE_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_clearance_test_functions.cpp drc/drc_engine.cpp drc/drc_rule_parser.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_hole_clearance.cpp drc/drc_test_provider_hole_size.cpp + drc/drc_test_provider_lvs.cpp drc/drc_test_provider_misc.cpp drc/drc_test_provider_track_width.cpp drc/drc_test_provider_via_diameter.cpp @@ -333,6 +328,7 @@ set( PCBNEW_CLASS_SRCS tools/convert_tool.cpp tools/drawing_tool.cpp + tools/drc_tool.cpp tools/edit_tool.cpp tools/global_edit_tool.cpp tools/footprint_editor_tools.cpp diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp index 3f2119a4da..1871797d11 100644 --- a/pcbnew/class_zone.cpp +++ b/pcbnew/class_zone.cpp @@ -1165,10 +1165,18 @@ void ZONE_CONTAINER::SwapData( BOARD_ITEM* aImage ) } -void ZONE_CONTAINER::CacheTriangulation() +void ZONE_CONTAINER::CacheTriangulation( PCB_LAYER_ID aLayer ) { - for( std::pair& pair : m_FilledPolysList ) - pair.second.CacheTriangulation(); + if( aLayer == UNDEFINED_LAYER ) + { + for( std::pair& pair : m_FilledPolysList ) + pair.second.CacheTriangulation(); + } + else + { + if( m_FilledPolysList.count( aLayer ) ) + m_FilledPolysList[ aLayer ].CacheTriangulation(); + } } diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index 8afbade1c6..76515b7d5f 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -620,7 +620,7 @@ public: /** (re)create a list of triangles that "fill" the solid areas. * used for instance to draw these solid areas on opengl */ - void CacheTriangulation(); + void CacheTriangulation( PCB_LAYER_ID aLayer = UNDEFINED_LAYER ); /** * Function SetFilledPolysList diff --git a/pcbnew/dialogs/dialog_cleanup_tracks_and_vias.cpp b/pcbnew/dialogs/dialog_cleanup_tracks_and_vias.cpp index e5a3236a8e..9233b2fed3 100644 --- a/pcbnew/dialogs/dialog_cleanup_tracks_and_vias.cpp +++ b/pcbnew/dialogs/dialog_cleanup_tracks_and_vias.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include DIALOG_CLEANUP_TRACKS_AND_VIAS::DIALOG_CLEANUP_TRACKS_AND_VIAS( PCB_EDIT_FRAME* aParentFrame ) : diff --git a/pcbnew/dialogs/dialog_drc.cpp b/pcbnew/dialogs/dialog_drc.cpp index 8915454ec1..d991e1527c 100644 --- a/pcbnew/dialogs/dialog_drc.cpp +++ b/pcbnew/dialogs/dialog_drc.cpp @@ -23,9 +23,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#include #include -#include #include #include #include @@ -40,10 +38,41 @@ #include #include #include +#include +#include +#include -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 ), + m_drcRun( false ), + m_footprintTestsRun( false ), m_trackMinWidth( aEditorFrame, m_MinWidthLabel, m_MinWidthCtrl, m_MinWidthUnits, true ), m_viaMinSize( aEditorFrame, m_ViaMinLabel, m_ViaMinCtrl, m_ViaMinUnits, 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 - m_tester = aTester; m_brdEditor = aEditorFrame; m_currentBoard = m_brdEditor->GetBoard(); @@ -105,13 +133,14 @@ void DIALOG_DRC::OnActivateDlg( wxActivateEvent& aEvent ) { if( m_currentBoard != m_brdEditor->GetBoard() ) { - // If m_currentBoard is not the current parent board, - // (for instance because a new board was loaded), - // close the dialog, because many pointers are now invalid - // in lists + // If m_currentBoard is not the current board, (for instance because a new board + // was loaded), close the dialog, because many pointers are now invalid in lists SetReturnCode( wxID_CANCEL ); Close(); - m_tester->DestroyDRCDialog( wxID_CANCEL ); + + DRC_TOOL* drcTool = m_brdEditor->GetToolManager()->GetTool(); + drcTool->DestroyDRCDialog( wxID_CANCEL ); + return; } @@ -183,22 +212,35 @@ void DIALOG_DRC::syncCheckboxes() void DIALOG_DRC::OnRunDRCClick( wxCommandEvent& aEvent ) { + DRC_TOOL* drcTool = m_parentFrame->GetToolManager()->GetTool(); + 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(); - m_tester->m_testTracksAgainstZones = m_cbReportTracksToZonesErrors->GetValue(); - m_tester->m_refillZones = m_cbRefillZones->GetValue(); - m_tester->m_reportAllTrackErrors = m_cbReportAllTrackErrors->GetValue(); - m_tester->m_testFootprints = m_cbTestFootprints->GetValue(); + + m_drcRun = false; + m_footprintTestsRun = false; m_brdEditor->RecordDRCExclusions(); deleteAllMarkers( true ); wxBeginBusyCursor(); - wxWindowDisabler disabler; + wxWindowDisabler disabler( &progressReporter ); + Raise(); // run all the tests, with no UI at this time. m_Messages->Clear(); - wxSafeYield(); // Allows time slice to refresh the Messages - m_tester->RunTests( m_Messages ); + wxYield(); // Allows time slice to refresh the 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 @@ -206,7 +248,7 @@ void DIALOG_DRC::OnRunDRCClick( wxCommandEvent& aEvent ) refreshBoardEditor(); - wxSafeYield(); + wxYield(); Raise(); 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. // Leave the DRC caller destroy (or not) the dialog - m_tester->DestroyDRCDialog( wxID_CANCEL ); + DRC_TOOL* drcTool = m_brdEditor->GetToolManager()->GetTool(); + drcTool->DestroyDRCDialog( wxID_CANCEL ); } @@ -689,7 +732,7 @@ void DIALOG_DRC::updateDisplayedCounts() // First the tab headers: // - if( m_tester->m_drcRun ) + if( m_drcRun ) { msg.sprintf( m_markersTitleTemplate, m_markerTreeModel->GetDRCItemCount() ); m_Notebook->SetPageText( 0, msg ); @@ -697,7 +740,7 @@ void DIALOG_DRC::updateDisplayedCounts() msg.sprintf( m_unconnectedTitleTemplate, m_unconnectedTreeModel->GetDRCItemCount() ); m_Notebook->SetPageText( 1, msg ); - if( m_tester->m_footprintsTested ) + if( m_footprintTestsRun ) msg.sprintf( m_footprintsTitleTemplate, m_footprintWarningsTreeModel->GetDRCItemCount() ); else { diff --git a/pcbnew/dialogs/dialog_drc.h b/pcbnew/dialogs/dialog_drc.h index 38706f449f..f839e6757a 100644 --- a/pcbnew/dialogs/dialog_drc.h +++ b/pcbnew/dialogs/dialog_drc.h @@ -48,7 +48,7 @@ DIALOG_DRC: public DIALOG_DRC_BASE { public: /// Constructors - DIALOG_DRC( DRC* aTester, PCB_EDIT_FRAME* aEditorFrame, wxWindow* aParent ); + DIALOG_DRC( PCB_EDIT_FRAME* aEditorFrame, wxWindow* aParent ); ~DIALOG_DRC(); void SetMarkersProvider( RC_ITEMS_PROVIDER* aProvider ); @@ -95,8 +95,9 @@ private: BOARD_DESIGN_SETTINGS& bds() { return m_currentBoard->GetDesignSettings(); } BOARD* m_currentBoard; // the board currently on test - DRC* m_tester; PCB_EDIT_FRAME* m_brdEditor; + bool m_drcRun; + bool m_footprintTestsRun; wxString m_markersTitleTemplate; wxString m_unconnectedTitleTemplate; diff --git a/pcbnew/dialogs/dialog_netlist.cpp b/pcbnew/dialogs/dialog_netlist.cpp index acfa5f110b..53af06d1bc 100644 --- a/pcbnew/dialogs/dialog_netlist.cpp +++ b/pcbnew/dialogs/dialog_netlist.cpp @@ -31,9 +31,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -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 > 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 ) { 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 ) { wxString netlistFileName = m_NetlistFilenameCtrl->GetValue(); diff --git a/pcbnew/dialogs/dialog_netlist.h b/pcbnew/dialogs/dialog_netlist.h index b6ae473724..4ab59202d8 100644 --- a/pcbnew/dialogs/dialog_netlist.h +++ b/pcbnew/dialogs/dialog_netlist.h @@ -64,9 +64,7 @@ private: void OnFilenameKillFocus( wxFocusEvent& event ) override; void OnMatchChanged( wxCommandEvent& event ) override; void OnOptionChanged( wxCommandEvent& event ) override; - void OnTestFootprintsClick( wxCommandEvent& event ) override; void OnCompileRatsnestClick( wxCommandEvent& event ) override; - void OnUpdateUIValidNetlistFile( wxUpdateUIEvent& aEvent ) override; }; diff --git a/pcbnew/dialogs/dialog_netlist_base.cpp b/pcbnew/dialogs/dialog_netlist_base.cpp index c4395e0451..a9e57c4492 100644 --- a/pcbnew/dialogs/dialog_netlist_base.cpp +++ b/pcbnew/dialogs/dialog_netlist_base.cpp @@ -86,11 +86,6 @@ DIALOG_NETLIST_BASE::DIALOG_NETLIST_BASE( wxWindow* parent, wxWindowID id, const 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_sdbSizer1OK = new wxButton( this, wxID_OK ); m_sdbSizer1->AddButton( m_sdbSizer1OK ); @@ -111,6 +106,7 @@ DIALOG_NETLIST_BASE::DIALOG_NETLIST_BASE( wxWindow* parent, wxWindowID id, const bMainSizer->Fit( this ); // 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_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 ); @@ -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_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_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_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() { // 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_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 ); @@ -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_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_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_sdbSizer1OK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnUpdatePCB ), NULL, this ); diff --git a/pcbnew/dialogs/dialog_netlist_base.fbp b/pcbnew/dialogs/dialog_netlist_base.fbp index 70a9dd8640..96553db947 100644 --- a/pcbnew/dialogs/dialog_netlist_base.fbp +++ b/pcbnew/dialogs/dialog_netlist_base.fbp @@ -762,80 +762,6 @@ m_buttonsSizer wxHORIZONTAL protected - - 10 - wxEXPAND|wxLEFT|wxRIGHT - 0 - - 1 - 1 - 1 - 1 - - - - - - - - - 1 - 0 - 1 - - 1 - - 0 - 0 - - Dock - 0 - Left - 1 - - 1 - - - 0 - 0 - ID_TEST_NETLIST - Test Footprints - - 0 - - 0 - - - 0 - - 1 - m_buttonFPTest - 1 - - - protected - 1 - - - - Resizable - 1 - - - - 0 - Read the current netlist file and list missing and extra footprints - - wxFILTER_NONE - wxDefaultValidator - - - - - OnTestFootprintsClick - OnUpdateUIValidNetlistFile - - 5 wxEXPAND diff --git a/pcbnew/dialogs/dialog_netlist_base.h b/pcbnew/dialogs/dialog_netlist_base.h index 20b5518392..c7e93193bb 100644 --- a/pcbnew/dialogs/dialog_netlist_base.h +++ b/pcbnew/dialogs/dialog_netlist_base.h @@ -42,11 +42,6 @@ class DIALOG_NETLIST_BASE : public DIALOG_SHIM private: protected: - enum - { - ID_TEST_NETLIST = 1000 - }; - wxTextCtrl* m_NetlistFilenameCtrl; wxBitmapButton* m_browseButton; wxRadioBox* m_matchByTimestamp; @@ -57,19 +52,17 @@ class DIALOG_NETLIST_BASE : public DIALOG_SHIM wxCheckBox* m_cbWarnNoNetPad; WX_HTML_REPORT_PANEL* m_MessageWindow; wxBoxSizer* m_buttonsSizer; - wxButton* m_buttonFPTest; wxStdDialogButtonSizer* m_sdbSizer1; wxButton* m_sdbSizer1OK; wxButton* m_sdbSizer1Apply; wxButton* m_sdbSizer1Cancel; // 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 OnOpenNetlistClick( wxCommandEvent& event ) { event.Skip(); } virtual void OnMatchChanged( 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 OnUpdatePCB( wxCommandEvent& event ) { event.Skip(); } diff --git a/pcbnew/dialogs/dialog_plot.cpp b/pcbnew/dialogs/dialog_plot.cpp index 63a731de38..2c1dd2669a 100644 --- a/pcbnew/dialogs/dialog_plot.cpp +++ b/pcbnew/dialogs/dialog_plot.cpp @@ -37,9 +37,9 @@ #include #include #include -#include #include #include +#include #include // for KiROUND #include @@ -903,7 +903,7 @@ void DIALOG_PLOT::onRunDRC( wxCommandEvent& event ) if( parent ) { - DRC* drcTool = parent->GetToolManager()->GetTool(); + DRC_TOOL* drcTool = parent->GetToolManager()->GetTool(); // First close an existing dialog if open // (low probability, but can happen) diff --git a/pcbnew/drc/drc.cpp b/pcbnew/drc/drc.cpp index bad7a4f763..908b2284b4 100644 --- a/pcbnew/drc/drc.cpp +++ b/pcbnew/drc/drc.cpp @@ -25,63 +25,22 @@ #include #include -#include #include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include #include -#include -#include -#include #include -#include // for KiROUND -#include -#include -#include -#include -#include #include #include -#include -#include -#include -#include -#include -#include #include +#include #include -#include DRC::DRC() : - PCB_TOOL_BASE( "pcbnew.DRCTool" ), - m_editFrame( nullptr ), - m_pcb( nullptr ), - m_board_outline_valid( false ), - m_drcDialog( nullptr ), - m_largestClearance( 0 ) + PCB_TOOL_BASE( "pcbnew.legacyDRCTool" ), + m_editFrame( nullptr ) { - // establish initial values for everything: - m_doUnconnectedTest = true; // enable unconnected tests - m_testTracksAgainstZones = false; // disable zone to items clearance tests - m_doKeepoutTest = true; // enable keepout areas to items clearance tests - m_refillZones = false; // Only fill zones if requested by user. - m_reportAllTrackErrors = false; - m_testFootprints = false; - - m_drcRun = false; - m_footprintsTested = false; } @@ -93,89 +52,11 @@ DRC::~DRC() void DRC::Reset( RESET_REASON aReason ) { m_editFrame = getEditFrame(); - - if( m_pcb != m_editFrame->GetBoard() ) - { - if( m_drcDialog ) - DestroyDRCDialog( wxID_OK ); - - m_pcb = m_editFrame->GetBoard(); - } } -void DRC::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 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( this, 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::ShowDRCDialog( const TOOL_EVENT& aEvent ) -{ - ShowDRCDialog( nullptr ); - return 0; -} - - -bool DRC::IsDRCDialogShown() -{ - if( m_drcDialog ) - return m_drcDialog->IsShown(); - - return false; -} - - -void DRC::addMarkerToPcb( BOARD_COMMIT& aCommit, MARKER_PCB* aMarker ) -{ - if( m_pcb->GetDesignSettings().Ignore( aMarker->GetRCItem()->GetErrorCode() ) ) - { - delete aMarker; - return; - } - - aCommit.Add( aMarker ); -} - - -void DRC::DestroyDRCDialog( int aReason ) -{ - if( m_drcDialog ) - { - m_drcDialog->Destroy(); - m_drcDialog = nullptr; - } -} - +// JEY TODO: make DRC_TOOL's DRC_ENGINE be long-lived so it can be used for BOARD_CONNECTED_ITEM's +// GetClearance() and the retire this. bool DRC::LoadRules() { @@ -192,7 +73,7 @@ bool DRC::LoadRules() { try { - DRC_RULES_PARSER parser( m_pcb, fp, rulesFilepath ); + DRC_RULES_PARSER parser( m_editFrame->GetBoard(), fp, rulesFilepath ); parser.Parse( m_rules, &NULL_REPORTER::GetInstance() ); } catch( PARSE_ERROR& pe ) @@ -211,1105 +92,10 @@ bool DRC::LoadRules() std::reverse( std::begin( m_rules ), std::end( m_rules ) ); - BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings(); + BOARD_DESIGN_SETTINGS& bds = m_editFrame->GetBoard()->GetDesignSettings(); bds.m_DRCRules = m_rules; return true; } -void DRC::RunTests( wxTextCtrl* aMessages ) -{ - // Make absolutely sure these are up-to-date - if( !LoadRules() ) - return; - - wxASSERT( m_pcb == m_editFrame->GetBoard() ); - - BOARD_COMMIT commit( m_editFrame ); - BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings(); - - m_largestClearance = bds.GetBiggestClearanceValue(); - - if( !bds.Ignore( DRCE_INVALID_OUTLINE ) - || !bds.Ignore( DRCE_COPPER_EDGE_CLEARANCE ) ) - { - if( aMessages ) - { - aMessages->AppendText( _( "Board Outline...\n" ) ); - wxSafeYield(); - } - - testOutline( commit ); - } - - // test pad to pad clearances, nothing to do with tracks, vias or zones. - if( !bds.Ignore( DRCE_COPPER_EDGE_CLEARANCE ) ) - { - if( aMessages ) - { - aMessages->AppendText( _( "Pad clearances...\n" ) ); - wxSafeYield(); - } - - testPadClearances( commit ); - } - - // test drilled holes - if( !bds.Ignore( DRCE_DRILLED_HOLES_TOO_CLOSE ) - || !bds.Ignore( DRCE_TOO_SMALL_DRILL ) - || !bds.Ignore( DRCE_TOO_SMALL_MICROVIA_DRILL ) ) - { - if( aMessages ) - { - aMessages->AppendText( _( "Drill sizes and clearances...\n" ) ); - wxSafeYield(); - } - - DRC_DRILLED_HOLE_TESTER tester( [&]( MARKER_PCB* aMarker ) - { - addMarkerToPcb( commit, aMarker ); - } ); - - tester.RunDRC( userUnits(), *m_pcb ); - } - - // caller (a wxTopLevelFrame) is the wxDialog or the Pcb Editor frame that call DRC: - wxWindow* caller = aMessages ? aMessages->GetParent() : m_editFrame; - - if( m_refillZones ) - { - if( aMessages ) - aMessages->AppendText( _( "Refilling all zones...\n" ) ); - - m_toolMgr->GetTool()->FillAllZones( caller ); - } - else - { - if( aMessages ) - aMessages->AppendText( _( "Checking zone fills...\n" ) ); - - m_toolMgr->GetTool()->CheckAllZones( caller ); - } - - // test track and via clearances to other tracks, pads, and vias - if( aMessages ) - { - aMessages->AppendText( _( "Track clearances...\n" ) ); - wxSafeYield(); - } - - testTracks( commit, aMessages ? aMessages->GetParent() : m_editFrame, true ); - - // test zone clearances to other zones - if( aMessages ) - { - aMessages->AppendText( _( "Zone to zone clearances...\n" ) ); - wxSafeYield(); - } - - testZones( commit ); - - // find and gather unconnected pads. - if( m_doUnconnectedTest - && !bds.Ignore( DRCE_UNCONNECTED_ITEMS ) ) - { - if( aMessages ) - { - aMessages->AppendText( _( "Unconnected pads...\n" ) ); - aMessages->Refresh(); - } - - testUnconnected(); - } - - // find and gather vias, tracks, pads inside keepout areas. - if( m_doKeepoutTest ) - { - if( aMessages ) - { - aMessages->AppendText( _( "Keepout areas ...\n" ) ); - aMessages->Refresh(); - } - - DRC_KEEPOUT_TESTER tester( [&]( MARKER_PCB* aMarker ) - { - addMarkerToPcb( commit, aMarker ); - } ); - - tester.RunDRC( userUnits(), *m_pcb ); - } - - // find and gather vias, tracks, pads inside text boxes. - if( !bds.Ignore( DRCE_CLEARANCE ) ) - { - if( aMessages ) - { - aMessages->AppendText( _( "Text and graphic clearances...\n" ) ); - wxSafeYield(); - } - - testCopperTextAndGraphics( commit ); - } - - // test courtyards - if( !bds.Ignore( DRCE_OVERLAPPING_FOOTPRINTS ) - || !bds.Ignore( DRCE_MISSING_COURTYARD ) - || !bds.Ignore( DRCE_MALFORMED_COURTYARD ) - || !bds.Ignore( DRCE_PTH_IN_COURTYARD ) - || !bds.Ignore( DRCE_NPTH_IN_COURTYARD ) ) - { - if( aMessages ) - { - aMessages->AppendText( _( "Courtyard areas...\n" ) ); - aMessages->Refresh(); - } - - DRC_COURTYARD_TESTER tester( [&]( MARKER_PCB* aMarker ) - { - addMarkerToPcb( commit, aMarker ); - } ); - - tester.RunDRC( userUnits(), *m_pcb ); - } - - m_footprints.clear(); - m_footprintsTested = false; - - if( m_testFootprints && !Kiface().IsSingle() ) - { - if( aMessages ) - { - aMessages->AppendText( _( "Checking footprints against schematic...\n" ) ); - aMessages->Refresh(); - } - - NETLIST netlist; - m_editFrame->FetchNetlistFromSchematic( netlist, PCB_EDIT_FRAME::ANNOTATION_DIALOG ); - - if( m_drcDialog ) - m_drcDialog->Raise(); - - TestFootprints( netlist, m_pcb, m_footprints ); - m_footprintsTested = true; - } - - // Check if there are items on disabled layers - if( !bds.Ignore( DRCE_DISABLED_LAYER_ITEM ) ) - { - if( aMessages ) - { - aMessages->AppendText( _( "Items on disabled layers...\n" ) ); - aMessages->Refresh(); - } - - testDisabledLayers( commit ); - } - - if( !bds.Ignore( DRCE_UNRESOLVED_VARIABLE ) ) - { - if( aMessages ) - { - aMessages->AppendText( _( "Unresolved text variables...\n" ) ); - aMessages->Refresh(); - } - - DRC_TEXTVAR_TESTER tester( [&]( MARKER_PCB* aMarker ) - { - addMarkerToPcb( commit, aMarker ); - }, - m_editFrame->GetCanvas()->GetWorksheet() ); - - tester.RunDRC( userUnits(), *m_pcb ); - } - - commit.Push( wxEmptyString, false, false ); - m_drcRun = true; - - // update the m_drcDialog listboxes - updatePointers(); - - if( aMessages ) - { - // no newline on this one because it is last, don't want the window - // to unnecessarily scroll. - aMessages->AppendText( _( "Finished" ) ); - } -} - - -void DRC::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 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::testPadClearances( BOARD_COMMIT& aCommit ) -{ - BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings(); - std::vector sortedPads; - - m_pcb->GetSortedPadListByXthenYCoord( sortedPads ); - - if( sortedPads.empty() ) - return; - - // find the max size of the pads (used to stop the pad-to-pad tests) - int max_size = 0; - - for( D_PAD* pad : sortedPads ) - { - // GetBoundingRadius() is the radius of the minimum sized circle fully containing the pad - int radius = pad->GetBoundingRadius(); - - if( radius > max_size ) - max_size = radius; - } - - // Better to be fast than accurate; this keeps us from having to look up / calculate the - // actual clearances - max_size += m_largestClearance; - - // Upper limit of pad list (limit not included) - D_PAD** listEnd = &sortedPads[0] + sortedPads.size(); - - // Test the pads - for( auto& pad : sortedPads ) - { - if( !bds.Ignore( DRCE_COPPER_EDGE_CLEARANCE ) && m_board_outline_valid ) - { - int minClearance = bds.m_CopperEdgeClearance; - m_clearanceSource = _( "board edge" ); - - static DRAWSEGMENT dummyEdge; - dummyEdge.SetParent( m_pcb ); - dummyEdge.SetLayer( Edge_Cuts ); - - pad->GetRuleClearance( &dummyEdge, pad->GetLayer(), &minClearance, &m_clearanceSource ); - - for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ ) - { - SHAPE_SEGMENT edge( *it ); - int actual; - - if( pad->Collide( &edge, minClearance, &actual ) ) - { - std::shared_ptr 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( pad ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() ); - addMarkerToPcb( aCommit, marker ); - - break; - } - } - } - - if( !bds.Ignore( DRCE_CLEARANCE ) ) - { - int x_limit = pad->GetPosition().x + pad->GetBoundingRadius() + max_size; - - doPadToPadsDrc( aCommit, pad, &pad, listEnd, x_limit ); - } - } -} - - -void DRC::testTracks( BOARD_COMMIT& aCommit, wxWindow *aActiveWindow, bool aShowProgressBar ) -{ - APP_PROGRESS_DIALOG* progressDialog = NULL; - const int delta = 500; // This is the number of tests between 2 calls to the - // progress bar - int count = m_pcb->Tracks().size(); - int deltamax = count/delta; - - if( aShowProgressBar && deltamax > 3 ) - { - // Do not use wxPD_APP_MODAL style here: it is not necessary and create issues - // on OSX - progressDialog = new APP_PROGRESS_DIALOG( _( "Track clearances" ), wxEmptyString, - deltamax, aActiveWindow, false, - wxPD_AUTO_HIDE | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME ); - progressDialog->Update( 0, wxEmptyString ); - } - - std::shared_ptr connectivity = m_pcb->GetConnectivity(); - BOARD_DESIGN_SETTINGS& settings = m_pcb->GetDesignSettings(); - - - if( !m_pcb->GetDesignSettings().Ignore( DRCE_DANGLING_TRACK ) - || !m_pcb->GetDesignSettings().Ignore( DRCE_DANGLING_VIA ) ) - { - connectivity->Clear(); - connectivity->Build( m_pcb ); // just in case. This really needs to be reliable. - } - - int ii = 0; - count = 0; - - for( auto seg_it = m_pcb->Tracks().begin(); seg_it != m_pcb->Tracks().end(); seg_it++ ) - { - if( ii++ > delta ) - { - ii = 0; - count++; - - if( progressDialog ) - { - if( !progressDialog->Update( count, wxEmptyString ) ) - break; // Aborted by user -#ifdef __WXMAC__ - // Work around a dialog z-order issue on OS X - if( count == deltamax ) - aActiveWindow->Raise(); -#endif - } - } - - // Test new segment against tracks and pads, optionally against copper zones - LSEQ layer_seq = ( *seg_it )->GetLayerSet().Seq(); - - if( ( *seg_it )->Type() == PCB_VIA_T ) - doSingleViaDRC( aCommit, static_cast( *seg_it ) ); - else - doSingleTrackDRC( aCommit, *seg_it ); - - for( PCB_LAYER_ID layer : layer_seq ) - doTrackDrc( aCommit, *seg_it, seg_it + 1, m_pcb->Tracks().end(), m_testTracksAgainstZones, layer ); - - // Test for dangling items - int code = (*seg_it)->Type() == PCB_VIA_T ? DRCE_DANGLING_VIA : DRCE_DANGLING_TRACK; - wxPoint pos; - - if( !settings.Ignore( code ) && connectivity->TestTrackEndpointDangling( *seg_it, &pos ) ) - { - std::shared_ptr drcItem = DRC_ITEM::Create( code ); - drcItem->SetItems( *seg_it ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, pos ); - addMarkerToPcb( aCommit, marker ); - } - } - - if( progressDialog ) - progressDialog->Destroy(); -} - - -void DRC::testUnconnected() -{ - m_unconnected.clear(); - - auto connectivity = m_pcb->GetConnectivity(); - - connectivity->Clear(); - connectivity->Build( m_pcb ); // just in case. This really needs to be reliable. - connectivity->RecalculateRatsnest(); - - std::vector edges; - connectivity->GetUnconnectedEdges( edges ); - - for( const CN_EDGE& edge : edges ) - { - std::shared_ptr item = DRC_ITEM::Create( DRCE_UNCONNECTED_ITEMS ); - item->SetItems( edge.GetSourceNode()->Parent(), edge.GetTargetNode()->Parent() ); - m_unconnected.push_back( item ); - } -} - - -void DRC::testZones( BOARD_COMMIT& aCommit ) -{ - BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings(); - - // Test copper areas for valid netcodes - // if a netcode is < 0 the netname was not found when reading a netlist - // if a netcode is == 0 the netname is void, and the zone is not connected. - // This is allowed, but i am not sure this is a good idea - // - // In recent Pcbnew versions, the netcode is always >= 0, but an internal net name - // is stored, and initialized from the file or the zone properties editor. - // if it differs from the net name from net code, there is a DRC issue - - std::vector smoothed_polys; - smoothed_polys.resize( m_pcb->GetAreaCount() ); - - for( int ii = 0; ii < m_pcb->GetAreaCount(); ii++ ) - { - ZONE_CONTAINER* zone = m_pcb->GetArea( ii ); - - if( !bds.Ignore( DRCE_ZONE_HAS_EMPTY_NET ) && zone->IsOnCopperLayer() ) - { - int netcode = zone->GetNetCode(); - // a netcode < 0 or > 0 and no pad in net is a error or strange - // perhaps a "dead" net, which happens when all pads in this net were removed - // Remark: a netcode < 0 should not happen (this is more a bug somewhere) - int pads_in_net = ( netcode > 0 ) ? m_pcb->GetConnectivity()->GetPadCount( netcode ) : 1; - - if( ( netcode < 0 ) || pads_in_net == 0 ) - { - std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_ZONE_HAS_EMPTY_NET ); - drcItem->SetItems( zone ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, zone->GetPosition() ); - addMarkerToPcb( aCommit, marker ); - } - } - - ZONE_CONTAINER* zoneRef = m_pcb->GetArea( ii ); - zoneRef->BuildSmoothedPoly( smoothed_polys[ii], zoneRef->GetLayer() ); - } - - // iterate through all areas - for( int ia = 0; ia < m_pcb->GetAreaCount(); ia++ ) - { - ZONE_CONTAINER* zoneRef = m_pcb->GetArea( ia ); - - if( !zoneRef->IsOnCopperLayer() ) - continue; - - // If we are testing a single zone, then iterate through all other zones - // Otherwise, we have already tested the zone combination - for( int ia2 = ia + 1; ia2 < m_pcb->GetAreaCount(); ia2++ ) - { - ZONE_CONTAINER* zoneToTest = m_pcb->GetArea( ia2 ); - - if( zoneRef == zoneToTest ) - continue; - - // test for same layer - if( zoneRef->GetLayer() != zoneToTest->GetLayer() ) - continue; - - // Test for same net - if( zoneRef->GetNetCode() == zoneToTest->GetNetCode() && zoneRef->GetNetCode() >= 0 ) - continue; - - // test for different priorities - if( zoneRef->GetPriority() != zoneToTest->GetPriority() ) - continue; - - // test for different types - if( zoneRef->GetIsKeepout() != zoneToTest->GetIsKeepout() ) - continue; - - // Examine a candidate zone: compare zoneToTest to zoneRef - - // Get clearance used in zone to zone test. The policy used to - // obtain that value is now part of the zone object itself by way of - // ZONE_CONTAINER::GetClearance(). - int zone2zoneClearance = zoneRef->GetClearance( zoneRef->GetLayer(), zoneToTest, - &m_clearanceSource ); - - // Keepout areas have no clearance, so set zone2zoneClearance to 1 - // ( zone2zoneClearance = 0 can create problems in test functions) - if( zoneRef->GetIsKeepout() ) - zone2zoneClearance = 1; - - // test for some corners of zoneRef inside zoneToTest - for( auto iterator = smoothed_polys[ia].IterateWithHoles(); iterator; iterator++ ) - { - VECTOR2I currentVertex = *iterator; - wxPoint pt( currentVertex.x, currentVertex.y ); - - if( smoothed_polys[ia2].Contains( currentVertex ) ) - { - std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_ZONES_INTERSECT ); - drcItem->SetItems( zoneRef, zoneToTest ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, pt ); - addMarkerToPcb( aCommit, marker ); - } - } - - // test for some corners of zoneToTest inside zoneRef - for( auto iterator = smoothed_polys[ia2].IterateWithHoles(); iterator; iterator++ ) - { - VECTOR2I currentVertex = *iterator; - wxPoint pt( currentVertex.x, currentVertex.y ); - - if( smoothed_polys[ia].Contains( currentVertex ) ) - { - std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_ZONES_INTERSECT ); - drcItem->SetItems( zoneToTest, zoneRef ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, pt ); - addMarkerToPcb( aCommit, marker ); - } - } - - // Iterate through all the segments of refSmoothedPoly - std::map conflictPoints; - - for( auto refIt = smoothed_polys[ia].IterateSegmentsWithHoles(); refIt; refIt++ ) - { - // Build ref segment - SEG refSegment = *refIt; - - // Iterate through all the segments in smoothed_polys[ia2] - for( auto testIt = smoothed_polys[ia2].IterateSegmentsWithHoles(); testIt; testIt++ ) - { - // Build test segment - SEG testSegment = *testIt; - wxPoint pt; - - int ax1, ay1, ax2, ay2; - ax1 = refSegment.A.x; - ay1 = refSegment.A.y; - ax2 = refSegment.B.x; - ay2 = refSegment.B.y; - - int bx1, by1, bx2, by2; - bx1 = testSegment.A.x; - by1 = testSegment.A.y; - bx2 = testSegment.B.x; - by2 = testSegment.B.y; - - int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, - 0, - ax1, ay1, ax2, ay2, - 0, - zone2zoneClearance, - &pt.x, &pt.y ); - - if( d < zone2zoneClearance ) - { - if( conflictPoints.count( pt ) ) - conflictPoints[ pt ] = std::min( conflictPoints[ pt ], d ); - else - conflictPoints[ pt ] = d; - } - } - } - - for( const std::pair& conflict : conflictPoints ) - { - int actual = conflict.second; - std::shared_ptr drcItem; - - if( actual <= 0 ) - { - drcItem = DRC_ITEM::Create( DRCE_ZONES_INTERSECT ); - } - else - { - drcItem = DRC_ITEM::Create( DRCE_CLEARANCE ); - - m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), - m_clearanceSource, - MessageTextFromValue( userUnits(), zone2zoneClearance, true ), - MessageTextFromValue( userUnits(), conflict.second, true ) ); - - drcItem->SetErrorMessage( m_msg ); - } - - drcItem->SetItems( zoneRef, zoneToTest ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, conflict.first ); - addMarkerToPcb( aCommit, marker ); - } - } - } -} - - -void DRC::testCopperTextAndGraphics( BOARD_COMMIT& aCommit ) -{ - // Test copper items for clearance violations with vias, tracks and pads - - for( BOARD_ITEM* brdItem : m_pcb->Drawings() ) - { - if( IsCopperLayer( brdItem->GetLayer() ) ) - testCopperDrawItem( aCommit, brdItem ); - } - - for( MODULE* module : m_pcb->Modules() ) - { - TEXTE_MODULE& ref = module->Reference(); - TEXTE_MODULE& val = module->Value(); - - if( ref.IsVisible() && IsCopperLayer( ref.GetLayer() ) ) - testCopperDrawItem( aCommit, &ref ); - - if( val.IsVisible() && IsCopperLayer( val.GetLayer() ) ) - testCopperDrawItem( aCommit, &val ); - - if( module->IsNetTie() ) - continue; - - for( BOARD_ITEM* item : module->GraphicalItems() ) - { - if( IsCopperLayer( item->GetLayer() ) ) - { - if( item->Type() == PCB_MODULE_TEXT_T && ( (TEXTE_MODULE*) item )->IsVisible() ) - testCopperDrawItem( aCommit, item ); - else if( item->Type() == PCB_MODULE_EDGE_T ) - testCopperDrawItem( aCommit, item ); - } - } - } -} - - -void DRC::testCopperDrawItem( BOARD_COMMIT& aCommit, BOARD_ITEM* aItem ) -{ - EDA_RECT bbox; - std::vector itemShapes; - DRAWSEGMENT* drawItem = dynamic_cast( aItem ); - EDA_TEXT* textItem = dynamic_cast( aItem ); - - if( drawItem ) - { - bbox = drawItem->GetBoundingBox(); - itemShapes = drawItem->MakeEffectiveShapes(); - } - else if( textItem ) - { - bbox = textItem->GetTextBox(); - - int penWidth = textItem->GetEffectiveTextPenWidth(); - std::vector pts; - textItem->TransformTextShapeToSegmentList( pts ); - - for( unsigned jj = 0; jj < pts.size(); jj += 2 ) - itemShapes.push_back( new SHAPE_SEGMENT( pts[jj], pts[jj+1], penWidth ) ); - } - else - { - wxFAIL_MSG( "unknown item type in testCopperDrawItem()" ); - return; - } - - SHAPE_RECT bboxShape( bbox.GetX(), bbox.GetY(), bbox.GetWidth(), bbox.GetHeight() ); - - // Test tracks and vias - for( TRACK* track : m_pcb->Tracks() ) - { - if( !track->IsOnLayer( aItem->GetLayer() ) ) - continue; - - int minClearance = track->GetClearance( track->GetLayer(), aItem, &m_clearanceSource ); - int actual = INT_MAX; - wxPoint pos; - - SHAPE_SEGMENT trackSeg( track->GetStart(), track->GetEnd(), track->GetWidth() ); - - // Fast test to detect a track segment candidate inside the text bounding box - if( !bboxShape.Collide( &trackSeg, 0 ) ) - continue; - - for( const SHAPE* shape : itemShapes ) - { - int this_dist; - - if( shape->Collide( &trackSeg, minClearance, &this_dist ) ) - { - if( this_dist < actual ) - { - actual = this_dist; - pos = (wxPoint) shape->Centre(); - } - } - } - - if( actual < INT_MAX ) - { - std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_CLEARANCE ); - - m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), - m_clearanceSource, - MessageTextFromValue( userUnits(), minClearance, true ), - MessageTextFromValue( userUnits(), std::max( 0, actual ), true ) ); - - drcItem->SetErrorMessage( m_msg ); - drcItem->SetItems( track, aItem ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, pos ); - addMarkerToPcb( aCommit, marker ); - } - } - - // Test pads - for( D_PAD* pad : m_pcb->GetPads() ) - { - if( !pad->IsOnLayer( aItem->GetLayer() ) ) - continue; - - // Graphic items are allowed to act as net-ties within their own footprint - if( drawItem && pad->GetParent() == drawItem->GetParent() ) - continue; - - int minClearance = pad->GetClearance( aItem->GetLayer(), aItem, &m_clearanceSource ); - int actual = INT_MAX; - - // Fast test to detect a pad candidate inside the text bounding box - // Finer test (time consumming) is made only for pads near the text. - int bb_radius = pad->GetBoundingRadius() + minClearance; - - if( !bboxShape.Collide( SEG( pad->GetPosition(), pad->GetPosition() ), bb_radius ) ) - continue; - - for( const SHAPE* bShape : itemShapes ) - { - int this_dist; - - if( pad->GetEffectiveShape()->Collide( bShape, minClearance, &this_dist ) ) - actual = std::min( actual, this_dist ); - } - - if( actual < INT_MAX ) - { - std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_CLEARANCE ); - - m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), - m_clearanceSource, - MessageTextFromValue( userUnits(), minClearance, true ), - MessageTextFromValue( userUnits(), std::max( 0, actual ), true ) ); - - drcItem->SetErrorMessage( m_msg ); - drcItem->SetItems( pad, aItem ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() ); - addMarkerToPcb( aCommit, marker ); - } - } - - for( SHAPE* shape : itemShapes ) - delete shape; -} - - -void DRC::testOutline( BOARD_COMMIT& aCommit ) -{ - wxPoint error_loc( m_pcb->GetBoardEdgesBoundingBox().GetPosition() ); - - m_board_outlines.RemoveAllContours(); - m_board_outline_valid = false; - - if( m_pcb->GetBoardPolygonOutlines( m_board_outlines, nullptr, &error_loc ) ) - { - m_board_outline_valid = true; - } - else - { - std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_INVALID_OUTLINE ); - - m_msg.Printf( drcItem->GetErrorText() + _( " (not a closed shape)" ) ); - - drcItem->SetErrorMessage( m_msg ); - drcItem->SetItems( m_pcb ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, error_loc ); - addMarkerToPcb( aCommit, marker ); - } -} - - -void DRC::testDisabledLayers( BOARD_COMMIT& aCommit ) -{ - LSET disabledLayers = m_pcb->GetEnabledLayers().flip(); - - // Perform the test only for copper layers - disabledLayers &= LSET::AllCuMask(); - - for( TRACK* track : m_pcb->Tracks() ) - { - if( disabledLayers.test( track->GetLayer() ) ) - { - std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_DISABLED_LAYER_ITEM ); - - m_msg.Printf( drcItem->GetErrorText() + _( "layer %s" ), - track->GetLayerName() ); - - drcItem->SetErrorMessage( m_msg ); - drcItem->SetItems( track ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, track->GetPosition() ); - addMarkerToPcb( aCommit, marker ); - } - } - - for( MODULE* module : m_pcb->Modules() ) - { - module->RunOnChildren( - [&]( BOARD_ITEM* child ) - { - if( disabledLayers.test( child->GetLayer() ) ) - { - std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_DISABLED_LAYER_ITEM ); - - m_msg.Printf( drcItem->GetErrorText() + _( "layer %s" ), - child->GetLayerName() ); - - drcItem->SetErrorMessage( m_msg ); - drcItem->SetItems( child ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, child->GetPosition() ); - addMarkerToPcb( aCommit, marker ); - } - } ); - } - - for( ZONE_CONTAINER* zone : m_pcb->Zones() ) - { - if( disabledLayers.test( zone->GetLayer() ) ) - { - std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_DISABLED_LAYER_ITEM ); - - m_msg.Printf( drcItem->GetErrorText() + _( "layer %s" ), - zone->GetLayerName() ); - - drcItem->SetErrorMessage( m_msg ); - drcItem->SetItems( zone ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, zone->GetPosition() ); - addMarkerToPcb( aCommit, marker ); - } - } -} - - -bool DRC::doPadToPadsDrc( BOARD_COMMIT& aCommit, D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd, - int x_limit ) -{ - const static LSET all_cu = LSET::AllCuMask(); - - LSET layerMask = aRefPad->GetLayerSet() & all_cu; - - for( D_PAD** pad_list = aStart; pad_listGetPosition().x > x_limit - // because the list is sorted by X values - if( pad->GetPosition().x > x_limit ) - break; - - // No problem if pads which are on copper layers are on different copper layers, - // (pads can be only on a technical layer, to build complex pads) - // but their hole (if any ) can create DRC error because they are on all - // copper layers, so we test them - if( ( pad->GetLayerSet() & layerMask ) == 0 && - ( pad->GetLayerSet() & all_cu ) != 0 && - ( aRefPad->GetLayerSet() & all_cu ) != 0 ) - { - // if holes are in the same location and have the same size and shape, - // this can be accepted - if( pad->GetPosition() == aRefPad->GetPosition() - && pad->GetDrillSize() == aRefPad->GetDrillSize() - && pad->GetDrillShape() == aRefPad->GetDrillShape() ) - { - if( aRefPad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE ) - continue; - - // for oval holes: must also have the same orientation - if( pad->GetOrientation() == aRefPad->GetOrientation() ) - continue; - } - - if( pad->GetDrillSize().x ) - { - int minClearance = aRefPad->GetClearance( aRefPad->GetLayer(), nullptr, - &m_clearanceSource ); - int actual; - - if( aRefPad->Collide( pad->GetEffectiveHoleShape(), minClearance, &actual ) ) - { - std::shared_ptr 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( pad, aRefPad ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() ); - addMarkerToPcb( aCommit, marker ); - return false; - } - } - - if( aRefPad->GetDrillSize().x ) - { - int minClearance = pad->GetClearance( pad->GetLayer(), nullptr, - &m_clearanceSource ); - int actual; - - if( pad->Collide( aRefPad->GetEffectiveHoleShape(), minClearance, &actual ) ) - { - std::shared_ptr 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( aRefPad, pad ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefPad->GetPosition() ); - addMarkerToPcb( aCommit, marker ); - return false; - } - } - - continue; - } - - // The pad must be in a net (i.e pt_pad->GetNet() != 0 ), - // But no problem if pads have the same netcode (same net) - if( pad->GetNetCode() && ( aRefPad->GetNetCode() == pad->GetNetCode() ) ) - continue; - - // If pads are equivalent (ie: from the same footprint with the same pad number)... - if( pad->GetParent() == aRefPad->GetParent() && pad->PadNameEqual( aRefPad ) ) - { - // ...and have nets, then they must be the same net - if( pad->GetNetCode() && aRefPad->GetNetCode() - && pad->GetNetCode() != aRefPad->GetNetCode() ) - { - std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_SHORTING_ITEMS ); - - m_msg.Printf( drcItem->GetErrorText() + _( " (nets %s and %s)" ), - pad->GetNetname(), aRefPad->GetNetname() ); - - drcItem->SetErrorMessage( m_msg ); - drcItem->SetItems( pad, aRefPad ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefPad->GetPosition() ); - addMarkerToPcb( aCommit, marker ); - } - - continue; - } - - // if either pad has no drill and is only on technical layers, not a clearance violation - if( ( ( pad->GetLayerSet() & layerMask ) == 0 && !pad->GetDrillSize().x ) || - ( ( aRefPad->GetLayerSet() & layerMask ) == 0 && !aRefPad->GetDrillSize().x ) ) - { - continue; - } - - for( PCB_LAYER_ID layer : aRefPad->GetLayerSet().Seq() ) - { - int minClearance = aRefPad->GetClearance( layer, pad, &m_clearanceSource ); - int clearanceAllowed = minClearance - m_pcb->GetDesignSettings().GetDRCEpsilon(); - int actual; - - if( aRefPad->Collide( pad, clearanceAllowed, &actual ) ) - { - std::shared_ptr 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( aRefPad, pad ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefPad->GetPosition() ); - addMarkerToPcb( aCommit, marker ); - return false; - } - } - } - - return true; -} - - -void DRC::setTransitions() -{ - Go( &DRC::ShowDRCDialog, PCB_ACTIONS::runDRC.MakeEvent() ); -} - - -const int UI_EPSILON = Mils2iu( 5 ); - - -wxPoint DRC::GetLocation( PCB_LAYER_ID aLayer, TRACK* aTrack, ZONE_CONTAINER* aZone ) -{ - SHAPE_POLY_SET* zonePoly = nullptr; - - if( aZone->IsFilled() && aZone->HasFilledPolysForLayer( aLayer ) ) - zonePoly = const_cast( &aZone->GetFilledPolysList( aLayer ) ); - - if( !zonePoly || zonePoly->IsEmpty() ) - zonePoly = aZone->Outline(); - - SEG trackSeg( aTrack->GetStart(), aTrack->GetEnd() ); - SEG::ecoord closestDist_sq = VECTOR2I::ECOORD_MAX; - SEG closestSeg; - - for( auto it = zonePoly->CIterateSegments( 0, -1, true ); it; it++ ) - { - SEG::ecoord dist_sq = trackSeg.SquaredDistance( *it ); - - if( dist_sq < closestDist_sq ) - { - closestDist_sq = dist_sq; - closestSeg = *it; - } - } - - VECTOR2I pt1 = closestSeg.A; - VECTOR2I pt2 = closestSeg.B; - - // Do a binary search for a "good enough" marker location - while( GetLineLength( (wxPoint) pt1, (wxPoint) pt2 ) > UI_EPSILON ) - { - if( trackSeg.SquaredDistance( pt1 ) < trackSeg.SquaredDistance( pt2 ) ) - pt2 = ( pt1 + pt2 ) / 2; - else - pt1 = ( pt1 + pt2 ) / 2; - } - - // Once we're within UI_EPSILON pt1 and pt2 are "equivalent" - return (wxPoint) pt1; -} - - -wxPoint DRC::GetLocation( TRACK* aTrack, const SEG& aConflictSeg ) -{ - wxPoint pt1 = aTrack->GetPosition(); - wxPoint pt2 = aTrack->GetEnd(); - - // Do a binary search along the track for a "good enough" marker location - while( GetLineLength( pt1, pt2 ) > UI_EPSILON ) - { - if( aConflictSeg.SquaredDistance( pt1 ) < aConflictSeg.SquaredDistance( pt2 ) ) - pt2 = ( pt1 + pt2 ) / 2; - else - pt1 = ( pt1 + pt2 ) / 2; - } - - // Once we're within UI_EPSILON pt1 and pt2 are "equivalent" - return pt1; -} - - diff --git a/pcbnew/drc/drc.h b/pcbnew/drc/drc.h index 3d63533f88..5651c707ce 100644 --- a/pcbnew/drc/drc.h +++ b/pcbnew/drc/drc.h @@ -36,67 +36,7 @@ #include -/// 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 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 { - friend class DIALOG_DRC; - public: DRC(); ~DRC(); @@ -119,179 +57,14 @@ public: void Reset( RESET_REASON aReason ) override; 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 - 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 > m_unconnected; // list of unconnected pads - std::vector > 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 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 ); - - //---------------------------------------------- - - /** - * 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 ); - - //---------------------------------------------- - - /** - * 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: /** * Load the DRC rules. Must be called after the netclasses have been read. */ 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 ); }; diff --git a/pcbnew/drc/drc_clearance_test_functions.cpp b/pcbnew/drc/drc_clearance_test_functions.cpp deleted file mode 100644 index 7ee64f8ebd..0000000000 --- a/pcbnew/drc/drc_clearance_test_functions.cpp +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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 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 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 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 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 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 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 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( 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 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 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 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 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( 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 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 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 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( 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( m_pcb->Drawings(), inspector, nullptr, types ); - - int actual = std::max( 0.0, sqrt( center2center_squared ) - halfWidth ); - std::shared_ptr 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 ); - } - } - } -} - diff --git a/pcbnew/drc/drc_courtyard_tester.cpp b/pcbnew/drc/drc_courtyard_tester.cpp deleted file mode 100644 index f6728ea45e..0000000000 --- a/pcbnew/drc/drc_courtyard_tester.cpp +++ /dev/null @@ -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 - -#include -#include - -#include - -#include -#include - -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 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 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 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 drcItem = DRC_ITEM::Create( code ); - drcItem->SetItems( footprint, pad ); - HandleMarker( new MARKER_PCB( drcItem, pos ) ); - success = false; - } - } - } - } - } - - return success; -} diff --git a/pcbnew/drc/drc_courtyard_tester.h b/pcbnew/drc/drc_courtyard_tester.h deleted file mode 100644 index 225cda3e36..0000000000 --- a/pcbnew/drc/drc_courtyard_tester.h +++ /dev/null @@ -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 - - -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 diff --git a/pcbnew/drc/drc_drilled_hole_tester.cpp b/pcbnew/drc/drc_drilled_hole_tester.cpp deleted file mode 100644 index 14a22ca927..0000000000 --- a/pcbnew/drc/drc_drilled_hole_tester.cpp +++ /dev/null @@ -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 - -#include -#include - -#include - - -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( 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 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 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 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 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; -} diff --git a/pcbnew/drc/drc_drilled_hole_tester.h b/pcbnew/drc/drc_drilled_hole_tester.h deleted file mode 100644 index eeeba0aa71..0000000000 --- a/pcbnew/drc/drc_drilled_hole_tester.h +++ /dev/null @@ -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 - - -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 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 diff --git a/pcbnew/drc/drc_engine.cpp b/pcbnew/drc/drc_engine.cpp index c75bab1d64..a90a37f9fb 100644 --- a/pcbnew/drc/drc_engine.cpp +++ b/pcbnew/drc/drc_engine.cpp @@ -87,7 +87,7 @@ void DRC_ENGINE::loadImplicitRules() // 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 ); 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) - 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'" ); @@ -144,7 +144,7 @@ void DRC_ENGINE::loadImplicitRules() 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'" ); @@ -188,13 +188,6 @@ void DRC_ENGINE::loadImplicitRules() ncClearanceConstraint.Value().SetMin( nc->GetClearance() ); 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 ) { 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 ); if( m_constraintMap.find( id ) == m_constraintMap.end() ) - m_constraintMap[ id ] = new CONSTRAINT_SET; - - m_constraintMap[ id ]->provider = provider; + m_constraintMap[ id ] = new std::vector(); for( DRC_RULE* rule : m_rules ) { DRC_RULE_CONDITION* condition = nullptr; bool compileOk = false; std::vector 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() ) { @@ -342,7 +333,7 @@ bool DRC_ENGINE::CompileRules() rcons->constraint = constraint; rcons->parentRule = rule; - m_constraintMap[ id ]->sortedConstraints.push_back( rcons ); + m_constraintMap[ id ]->push_back( rcons ); } 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 ) { @@ -405,27 +409,8 @@ void DRC_ENGINE::RunTests( DRC_VIOLATION_HANDLER aViolationHandler ) for( DRC_TEST_PROVIDER* provider : m_testProviders ) { - bool skipProvider = false; - auto providedConstraints = provider->GetConstraintTypes(); + drc_dbg( 0, "Running test provider: '%s'\n", provider->GetName() ); - 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() ) ); provider->Run(); } @@ -438,39 +423,33 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRulesForItems( DRC_CONSTRAINT_TYPE_T aConstraintI { #define REPORT( s ) { if( aReporter ) { aReporter->Report( s ); } } + auto* connectedA = a && a->IsConnected() ? static_cast( a ) : nullptr; + auto* connectedB = b && b->IsConnected() ? static_cast( b ) : nullptr; + // Local overrides take precedence if( aConstraintId == DRC_CONSTRAINT_TYPE_CLEARANCE ) { - BOARD_CONNECTED_ITEM* ac = a->IsConnected() ? static_cast( a ) - : nullptr; - BOARD_CONNECTED_ITEM* bc = b->IsConnected() ? static_cast( b ) - : nullptr; int overrideA = 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." ), a->GetSelectMenuText( aReporter->GetUnits() ), 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." ), b->GetSelectMenuText( aReporter->GetUnits() ), 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 ) @@ -481,17 +460,34 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRulesForItems( DRC_CONSTRAINT_TYPE_T aConstraintI } } - CONSTRAINT_SET* ruleset = m_constraintMap[ aConstraintId ]; + std::vector* 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 ]; - bool implicit = rcons->parentRule && rcons->parentRule->m_Implicit; + const CONSTRAINT_WITH_CONDITIONS* rcons = ruleset->at( ii ); + implicit = rcons->parentRule && rcons->parentRule->m_Implicit; - if( implicit ) - REPORT( wxString::Format( _( "Checking %s." ), rcons->parentRule->m_Name ) ) + REPORT( "" ) + + 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 - 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 ) ) { REPORT( wxString::Format( _( "Rule layer \"%s\" not matched." ), @@ -501,50 +497,103 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRulesForItems( DRC_CONSTRAINT_TYPE_T aConstraintI continue; } - const wxString& expression = rcons->condition->GetExpression(); - - if( expression.IsEmpty() ) + if( !rcons->condition || rcons->condition->GetExpression().IsEmpty() ) { REPORT( implicit ? _( "Unconditional constraint applied." ) : _( "Unconditional rule applied." ) ) - return rcons->constraint; + constraintRef = &rcons->constraint; + break; } 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 ) - REPORT( _( "Checking rule condition \"" + expression + "\"." ) ) + { + REPORT( wxString::Format( _( "Checking rule condition \"%s\"." ), + rcons->condition->GetExpression() ) ) + } if( rcons->condition->EvaluateFor( a, b, aLayer, aReporter ) ) { - REPORT( implicit ? _( "Constraint applied." ) + REPORT( implicit ? _( "Constraint applicable." ) : _( "Rule applied." ) ) - return rcons->constraint; + constraintRef = &rcons->constraint; + break; } else { - REPORT( implicit ? _( "Membership not satisfied; constraint not applied." ) + REPORT( implicit ? _( "Membership not satisfied; constraint not applicable." ) : _( "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, let the particular test decide what to do if no matching constraint // is found static DRC_CONSTRAINT nullConstraint; nullConstraint.m_DisallowFlags = 0; - return nullConstraint; + return constraintRef ? *constraintRef : nullConstraint; #undef REPORT } +bool DRC_ENGINE::IsErrorLimitExceeded( int error_code ) +{ + return m_errorLimits[ error_code ] <= 0; +} + + void DRC_ENGINE::ReportViolation( const std::shared_ptr& aItem, wxPoint aPos ) { + m_errorLimits[ aItem->GetErrorCode() ] -= 1; + + if( m_violationHandler ) + m_violationHandler( aItem, aPos ); + if( m_reporter ) { wxString msg = wxString::Format( "Test '%s': %s (code %d)", @@ -561,12 +610,10 @@ void DRC_ENGINE::ReportViolation( const std::shared_ptr& aItem, wxPoin wxString violatingItemsStr = "Violating items: "; - m_reporter->Report( wxString::Format( " |- violating position (%d, %d)", - aPos.x, - aPos.y ) ); + m_reporter->Report( wxString::Format( " |- violating position (%d, %d)", + aPos.x, + aPos.y ) ); } - - m_violationHandler( aItem, aPos ); } 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 ) return; - m_progressReporter->SetNumPhases( total ); - m_progressReporter->BeginPhase( index ); // fixme: coalesce all stages/test providers - m_progressReporter->Report( aStageName ); + m_progressReporter->AdvancePhase( aStageName ); } @@ -623,8 +668,8 @@ std::vector DRC_ENGINE::QueryConstraintsById( DRC_CONSTRAINT_TYP { std::vector rv; - for ( CONSTRAINT_WITH_CONDITIONS* c : m_constraintMap[constraintID]->sortedConstraints ) - rv.push_back(c->constraint); + for ( CONSTRAINT_WITH_CONDITIONS* c : *m_constraintMap[constraintID] ) + rv.push_back( c->constraint ); return rv; } @@ -633,7 +678,7 @@ std::vector DRC_ENGINE::QueryConstraintsById( DRC_CONSTRAINT_TYP bool DRC_ENGINE::HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_T constraintID ) { //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; } diff --git a/pcbnew/drc/drc_engine.h b/pcbnew/drc/drc_engine.h index 23d42902a4..5b20a238cc 100644 --- a/pcbnew/drc/drc_engine.h +++ b/pcbnew/drc/drc_engine.h @@ -79,7 +79,6 @@ std::function& aItem, wxPoint aPos )> DRC_ */ class DRC_ENGINE { - public: DRC_ENGINE( BOARD* aBoard, BOARD_DESIGN_SETTINGS* aSettings ); ~DRC_ENGINE(); @@ -87,31 +86,42 @@ public: void SetSchematicNetlist( NETLIST* aNetlist ) { m_schematicNetlist = aNetlist; } NETLIST* GetSchematicNetlist() const { return m_schematicNetlist; } - // JEY TODO: why isn't this called? void SetWorksheet( KIGFX::WS_PROXY_VIEW_ITEM* aWorksheet ) { m_worksheet = aWorksheet; } 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; } + /* + * Receives debug information for a developer. + */ void SetLogReporter( REPORTER* aReporter ) { m_reporter = aReporter; } + /* + * Loads and parses a rule set from an sexpr text file. + */ bool LoadRules( const wxFileName& aPath ); 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* GetBoard() const { return m_board; } - bool IsErrorLimitExceeded( int error_code ) - { - m_errorLimits[ error_code ] -= 1; - - return m_errorLimits[ error_code ] <= 0; - } + bool IsErrorLimitExceeded( int error_code ); DRC_CONSTRAINT EvalRulesForItems( DRC_CONSTRAINT_TYPE_T ruleID, BOARD_ITEM* a, BOARD_ITEM* b = nullptr, @@ -122,23 +132,16 @@ public: bool HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_T constraintID ); - EDA_UNITS UserUnits() const - { - // JEY TODO - return EDA_UNITS::MILLIMETRES; - } - - bool GetTestTracksAgainstZones() const - { - // JEY TODO - return true; - } + EDA_UNITS UserUnits() const { return m_userUnits; } + bool GetTestTracksAgainstZones() const { return m_testTracksAgainstZones; } + bool GetReportAllTrackErrors() const { return m_reportAllTrackErrors; } + bool GetTestFootprints() const { return m_testFootprints; } bool CompileRules(); void ReportViolation( const std::shared_ptr& aItem, wxPoint aPos ); void ReportProgress( double aProgress ); - void ReportStage ( const wxString& aStageName, int index, int total ); + void ReportStage( const wxString& aStageName ); void ReportAux( const wxString& aStr ); bool QueryWorstConstraint( DRC_CONSTRAINT_TYPE_T aRuleId, DRC_CONSTRAINT& aConstraint, @@ -160,12 +163,6 @@ private: DRC_CONSTRAINT constraint; }; - struct CONSTRAINT_SET - { - std::vector sortedConstraints; - DRC_TEST_PROVIDER* provider; - }; - void loadImplicitRules(); void loadTestProviders(); DRC_RULE* createImplicitRule( const wxString& name ); @@ -179,10 +176,16 @@ protected: std::vector m_ruleConditions; std::vector m_rules; std::vector m_testProviders; + + EDA_UNITS m_userUnits; std::vector m_errorLimits; + bool m_testTracksAgainstZones; + bool m_reportAllTrackErrors; + bool m_testFootprints; // constraint -> rule -> provider - std::unordered_map m_constraintMap; + std::unordered_map< DRC_CONSTRAINT_TYPE_T, + std::vector* > m_constraintMap; DRC_VIOLATION_HANDLER m_violationHandler; REPORTER* m_reporter; diff --git a/pcbnew/drc/drc_item.h b/pcbnew/drc/drc_item.h index 7f7fed8374..2c9adb9b8f 100644 --- a/pcbnew/drc/drc_item.h +++ b/pcbnew/drc/drc_item.h @@ -31,6 +31,50 @@ class PCB_BASE_FRAME; class DRC_RULE; 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 { public: diff --git a/pcbnew/drc/drc_keepout_tester.cpp b/pcbnew/drc/drc_keepout_tester.cpp deleted file mode 100644 index 04d074eba5..0000000000 --- a/pcbnew/drc/drc_keepout_tester.cpp +++ /dev/null @@ -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 -#include -#include -#include -#include - -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 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 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( 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 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 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 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 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 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; -} - - diff --git a/pcbnew/drc/drc_keepout_tester.h b/pcbnew/drc/drc_keepout_tester.h deleted file mode 100644 index d8d484a40b..0000000000 --- a/pcbnew/drc/drc_keepout_tester.h +++ /dev/null @@ -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 - - -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 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 diff --git a/pcbnew/drc/drc_results_provider.h b/pcbnew/drc/drc_results_provider.h index 22f93f21f6..62bb51a068 100644 --- a/pcbnew/drc/drc_results_provider.h +++ b/pcbnew/drc/drc_results_provider.h @@ -1,7 +1,7 @@ /* * 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 * modify it under the terms of the GNU General Public License @@ -28,58 +28,11 @@ #include #include #include -#include #include #include #include -/** - * 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; - - /** - * 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 * is an implementation of the RC_ITEMS_PROVIDER interface which uses a BOARD instance diff --git a/pcbnew/drc/drc_test_provider.cpp b/pcbnew/drc/drc_test_provider.cpp index e9c399365a..0029f1e4ca 100644 --- a/pcbnew/drc/drc_test_provider.cpp +++ b/pcbnew/drc/drc_test_provider.cpp @@ -39,27 +39,27 @@ const wxString DRC_TEST_PROVIDER::GetName() const { return ""; } const wxString DRC_TEST_PROVIDER::GetDescription() const { return ""; } -void DRC_TEST_PROVIDER::ReportViolation( std::shared_ptr aItem, wxPoint aPos ) +void DRC_TEST_PROVIDER::reportViolation( std::shared_ptr item, wxPoint aMarkerPos ) { - aItem->SetViolatingTest( this ); - m_drcEngine->ReportViolation( aItem, aPos ); + item->SetViolatingTest( this ); + m_drcEngine->ReportViolation( item, aMarkerPos ); } -void DRC_TEST_PROVIDER::ReportProgress( double aProgress ) +void DRC_TEST_PROVIDER::reportProgress( double 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 ); - ReportAux( aStageName ); + m_drcEngine->ReportStage( aStageName ); + reportAux( aStageName ); } -void DRC_TEST_PROVIDER::ReportAux( wxString fmt, ... ) +void DRC_TEST_PROVIDER::reportAux( wxString fmt, ... ) { va_list vargs; va_start( vargs, fmt ); @@ -83,7 +83,7 @@ void DRC_TEST_PROVIDER::accountCheck( const DRC_RULE* ruleToTest ) if( it == m_stats.end() ) m_stats[ ruleToTest ] = 1; else - it->second++; + m_stats[ ruleToTest ] += 1; } @@ -98,13 +98,16 @@ void DRC_TEST_PROVIDER::reportRuleStatistics() if( !m_isRuleDriven ) return; - m_drcEngine->ReportAux("Rule hit statistics: "); + m_drcEngine->ReportAux( "Rule hit statistics: " ); for( const std::pair& stat : m_stats ) { - m_drcEngine->ReportAux( wxString::Format( " - rule '%s': %d hits ", - stat.first->m_Name, - stat.second ) ); + if( stat.first ) + { + m_drcEngine->ReportAux( wxString::Format( " - rule '%s': %d hits ", + stat.first->m_Name, + stat.second ) ); + } } } diff --git a/pcbnew/drc/drc_test_provider.h b/pcbnew/drc/drc_test_provider.h index 0ecb45009d..0874c990b2 100644 --- a/pcbnew/drc/drc_test_provider.h +++ b/pcbnew/drc/drc_test_provider.h @@ -67,7 +67,7 @@ public: /** * 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. + * #BOARD and spits out #DRC_ITEMs and positions as needed. */ class DRC_TEST_PROVIDER { @@ -82,23 +82,16 @@ public: /** * 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 const wxString GetName() const; virtual const wxString GetDescription() const; - virtual void ReportAux( wxString fmt, ... ); - virtual void ReportViolation( std::shared_ptr item, wxPoint aMarkerPos ); - virtual void ReportProgress( double aProgress ); - virtual void ReportStage ( const wxString& aStageName, int index, int total ); - virtual std::set GetConstraintTypes() const = 0; + virtual int GetNumPhases() const = 0; + virtual bool IsRuleDriven() const { return m_isRuleDriven; @@ -108,6 +101,11 @@ protected: int forEachGeometryItem( const std::vector& aTypes, LSET aLayers, const std::function& aFunc ); + virtual void reportAux( wxString fmt, ... ); + virtual void reportViolation( std::shared_ptr item, wxPoint aMarkerPos ); + virtual void reportProgress( double aProgress ); + virtual void reportStage( const wxString& aStageName ); + virtual void reportRuleStatistics(); virtual void accountCheck( const DRC_RULE* ruleToTest ); virtual void accountCheck( const DRC_CONSTRAINT& constraintToTest ); diff --git a/pcbnew/drc/drc_test_provider_annulus.cpp b/pcbnew/drc/drc_test_provider_annulus.cpp index dbac1a0d04..b3142464f0 100644 --- a/pcbnew/drc/drc_test_provider_annulus.cpp +++ b/pcbnew/drc/drc_test_provider_annulus.cpp @@ -63,6 +63,8 @@ public: } virtual std::set 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 ) ) { - ReportAux( "No annulus constraints found. Skipping check." ); + reportAux( "No annulus constraints found. Skipping check." ); return false; } - ReportStage( _( "Testing via annular rings" ), 0, 2 ); + reportStage( _( "Via annular rings..." )); auto checkAnnulus = [&]( 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)" ), constraint.GetName(), - fail_min ? _( "minimum" ) : _( "maximum" ), + fail_min ? _( "min" ) : _( "max" ), MessageTextFromValue( userUnits(), annulus, true ), MessageTextFromValue( userUnits(), fail_min ? v_min : v_max, true ) ); @@ -125,7 +127,7 @@ bool DRC_TEST_PROVIDER_ANNULUS::Run() drcItem->SetItems( item ); drcItem->SetViolatingRule( constraint.GetParentRule() ); - ReportViolation( drcItem, via->GetPosition() ); + reportViolation( drcItem, via->GetPosition()); } return true; @@ -139,6 +141,12 @@ bool DRC_TEST_PROVIDER_ANNULUS::Run() } +int DRC_TEST_PROVIDER_ANNULUS::GetNumPhases() const +{ + return 1; +} + + std::set DRC_TEST_PROVIDER_ANNULUS::GetConstraintTypes() const { return { DRC_CONSTRAINT_TYPE_ANNULUS_WIDTH }; diff --git a/pcbnew/drc/drc_test_provider_connectivity.cpp b/pcbnew/drc/drc_test_provider_connectivity.cpp index b0ed275343..d8dc2c2b7e 100644 --- a/pcbnew/drc/drc_test_provider_connectivity.cpp +++ b/pcbnew/drc/drc_test_provider_connectivity.cpp @@ -66,12 +66,14 @@ public: } virtual std::set GetConstraintTypes() const override; + + int GetNumPhases() const override; }; bool DRC_TEST_PROVIDER_CONNECTIVITY::Run() { - ReportStage( _( "Testing dangling pads/vias" ), 0, 2 ); + reportStage( _( "Dangling pads/vias..." )); BOARD* board = m_drcEngine->GetBoard(); @@ -100,11 +102,11 @@ bool DRC_TEST_PROVIDER_CONNECTIVITY::Run() { std::shared_ptr drcItem = DRC_ITEM::Create( code ); drcItem->SetItems( track ); - ReportViolation( drcItem, pos ); + reportViolation( drcItem, pos ); } } - ReportStage( _( "Testing starved zones" ), 0, 2 ); + reportStage( _( "Starved zones..." )); /* test starved zones */ for( ZONE_CONTAINER* zone : board->Zones() ) @@ -125,11 +127,11 @@ bool DRC_TEST_PROVIDER_CONNECTIVITY::Run() { std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_ZONE_HAS_EMPTY_NET ); drcItem->SetItems( zone ); - ReportViolation( drcItem, zone->GetPosition() ); + reportViolation( drcItem, zone->GetPosition()); } } - ReportStage( _( "Testing unconnected nets" ), 0, 2 ); + reportStage( _( "Unconnected nets..." )); connectivity->RecalculateRatsnest(); std::vector edges; @@ -142,7 +144,7 @@ bool DRC_TEST_PROVIDER_CONNECTIVITY::Run() std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_UNCONNECTED_ITEMS ); drcItem->SetItems( edge.GetSourceNode()->Parent(), edge.GetTargetNode()->Parent() ); - ReportViolation( drcItem, (wxPoint) edge.GetSourceNode()->Pos() ); + reportViolation( drcItem, (wxPoint) edge.GetSourceNode()->Pos()); } reportRuleStatistics(); @@ -151,6 +153,12 @@ bool DRC_TEST_PROVIDER_CONNECTIVITY::Run() } +int DRC_TEST_PROVIDER_CONNECTIVITY::GetNumPhases() const +{ + return 3; +} + + std::set DRC_TEST_PROVIDER_CONNECTIVITY::GetConstraintTypes() const { return {}; diff --git a/pcbnew/drc/drc_test_provider_copper_clearance.cpp b/pcbnew/drc/drc_test_provider_copper_clearance.cpp index 31cd1fe0be..d601d57bd0 100644 --- a/pcbnew/drc/drc_test_provider_copper_clearance.cpp +++ b/pcbnew/drc/drc_test_provider_copper_clearance.cpp @@ -75,10 +75,12 @@ public: virtual std::set GetConstraintTypes() const override; + int GetNumPhases() const override; + private: void testPadClearances(); - void testTrackClearances( bool aTestZones ); + void testTrackClearances(); void testCopperTextAndGraphics(); @@ -87,7 +89,7 @@ private: void testCopperDrawItem( BOARD_ITEM* aItem ); 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 ); }; @@ -105,22 +107,22 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::Run() } else { - ReportAux( "No Clearance constraints found..." ); + reportAux( "No Clearance constraints found..." ); 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(); - ReportStage( _( "Testing track/via copper clerances" ), 1, 2 ); - testTrackClearances( m_drcEngine->GetTestTracksAgainstZones() ); + reportStage( _( "Track/via clerances..." )); + testTrackClearances(); - ReportStage( _( "Testing copper drawing/text clerances" ), 1, 2 ); + reportStage( _( "Copper drawing/text clerances..." )); testCopperTextAndGraphics(); - ReportStage( _( "Testing copper zone clearances" ), 1, 2 ); + reportStage( _( "Zone clearances..." )); testZones(); reportRuleStatistics(); @@ -230,7 +232,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* aItem ) drcItem->SetItems( track, aItem ); 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 - // 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; 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->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 int count = m_board->Tracks().size(); - ReportProgress( 0.0 ); - ReportAux( "Testing %d tracks...", count ); + reportProgress( 0.0 ); + reportAux( "Testing %d tracks...", count ); int ii = 0; for( auto seg_it = m_board->Tracks().begin(); seg_it != m_board->Tracks().end(); seg_it++ ) { if( (ii % delta) == 0) - ReportProgress( (double) ii / (double) m_board->Tracks().size() ); + reportProgress((double) ii / (double) m_board->Tracks().size()); ii++; // Test segment against tracks and pads, optionally against copper zones 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, TRACKS::iterator aStartIt, - TRACKS::iterator aEndIt, bool aTestZones ) + TRACKS::iterator aEndIt ) { 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->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->SetViolatingRule( constraint.GetParentRule() ); - ReportViolation( drcItem, (wxPoint) intersection.get() ); + reportViolation( drcItem, (wxPoint) intersection.get()); } 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->SetViolatingRule( constraint.GetParentRule() ); - ReportViolation( drcItem, pos ); + reportViolation( drcItem, pos ); + + if( !m_drcEngine->GetReportAllTrackErrors() ) + break; } } /***************************************/ /* 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() ); @@ -490,7 +495,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_I drcItem->SetItems( aRefSeg, zone ); 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 ); - ReportAux( "Testing %d pads...", sortedPads.size() ); + reportAux( "Testing %d pads...", sortedPads.size()); if( sortedPads.empty() ) return; @@ -533,7 +538,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( ) for( D_PAD* pad : sortedPads ) { if( ii % 100 == 0 ) - ReportProgress( (double) ii / (double) sortedPads.size() ); + reportProgress((double) ii / (double) sortedPads.size()); ii++; 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->SetItems( pad, aRefPad ); - ReportViolation( drcItem, aRefPad->GetPosition() ); + reportViolation( drcItem, aRefPad->GetPosition()); } continue; @@ -630,7 +635,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doPadToPadsDrc( D_PAD* aRefPad, D_PAD** drcItem->SetItems( aRefPad, pad ); drcItem->SetViolatingRule( constraint.GetParentRule() ); - ReportViolation( drcItem, aRefPad->GetPosition() ); + reportViolation( drcItem, aRefPad->GetPosition()); break; } } @@ -711,7 +716,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZones() drcItem->SetItems( zoneRef, zoneToTest ); 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->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->SetViolatingRule( constraint.GetParentRule() ); - ReportViolation( drcItem, conflict.first ); + reportViolation( drcItem, conflict.first ); } } } } +int DRC_TEST_PROVIDER_COPPER_CLEARANCE::GetNumPhases() const +{ + return 4; +} + + std::set DRC_TEST_PROVIDER_COPPER_CLEARANCE::GetConstraintTypes() const { return { DRC_CONSTRAINT_TYPE_CLEARANCE }; diff --git a/pcbnew/drc/drc_test_provider_courtyard_clearance.cpp b/pcbnew/drc/drc_test_provider_courtyard_clearance.cpp index 76a1d31324..50f1a90714 100644 --- a/pcbnew/drc/drc_test_provider_courtyard_clearance.cpp +++ b/pcbnew/drc/drc_test_provider_courtyard_clearance.cpp @@ -65,6 +65,8 @@ public: virtual std::set GetConstraintTypes() const override; + int GetNumPhases() const override; + private: void testFootprintCourtyardDefinitions(); @@ -75,7 +77,7 @@ private: void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions() { // Detects missing (or malformed) footprint courtyards - ReportStage( _( "Testing component courtyard definitions" ), 0, 2 ); + reportStage( _( "Footprint courtyard definitions..." )); for( MODULE* footprint : m_board->Modules() ) { @@ -89,7 +91,7 @@ void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions() std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_MISSING_COURTYARD ); drcItem->SetItems( footprint ); - ReportViolation( drcItem, footprint->GetPosition() ); + reportViolation( drcItem, footprint->GetPosition()); } else { @@ -108,7 +110,7 @@ void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions() drcItem->SetErrorMessage( m_msg ); 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() { - ReportStage( _( "Testing component courtyard overlap" ), 0, 2 ); + reportStage( _( "Footprint courtyard overlap..." )); 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 drcItem = DRC_ITEM::Create( DRCE_OVERLAPPING_FOOTPRINTS ); 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_TEST_PROVIDER_COURTYARD_CLEARANCE::GetConstraintTypes() const { return { DRC_CONSTRAINT_TYPE_COURTYARD_CLEARANCE }; diff --git a/pcbnew/drc/drc_test_provider_disallow.cpp b/pcbnew/drc/drc_test_provider_disallow.cpp index f0d48416e6..ee66688242 100644 --- a/pcbnew/drc/drc_test_provider_disallow.cpp +++ b/pcbnew/drc/drc_test_provider_disallow.cpp @@ -21,11 +21,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -//#include #include - -//#include - #include #include #include @@ -62,18 +58,20 @@ public: } virtual std::set GetConstraintTypes() const override; + + int GetNumPhases() const override; }; 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; } - ReportStage( _( "Testing disallow constraints" ), 0, 2 ); + reportStage( _( "Keepouts & disallow constraints..." )); auto checkItem = [&]( BOARD_ITEM *item ) -> bool { @@ -93,7 +91,7 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run() drcItem->SetItems( item ); drcItem->SetViolatingRule( constraint.GetParentRule() ); - ReportViolation( drcItem, item->GetPosition() ); + reportViolation( drcItem, item->GetPosition()); } return true; @@ -107,6 +105,12 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run() } +int DRC_TEST_PROVIDER_DISALLOW::GetNumPhases() const +{ + return 1; +} + + std::set DRC_TEST_PROVIDER_DISALLOW::GetConstraintTypes() const { return { DRC_CONSTRAINT_TYPE_DISALLOW }; diff --git a/pcbnew/drc/drc_test_provider_edge_clearance.cpp b/pcbnew/drc/drc_test_provider_edge_clearance.cpp index febdfd476c..395663448f 100644 --- a/pcbnew/drc/drc_test_provider_edge_clearance.cpp +++ b/pcbnew/drc/drc_test_provider_edge_clearance.cpp @@ -66,6 +66,8 @@ public: } virtual std::set GetConstraintTypes() const override; + + int GetNumPhases() const override; }; @@ -82,13 +84,13 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run() } else { - ReportAux("No Clearance constraints found..."); + reportAux( "No Clearance constraints found..." ); 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 boardOutline; std::vector boardItems; @@ -108,12 +110,13 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run() }; forEachGeometryItem( { PCB_LINE_T }, LSET( Edge_Cuts ), queryBoardOutlineItems ); - forEachGeometryItem( {}, LSET::AllTechMask() | LSET::AllCuMask(), queryBoardGeometryItems ); + forEachGeometryItem( {}, LSET::AllCuMask(), queryBoardGeometryItems ); wxString 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 ) { @@ -154,7 +157,7 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run() drcItem->SetItems( outlineItem, boardItem ); 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_TEST_PROVIDER_EDGE_CLEARANCE::GetConstraintTypes() const { return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE }; diff --git a/pcbnew/drc/drc_test_provider_hole_clearance.cpp b/pcbnew/drc/drc_test_provider_hole_clearance.cpp index 565da2805d..71e2a4b760 100644 --- a/pcbnew/drc/drc_test_provider_hole_clearance.cpp +++ b/pcbnew/drc/drc_test_provider_hole_clearance.cpp @@ -67,6 +67,8 @@ public: virtual std::set GetConstraintTypes() const override; + int GetNumPhases() const override; + private: 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 ) ) { m_largestClearance = worstClearanceConstraint.GetValue().Min(); + reportAux( "Worst hole clearance : %d nm", m_largestClearance ); } else { - ReportAux( "No Clearance constraints found..." ); + reportAux( "No hole clearance constraints found..." ); return false; } - ReportAux( "Worst hole clearance : %d nm", m_largestClearance ); - buildDrilledHoleList(); - ReportStage( _( "Testing hole<->pad clearances" ), 0, 2 ); + reportStage( _( "Hole to pad clearances..." )); testPads2Holes(); - ReportStage( _( "Testing hole<->hole clearances" ), 0, 2 ); + reportStage( _( "Hole to hole clearances..." )); testHoles2Holes(); 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() @@ -277,7 +278,7 @@ bool DRC_TEST_PROVIDER_HOLE_CLEARANCE::doPadToPadHoleDrc( D_PAD* aRefPad, D_PAD drcItem->SetItems( pad, aRefPad ); drcItem->SetViolatingRule( constraint.GetParentRule() ); - ReportViolation( drcItem, pad->GetPosition() ); + reportViolation( drcItem, pad->GetPosition()); return false; } } @@ -310,7 +311,7 @@ bool DRC_TEST_PROVIDER_HOLE_CLEARANCE::doPadToPadHoleDrc( D_PAD* aRefPad, D_PAD drcItem->SetItems( aRefPad, pad ); drcItem->SetViolatingRule( constraint.GetParentRule() ); - ReportViolation( drcItem, pad->GetPosition() ); + reportViolation( drcItem, pad->GetPosition()); return false; } } @@ -395,13 +396,19 @@ void DRC_TEST_PROVIDER_HOLE_CLEARANCE::testHoles2Holes() drcItem->SetItems( refHole.m_owner, checkHole.m_owner ); 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_TEST_PROVIDER_HOLE_CLEARANCE::GetConstraintTypes() const { return { DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE }; diff --git a/pcbnew/drc/drc_test_provider_hole_size.cpp b/pcbnew/drc/drc_test_provider_hole_size.cpp index c74bc598e5..852d240bef 100644 --- a/pcbnew/drc/drc_test_provider_hole_size.cpp +++ b/pcbnew/drc/drc_test_provider_hole_size.cpp @@ -64,6 +64,8 @@ public: virtual std::set GetConstraintTypes() const override; + int GetNumPhases() const override; + private: void checkVia( VIA* via, bool aExceedMicro, bool aExceedStd ); void checkPad( D_PAD* aPad ); @@ -74,7 +76,7 @@ private: bool DRC_TEST_PROVIDER_HOLE_SIZE::Run() { - ReportStage( _( "Testing pad holes" ), 0, 2 ); + reportStage( _( "Pad holes..." )); 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 vias; @@ -145,7 +147,7 @@ void DRC_TEST_PROVIDER_HOLE_SIZE::checkPad( D_PAD* aPad ) drcItem->SetItems( aPad ); 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->SetViolatingRule( constraint.GetParentRule() ); - ReportViolation( drcItem, via->GetPosition() ); + reportViolation( drcItem, via->GetPosition()); } } +int DRC_TEST_PROVIDER_HOLE_SIZE::GetNumPhases() const +{ + return 2; +} + + std::set DRC_TEST_PROVIDER_HOLE_SIZE::GetConstraintTypes() const { return { DRC_CONSTRAINT_TYPE_HOLE_SIZE }; diff --git a/pcbnew/drc/drc_test_provider_lvs.cpp b/pcbnew/drc/drc_test_provider_lvs.cpp index ca1f321fab..1ca0364084 100644 --- a/pcbnew/drc/drc_test_provider_lvs.cpp +++ b/pcbnew/drc/drc_test_provider_lvs.cpp @@ -70,9 +70,9 @@ public: virtual std::set GetConstraintTypes() const override; -private: + int GetNumPhases() const override; - bool fetchNetlistFromSchematic( NETLIST& aNetlist ); +private: void testFootprints( NETLIST& aNetlist ); }; @@ -101,7 +101,7 @@ void DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist ) std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_DUPLICATE_FOOTPRINT ); 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 drcItem = DRC_ITEM::Create( DRCE_MISSING_FOOTPRINT ); drcItem->SetErrorMessage( m_msg ); - ReportViolation( drcItem, wxPoint() ); + reportViolation( drcItem, wxPoint()); } else { @@ -142,7 +142,7 @@ void DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist ) std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT ); drcItem->SetErrorMessage( m_msg ); drcItem->SetItems( pad ); - ReportViolation( drcItem, module->GetPosition() ); + reportViolation( drcItem, module->GetPosition()); } else if( pcb_netname.IsEmpty() && !sch_net.GetNetName().IsEmpty() ) { @@ -152,7 +152,7 @@ void DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist ) std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT ); drcItem->SetErrorMessage( m_msg ); drcItem->SetItems( pad ); - ReportViolation( drcItem, module->GetPosition() ); + reportViolation( drcItem, module->GetPosition()); } else if( pcb_netname != sch_net.GetNetName() ) { @@ -163,7 +163,7 @@ void DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist ) std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT ); drcItem->SetErrorMessage( m_msg ); 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 drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT ); drcItem->SetErrorMessage( m_msg ); 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 drcItem = DRC_ITEM::Create( DRCE_EXTRA_FOOTPRINT ); 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() { - ReportStage( _( "Layout-vs-Schematic checks..." ), 0, 2 ); - -#if 0 - - if ( !Kiface().IsSingle() ) + if( m_drcEngine->GetTestFootprints() ) { - NETLIST netlist; // fixme: fetch from schematic without referring directly to the FRAME + reportStage( _( "Layout-vs-Schematic checks..." )); - if( ! fetchNetlistFromSchematic( netlist ) ) - { - ReportAux( _( "Unable to fetch the schematic netlist. Skipping LVS checks. ") ); - return true; - } - - testFootprints( netlist ); + testFootprints( *m_drcEngine->GetSchematicNetlist() ); + + reportRuleStatistics(); } -#endif - - reportRuleStatistics(); return true; } +int DRC_TEST_PROVIDER_LVS::GetNumPhases() const +{ + return m_drcEngine->GetTestFootprints() ? 1 : 0; +} + + std::set DRC_TEST_PROVIDER_LVS::GetConstraintTypes() const { return {}; diff --git a/pcbnew/drc/drc_test_provider_misc.cpp b/pcbnew/drc/drc_test_provider_misc.cpp index 33fbb8913d..c82901d132 100644 --- a/pcbnew/drc/drc_test_provider_misc.cpp +++ b/pcbnew/drc/drc_test_provider_misc.cpp @@ -68,6 +68,8 @@ public: virtual std::set GetConstraintTypes() const override; + int GetNumPhases() const override; + private: void testOutline(); void testDisabledLayers(); @@ -93,7 +95,7 @@ void DRC_TEST_PROVIDER_MISC::testOutline() drcItem->SetErrorMessage( m_msg ); 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->SetItems( item ); - ReportViolation( drcItem, item->GetPosition() ); + reportViolation( drcItem, item->GetPosition()); } return true; }; @@ -144,7 +146,7 @@ void DRC_TEST_PROVIDER_MISC::testTextVars() std::shared_ptrdrcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE ); drcItem->SetItems( item ); - ReportViolation( drcItem, item->GetPosition() ); + reportViolation( drcItem, item->GetPosition()); } return true; }; @@ -179,7 +181,7 @@ void DRC_TEST_PROVIDER_MISC::testTextVars() std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE ); 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(); - ReportStage( _( "Test board outline" ), 0, 3 ); + reportStage( _( "Board outline..." )); testOutline(); - ReportStage( _( "Test disabled layers" ), 1, 3 ); + reportStage( _( "Disabled layers..." )); testDisabledLayers(); - ReportStage( _( "Test text variables" ), 2, 3 ); + reportStage( _( "Text variables..." )); testTextVars(); return true; } +int DRC_TEST_PROVIDER_MISC::GetNumPhases() const +{ + return 3; +} + + std::set DRC_TEST_PROVIDER_MISC::GetConstraintTypes() const { return {}; diff --git a/pcbnew/drc/drc_test_provider_track_width.cpp b/pcbnew/drc/drc_test_provider_track_width.cpp index 22060dd010..20d8a7a9db 100644 --- a/pcbnew/drc/drc_test_provider_track_width.cpp +++ b/pcbnew/drc/drc_test_provider_track_width.cpp @@ -60,6 +60,8 @@ public: } virtual std::set 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 ) ) { - ReportAux( "No track width constraints found. Skipping check." ); + reportAux( "No track width constraints found. Skipping check." ); return false; } - ReportStage( _( "Testing track widths" ), 0, 2 ); + reportStage( _( "Track widths..." )); auto checkTrackWidth = [&]( 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)" ), constraint.GetName(), - fail_min ? _( "minimum" ) : _( "maximum" ), - MessageTextFromValue( userUnits(), constraintWidth, true ) ); - MessageTextFromValue( userUnits(), actual, true ), + fail_min ? _( "min" ) : _( "max" ), + MessageTextFromValue( userUnits(), constraintWidth, true ), + MessageTextFromValue( userUnits(), actual, true ) ); drcItem->SetErrorMessage( m_msg ); drcItem->SetItems( item ); drcItem->SetViolatingRule( constraint.GetParentRule() ); - ReportViolation( drcItem, p0 ); + reportViolation( drcItem, p0 ); } 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_TEST_PROVIDER_TRACK_WIDTH::GetConstraintTypes() const { return { DRC_CONSTRAINT_TYPE_TRACK_WIDTH }; diff --git a/pcbnew/drc/drc_test_provider_via_diameter.cpp b/pcbnew/drc/drc_test_provider_via_diameter.cpp index 986e094005..32822955d1 100644 --- a/pcbnew/drc/drc_test_provider_via_diameter.cpp +++ b/pcbnew/drc/drc_test_provider_via_diameter.cpp @@ -61,6 +61,8 @@ public: } virtual std::set 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 ) ) { - ReportAux( "No diameter constraints found. Skipping check." ); + reportAux( "No diameter constraints found. Skipping check." ); return false; } - ReportStage( ( "Testing via diameters" ), 0, 2 ); + reportStage(( "Via diameters..." )); auto checkViaDiameter = [&]( 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)" ), constraint.GetName(), - fail_min ? _( "minimum" ) : _( "maximum" ), + fail_min ? _( "min" ) : _( "max" ), MessageTextFromValue( userUnits(), constraintDiameter, true ) ); MessageTextFromValue( userUnits(), actual, true ), @@ -119,7 +121,7 @@ bool DRC_TEST_PROVIDER_VIA_DIAMETER::Run() drcItem->SetItems( item ); drcItem->SetViolatingRule( constraint.GetParentRule() ); - ReportViolation( drcItem, via->GetPosition() ); + reportViolation( drcItem, via->GetPosition()); } 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_TEST_PROVIDER_VIA_DIAMETER::GetConstraintTypes() const { return { DRC_CONSTRAINT_TYPE_VIA_DIAMETER }; diff --git a/pcbnew/drc/drc_textvar_tester.cpp b/pcbnew/drc/drc_textvar_tester.cpp deleted file mode 100644 index bd916a4251..0000000000 --- a/pcbnew/drc/drc_textvar_tester.cpp +++ /dev/null @@ -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 - -#include -#include -#include -#include - -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( child ); - - if( text->GetShownText().Matches( wxT( "*${*}*" ) ) ) - { - std::shared_ptr 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( drawing ); - - if( text->GetShownText().Matches( wxT( "*${*}*" ) ) ) - { - std::shared_ptr 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( item ) ) - { - if( text->GetShownText().Matches( wxT( "*${*}*" ) ) ) - { - std::shared_ptr 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; -} - - diff --git a/pcbnew/drc/drc_textvar_tester.h b/pcbnew/drc/drc_textvar_tester.h deleted file mode 100644 index b453560b35..0000000000 --- a/pcbnew/drc/drc_textvar_tester.h +++ /dev/null @@ -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 - - -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 diff --git a/pcbnew/drc/footprint_tester.cpp b/pcbnew/drc/footprint_tester.cpp deleted file mode 100644 index 499e7f6b3d..0000000000 --- a/pcbnew/drc/footprint_tester.cpp +++ /dev/null @@ -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 -#include -#include -#include - -void TestFootprints( NETLIST& aNetlist, BOARD* aBoard, std::vector >& aDRCList ) -{ - wxString msg; - - auto comp = []( const MODULE* x, const MODULE* y ) - { - return x->GetReference().CmpNoCase( y->GetReference() ) < 0; - }; - auto mods = std::set( 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 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 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 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 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 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 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 item = DRC_ITEM::Create( DRCE_EXTRA_FOOTPRINT ); - item->SetItems( module ); - aDRCList.push_back( item ); - } - } - } -} diff --git a/pcbnew/drc/footprint_tester.h b/pcbnew/drc/footprint_tester.h deleted file mode 100644 index a492b25712..0000000000 --- a/pcbnew/drc/footprint_tester.h +++ /dev/null @@ -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 - -class BOARD; - - -void TestFootprints( NETLIST& aNetlist, BOARD* aBoard, std::vector >& aDRCList ); - -#endif // FOOTPRINT_TESTER_H diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp index f0e57b640b..e2b9519592 100644 --- a/pcbnew/pcb_edit_frame.cpp +++ b/pcbnew/pcb_edit_frame.cpp @@ -64,6 +64,7 @@ #include #include #include +#include #include #include #include @@ -504,6 +505,7 @@ void PCB_EDIT_FRAME::setupTools() m_toolManager->RegisterTool( new ZONE_FILLER_TOOL ); m_toolManager->RegisterTool( new AUTOPLACE_TOOL ); m_toolManager->RegisterTool( new DRC ); + m_toolManager->RegisterTool( new DRC_TOOL ); m_toolManager->RegisterTool( new PCB_VIEWER_TOOLS ); m_toolManager->RegisterTool( new CONVERT_TOOL ); m_toolManager->InitTools(); @@ -573,7 +575,7 @@ void PCB_EDIT_FRAME::setupUIConditions() auto enableBoardSetupCondition = [this] ( const SELECTION& ) { - if( DRC* tool = m_toolManager->GetTool() ) + if( DRC_TOOL* tool = m_toolManager->GetTool() ) return !tool->IsDRCDialogShown(); return true; diff --git a/pcbnew/tools/drc_tool.cpp b/pcbnew/tools/drc_tool.cpp new file mode 100644 index 0000000000..0d073d68b8 --- /dev/null +++ b/pcbnew/tools/drc_tool.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +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(); + + 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(); + + 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& 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() ); +} + + diff --git a/pcbnew/tools/drc_tool.h b/pcbnew/tools/drc_tool.h new file mode 100644 index 0000000000..a8b61204fa --- /dev/null +++ b/pcbnew/tools/drc_tool.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + + +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> m_unconnected; // list of unconnected pads + std::vector> 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 diff --git a/pcbnew/tools/pcb_inspection_tool.cpp b/pcbnew/tools/pcb_inspection_tool.cpp index 81a9c0d41c..d5bb692bcf 100644 --- a/pcbnew/tools/pcb_inspection_tool.cpp +++ b/pcbnew/tools/pcb_inspection_tool.cpp @@ -194,6 +194,8 @@ void PCB_INSPECTION_TOOL::reportCopperClearance( PCB_LAYER_ID aLayer, BOARD_CONN if( r ) { wxString clearance = StringFromValue( r->GetUnits(), constraint.m_Value.Min(), true ); + + r->Report( "" ); r->Report( wxString::Format( _( "Clearance: %s." ), clearance ) ); } diff --git a/pcbnew/tools/zone_filler_tool.cpp b/pcbnew/tools/zone_filler_tool.cpp index aa5b52a544..7515de7fc5 100644 --- a/pcbnew/tools/zone_filler_tool.cpp +++ b/pcbnew/tools/zone_filler_tool.cpp @@ -30,9 +30,7 @@ #include #include #include -#include #include "pcb_actions.h" -#include "selection_tool.h" #include "zone_filler_tool.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()->m_ZoneFillsDirty ) return; @@ -66,7 +64,11 @@ void ZONE_FILLER_TOOL::CheckAllZones( wxWindow* aCaller ) BOARD_COMMIT commit( this ); ZONE_FILLER filler( frame()->GetBoard(), &commit ); - filler.InstallNewProgressReporter( aCaller, _( "Checking Zones" ), 4 ); + + if( aReporter ) + filler.SetProgressReporter( aReporter ); + else + filler.InstallNewProgressReporter( aCaller, _( "Checking Zones" ), 4 ); 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 toFill; @@ -99,7 +101,11 @@ void ZONE_FILLER_TOOL::FillAllZones( wxWindow* aCaller ) toFill.push_back(zone); ZONE_FILLER filler( board(), &commit ); - filler.InstallNewProgressReporter( aCaller, _( "Fill All Zones" ), 4 ); + + if( aReporter ) + filler.SetProgressReporter( aReporter ); + else + filler.InstallNewProgressReporter( aCaller, _( "Fill All Zones" ), 4 ); if( filler.Fill( toFill ) ) { diff --git a/pcbnew/tools/zone_filler_tool.h b/pcbnew/tools/zone_filler_tool.h index 30c5c1fd7f..55610bb8ca 100644 --- a/pcbnew/tools/zone_filler_tool.h +++ b/pcbnew/tools/zone_filler_tool.h @@ -29,6 +29,8 @@ class PCB_EDIT_FRAME; +class WX_PROGRESS_REPORTER; + /** * ZONE_FILLER_TOOL @@ -44,8 +46,8 @@ public: /// @copydoc TOOL_INTERACTIVE::Reset() void Reset( RESET_REASON aReason ) override; - void CheckAllZones( wxWindow* aCaller ); - void FillAllZones( wxWindow* aCaller ); + void CheckAllZones( wxWindow* aCaller, WX_PROGRESS_REPORTER* aReporter = nullptr ); + void FillAllZones( wxWindow* aCaller, WX_PROGRESS_REPORTER* aReporter = nullptr ); int ZoneFill( const TOOL_EVENT& aEvent ); int ZoneFillAll( const TOOL_EVENT& aEvent ); diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp index e05c663eff..8876fb76c4 100644 --- a/pcbnew/zone_filler.cpp +++ b/pcbnew/zone_filler.cpp @@ -96,7 +96,13 @@ void ZONE_FILLER::InstallNewProgressReporter( wxWindow* aParent, const wxString& int aNumPhases ) { m_uniqueReporter = std::make_unique( 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& aZones, bool aCheck m_progressReporter->Report( aCheck ? _( "Checking zone fills..." ) : _( "Building zone fills..." ) ); m_progressReporter->SetMaxProgress( aZones.size() ); + m_progressReporter->KeepRefreshing(); } // 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& aZones, bool aCheck m_brdOutlinesValid = m_board->GetBoardPolygonOutlines( m_boardOutline ); // 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() ) pad->BuildEffectiveShapes( UNDEFINED_LAYER ); @@ -263,8 +270,6 @@ bool ZONE_FILLER::Fill( const std::vector& aZones, bool aCheck } // Now remove insulated copper islands and islands outside the board edge - bool outOfDate = false; - for( auto& zone : islandsList ) { for( PCB_LAYER_ID layer : zone.m_zone->GetLayerSet().Seq() ) @@ -322,25 +327,45 @@ bool ZONE_FILLER::Fill( const std::vector& aZones, bool aCheck zone.m_zone->SetFilledPolysList( layer, poly ); zone.m_zone->CalculateFilledArea(); - if( aCheck && zone.m_zone->GetHashValue( layer ) != poly.GetHash() ) - outOfDate = true; - if( m_progressReporter && m_progressReporter->IsCancelled() ) return false; } } - if( aCheck && outOfDate ) + if( aCheck ) { - PROGRESS_REPORTER_HIDER raii( m_progressReporter ); - KIDIALOG dlg( m_progressReporter->GetParent(), - _( "Zone fills are out-of-date. Refill?" ), - _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING ); - dlg.SetOKCancelLabels( _( "Refill" ), _( "Continue without Refill" ) ); - dlg.DoNotShowCheckbox( __FILE__, __LINE__ ); + bool outOfDate = false; - if( dlg.ShowModal() == wxID_CANCEL ) - return 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 ); + KIDIALOG dlg( m_progressReporter->GetParent(), + _( "Zone fills are out-of-date. Refill?" ), + _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING ); + dlg.SetOKCancelLabels( _( "Refill" ), _( "Continue without Refill" ) ); + dlg.DoNotShowCheckbox( __FILE__, __LINE__ ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return false; + } } if( m_progressReporter ) @@ -406,7 +431,6 @@ bool ZONE_FILLER::Fill( const std::vector& aZones, bool aCheck return false; m_progressReporter->AdvancePhase(); - m_progressReporter->Report( _( "Committing changes..." ) ); m_progressReporter->KeepRefreshing(); } diff --git a/pcbnew/zone_filler.h b/pcbnew/zone_filler.h index 4dbba156cd..b81a09d960 100644 --- a/pcbnew/zone_filler.h +++ b/pcbnew/zone_filler.h @@ -42,6 +42,7 @@ public: ZONE_FILLER( BOARD* aBoard, COMMIT* aCommit ); ~ZONE_FILLER(); + void SetProgressReporter( WX_PROGRESS_REPORTER* aReporter ); void InstallNewProgressReporter( wxWindow* aParent, const wxString& aTitle, int aNumPhases ); bool Fill( const std::vector& aZones, bool aCheck = false ); @@ -107,15 +108,15 @@ private: void addHatchFillTypeOnZone( const ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET& aRawPolys ); - BOARD* m_board; - SHAPE_POLY_SET m_boardOutline; // The board outlines, if exists - bool m_brdOutlinesValid; // true if m_boardOutline can be calculated - // false if not (not closed outlines for instance) - COMMIT* m_commit; + BOARD* m_board; + SHAPE_POLY_SET m_boardOutline; // the board outlines, if exists + bool m_brdOutlinesValid; // true if m_boardOutline is well-formed + COMMIT* m_commit; WX_PROGRESS_REPORTER* m_progressReporter; + std::unique_ptr m_uniqueReporter; - int m_maxError; + int m_maxError; }; #endif diff --git a/qa/drc_proto/drc_proto_test.cpp b/qa/drc_proto/drc_proto_test.cpp index 8f7cb36dbd..36d52aea75 100644 --- a/qa/drc_proto/drc_proto_test.cpp +++ b/qa/drc_proto/drc_proto_test.cpp @@ -236,6 +236,12 @@ int main( int argc, char *argv[] ) drcEngine.SetLogReporter( new CONSOLE_MSG_REPORTER ( &consoleLog ) ); drcEngine.SetProgressReporter( new CONSOLE_PROGRESS_REPORTER ( &consoleLog ) ); + drcEngine.SetViolationHandler( + [&]( const std::shared_ptr& aItem, wxPoint aPos ) + { + // fixme + } ); + wxString rulesFilepath; if( argc > 2 ) @@ -245,10 +251,7 @@ int main( int argc, char *argv[] ) drcEngine.InitEngine( rulesFilepath ); - drcEngine.RunTests( - [&]( const std::shared_ptr& aItem, wxPoint aPos ) - { - } ); + drcEngine.RunTests(); return 0; } diff --git a/qa/drc_proto/drc_test_provider_silk_to_pad.cpp b/qa/drc_proto/drc_test_provider_silk_to_pad.cpp index 762264ab2d..1b6ce2debd 100644 --- a/qa/drc_proto/drc_test_provider_silk_to_pad.cpp +++ b/qa/drc_proto/drc_test_provider_silk_to_pad.cpp @@ -50,7 +50,7 @@ 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: 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(); } - ReportAux( "Worst clearance : %d nm", m_largestClearance ); - ReportStage( ("Testing pads vs silkscreen clearance"), 0, 2 ); + reportAux( "Worst clearance : %d nm", m_largestClearance ); + reportStage(( "Pad to silkscreen clearances..." )); std::vector boardOutline; std::vector boardItems; @@ -116,7 +116,7 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_PAD::Run() 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 ) { @@ -129,13 +129,14 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_PAD::Run() auto shape = boardItem->GetEffectiveShape(); - test::DRC_RULE* rule = m_drcEngine->EvalRulesForItems( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE, outlineItem, boardItem ); - int minClearance = rule->GetConstraint().GetValue().Min(); - int actual; + auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE, + outlineItem, boardItem ); + int minClearance = constraint.GetValue().Min(); + int actual; if( refShape->Collide( shape.get(), minClearance, &actual ) ) { - DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_COPPER_EDGE_CLEARANCE ); + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_COPPER_EDGE_CLEARANCE ); wxString msg; 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->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 test::DRC_TEST_PROVIDER_EDGE_CLEARANCE::GetMatchingConstraintIds() const +std::set 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 { - static DRC_REGISTER_TEST_PROVIDER dummy; + static DRC_REGISTER_TEST_PROVIDER dummy; } \ No newline at end of file diff --git a/qa/pcbnew/drc/test_drc_courtyard_invalid.cpp b/qa/pcbnew/drc/test_drc_courtyard_invalid.cpp index 9dd8ce54e2..44e958d3cd 100644 --- a/qa/pcbnew/drc/test_drc_courtyard_invalid.cpp +++ b/qa/pcbnew/drc/test_drc_courtyard_invalid.cpp @@ -25,11 +25,11 @@ #include #include - +#include #include -#include +#include +#include #include -#include #include #include "../board_test_utils.h" @@ -294,13 +294,21 @@ void DoCourtyardInvalidTest( const COURTYARD_INVALID_CASE& aCase, // list of markers to collect std::vector> markers; - DRC_COURTYARD_TESTER drc_overlap( - [&]( MARKER_PCB* aMarker ) + DRC_ENGINE drcEngine( board.get(), &board->GetDesignSettings() ); + + drcEngine.InitEngine( wxFileName() ); + + drcEngine.SetViolationHandler( + [&]( const std::shared_ptr& aItem, wxPoint aPos ) { - markers.push_back( std::unique_ptr( aMarker ) ); + if( aItem->GetErrorCode() == DRCE_OVERLAPPING_FOOTPRINTS + || aItem->GetErrorCode() == DRCE_MISSING_COURTYARD ) + { + markers.push_back( std::make_unique( aItem, aPos ) ); + } } ); - drc_overlap.RunDRC( EDA_UNITS::MILLIMETRES, *board ); + drcEngine.RunTests(); CheckInvalidsMatchExpected( *board, markers, aCase.m_exp_errors ); } diff --git a/qa/pcbnew/drc/test_drc_courtyard_overlap.cpp b/qa/pcbnew/drc/test_drc_courtyard_overlap.cpp index 39bae76a7c..5baaf3406c 100644 --- a/qa/pcbnew/drc/test_drc_courtyard_overlap.cpp +++ b/qa/pcbnew/drc/test_drc_courtyard_overlap.cpp @@ -25,11 +25,11 @@ #include #include - +#include #include -#include +#include #include -#include +#include #include #include "../board_test_utils.h" @@ -463,13 +463,21 @@ static void DoCourtyardOverlapTest( const COURTYARD_OVERLAP_TEST_CASE& aCase, // list of markers to collect std::vector> markers; - DRC_COURTYARD_TESTER drc_overlap( - [&]( MARKER_PCB* aMarker ) + DRC_ENGINE drcEngine( board.get(), &board->GetDesignSettings() ); + + drcEngine.InitEngine( wxFileName() ); + + drcEngine.SetViolationHandler( + [&]( const std::shared_ptr& aItem, wxPoint aPos ) { - markers.push_back( std::unique_ptr( aMarker ) ); + if( aItem->GetErrorCode() == DRCE_OVERLAPPING_FOOTPRINTS + || aItem->GetErrorCode() == DRCE_MISSING_COURTYARD ) + { + markers.push_back( std::make_unique( aItem, aPos ) ); + } } ); - drc_overlap.RunDRC( EDA_UNITS::MILLIMETRES, *board ); + drcEngine.RunTests(); CheckCollisionsMatchExpected( *board, markers, aCase.m_collisions ); } diff --git a/qa/pcbnew_tools/CMakeLists.txt b/qa/pcbnew_tools/CMakeLists.txt index 376438aebb..bfd290dacf 100644 --- a/qa/pcbnew_tools/CMakeLists.txt +++ b/qa/pcbnew_tools/CMakeLists.txt @@ -29,8 +29,6 @@ add_executable( qa_pcbnew_tools # The main entry point pcbnew_tools.cpp - tools/drc_tool/drc_tool.cpp - tools/pcb_parser/pcb_parser_tool.cpp tools/polygon_generator/polygon_generator.cpp diff --git a/qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp b/qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp deleted file mode 100644 index a24a741b53..0000000000 --- a/qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp +++ /dev/null @@ -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 - -#include -#include - -#include - -#include -#include -#include -#include - -#include - -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> markers; - - auto marker_handler = [&]( MARKER_PCB* aMarker ) - { - markers.push_back( std::unique_ptr( aMarker ) ); - }; - - std::unique_ptr drc_prov = createDrcProvider( aBoard, marker_handler ); - - DRC_DURATION duration; - { - SCOPED_PROF_COUNTER 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 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>& aMarkers ) const - { - std::map 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 createDrcProvider( - BOARD& aBoard, LEGACY_DRC_TEST_PROVIDER::MARKER_HANDLER aHandler ) override - { - return std::make_unique( 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 createDrcProvider( - BOARD& aBoard, LEGACY_DRC_TEST_PROVIDER::MARKER_HANDLER aHandler ) override - { - return std::make_unique( 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 = 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 } );