Move DRC dialog to new DRC engine.
This commit is contained in:
parent
52d9a47d5b
commit
514da2f886
|
@ -43,13 +43,20 @@ void PROGRESS_REPORTER::BeginPhase( int aPhase )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PROGRESS_REPORTER::AdvancePhase( )
|
void PROGRESS_REPORTER::AdvancePhase()
|
||||||
{
|
{
|
||||||
m_phase.fetch_add( 1 );
|
m_phase.fetch_add( 1 );
|
||||||
m_progress.store( 0 );
|
m_progress.store( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PROGRESS_REPORTER::AdvancePhase( const wxString& aMessage )
|
||||||
|
{
|
||||||
|
AdvancePhase();
|
||||||
|
Report( aMessage );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PROGRESS_REPORTER::Report( const wxString& aMessage )
|
void PROGRESS_REPORTER::Report( const wxString& aMessage )
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> guard( m_mutex );
|
std::lock_guard<std::mutex> guard( m_mutex );
|
||||||
|
@ -81,6 +88,12 @@ void PROGRESS_REPORTER::SetNumPhases( int aNumPhases )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PROGRESS_REPORTER::AddPhases( int aNumPhases )
|
||||||
|
{
|
||||||
|
m_numPhases += aNumPhases;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int PROGRESS_REPORTER::currentProgress() const
|
int PROGRESS_REPORTER::currentProgress() const
|
||||||
{
|
{
|
||||||
double current = ( 1.0 / (double) m_numPhases ) *
|
double current = ( 1.0 / (double) m_numPhases ) *
|
||||||
|
|
|
@ -42,79 +42,86 @@
|
||||||
*/
|
*/
|
||||||
class PROGRESS_REPORTER
|
class PROGRESS_REPORTER
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
PROGRESS_REPORTER( int aNumPhases );
|
PROGRESS_REPORTER( int aNumPhases );
|
||||||
PROGRESS_REPORTER( const PROGRESS_REPORTER& ) = delete;
|
PROGRESS_REPORTER( const PROGRESS_REPORTER& ) = delete;
|
||||||
|
|
||||||
virtual ~PROGRESS_REPORTER()
|
virtual ~PROGRESS_REPORTER()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sets the number of phases
|
* sets the number of phases
|
||||||
*/
|
*/
|
||||||
void SetNumPhases( int aNumPhases );
|
void SetNumPhases( int aNumPhases );
|
||||||
|
void AddPhases( int aNumPhases );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* initialize the aPhase virtual zone of the dialog progress bar
|
* initialize the aPhase virtual zone of the dialog progress bar
|
||||||
*/
|
*/
|
||||||
void BeginPhase( int aPhase );
|
virtual void BeginPhase( int aPhase );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses the next vailable virtual zone of the dialog progress bar
|
* Uses the next vailable virtual zone of the dialog progress bar
|
||||||
*/
|
*/
|
||||||
void AdvancePhase();
|
virtual void AdvancePhase();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display aMessage in the progress bar dialog
|
* Uses the next vailable virtual zone of the dialog progress bar and updates
|
||||||
*/
|
* the message.
|
||||||
void Report( const wxString& aMessage );
|
*/
|
||||||
|
virtual void AdvancePhase( const wxString& aMessage );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the progress value to aProgress (0..1)
|
* Display aMessage in the progress bar dialog
|
||||||
*/
|
*/
|
||||||
virtual void SetCurrentProgress( double aProgress );
|
virtual void Report( const wxString& aMessage );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fix the value thar gives the 100 precent progress bar length
|
* Set the progress value to aProgress (0..1)
|
||||||
* (inside the current virtual zone)
|
*/
|
||||||
*/
|
virtual void SetCurrentProgress( double aProgress );
|
||||||
void SetMaxProgress( int aMaxProgress );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increment the progress bar length (inside the current virtual zone)
|
* Fix the value thar gives the 100 precent progress bar length
|
||||||
*/
|
* (inside the current virtual zone)
|
||||||
void AdvanceProgress();
|
*/
|
||||||
|
void SetMaxProgress( int aMaxProgress );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the UI dialog. *MUST* only be called from the main thread.
|
* Increment the progress bar length (inside the current virtual zone)
|
||||||
* Returns false if the user clicked Cancel.
|
*/
|
||||||
*/
|
void AdvanceProgress();
|
||||||
bool KeepRefreshing( bool aWait = false );
|
|
||||||
|
|
||||||
/** change the title displayed on the window caption
|
/**
|
||||||
* *MUST* only be called from the main thread.
|
* Update the UI dialog. *MUST* only be called from the main thread.
|
||||||
* Has meaning only for some reporters.
|
* Returns false if the user clicked Cancel.
|
||||||
* Do nothing for others
|
*/
|
||||||
*/
|
bool KeepRefreshing( bool aWait = false );
|
||||||
virtual void SetTitle( const wxString& aTitle ) {}
|
|
||||||
|
|
||||||
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;
|
virtual bool updateUI() = 0;
|
||||||
mutable std::mutex m_mutex;
|
|
||||||
std::atomic_int m_phase;
|
wxString m_rptMessage;
|
||||||
std::atomic_int m_numPhases;
|
mutable std::mutex m_mutex;
|
||||||
std::atomic_int m_progress;
|
std::atomic_int m_phase;
|
||||||
std::atomic_int m_maxProgress;
|
std::atomic_int m_numPhases;
|
||||||
std::atomic_bool m_cancelled;
|
std::atomic_int m_progress;
|
||||||
|
std::atomic_int m_maxProgress;
|
||||||
|
std::atomic_bool m_cancelled;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -232,13 +232,7 @@ set( PCBNEW_MICROWAVE_SRCS
|
||||||
)
|
)
|
||||||
|
|
||||||
set( PCBNEW_DRC_SRCS
|
set( PCBNEW_DRC_SRCS
|
||||||
drc/drc_courtyard_tester.cpp
|
|
||||||
drc/drc_drilled_hole_tester.cpp
|
|
||||||
drc/drc_keepout_tester.cpp
|
|
||||||
drc/drc_textvar_tester.cpp
|
|
||||||
drc/footprint_tester.cpp
|
|
||||||
drc/drc.cpp
|
drc/drc.cpp
|
||||||
drc/drc_clearance_test_functions.cpp
|
|
||||||
drc/drc_engine.cpp
|
drc/drc_engine.cpp
|
||||||
drc/drc_rule_parser.cpp
|
drc/drc_rule_parser.cpp
|
||||||
drc/drc_test_provider.cpp
|
drc/drc_test_provider.cpp
|
||||||
|
@ -250,6 +244,7 @@ set( PCBNEW_DRC_SRCS
|
||||||
drc/drc_test_provider_edge_clearance.cpp
|
drc/drc_test_provider_edge_clearance.cpp
|
||||||
drc/drc_test_provider_hole_clearance.cpp
|
drc/drc_test_provider_hole_clearance.cpp
|
||||||
drc/drc_test_provider_hole_size.cpp
|
drc/drc_test_provider_hole_size.cpp
|
||||||
|
drc/drc_test_provider_lvs.cpp
|
||||||
drc/drc_test_provider_misc.cpp
|
drc/drc_test_provider_misc.cpp
|
||||||
drc/drc_test_provider_track_width.cpp
|
drc/drc_test_provider_track_width.cpp
|
||||||
drc/drc_test_provider_via_diameter.cpp
|
drc/drc_test_provider_via_diameter.cpp
|
||||||
|
@ -333,6 +328,7 @@ set( PCBNEW_CLASS_SRCS
|
||||||
|
|
||||||
tools/convert_tool.cpp
|
tools/convert_tool.cpp
|
||||||
tools/drawing_tool.cpp
|
tools/drawing_tool.cpp
|
||||||
|
tools/drc_tool.cpp
|
||||||
tools/edit_tool.cpp
|
tools/edit_tool.cpp
|
||||||
tools/global_edit_tool.cpp
|
tools/global_edit_tool.cpp
|
||||||
tools/footprint_editor_tools.cpp
|
tools/footprint_editor_tools.cpp
|
||||||
|
|
|
@ -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<const PCB_LAYER_ID, SHAPE_POLY_SET>& pair : m_FilledPolysList )
|
if( aLayer == UNDEFINED_LAYER )
|
||||||
pair.second.CacheTriangulation();
|
{
|
||||||
|
for( std::pair<const PCB_LAYER_ID, SHAPE_POLY_SET>& pair : m_FilledPolysList )
|
||||||
|
pair.second.CacheTriangulation();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( m_FilledPolysList.count( aLayer ) )
|
||||||
|
m_FilledPolysList[ aLayer ].CacheTriangulation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -620,7 +620,7 @@ public:
|
||||||
/** (re)create a list of triangles that "fill" the solid areas.
|
/** (re)create a list of triangles that "fill" the solid areas.
|
||||||
* used for instance to draw these solid areas on opengl
|
* used for instance to draw these solid areas on opengl
|
||||||
*/
|
*/
|
||||||
void CacheTriangulation();
|
void CacheTriangulation( PCB_LAYER_ID aLayer = UNDEFINED_LAYER );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function SetFilledPolysList
|
* Function SetFilledPolysList
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
#include <tools/pcb_actions.h>
|
#include <tools/pcb_actions.h>
|
||||||
#include <tracks_cleaner.h>
|
#include <tracks_cleaner.h>
|
||||||
#include <drc/drc_item.h>
|
#include <drc/drc_item.h>
|
||||||
#include <drc/drc_results_provider.h>
|
|
||||||
#include <tools/zone_filler_tool.h>
|
#include <tools/zone_filler_tool.h>
|
||||||
|
|
||||||
DIALOG_CLEANUP_TRACKS_AND_VIAS::DIALOG_CLEANUP_TRACKS_AND_VIAS( PCB_EDIT_FRAME* aParentFrame ) :
|
DIALOG_CLEANUP_TRACKS_AND_VIAS::DIALOG_CLEANUP_TRACKS_AND_VIAS( PCB_EDIT_FRAME* aParentFrame ) :
|
||||||
|
|
|
@ -23,9 +23,7 @@
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <base_units.h>
|
|
||||||
#include <bitmaps.h>
|
#include <bitmaps.h>
|
||||||
#include <collectors.h>
|
|
||||||
#include <confirm.h>
|
#include <confirm.h>
|
||||||
#include <dialog_drc.h>
|
#include <dialog_drc.h>
|
||||||
#include <fctsys.h>
|
#include <fctsys.h>
|
||||||
|
@ -40,10 +38,41 @@
|
||||||
#include <wx/wupdlock.h>
|
#include <wx/wupdlock.h>
|
||||||
#include <widgets/appearance_controls.h>
|
#include <widgets/appearance_controls.h>
|
||||||
#include <widgets/ui_common.h>
|
#include <widgets/ui_common.h>
|
||||||
|
#include <widgets/progress_reporter.h>
|
||||||
|
#include <drc/drc_engine.h>
|
||||||
|
#include <tools/drc_tool.h>
|
||||||
|
|
||||||
|
|
||||||
DIALOG_DRC::DIALOG_DRC( DRC* aTester, PCB_EDIT_FRAME* aEditorFrame, wxWindow* aParent ) :
|
class DRC_PROGRESS_REPORTER : public WX_PROGRESS_REPORTER
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DRC_PROGRESS_REPORTER( wxWindow* aParent, wxTextCtrl* aAuxStageReporter ) :
|
||||||
|
WX_PROGRESS_REPORTER( aParent, _( "Test Progress" ), 1, true ),
|
||||||
|
m_auxStageReporter( aAuxStageReporter )
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void AdvancePhase( const wxString& aMessage ) override
|
||||||
|
{
|
||||||
|
WX_PROGRESS_REPORTER::AdvancePhase( aMessage );
|
||||||
|
|
||||||
|
m_auxStageReporter->AppendText( aMessage + "\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetCurrentProgress( double aProgress ) override
|
||||||
|
{
|
||||||
|
WX_PROGRESS_REPORTER::SetCurrentProgress( aProgress );
|
||||||
|
KeepRefreshing( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
wxTextCtrl* m_auxStageReporter;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
DIALOG_DRC::DIALOG_DRC( PCB_EDIT_FRAME* aEditorFrame, wxWindow* aParent ) :
|
||||||
DIALOG_DRC_BASE( aParent ),
|
DIALOG_DRC_BASE( aParent ),
|
||||||
|
m_drcRun( false ),
|
||||||
|
m_footprintTestsRun( false ),
|
||||||
m_trackMinWidth( aEditorFrame, m_MinWidthLabel, m_MinWidthCtrl, m_MinWidthUnits, true ),
|
m_trackMinWidth( aEditorFrame, m_MinWidthLabel, m_MinWidthCtrl, m_MinWidthUnits, true ),
|
||||||
m_viaMinSize( aEditorFrame, m_ViaMinLabel, m_ViaMinCtrl, m_ViaMinUnits, true ),
|
m_viaMinSize( aEditorFrame, m_ViaMinLabel, m_ViaMinCtrl, m_ViaMinUnits, true ),
|
||||||
m_uviaMinSize( aEditorFrame, m_uViaMinLabel, m_uViaMinCtrl, m_uViaMinUnits, true ),
|
m_uviaMinSize( aEditorFrame, m_uViaMinLabel, m_uViaMinCtrl, m_uViaMinUnits, true ),
|
||||||
|
@ -57,7 +86,6 @@ DIALOG_DRC::DIALOG_DRC( DRC* aTester, PCB_EDIT_FRAME* aEditorFrame, wxWindow* aP
|
||||||
{
|
{
|
||||||
SetName( DIALOG_DRC_WINDOW_NAME ); // Set a window name to be able to find it
|
SetName( DIALOG_DRC_WINDOW_NAME ); // Set a window name to be able to find it
|
||||||
|
|
||||||
m_tester = aTester;
|
|
||||||
m_brdEditor = aEditorFrame;
|
m_brdEditor = aEditorFrame;
|
||||||
m_currentBoard = m_brdEditor->GetBoard();
|
m_currentBoard = m_brdEditor->GetBoard();
|
||||||
|
|
||||||
|
@ -105,13 +133,14 @@ void DIALOG_DRC::OnActivateDlg( wxActivateEvent& aEvent )
|
||||||
{
|
{
|
||||||
if( m_currentBoard != m_brdEditor->GetBoard() )
|
if( m_currentBoard != m_brdEditor->GetBoard() )
|
||||||
{
|
{
|
||||||
// If m_currentBoard is not the current parent board,
|
// If m_currentBoard is not the current board, (for instance because a new board
|
||||||
// (for instance because a new board was loaded),
|
// was loaded), close the dialog, because many pointers are now invalid in lists
|
||||||
// close the dialog, because many pointers are now invalid
|
|
||||||
// in lists
|
|
||||||
SetReturnCode( wxID_CANCEL );
|
SetReturnCode( wxID_CANCEL );
|
||||||
Close();
|
Close();
|
||||||
m_tester->DestroyDRCDialog( wxID_CANCEL );
|
|
||||||
|
DRC_TOOL* drcTool = m_brdEditor->GetToolManager()->GetTool<DRC_TOOL>();
|
||||||
|
drcTool->DestroyDRCDialog( wxID_CANCEL );
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,22 +212,35 @@ void DIALOG_DRC::syncCheckboxes()
|
||||||
|
|
||||||
void DIALOG_DRC::OnRunDRCClick( wxCommandEvent& aEvent )
|
void DIALOG_DRC::OnRunDRCClick( wxCommandEvent& aEvent )
|
||||||
{
|
{
|
||||||
|
DRC_TOOL* drcTool = m_parentFrame->GetToolManager()->GetTool<DRC_TOOL>();
|
||||||
|
DRC_PROGRESS_REPORTER progressReporter( this, m_Messages );
|
||||||
|
bool testTracksAgainstZones = m_cbReportTracksToZonesErrors->GetValue();
|
||||||
|
bool refillZones = m_cbRefillZones->GetValue();
|
||||||
|
bool reportAllTrackErrors = m_cbReportAllTrackErrors->GetValue();
|
||||||
|
bool testFootprints = m_cbTestFootprints->GetValue();
|
||||||
|
|
||||||
setDRCParameters();
|
setDRCParameters();
|
||||||
m_tester->m_testTracksAgainstZones = m_cbReportTracksToZonesErrors->GetValue();
|
|
||||||
m_tester->m_refillZones = m_cbRefillZones->GetValue();
|
m_drcRun = false;
|
||||||
m_tester->m_reportAllTrackErrors = m_cbReportAllTrackErrors->GetValue();
|
m_footprintTestsRun = false;
|
||||||
m_tester->m_testFootprints = m_cbTestFootprints->GetValue();
|
|
||||||
|
|
||||||
m_brdEditor->RecordDRCExclusions();
|
m_brdEditor->RecordDRCExclusions();
|
||||||
deleteAllMarkers( true );
|
deleteAllMarkers( true );
|
||||||
|
|
||||||
wxBeginBusyCursor();
|
wxBeginBusyCursor();
|
||||||
wxWindowDisabler disabler;
|
wxWindowDisabler disabler( &progressReporter );
|
||||||
|
Raise();
|
||||||
|
|
||||||
// run all the tests, with no UI at this time.
|
// run all the tests, with no UI at this time.
|
||||||
m_Messages->Clear();
|
m_Messages->Clear();
|
||||||
wxSafeYield(); // Allows time slice to refresh the Messages
|
wxYield(); // Allows time slice to refresh the Messages
|
||||||
m_tester->RunTests( m_Messages );
|
|
||||||
|
drcTool->RunTests( &progressReporter, testTracksAgainstZones, refillZones,
|
||||||
|
reportAllTrackErrors, testFootprints );
|
||||||
|
m_drcRun = true;
|
||||||
|
|
||||||
|
if( testFootprints )
|
||||||
|
m_footprintTestsRun = true;
|
||||||
|
|
||||||
m_Notebook->ChangeSelection( 0 ); // display the "Problems/Markers" tab
|
m_Notebook->ChangeSelection( 0 ); // display the "Problems/Markers" tab
|
||||||
|
|
||||||
|
@ -206,7 +248,7 @@ void DIALOG_DRC::OnRunDRCClick( wxCommandEvent& aEvent )
|
||||||
|
|
||||||
refreshBoardEditor();
|
refreshBoardEditor();
|
||||||
|
|
||||||
wxSafeYield();
|
wxYield();
|
||||||
Raise();
|
Raise();
|
||||||
m_Notebook->GetPage( m_Notebook->GetSelection() )->SetFocus();
|
m_Notebook->GetPage( m_Notebook->GetSelection() )->SetFocus();
|
||||||
}
|
}
|
||||||
|
@ -538,7 +580,8 @@ void DIALOG_DRC::OnCancelClick( wxCommandEvent& aEvent )
|
||||||
|
|
||||||
// The dialog can be modal or not modal.
|
// The dialog can be modal or not modal.
|
||||||
// Leave the DRC caller destroy (or not) the dialog
|
// Leave the DRC caller destroy (or not) the dialog
|
||||||
m_tester->DestroyDRCDialog( wxID_CANCEL );
|
DRC_TOOL* drcTool = m_brdEditor->GetToolManager()->GetTool<DRC_TOOL>();
|
||||||
|
drcTool->DestroyDRCDialog( wxID_CANCEL );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -689,7 +732,7 @@ void DIALOG_DRC::updateDisplayedCounts()
|
||||||
// First the tab headers:
|
// First the tab headers:
|
||||||
//
|
//
|
||||||
|
|
||||||
if( m_tester->m_drcRun )
|
if( m_drcRun )
|
||||||
{
|
{
|
||||||
msg.sprintf( m_markersTitleTemplate, m_markerTreeModel->GetDRCItemCount() );
|
msg.sprintf( m_markersTitleTemplate, m_markerTreeModel->GetDRCItemCount() );
|
||||||
m_Notebook->SetPageText( 0, msg );
|
m_Notebook->SetPageText( 0, msg );
|
||||||
|
@ -697,7 +740,7 @@ void DIALOG_DRC::updateDisplayedCounts()
|
||||||
msg.sprintf( m_unconnectedTitleTemplate, m_unconnectedTreeModel->GetDRCItemCount() );
|
msg.sprintf( m_unconnectedTitleTemplate, m_unconnectedTreeModel->GetDRCItemCount() );
|
||||||
m_Notebook->SetPageText( 1, msg );
|
m_Notebook->SetPageText( 1, msg );
|
||||||
|
|
||||||
if( m_tester->m_footprintsTested )
|
if( m_footprintTestsRun )
|
||||||
msg.sprintf( m_footprintsTitleTemplate, m_footprintWarningsTreeModel->GetDRCItemCount() );
|
msg.sprintf( m_footprintsTitleTemplate, m_footprintWarningsTreeModel->GetDRCItemCount() );
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -48,7 +48,7 @@ DIALOG_DRC: public DIALOG_DRC_BASE
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Constructors
|
/// Constructors
|
||||||
DIALOG_DRC( DRC* aTester, PCB_EDIT_FRAME* aEditorFrame, wxWindow* aParent );
|
DIALOG_DRC( PCB_EDIT_FRAME* aEditorFrame, wxWindow* aParent );
|
||||||
~DIALOG_DRC();
|
~DIALOG_DRC();
|
||||||
|
|
||||||
void SetMarkersProvider( RC_ITEMS_PROVIDER* aProvider );
|
void SetMarkersProvider( RC_ITEMS_PROVIDER* aProvider );
|
||||||
|
@ -95,8 +95,9 @@ private:
|
||||||
BOARD_DESIGN_SETTINGS& bds() { return m_currentBoard->GetDesignSettings(); }
|
BOARD_DESIGN_SETTINGS& bds() { return m_currentBoard->GetDesignSettings(); }
|
||||||
|
|
||||||
BOARD* m_currentBoard; // the board currently on test
|
BOARD* m_currentBoard; // the board currently on test
|
||||||
DRC* m_tester;
|
|
||||||
PCB_EDIT_FRAME* m_brdEditor;
|
PCB_EDIT_FRAME* m_brdEditor;
|
||||||
|
bool m_drcRun;
|
||||||
|
bool m_footprintTestsRun;
|
||||||
|
|
||||||
wxString m_markersTitleTemplate;
|
wxString m_markersTitleTemplate;
|
||||||
wxString m_unconnectedTitleTemplate;
|
wxString m_unconnectedTitleTemplate;
|
||||||
|
|
|
@ -31,9 +31,6 @@
|
||||||
#include <pcbnew_settings.h>
|
#include <pcbnew_settings.h>
|
||||||
#include <reporter.h>
|
#include <reporter.h>
|
||||||
#include <bitmaps.h>
|
#include <bitmaps.h>
|
||||||
#include <drc/drc.h>
|
|
||||||
#include <drc/drc_item.h>
|
|
||||||
#include <drc/footprint_tester.h>
|
|
||||||
#include <tool/tool_manager.h>
|
#include <tool/tool_manager.h>
|
||||||
#include <tools/pcb_actions.h>
|
#include <tools/pcb_actions.h>
|
||||||
#include <class_board.h>
|
#include <class_board.h>
|
||||||
|
@ -174,33 +171,6 @@ void DIALOG_NETLIST::OnUpdatePCB( wxCommandEvent& event )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DIALOG_NETLIST::OnTestFootprintsClick( wxCommandEvent& event )
|
|
||||||
{
|
|
||||||
if( m_parent->GetBoard()->GetFirstModule() == nullptr )
|
|
||||||
{
|
|
||||||
DisplayInfoMessage( this, _( "No footprints." ) );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wxString netlistFilename = m_NetlistFilenameCtrl->GetValue();
|
|
||||||
NETLIST netlist;
|
|
||||||
wxBusyCursor dummy; // Shows an hourglass while calculating.
|
|
||||||
|
|
||||||
if( !m_parent->ReadNetlistFromFile( netlistFilename, netlist, NULL_REPORTER::GetInstance() ) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
HTML_MESSAGE_BOX dlg( this, _( "Check footprints" ) );
|
|
||||||
std::vector<std::shared_ptr<DRC_ITEM> > drcItems;
|
|
||||||
|
|
||||||
TestFootprints( netlist, m_parent->GetBoard(), drcItems );
|
|
||||||
|
|
||||||
for( auto item : drcItems )
|
|
||||||
dlg.AddHTML_Text( item->ShowHtml( m_parent ) );
|
|
||||||
|
|
||||||
dlg.ShowModal();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DIALOG_NETLIST::OnFilenameKillFocus( wxFocusEvent& event )
|
void DIALOG_NETLIST::OnFilenameKillFocus( wxFocusEvent& event )
|
||||||
{
|
{
|
||||||
onFilenameChanged();
|
onFilenameChanged();
|
||||||
|
@ -254,12 +224,6 @@ void DIALOG_NETLIST::OnCompileRatsnestClick( wxCommandEvent& event )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DIALOG_NETLIST::OnUpdateUIValidNetlistFile( wxUpdateUIEvent& aEvent )
|
|
||||||
{
|
|
||||||
aEvent.Enable( !m_NetlistFilenameCtrl->GetValue().IsEmpty() );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DIALOG_NETLIST::loadNetlist( bool aDryRun )
|
void DIALOG_NETLIST::loadNetlist( bool aDryRun )
|
||||||
{
|
{
|
||||||
wxString netlistFileName = m_NetlistFilenameCtrl->GetValue();
|
wxString netlistFileName = m_NetlistFilenameCtrl->GetValue();
|
||||||
|
|
|
@ -64,9 +64,7 @@ private:
|
||||||
void OnFilenameKillFocus( wxFocusEvent& event ) override;
|
void OnFilenameKillFocus( wxFocusEvent& event ) override;
|
||||||
void OnMatchChanged( wxCommandEvent& event ) override;
|
void OnMatchChanged( wxCommandEvent& event ) override;
|
||||||
void OnOptionChanged( wxCommandEvent& event ) override;
|
void OnOptionChanged( wxCommandEvent& event ) override;
|
||||||
void OnTestFootprintsClick( wxCommandEvent& event ) override;
|
|
||||||
void OnCompileRatsnestClick( wxCommandEvent& event ) override;
|
void OnCompileRatsnestClick( wxCommandEvent& event ) override;
|
||||||
void OnUpdateUIValidNetlistFile( wxUpdateUIEvent& aEvent ) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -86,11 +86,6 @@ DIALOG_NETLIST_BASE::DIALOG_NETLIST_BASE( wxWindow* parent, wxWindowID id, const
|
||||||
|
|
||||||
m_buttonsSizer = new wxBoxSizer( wxHORIZONTAL );
|
m_buttonsSizer = new wxBoxSizer( wxHORIZONTAL );
|
||||||
|
|
||||||
m_buttonFPTest = new wxButton( this, ID_TEST_NETLIST, _("Test Footprints"), wxDefaultPosition, wxDefaultSize, 0 );
|
|
||||||
m_buttonFPTest->SetToolTip( _("Read the current netlist file and list missing and extra footprints") );
|
|
||||||
|
|
||||||
m_buttonsSizer->Add( m_buttonFPTest, 0, wxEXPAND|wxLEFT|wxRIGHT, 10 );
|
|
||||||
|
|
||||||
m_sdbSizer1 = new wxStdDialogButtonSizer();
|
m_sdbSizer1 = new wxStdDialogButtonSizer();
|
||||||
m_sdbSizer1OK = new wxButton( this, wxID_OK );
|
m_sdbSizer1OK = new wxButton( this, wxID_OK );
|
||||||
m_sdbSizer1->AddButton( m_sdbSizer1OK );
|
m_sdbSizer1->AddButton( m_sdbSizer1OK );
|
||||||
|
@ -111,6 +106,7 @@ DIALOG_NETLIST_BASE::DIALOG_NETLIST_BASE( wxWindow* parent, wxWindowID id, const
|
||||||
bMainSizer->Fit( this );
|
bMainSizer->Fit( this );
|
||||||
|
|
||||||
// Connect Events
|
// Connect Events
|
||||||
|
this->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_NETLIST_BASE::OnUpdateUIValidNetlistFile ) );
|
||||||
m_NetlistFilenameCtrl->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_NETLIST_BASE::OnFilenameKillFocus ), NULL, this );
|
m_NetlistFilenameCtrl->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_NETLIST_BASE::OnFilenameKillFocus ), NULL, this );
|
||||||
m_browseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOpenNetlistClick ), NULL, this );
|
m_browseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOpenNetlistClick ), NULL, this );
|
||||||
m_matchByTimestamp->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnMatchChanged ), NULL, this );
|
m_matchByTimestamp->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnMatchChanged ), NULL, this );
|
||||||
|
@ -119,8 +115,6 @@ DIALOG_NETLIST_BASE::DIALOG_NETLIST_BASE( wxWindow* parent, wxWindowID id, const
|
||||||
m_cbDeleteShortingTracks->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this );
|
m_cbDeleteShortingTracks->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this );
|
||||||
m_cbDeleteSinglePadNets->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this );
|
m_cbDeleteSinglePadNets->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this );
|
||||||
m_cbWarnNoNetPad->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this );
|
m_cbWarnNoNetPad->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this );
|
||||||
m_buttonFPTest->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnTestFootprintsClick ), NULL, this );
|
|
||||||
m_buttonFPTest->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_NETLIST_BASE::OnUpdateUIValidNetlistFile ), NULL, this );
|
|
||||||
m_sdbSizer1Apply->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnCompileRatsnestClick ), NULL, this );
|
m_sdbSizer1Apply->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnCompileRatsnestClick ), NULL, this );
|
||||||
m_sdbSizer1OK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnUpdatePCB ), NULL, this );
|
m_sdbSizer1OK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnUpdatePCB ), NULL, this );
|
||||||
}
|
}
|
||||||
|
@ -128,6 +122,7 @@ DIALOG_NETLIST_BASE::DIALOG_NETLIST_BASE( wxWindow* parent, wxWindowID id, const
|
||||||
DIALOG_NETLIST_BASE::~DIALOG_NETLIST_BASE()
|
DIALOG_NETLIST_BASE::~DIALOG_NETLIST_BASE()
|
||||||
{
|
{
|
||||||
// Disconnect Events
|
// Disconnect Events
|
||||||
|
this->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_NETLIST_BASE::OnUpdateUIValidNetlistFile ) );
|
||||||
m_NetlistFilenameCtrl->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_NETLIST_BASE::OnFilenameKillFocus ), NULL, this );
|
m_NetlistFilenameCtrl->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_NETLIST_BASE::OnFilenameKillFocus ), NULL, this );
|
||||||
m_browseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOpenNetlistClick ), NULL, this );
|
m_browseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOpenNetlistClick ), NULL, this );
|
||||||
m_matchByTimestamp->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnMatchChanged ), NULL, this );
|
m_matchByTimestamp->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnMatchChanged ), NULL, this );
|
||||||
|
@ -136,8 +131,6 @@ DIALOG_NETLIST_BASE::~DIALOG_NETLIST_BASE()
|
||||||
m_cbDeleteShortingTracks->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this );
|
m_cbDeleteShortingTracks->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this );
|
||||||
m_cbDeleteSinglePadNets->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this );
|
m_cbDeleteSinglePadNets->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this );
|
||||||
m_cbWarnNoNetPad->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this );
|
m_cbWarnNoNetPad->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnOptionChanged ), NULL, this );
|
||||||
m_buttonFPTest->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnTestFootprintsClick ), NULL, this );
|
|
||||||
m_buttonFPTest->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_NETLIST_BASE::OnUpdateUIValidNetlistFile ), NULL, this );
|
|
||||||
m_sdbSizer1Apply->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnCompileRatsnestClick ), NULL, this );
|
m_sdbSizer1Apply->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnCompileRatsnestClick ), NULL, this );
|
||||||
m_sdbSizer1OK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnUpdatePCB ), NULL, this );
|
m_sdbSizer1OK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_NETLIST_BASE::OnUpdatePCB ), NULL, this );
|
||||||
|
|
||||||
|
|
|
@ -762,80 +762,6 @@
|
||||||
<property name="name">m_buttonsSizer</property>
|
<property name="name">m_buttonsSizer</property>
|
||||||
<property name="orient">wxHORIZONTAL</property>
|
<property name="orient">wxHORIZONTAL</property>
|
||||||
<property name="permission">protected</property>
|
<property name="permission">protected</property>
|
||||||
<object class="sizeritem" expanded="0">
|
|
||||||
<property name="border">10</property>
|
|
||||||
<property name="flag">wxEXPAND|wxLEFT|wxRIGHT</property>
|
|
||||||
<property name="proportion">0</property>
|
|
||||||
<object class="wxButton" expanded="0">
|
|
||||||
<property name="BottomDockable">1</property>
|
|
||||||
<property name="LeftDockable">1</property>
|
|
||||||
<property name="RightDockable">1</property>
|
|
||||||
<property name="TopDockable">1</property>
|
|
||||||
<property name="aui_layer"></property>
|
|
||||||
<property name="aui_name"></property>
|
|
||||||
<property name="aui_position"></property>
|
|
||||||
<property name="aui_row"></property>
|
|
||||||
<property name="best_size"></property>
|
|
||||||
<property name="bg"></property>
|
|
||||||
<property name="bitmap"></property>
|
|
||||||
<property name="caption"></property>
|
|
||||||
<property name="caption_visible">1</property>
|
|
||||||
<property name="center_pane">0</property>
|
|
||||||
<property name="close_button">1</property>
|
|
||||||
<property name="context_help"></property>
|
|
||||||
<property name="context_menu">1</property>
|
|
||||||
<property name="current"></property>
|
|
||||||
<property name="default">0</property>
|
|
||||||
<property name="default_pane">0</property>
|
|
||||||
<property name="disabled"></property>
|
|
||||||
<property name="dock">Dock</property>
|
|
||||||
<property name="dock_fixed">0</property>
|
|
||||||
<property name="docking">Left</property>
|
|
||||||
<property name="enabled">1</property>
|
|
||||||
<property name="fg"></property>
|
|
||||||
<property name="floatable">1</property>
|
|
||||||
<property name="focus"></property>
|
|
||||||
<property name="font"></property>
|
|
||||||
<property name="gripper">0</property>
|
|
||||||
<property name="hidden">0</property>
|
|
||||||
<property name="id">ID_TEST_NETLIST</property>
|
|
||||||
<property name="label">Test Footprints</property>
|
|
||||||
<property name="margins"></property>
|
|
||||||
<property name="markup">0</property>
|
|
||||||
<property name="max_size"></property>
|
|
||||||
<property name="maximize_button">0</property>
|
|
||||||
<property name="maximum_size"></property>
|
|
||||||
<property name="min_size"></property>
|
|
||||||
<property name="minimize_button">0</property>
|
|
||||||
<property name="minimum_size"></property>
|
|
||||||
<property name="moveable">1</property>
|
|
||||||
<property name="name">m_buttonFPTest</property>
|
|
||||||
<property name="pane_border">1</property>
|
|
||||||
<property name="pane_position"></property>
|
|
||||||
<property name="pane_size"></property>
|
|
||||||
<property name="permission">protected</property>
|
|
||||||
<property name="pin_button">1</property>
|
|
||||||
<property name="pos"></property>
|
|
||||||
<property name="position"></property>
|
|
||||||
<property name="pressed"></property>
|
|
||||||
<property name="resize">Resizable</property>
|
|
||||||
<property name="show">1</property>
|
|
||||||
<property name="size"></property>
|
|
||||||
<property name="style"></property>
|
|
||||||
<property name="subclass"></property>
|
|
||||||
<property name="toolbar_pane">0</property>
|
|
||||||
<property name="tooltip">Read the current netlist file and list missing and extra footprints</property>
|
|
||||||
<property name="validator_data_type"></property>
|
|
||||||
<property name="validator_style">wxFILTER_NONE</property>
|
|
||||||
<property name="validator_type">wxDefaultValidator</property>
|
|
||||||
<property name="validator_variable"></property>
|
|
||||||
<property name="window_extra_style"></property>
|
|
||||||
<property name="window_name"></property>
|
|
||||||
<property name="window_style"></property>
|
|
||||||
<event name="OnButtonClick">OnTestFootprintsClick</event>
|
|
||||||
<event name="OnUpdateUI">OnUpdateUIValidNetlistFile</event>
|
|
||||||
</object>
|
|
||||||
</object>
|
|
||||||
<object class="sizeritem" expanded="1">
|
<object class="sizeritem" expanded="1">
|
||||||
<property name="border">5</property>
|
<property name="border">5</property>
|
||||||
<property name="flag">wxEXPAND</property>
|
<property name="flag">wxEXPAND</property>
|
||||||
|
|
|
@ -42,11 +42,6 @@ class DIALOG_NETLIST_BASE : public DIALOG_SHIM
|
||||||
private:
|
private:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum
|
|
||||||
{
|
|
||||||
ID_TEST_NETLIST = 1000
|
|
||||||
};
|
|
||||||
|
|
||||||
wxTextCtrl* m_NetlistFilenameCtrl;
|
wxTextCtrl* m_NetlistFilenameCtrl;
|
||||||
wxBitmapButton* m_browseButton;
|
wxBitmapButton* m_browseButton;
|
||||||
wxRadioBox* m_matchByTimestamp;
|
wxRadioBox* m_matchByTimestamp;
|
||||||
|
@ -57,19 +52,17 @@ class DIALOG_NETLIST_BASE : public DIALOG_SHIM
|
||||||
wxCheckBox* m_cbWarnNoNetPad;
|
wxCheckBox* m_cbWarnNoNetPad;
|
||||||
WX_HTML_REPORT_PANEL* m_MessageWindow;
|
WX_HTML_REPORT_PANEL* m_MessageWindow;
|
||||||
wxBoxSizer* m_buttonsSizer;
|
wxBoxSizer* m_buttonsSizer;
|
||||||
wxButton* m_buttonFPTest;
|
|
||||||
wxStdDialogButtonSizer* m_sdbSizer1;
|
wxStdDialogButtonSizer* m_sdbSizer1;
|
||||||
wxButton* m_sdbSizer1OK;
|
wxButton* m_sdbSizer1OK;
|
||||||
wxButton* m_sdbSizer1Apply;
|
wxButton* m_sdbSizer1Apply;
|
||||||
wxButton* m_sdbSizer1Cancel;
|
wxButton* m_sdbSizer1Cancel;
|
||||||
|
|
||||||
// Virtual event handlers, overide them in your derived class
|
// Virtual event handlers, overide them in your derived class
|
||||||
|
virtual void OnUpdateUIValidNetlistFile( wxUpdateUIEvent& event ) { event.Skip(); }
|
||||||
virtual void OnFilenameKillFocus( wxFocusEvent& event ) { event.Skip(); }
|
virtual void OnFilenameKillFocus( wxFocusEvent& event ) { event.Skip(); }
|
||||||
virtual void OnOpenNetlistClick( wxCommandEvent& event ) { event.Skip(); }
|
virtual void OnOpenNetlistClick( wxCommandEvent& event ) { event.Skip(); }
|
||||||
virtual void OnMatchChanged( wxCommandEvent& event ) { event.Skip(); }
|
virtual void OnMatchChanged( wxCommandEvent& event ) { event.Skip(); }
|
||||||
virtual void OnOptionChanged( wxCommandEvent& event ) { event.Skip(); }
|
virtual void OnOptionChanged( wxCommandEvent& event ) { event.Skip(); }
|
||||||
virtual void OnTestFootprintsClick( wxCommandEvent& event ) { event.Skip(); }
|
|
||||||
virtual void OnUpdateUIValidNetlistFile( wxUpdateUIEvent& event ) { event.Skip(); }
|
|
||||||
virtual void OnCompileRatsnestClick( wxCommandEvent& event ) { event.Skip(); }
|
virtual void OnCompileRatsnestClick( wxCommandEvent& event ) { event.Skip(); }
|
||||||
virtual void OnUpdatePCB( wxCommandEvent& event ) { event.Skip(); }
|
virtual void OnUpdatePCB( wxCommandEvent& event ) { event.Skip(); }
|
||||||
|
|
||||||
|
|
|
@ -37,9 +37,9 @@
|
||||||
#include <dialog_plot.h>
|
#include <dialog_plot.h>
|
||||||
#include <dialog_gendrill.h>
|
#include <dialog_gendrill.h>
|
||||||
#include <wx_html_report_panel.h>
|
#include <wx_html_report_panel.h>
|
||||||
#include <drc/drc.h>
|
|
||||||
#include <tool/tool_manager.h>
|
#include <tool/tool_manager.h>
|
||||||
#include <tools/zone_filler_tool.h>
|
#include <tools/zone_filler_tool.h>
|
||||||
|
#include <tools/drc_tool.h>
|
||||||
#include <math/util.h> // for KiROUND
|
#include <math/util.h> // for KiROUND
|
||||||
#include <macros.h>
|
#include <macros.h>
|
||||||
|
|
||||||
|
@ -903,7 +903,7 @@ void DIALOG_PLOT::onRunDRC( wxCommandEvent& event )
|
||||||
|
|
||||||
if( parent )
|
if( parent )
|
||||||
{
|
{
|
||||||
DRC* drcTool = parent->GetToolManager()->GetTool<DRC>();
|
DRC_TOOL* drcTool = parent->GetToolManager()->GetTool<DRC_TOOL>();
|
||||||
|
|
||||||
// First close an existing dialog if open
|
// First close an existing dialog if open
|
||||||
// (low probability, but can happen)
|
// (low probability, but can happen)
|
||||||
|
|
1228
pcbnew/drc/drc.cpp
1228
pcbnew/drc/drc.cpp
File diff suppressed because it is too large
Load Diff
227
pcbnew/drc/drc.h
227
pcbnew/drc/drc.h
|
@ -36,67 +36,7 @@
|
||||||
#include <tools/pcb_tool_base.h>
|
#include <tools/pcb_tool_base.h>
|
||||||
|
|
||||||
|
|
||||||
/// DRC error codes:
|
|
||||||
enum PCB_DRC_CODE {
|
|
||||||
DRCE_FIRST = 1,
|
|
||||||
DRCE_UNCONNECTED_ITEMS = DRCE_FIRST, // items are unconnected
|
|
||||||
DRCE_SHORTING_ITEMS, // items short two nets but are not a net-tie
|
|
||||||
DRCE_ALLOWED_ITEMS, // a disallowed item has been used
|
|
||||||
DRCE_CLEARANCE, // items are too close together
|
|
||||||
DRCE_TRACKS_CROSSING, // tracks are crossing
|
|
||||||
DRCE_COPPER_EDGE_CLEARANCE, // a copper item is too close to the board edge
|
|
||||||
DRCE_ZONES_INTERSECT, // copper area outlines intersect
|
|
||||||
DRCE_ZONE_HAS_EMPTY_NET, // copper area has a net but no pads in nets, which is suspicious
|
|
||||||
DRCE_DANGLING_VIA, // via which isn't connected to anything
|
|
||||||
DRCE_DANGLING_TRACK, // track with at least one end not connected to anything
|
|
||||||
DRCE_DRILLED_HOLES_TOO_CLOSE, // overlapping drilled holes break drill bits
|
|
||||||
DRCE_HOLE_CLEARANCE, //
|
|
||||||
DRCE_TRACK_WIDTH, // Track width is too small or too large
|
|
||||||
DRCE_TOO_SMALL_VIA, // Too small via size
|
|
||||||
DRCE_ANNULUS, // Via size and drill leave annulus too small or too large
|
|
||||||
DRCE_TOO_SMALL_DRILL, // Too small via or pad drill
|
|
||||||
DRCE_VIA_HOLE_BIGGER, // via's hole is bigger than its diameter
|
|
||||||
DRCE_VIA_DIAMETER, // Via diameter checks (min/max)
|
|
||||||
DRCE_PADSTACK, // something is wrong with a pad or via stackup
|
|
||||||
DRCE_TOO_SMALL_MICROVIA, // Too small micro via size
|
|
||||||
DRCE_TOO_SMALL_MICROVIA_DRILL, // Too small micro via drill
|
|
||||||
DRCE_KEEPOUT, // A disallowed object is inside a keepout
|
|
||||||
DRCE_OVERLAPPING_FOOTPRINTS, // footprint courtyards overlap
|
|
||||||
DRCE_MISSING_COURTYARD, // footprint has no courtyard defined
|
|
||||||
DRCE_MALFORMED_COURTYARD, // footprint has a courtyard but malformed
|
|
||||||
// (not convertible to a closed polygon with holes)
|
|
||||||
DRCE_PTH_IN_COURTYARD,
|
|
||||||
DRCE_NPTH_IN_COURTYARD,
|
|
||||||
DRCE_DISABLED_LAYER_ITEM, // item on a disabled layer
|
|
||||||
DRCE_INVALID_OUTLINE, // invalid board outline
|
|
||||||
|
|
||||||
DRCE_MISSING_FOOTPRINT, // footprint not found for netlist item
|
|
||||||
DRCE_DUPLICATE_FOOTPRINT, // more than one footprints found for netlist item
|
|
||||||
DRCE_EXTRA_FOOTPRINT, // netlist item not found for footprint
|
|
||||||
DRCE_NET_CONFLICT, // pad net doesn't match netlist
|
|
||||||
|
|
||||||
DRCE_UNRESOLVED_VARIABLE,
|
|
||||||
|
|
||||||
DRCE_LAST = DRCE_UNRESOLVED_VARIABLE
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class PCB_EDIT_FRAME;
|
class PCB_EDIT_FRAME;
|
||||||
class DIALOG_DRC;
|
|
||||||
class BOARD_ITEM;
|
|
||||||
class BOARD;
|
|
||||||
class D_PAD;
|
|
||||||
class ZONE_CONTAINER;
|
|
||||||
class TRACK;
|
|
||||||
class MARKER_PCB;
|
|
||||||
class DRC_ITEM;
|
|
||||||
class NETCLASS;
|
|
||||||
class EDA_TEXT;
|
|
||||||
class DRAWSEGMENT;
|
|
||||||
class NETLIST;
|
|
||||||
class wxWindow;
|
|
||||||
class wxString;
|
|
||||||
class wxTextCtrl;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -109,8 +49,6 @@ class wxTextCtrl;
|
||||||
*/
|
*/
|
||||||
class DRC : public PCB_TOOL_BASE
|
class DRC : public PCB_TOOL_BASE
|
||||||
{
|
{
|
||||||
friend class DIALOG_DRC;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DRC();
|
DRC();
|
||||||
~DRC();
|
~DRC();
|
||||||
|
@ -119,179 +57,14 @@ public:
|
||||||
void Reset( RESET_REASON aReason ) override;
|
void Reset( RESET_REASON aReason ) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_doUnconnectedTest; // enable unconnected tests
|
|
||||||
bool m_testTracksAgainstZones; // enable zone to items clearance tests
|
|
||||||
bool m_doKeepoutTest; // enable keepout areas to items clearance tests
|
|
||||||
bool m_refillZones; // refill zones if requested (by user).
|
|
||||||
bool m_reportAllTrackErrors; // Report all tracks errors (or only 4 first errors)
|
|
||||||
bool m_testFootprints; // Test footprints against schematic
|
|
||||||
|
|
||||||
PCB_EDIT_FRAME* m_editFrame; // The pcb frame editor which owns the board
|
PCB_EDIT_FRAME* m_editFrame; // The pcb frame editor which owns the board
|
||||||
BOARD* m_pcb;
|
|
||||||
SHAPE_POLY_SET m_board_outlines; // The board outline including cutouts
|
|
||||||
bool m_board_outline_valid;
|
|
||||||
DIALOG_DRC* m_drcDialog;
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<DRC_ITEM> > m_unconnected; // list of unconnected pads
|
|
||||||
std::vector<std::shared_ptr<DRC_ITEM> > m_footprints; // list of footprint warnings
|
|
||||||
bool m_drcRun; // indicates DRC has been run at least once
|
|
||||||
bool m_footprintsTested; // indicates footprints were tested in last run
|
|
||||||
|
|
||||||
std::vector<DRC_RULE*> m_rules;
|
std::vector<DRC_RULE*> m_rules;
|
||||||
|
|
||||||
// Temp variables for performance during a single DRC run
|
|
||||||
//
|
|
||||||
// wxString's c'tor is surprisingly expensive, and in the world of DRC everything matters
|
|
||||||
//
|
|
||||||
wxString m_msg;
|
|
||||||
wxString m_clearanceSource;
|
|
||||||
int m_largestClearance;
|
|
||||||
|
|
||||||
private:
|
|
||||||
///> Sets up handlers for various events.
|
|
||||||
void setTransitions() override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update needed pointers from the one pointer which is known not to change.
|
|
||||||
*/
|
|
||||||
void updatePointers();
|
|
||||||
|
|
||||||
EDA_UNITS userUnits() const { return m_editFrame->GetUserUnits(); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a DRC marker to the PCB through the COMMIT mechanism.
|
|
||||||
*/
|
|
||||||
void addMarkerToPcb( BOARD_COMMIT& aCommit, MARKER_PCB* aMarker );
|
|
||||||
|
|
||||||
//-----<categorical group tests>-----------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform the DRC on all tracks.
|
|
||||||
*
|
|
||||||
* This test can take a while, a progress bar can be displayed
|
|
||||||
* @param aActiveWindow = the active window ued as parent for the progress bar
|
|
||||||
* @param aShowProgressBar = true to show a progress bar
|
|
||||||
* (Note: it is shown only if there are many tracks)
|
|
||||||
*/
|
|
||||||
void testTracks( BOARD_COMMIT& aCommit, wxWindow * aActiveWindow, bool aShowProgressBar );
|
|
||||||
|
|
||||||
void testPadClearances( BOARD_COMMIT& aCommit );
|
|
||||||
|
|
||||||
void testUnconnected();
|
|
||||||
|
|
||||||
void testZones( BOARD_COMMIT& aCommit );
|
|
||||||
|
|
||||||
void testCopperDrawItem( BOARD_COMMIT& aCommit, BOARD_ITEM* aDrawing );
|
|
||||||
|
|
||||||
void testCopperTextAndGraphics( BOARD_COMMIT& aCommit );
|
|
||||||
|
|
||||||
// Tests for items placed on disabled layers (causing false connections).
|
|
||||||
void testDisabledLayers( BOARD_COMMIT& aCommit );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that the board outline is contiguous and composed of valid elements
|
|
||||||
*/
|
|
||||||
void testOutline( BOARD_COMMIT& aCommit );
|
|
||||||
|
|
||||||
//-----<single "item" tests>-----------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the clearance between aRefPad and other pads.
|
|
||||||
*
|
|
||||||
* The pad list must be sorted by x coordinate.
|
|
||||||
*
|
|
||||||
* @param aRefPad is the pad to test
|
|
||||||
* @param aStart is the first pad of the list to test against aRefPad
|
|
||||||
* @param aEnd is the end of the list and is not included
|
|
||||||
* @param x_limit is used to stop the test
|
|
||||||
* (i.e. when the current pad pos X in list exceeds this limit, because the list
|
|
||||||
* is sorted by X coordinate)
|
|
||||||
*/
|
|
||||||
bool doPadToPadsDrc( BOARD_COMMIT& aCommit, D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd,
|
|
||||||
int x_limit );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the current segment.
|
|
||||||
*
|
|
||||||
* @param aRefSeg The segment to test
|
|
||||||
* @param aStartIt the iterator to the first track to test
|
|
||||||
* @param aEndIt the marker for the iterator end
|
|
||||||
* @param aTestZones true if should do copper zones test. This can be very time consumming
|
|
||||||
* @param aLayer sets the layer to test against
|
|
||||||
* @return bool - true if no problems, else false and m_currentMarker is
|
|
||||||
* filled in with the problem information.
|
|
||||||
*/
|
|
||||||
void doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
|
|
||||||
TRACKS::iterator aEndIt, bool aTestZones, PCB_LAYER_ID aLayer );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test a single via for DRC errors
|
|
||||||
*
|
|
||||||
* @param aCommit The board commit to add DRC errors
|
|
||||||
* @param aRefVia The via to test against design settings
|
|
||||||
*/
|
|
||||||
void doSingleViaDRC( BOARD_COMMIT& aCommit, VIA* aRefVia );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test a single track segment for DRC errors
|
|
||||||
*
|
|
||||||
* @param aCommit The board commit to add DRC errors
|
|
||||||
* @param aRefSeg The track to test against design settings
|
|
||||||
*/
|
|
||||||
void doSingleTrackDRC( BOARD_COMMIT& aCommit, TRACK* aRefSeg );
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Load the DRC rules. Must be called after the netclasses have been read.
|
* Load the DRC rules. Must be called after the netclasses have been read.
|
||||||
*/
|
*/
|
||||||
bool LoadRules();
|
bool LoadRules();
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches a reasonable point for marking a violoation between two non-point objects.
|
|
||||||
*/
|
|
||||||
static wxPoint GetLocation( PCB_LAYER_ID aLayer, TRACK* aTrack, ZONE_CONTAINER* aZone );
|
|
||||||
static wxPoint GetLocation( TRACK* aTrack, const SEG& aSeg );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open a dialog and prompts the user, then if a test run button is
|
|
||||||
* clicked, runs the test(s) and creates the MARKERS. The dialog is only
|
|
||||||
* created if it is not already in existence.
|
|
||||||
*
|
|
||||||
* @param aParent is the parent window for wxWidgets. Usually the PCB editor frame
|
|
||||||
* but can be another dialog
|
|
||||||
* if aParent == NULL (default), the parent will be the PCB editor frame
|
|
||||||
* and the dialog will be not modal (just float on parent
|
|
||||||
* if aParent is specified, the dialog will be modal.
|
|
||||||
* The modal mode is mandatory if the dialog is created from another dialog, not
|
|
||||||
* from the PCB editor frame
|
|
||||||
*/
|
|
||||||
void ShowDRCDialog( wxWindow* aParent );
|
|
||||||
|
|
||||||
int ShowDRCDialog( const TOOL_EVENT& aEvent );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check to see if the DRC dialog is currently shown
|
|
||||||
*
|
|
||||||
* @return true if the dialog is shown
|
|
||||||
*/
|
|
||||||
bool IsDRCDialogShown();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes this ui dialog box and zeros out its pointer to remember
|
|
||||||
* the state of the dialog's existence.
|
|
||||||
*
|
|
||||||
* @param aReason Indication of which button was clicked to cause the destruction.
|
|
||||||
* if aReason == wxID_OK, design parameters values which can be entered from the dialog
|
|
||||||
* will bbe saved in design parameters list
|
|
||||||
*/
|
|
||||||
void DestroyDRCDialog( int aReason );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run all the tests specified with a previous call to
|
|
||||||
* SetSettings()
|
|
||||||
* @param aMessages = a wxTextControl where to display some activity messages. Can be NULL
|
|
||||||
*/
|
|
||||||
void RunTests( wxTextCtrl* aMessages = NULL );
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,546 +0,0 @@
|
||||||
/*
|
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2004-2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
|
||||||
* Copyright (C) 2007 Dick Hollenbeck, dick@softplc.com
|
|
||||||
* Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, you may find one here:
|
|
||||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
||||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
||||||
* or you may write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <fctsys.h>
|
|
||||||
#include <trigo.h>
|
|
||||||
#include <drc/drc.h>
|
|
||||||
#include <class_board.h>
|
|
||||||
#include <class_track.h>
|
|
||||||
#include <class_drawsegment.h>
|
|
||||||
#include <class_marker_pcb.h>
|
|
||||||
#include <geometry/polygon_test_point_inside.h>
|
|
||||||
#include <geometry/shape_rect.h>
|
|
||||||
#include <geometry/shape_segment.h>
|
|
||||||
|
|
||||||
void DRC::doSingleViaDRC( BOARD_COMMIT& aCommit, VIA* aRefVia )
|
|
||||||
{
|
|
||||||
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
|
|
||||||
|
|
||||||
// test if the via size is smaller than minimum
|
|
||||||
if( aRefVia->GetViaType() == VIATYPE::MICROVIA )
|
|
||||||
{
|
|
||||||
if( aRefVia->GetWidth() < bds.m_MicroViasMinSize )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ANNULUS );
|
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
|
|
||||||
MessageTextFromValue( userUnits(), bds.m_MicroViasMinSize, true ),
|
|
||||||
MessageTextFromValue( userUnits(), aRefVia->GetWidth(), true ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( aRefVia );
|
|
||||||
|
|
||||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
|
|
||||||
addMarkerToPcb( aCommit, marker );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( aRefVia->GetWidth() < bds.m_ViasMinSize )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ANNULUS );
|
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
|
|
||||||
MessageTextFromValue( userUnits(), bds.m_ViasMinSize, true ),
|
|
||||||
MessageTextFromValue( userUnits(), aRefVia->GetWidth(), true ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( aRefVia );
|
|
||||||
|
|
||||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
|
|
||||||
addMarkerToPcb( aCommit, marker );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// test if via's hole is bigger than its diameter
|
|
||||||
// This test is necessary since the via hole size and width can be modified
|
|
||||||
// and a default via hole can be bigger than some vias sizes
|
|
||||||
if( aRefVia->GetDrillValue() > aRefVia->GetWidth() )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_VIA_HOLE_BIGGER );
|
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (diameter %s; drill %s)" ),
|
|
||||||
MessageTextFromValue( userUnits(), aRefVia->GetWidth(), true ),
|
|
||||||
MessageTextFromValue( userUnits(), aRefVia->GetDrillValue(), true ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( aRefVia );
|
|
||||||
|
|
||||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
|
|
||||||
addMarkerToPcb( aCommit, marker );
|
|
||||||
}
|
|
||||||
|
|
||||||
// test if the type of via is allowed due to design rules
|
|
||||||
if( aRefVia->GetViaType() == VIATYPE::MICROVIA && !bds.m_MicroViasAllowed )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ALLOWED_ITEMS );
|
|
||||||
|
|
||||||
m_msg.Printf( _( "Microvia not allowed (board design rule constraints)" ) );
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( aRefVia );
|
|
||||||
|
|
||||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
|
|
||||||
addMarkerToPcb( aCommit, marker );
|
|
||||||
}
|
|
||||||
|
|
||||||
// test if the type of via is allowed due to design rules
|
|
||||||
if( aRefVia->GetViaType() == VIATYPE::BLIND_BURIED && !bds.m_BlindBuriedViaAllowed )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ALLOWED_ITEMS );
|
|
||||||
|
|
||||||
m_msg.Printf( _( "Blind/buried via not allowed (board design rule constraints)" ) );
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( aRefVia );
|
|
||||||
|
|
||||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
|
|
||||||
addMarkerToPcb( aCommit, marker );
|
|
||||||
}
|
|
||||||
|
|
||||||
// For microvias: test if they are blind vias and only between 2 layers
|
|
||||||
// because they are used for very small drill size and are drill by laser
|
|
||||||
// and **only one layer** can be drilled
|
|
||||||
if( aRefVia->GetViaType() == VIATYPE::MICROVIA )
|
|
||||||
{
|
|
||||||
PCB_LAYER_ID layer1, layer2;
|
|
||||||
bool err = true;
|
|
||||||
|
|
||||||
aRefVia->LayerPair( &layer1, &layer2 );
|
|
||||||
|
|
||||||
if( layer1 > layer2 )
|
|
||||||
std::swap( layer1, layer2 );
|
|
||||||
|
|
||||||
if( layer2 == B_Cu && layer1 == bds.GetCopperLayerCount() - 2 )
|
|
||||||
err = false;
|
|
||||||
else if( layer1 == F_Cu && layer2 == In1_Cu )
|
|
||||||
err = false;
|
|
||||||
else if ( layer1 == layer2 - 1 )
|
|
||||||
err = false;
|
|
||||||
|
|
||||||
if( err )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_PADSTACK );
|
|
||||||
|
|
||||||
m_msg.Printf( _( "Microvia through too many layers (%s and %s not adjacent)" ),
|
|
||||||
m_pcb->GetLayerName( layer1 ),
|
|
||||||
m_pcb->GetLayerName( layer2 ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( aRefVia );
|
|
||||||
|
|
||||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
|
|
||||||
addMarkerToPcb( aCommit, marker );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DRC::doSingleTrackDRC( BOARD_COMMIT& aCommit, TRACK* aRefSeg )
|
|
||||||
{
|
|
||||||
SHAPE_SEGMENT refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd(), aRefSeg->GetWidth() );
|
|
||||||
EDA_RECT refSegBB = aRefSeg->GetBoundingBox();
|
|
||||||
int refSegWidth = aRefSeg->GetWidth();
|
|
||||||
|
|
||||||
int minWidth, maxWidth;
|
|
||||||
aRefSeg->GetWidthConstraints( &minWidth, &maxWidth, &m_clearanceSource );
|
|
||||||
|
|
||||||
int errorCode = 0;
|
|
||||||
int constraintWidth;
|
|
||||||
|
|
||||||
if( refSegWidth < minWidth )
|
|
||||||
{
|
|
||||||
errorCode = DRCE_TRACK_WIDTH;
|
|
||||||
constraintWidth = minWidth;
|
|
||||||
}
|
|
||||||
else if( refSegWidth > maxWidth )
|
|
||||||
{
|
|
||||||
errorCode = DRCE_TRACK_WIDTH;
|
|
||||||
constraintWidth = maxWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( errorCode )
|
|
||||||
{
|
|
||||||
wxPoint refsegMiddle = ( aRefSeg->GetStart() + aRefSeg->GetEnd() ) / 2;
|
|
||||||
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( errorCode );
|
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
|
|
||||||
m_clearanceSource,
|
|
||||||
MessageTextFromValue( userUnits(), constraintWidth, true ),
|
|
||||||
MessageTextFromValue( userUnits(), refSegWidth, true ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( aRefSeg );
|
|
||||||
|
|
||||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refsegMiddle );
|
|
||||||
addMarkerToPcb( aCommit, marker );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
|
|
||||||
TRACKS::iterator aEndIt, bool aTestZones, PCB_LAYER_ID aLayer )
|
|
||||||
{
|
|
||||||
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
|
|
||||||
SHAPE_SEGMENT refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd(), aRefSeg->GetWidth() );
|
|
||||||
|
|
||||||
EDA_RECT refSegBB = aRefSeg->GetBoundingBox();
|
|
||||||
SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
|
|
||||||
int halfWidth = ( aRefSeg->GetWidth() + 1 ) / 2;
|
|
||||||
|
|
||||||
/******************************************/
|
|
||||||
/* Phase 0 : via DRC tests : */
|
|
||||||
/******************************************/
|
|
||||||
|
|
||||||
if( aRefSeg->Type() == PCB_VIA_T )
|
|
||||||
{
|
|
||||||
VIA* refvia = static_cast<VIA*>( aRefSeg );
|
|
||||||
int viaAnnulus = ( refvia->GetWidth() - refvia->GetDrill() ) / 2;
|
|
||||||
int minAnnulus = refvia->GetMinAnnulus( aLayer, &m_clearanceSource );
|
|
||||||
|
|
||||||
if( !refvia->IsPadOnLayer( aLayer ) )
|
|
||||||
{
|
|
||||||
halfWidth = ( refvia->GetDrillValue() + 1 ) / 2;
|
|
||||||
refSegBB = EDA_RECT( refvia->GetStart(),
|
|
||||||
wxSize( refvia->GetDrillValue(), refvia->GetDrillValue() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// test if the via size is smaller than minimum
|
|
||||||
if( refvia->GetViaType() == VIATYPE::MICROVIA )
|
|
||||||
{
|
|
||||||
if( viaAnnulus < minAnnulus )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ANNULUS );
|
|
||||||
|
|
||||||
m_msg.Printf( _( "Via annulus too small (%s %s; actual %s)" ),
|
|
||||||
m_clearanceSource,
|
|
||||||
MessageTextFromValue( userUnits(), minAnnulus, true ),
|
|
||||||
MessageTextFromValue( userUnits(), viaAnnulus, true ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( refvia );
|
|
||||||
|
|
||||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
|
|
||||||
addMarkerToPcb( aCommit, marker );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( bds.m_ViasMinAnnulus > minAnnulus )
|
|
||||||
{
|
|
||||||
minAnnulus = bds.m_ViasMinAnnulus;
|
|
||||||
m_clearanceSource = _( "board minimum" );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( viaAnnulus < minAnnulus )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ANNULUS );
|
|
||||||
|
|
||||||
m_msg.Printf( _( "Via annulus too small (%s %s; actual %s)" ),
|
|
||||||
m_clearanceSource,
|
|
||||||
MessageTextFromValue( userUnits(), minAnnulus, true ),
|
|
||||||
MessageTextFromValue( userUnits(), viaAnnulus, true ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( refvia );
|
|
||||||
|
|
||||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
|
|
||||||
addMarkerToPcb( aCommit, marker );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************/
|
|
||||||
/* Phase 1 : test DRC track to pads : */
|
|
||||||
/******************************************/
|
|
||||||
|
|
||||||
// Compute the min distance to pads
|
|
||||||
for( MODULE* mod : m_pcb->Modules() )
|
|
||||||
{
|
|
||||||
// Don't preflight at the module level. Getting a module's bounding box goes
|
|
||||||
// through all its pads anyway (so it's no faster), and also all its drawings
|
|
||||||
// (so it's in fact slower).
|
|
||||||
|
|
||||||
for( D_PAD* pad : mod->Pads() )
|
|
||||||
{
|
|
||||||
// Preflight based on bounding boxes.
|
|
||||||
EDA_RECT inflatedBB = refSegBB;
|
|
||||||
inflatedBB.Inflate( pad->GetBoundingRadius() + m_largestClearance );
|
|
||||||
|
|
||||||
if( !inflatedBB.Contains( pad->GetPosition() ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( !( pad->IsOnLayer( aLayer ) ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// No need to check pads with the same net as the refSeg.
|
|
||||||
if( pad->GetNetCode() && aRefSeg->GetNetCode() == pad->GetNetCode() )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( pad->GetDrillSize().x > 0 )
|
|
||||||
{
|
|
||||||
const SHAPE_SEGMENT* slot = pad->GetEffectiveHoleShape();
|
|
||||||
const DRC_CONSTRAINT* constraint = GetConstraint( aRefSeg, pad,
|
|
||||||
DRC_CONSTRAINT_TYPE_CLEARANCE,
|
|
||||||
aLayer, &m_clearanceSource );
|
|
||||||
int minClearance;
|
|
||||||
int actual;
|
|
||||||
|
|
||||||
if( constraint )
|
|
||||||
{
|
|
||||||
m_clearanceSource = wxString::Format( _( "'%s' rule" ), m_clearanceSource );
|
|
||||||
minClearance = constraint->m_Value.Min();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
minClearance = aRefSeg->GetClearance( aLayer, nullptr, &m_clearanceSource );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( pad->GetAttribute() == PAD_ATTRIB_STANDARD )
|
|
||||||
minClearance += bds.GetHolePlatingThickness();
|
|
||||||
|
|
||||||
if( slot->Collide( &refSeg, minClearance + bds.GetDRCEpsilon(), &actual ) )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
|
||||||
m_clearanceSource,
|
|
||||||
MessageTextFromValue( userUnits(), minClearance, true ),
|
|
||||||
MessageTextFromValue( userUnits(), actual, true ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( aRefSeg, pad );
|
|
||||||
|
|
||||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() );
|
|
||||||
addMarkerToPcb( aCommit, marker );
|
|
||||||
|
|
||||||
if( !m_reportAllTrackErrors )
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Skip checking pad copper when it has been removed
|
|
||||||
if( !pad->IsPadOnLayer( aLayer ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int minClearance = aRefSeg->GetClearance( aLayer, pad, &m_clearanceSource );
|
|
||||||
int actual;
|
|
||||||
|
|
||||||
if( pad->Collide( &refSeg, minClearance - bds.GetDRCEpsilon(), &actual ) )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
|
||||||
m_clearanceSource,
|
|
||||||
MessageTextFromValue( userUnits(), minClearance, true ),
|
|
||||||
MessageTextFromValue( userUnits(), actual, true ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( aRefSeg, pad );
|
|
||||||
|
|
||||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() );
|
|
||||||
addMarkerToPcb( aCommit, marker );
|
|
||||||
|
|
||||||
if( !m_reportAllTrackErrors )
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************/
|
|
||||||
/* Phase 2: test DRC with other track segments */
|
|
||||||
/***********************************************/
|
|
||||||
|
|
||||||
// Test the reference segment with other track segments
|
|
||||||
for( auto it = aStartIt; it != aEndIt; it++ )
|
|
||||||
{
|
|
||||||
TRACK* track = *it;
|
|
||||||
|
|
||||||
// No problem if segments have the same net code:
|
|
||||||
if( aRefSeg->GetNetCode() == track->GetNetCode() )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( !track->GetLayerSet().test( aLayer ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Preflight based on worst-case inflated bounding boxes:
|
|
||||||
EDA_RECT trackBB = track->GetBoundingBox();
|
|
||||||
trackBB.Inflate( m_largestClearance );
|
|
||||||
|
|
||||||
if( !trackBB.Intersects( refSegBB ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int minClearance = aRefSeg->GetClearance( aLayer, track, &m_clearanceSource );
|
|
||||||
int actual;
|
|
||||||
SHAPE_SEGMENT trackSeg( track->GetStart(), track->GetEnd(), track->GetWidth() );
|
|
||||||
|
|
||||||
/// Check to see if the via has a pad on this layer
|
|
||||||
if( track->Type() == PCB_VIA_T )
|
|
||||||
{
|
|
||||||
VIA* via = static_cast<VIA*>( track );
|
|
||||||
|
|
||||||
if( !via->IsPadOnLayer( aLayer ) )
|
|
||||||
trackSeg.SetWidth( via->GetDrillValue() );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check two tracks crossing first as it reports a DRCE without distances
|
|
||||||
if( OPT_VECTOR2I intersection = refSeg.GetSeg().Intersect( trackSeg.GetSeg() ) )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TRACKS_CROSSING );
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( aRefSeg, track );
|
|
||||||
|
|
||||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, (wxPoint) intersection.get() );
|
|
||||||
addMarkerToPcb( aCommit, marker );
|
|
||||||
|
|
||||||
if( !m_reportAllTrackErrors )
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if( refSeg.Collide( &trackSeg, minClearance - bds.GetDRCEpsilon(), &actual ) )
|
|
||||||
{
|
|
||||||
wxPoint pos = GetLocation( aRefSeg, trackSeg.GetSeg() );
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
|
||||||
m_clearanceSource,
|
|
||||||
MessageTextFromValue( userUnits(), minClearance, true ),
|
|
||||||
MessageTextFromValue( userUnits(), actual, true ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( aRefSeg, track );
|
|
||||||
|
|
||||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, pos );
|
|
||||||
addMarkerToPcb( aCommit, marker );
|
|
||||||
|
|
||||||
if( !m_reportAllTrackErrors )
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************/
|
|
||||||
/* Phase 3: test DRC with copper zones */
|
|
||||||
/***************************************/
|
|
||||||
// Can be *very* time consumming.
|
|
||||||
|
|
||||||
if( aTestZones )
|
|
||||||
{
|
|
||||||
for( ZONE_CONTAINER* zone : m_pcb->Zones() )
|
|
||||||
{
|
|
||||||
if( !zone->GetLayerSet().test( aLayer ) || zone->GetIsKeepout() )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( zone->GetFilledPolysList( aLayer ).IsEmpty() )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int minClearance = aRefSeg->GetClearance( aLayer, zone, &m_clearanceSource );
|
|
||||||
int allowedDist = minClearance + halfWidth - bds.GetDRCEpsilon();
|
|
||||||
int actual;
|
|
||||||
|
|
||||||
if( zone->GetFilledPolysList( aLayer ).Collide( testSeg, allowedDist, &actual ) )
|
|
||||||
{
|
|
||||||
actual = std::max( 0, actual - halfWidth );
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
|
||||||
m_clearanceSource,
|
|
||||||
MessageTextFromValue( userUnits(), minClearance, true ),
|
|
||||||
MessageTextFromValue( userUnits(), actual, true ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( aRefSeg, zone );
|
|
||||||
|
|
||||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, GetLocation( aLayer, aRefSeg, zone ) );
|
|
||||||
addMarkerToPcb( aCommit, marker );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************/
|
|
||||||
/* Phase 4: test DRC with to board edge */
|
|
||||||
/***********************************************/
|
|
||||||
if( m_board_outline_valid )
|
|
||||||
{
|
|
||||||
int minClearance = bds.m_CopperEdgeClearance;
|
|
||||||
m_clearanceSource = _( "board edge" );
|
|
||||||
|
|
||||||
static DRAWSEGMENT dummyEdge;
|
|
||||||
dummyEdge.SetParent( m_pcb );
|
|
||||||
dummyEdge.SetLayer( Edge_Cuts );
|
|
||||||
|
|
||||||
aRefSeg->GetRuleClearance( &dummyEdge, aLayer, &minClearance, &m_clearanceSource );
|
|
||||||
|
|
||||||
int center2centerAllowed = minClearance + halfWidth - bds.GetDRCEpsilon();
|
|
||||||
|
|
||||||
for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ )
|
|
||||||
{
|
|
||||||
SEG::ecoord center2center_squared = testSeg.SquaredDistance( *it );
|
|
||||||
|
|
||||||
if( center2center_squared < SEG::Square( center2centerAllowed ) )
|
|
||||||
{
|
|
||||||
VECTOR2I pt = testSeg.NearestPoint( *it );
|
|
||||||
|
|
||||||
KICAD_T types[] = { PCB_LINE_T, EOT };
|
|
||||||
DRAWSEGMENT* edge = nullptr;
|
|
||||||
INSPECTOR_FUNC inspector =
|
|
||||||
[&] ( EDA_ITEM* item, void* testData )
|
|
||||||
{
|
|
||||||
DRAWSEGMENT* test_edge = dynamic_cast<DRAWSEGMENT*>( item );
|
|
||||||
|
|
||||||
if( !test_edge || test_edge->GetLayer() != Edge_Cuts )
|
|
||||||
return SEARCH_RESULT::CONTINUE;
|
|
||||||
|
|
||||||
if( test_edge->HitTest( (wxPoint) pt, minClearance + halfWidth ) )
|
|
||||||
{
|
|
||||||
edge = test_edge;
|
|
||||||
return SEARCH_RESULT::QUIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SEARCH_RESULT::CONTINUE;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Best-efforts search for edge segment
|
|
||||||
BOARD::IterateForward<BOARD_ITEM*>( m_pcb->Drawings(), inspector, nullptr, types );
|
|
||||||
|
|
||||||
int actual = std::max( 0.0, sqrt( center2center_squared ) - halfWidth );
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_COPPER_EDGE_CLEARANCE );
|
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
|
||||||
m_clearanceSource,
|
|
||||||
MessageTextFromValue( userUnits(), minClearance, true ),
|
|
||||||
MessageTextFromValue( userUnits(), actual, true ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( aRefSeg, edge );
|
|
||||||
|
|
||||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, (wxPoint) pt );
|
|
||||||
addMarkerToPcb( aCommit, marker );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,189 +0,0 @@
|
||||||
/*
|
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2010 Dick Hollenbeck, dick@softplc.com
|
|
||||||
* Copyright (C) 2004-2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
|
||||||
* Copyright (C) 2018-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, you may find one here:
|
|
||||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
||||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
||||||
* or you may write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <drc/drc_courtyard_tester.h>
|
|
||||||
|
|
||||||
#include <class_module.h>
|
|
||||||
#include <drc/drc.h>
|
|
||||||
|
|
||||||
#include <widgets/ui_common.h>
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <drc/drc_item.h>
|
|
||||||
|
|
||||||
DRC_COURTYARD_TESTER::DRC_COURTYARD_TESTER( MARKER_HANDLER aMarkerHandler ) :
|
|
||||||
LEGACY_DRC_TEST_PROVIDER( std::move( aMarkerHandler ) )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool DRC_COURTYARD_TESTER::RunDRC( EDA_UNITS aUnits, BOARD& aBoard )
|
|
||||||
{
|
|
||||||
// Detects missing (or malformed) footprint courtyards and courtyard incursions (for those
|
|
||||||
// with a courtyard).
|
|
||||||
wxString msg;
|
|
||||||
bool success = true;
|
|
||||||
|
|
||||||
// Update courtyard polygons, and test for missing courtyard definition:
|
|
||||||
for( MODULE* footprint : aBoard.Modules() )
|
|
||||||
{
|
|
||||||
if( footprint->BuildPolyCourtyard() )
|
|
||||||
{
|
|
||||||
if( !aBoard.GetDesignSettings().Ignore( DRCE_MISSING_COURTYARD )
|
|
||||||
&& footprint->GetPolyCourtyardFront().OutlineCount() == 0
|
|
||||||
&& footprint->GetPolyCourtyardBack().OutlineCount() == 0 )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MISSING_COURTYARD );
|
|
||||||
drcItem->SetItems( footprint );
|
|
||||||
HandleMarker( new MARKER_PCB( drcItem, footprint->GetPosition() ) );
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
footprint->GetPolyCourtyardFront().BuildBBoxCaches();
|
|
||||||
footprint->GetPolyCourtyardBack().BuildBBoxCaches();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( !aBoard.GetDesignSettings().Ignore( DRCE_MALFORMED_COURTYARD ) )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MALFORMED_COURTYARD );
|
|
||||||
|
|
||||||
msg.Printf( drcItem->GetErrorText() + _( " (not a closed shape)" ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( msg );
|
|
||||||
drcItem->SetItems( footprint );
|
|
||||||
HandleMarker( new MARKER_PCB( drcItem, footprint->GetPosition() ) );
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !aBoard.GetDesignSettings().Ignore( DRCE_OVERLAPPING_FOOTPRINTS ) )
|
|
||||||
{
|
|
||||||
for( auto it1 = aBoard.Modules().begin(); it1 != aBoard.Modules().end(); it1++ )
|
|
||||||
{
|
|
||||||
MODULE* footprint = *it1;
|
|
||||||
SHAPE_POLY_SET& footprintFront = footprint->GetPolyCourtyardFront();
|
|
||||||
SHAPE_POLY_SET& footprintBack = footprint->GetPolyCourtyardBack();
|
|
||||||
|
|
||||||
if( footprintFront.OutlineCount() == 0 && footprintBack.OutlineCount() == 0 )
|
|
||||||
continue; // No courtyards defined
|
|
||||||
|
|
||||||
for( auto it2 = it1 + 1; it2 != aBoard.Modules().end(); it2++ )
|
|
||||||
{
|
|
||||||
MODULE* test = *it2;
|
|
||||||
SHAPE_POLY_SET& testFront = test->GetPolyCourtyardFront();
|
|
||||||
SHAPE_POLY_SET& testBack = test->GetPolyCourtyardBack();
|
|
||||||
SHAPE_POLY_SET intersection;
|
|
||||||
bool overlap = false;
|
|
||||||
wxPoint pos;
|
|
||||||
|
|
||||||
if( footprintFront.OutlineCount() > 0 && testFront.OutlineCount() > 0
|
|
||||||
&& footprintFront.BBoxFromCaches().Intersects( testFront.BBoxFromCaches() ) )
|
|
||||||
{
|
|
||||||
intersection.RemoveAllContours();
|
|
||||||
intersection.Append( footprintFront );
|
|
||||||
|
|
||||||
// Build the common area between footprint and the test:
|
|
||||||
intersection.BooleanIntersection( testFront, SHAPE_POLY_SET::PM_FAST );
|
|
||||||
|
|
||||||
// If the intersection exists then they overlap
|
|
||||||
if( intersection.OutlineCount() > 0 )
|
|
||||||
{
|
|
||||||
overlap = true;
|
|
||||||
pos = (wxPoint) intersection.CVertex( 0, 0, -1 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( footprintBack.OutlineCount() > 0 && testBack.OutlineCount() > 0
|
|
||||||
&& footprintBack.BBoxFromCaches().Intersects( testBack.BBoxFromCaches() ) )
|
|
||||||
{
|
|
||||||
intersection.RemoveAllContours();
|
|
||||||
intersection.Append( footprintBack );
|
|
||||||
|
|
||||||
intersection.BooleanIntersection( testBack, SHAPE_POLY_SET::PM_FAST );
|
|
||||||
|
|
||||||
if( intersection.OutlineCount() > 0 )
|
|
||||||
{
|
|
||||||
overlap = true;
|
|
||||||
pos = (wxPoint) intersection.CVertex( 0, 0, -1 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( overlap )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_OVERLAPPING_FOOTPRINTS );
|
|
||||||
drcItem->SetItems( footprint, test );
|
|
||||||
HandleMarker( new MARKER_PCB( drcItem, pos ) );
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !aBoard.GetDesignSettings().Ignore( DRCE_PTH_IN_COURTYARD )
|
|
||||||
|| !aBoard.GetDesignSettings().Ignore( DRCE_NPTH_IN_COURTYARD ) )
|
|
||||||
{
|
|
||||||
for( MODULE* footprint : aBoard.Modules() )
|
|
||||||
{
|
|
||||||
SHAPE_POLY_SET& footprintFront = footprint->GetPolyCourtyardFront();
|
|
||||||
SHAPE_POLY_SET& footprintBack = footprint->GetPolyCourtyardBack();
|
|
||||||
|
|
||||||
if( footprintFront.OutlineCount() == 0 && footprintBack.OutlineCount() == 0 )
|
|
||||||
continue; // No courtyards defined
|
|
||||||
|
|
||||||
for( MODULE* candidate : aBoard.Modules() )
|
|
||||||
{
|
|
||||||
if( footprint == candidate )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for( D_PAD* pad : candidate->Pads() )
|
|
||||||
{
|
|
||||||
if( pad->GetDrillSize().x == 0 || pad->GetDrillSize().y == 0 )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
wxPoint pos = pad->GetPosition();
|
|
||||||
|
|
||||||
if( footprintFront.Contains( pos, -1, 0, true /* use bbox caches */ )
|
|
||||||
|| footprintBack.Contains( pos, -1, 0, true /* use bbox caches */ ) )
|
|
||||||
{
|
|
||||||
int code = pad->GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED ?
|
|
||||||
DRCE_NPTH_IN_COURTYARD :
|
|
||||||
DRCE_PTH_IN_COURTYARD;
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( code );
|
|
||||||
drcItem->SetItems( footprint, pad );
|
|
||||||
HandleMarker( new MARKER_PCB( drcItem, pos ) );
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
/*
|
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 KiCad Developers, see change_log.txt for contributors.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, you may find one here:
|
|
||||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
||||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
||||||
* or you may write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef DRC_COURTYARD_OVERLAP__H
|
|
||||||
#define DRC_COURTYARD_OVERLAP__H
|
|
||||||
|
|
||||||
#include <drc/drc_results_provider.h>
|
|
||||||
|
|
||||||
|
|
||||||
class BOARD;
|
|
||||||
|
|
||||||
class DRC_COURTYARD_TESTER : public LEGACY_DRC_TEST_PROVIDER
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DRC_COURTYARD_TESTER( MARKER_HANDLER aMarkerHandler );
|
|
||||||
|
|
||||||
virtual ~DRC_COURTYARD_TESTER() {};
|
|
||||||
|
|
||||||
bool RunDRC( EDA_UNITS aUnits, BOARD& aBoard ) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // DRC_COURTYARD_OVERLAP__H
|
|
|
@ -1,307 +0,0 @@
|
||||||
/*
|
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, you may find one here:
|
|
||||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
||||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
||||||
* or you may write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <drc/drc_drilled_hole_tester.h>
|
|
||||||
|
|
||||||
#include <class_module.h>
|
|
||||||
#include <drc/drc.h>
|
|
||||||
|
|
||||||
#include <widgets/ui_common.h>
|
|
||||||
|
|
||||||
|
|
||||||
DRC_DRILLED_HOLE_TESTER::DRC_DRILLED_HOLE_TESTER( MARKER_HANDLER aMarkerHandler ) :
|
|
||||||
LEGACY_DRC_TEST_PROVIDER( std::move( aMarkerHandler ) ),
|
|
||||||
m_units( EDA_UNITS::MILLIMETRES ),
|
|
||||||
m_board( nullptr ),
|
|
||||||
m_largestRadius( 0 )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool DRC_DRILLED_HOLE_TESTER::RunDRC( EDA_UNITS aUnits, BOARD& aBoard )
|
|
||||||
{
|
|
||||||
bool success = true;
|
|
||||||
|
|
||||||
// Test drilled holes to minimize drill bit breakage.
|
|
||||||
//
|
|
||||||
// Check pad & std. via circular holes for hole-to-hole-min (non-circular holes are milled)
|
|
||||||
// Check pad & std. via holes for via-min-drill (minimum hole classification)
|
|
||||||
// Check uvia holes for uvia-min-drill (laser drill classification)
|
|
||||||
|
|
||||||
m_units = aUnits;
|
|
||||||
m_board = &aBoard;
|
|
||||||
m_holes.clear();
|
|
||||||
m_largestRadius = 0;
|
|
||||||
|
|
||||||
for( MODULE* mod : aBoard.Modules() )
|
|
||||||
{
|
|
||||||
for( D_PAD* pad : mod->Pads( ) )
|
|
||||||
success &= checkPad( pad );
|
|
||||||
}
|
|
||||||
|
|
||||||
for( TRACK* track : aBoard.Tracks() )
|
|
||||||
{
|
|
||||||
VIA* via = dynamic_cast<VIA*>( track );
|
|
||||||
|
|
||||||
if( via )
|
|
||||||
{
|
|
||||||
if( via->GetViaType() == VIATYPE::MICROVIA )
|
|
||||||
success &= checkMicroVia( via );
|
|
||||||
else
|
|
||||||
success &= checkVia( via );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
success &= checkHoles();
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool DRC_DRILLED_HOLE_TESTER::checkPad( D_PAD* aPad )
|
|
||||||
{
|
|
||||||
bool success = true;
|
|
||||||
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
|
||||||
|
|
||||||
// drilled holes go all the way through, so which layer we use shouldn't matter
|
|
||||||
PCB_LAYER_ID layer = F_Cu;
|
|
||||||
int holeSize = std::min( aPad->GetDrillSize().x, aPad->GetDrillSize().y );
|
|
||||||
|
|
||||||
if( holeSize == 0 )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if( !bds.Ignore( DRCE_TOO_SMALL_DRILL ) )
|
|
||||||
{
|
|
||||||
int minHole;
|
|
||||||
const DRC_CONSTRAINT* constraint = GetConstraint( aPad, nullptr, DRC_CONSTRAINT_TYPE_HOLE_SIZE,
|
|
||||||
layer, &m_source );
|
|
||||||
|
|
||||||
if( constraint )
|
|
||||||
{
|
|
||||||
minHole = constraint->m_Value.Min();
|
|
||||||
m_source = wxString::Format( _( "'%s' rule" ), m_source );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
minHole = bds.m_MinThroughDrill;
|
|
||||||
m_source = _( "board minimum" );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( holeSize < minHole )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_DRILL );
|
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
|
|
||||||
m_source,
|
|
||||||
MessageTextFromValue( m_units, minHole, true ),
|
|
||||||
MessageTextFromValue( m_units, holeSize, true ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( aPad );
|
|
||||||
|
|
||||||
HandleMarker( new MARKER_PCB( drcItem, aPad->GetPosition() ) );
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !bds.Ignore( DRCE_DRILLED_HOLES_TOO_CLOSE ) && bds.m_HoleToHoleMin != 0 )
|
|
||||||
{
|
|
||||||
if( aPad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
|
|
||||||
addHole( aPad->GetPosition(), aPad->GetDrillSize().x / 2, aPad );
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DRC_DRILLED_HOLE_TESTER::checkVia( VIA* via )
|
|
||||||
{
|
|
||||||
bool success = true;
|
|
||||||
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
|
||||||
|
|
||||||
// drilled holes go all the way through, so which layer we use shouldn't matter
|
|
||||||
PCB_LAYER_ID layer = F_Cu;
|
|
||||||
|
|
||||||
if( !bds.Ignore( DRCE_TOO_SMALL_DRILL ) )
|
|
||||||
{
|
|
||||||
int minHole;
|
|
||||||
const DRC_CONSTRAINT* constraint = GetConstraint( via, nullptr, DRC_CONSTRAINT_TYPE_HOLE_SIZE,
|
|
||||||
layer, &m_source );
|
|
||||||
|
|
||||||
if( constraint )
|
|
||||||
{
|
|
||||||
minHole = constraint->m_Value.Min();
|
|
||||||
m_source = wxString::Format( _( "'%s' rule" ), m_source );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
minHole = bds.m_MinThroughDrill;
|
|
||||||
m_source = _( "board minimum" );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( via->GetDrillValue() < minHole )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_DRILL );
|
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
|
|
||||||
m_source,
|
|
||||||
MessageTextFromValue( m_units, minHole, true ),
|
|
||||||
MessageTextFromValue( m_units, via->GetDrillValue(), true ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( via );
|
|
||||||
|
|
||||||
HandleMarker( new MARKER_PCB( drcItem, via->GetPosition() ) );
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !bds.Ignore( DRCE_DRILLED_HOLES_TOO_CLOSE ) && bds.m_HoleToHoleMin != 0 )
|
|
||||||
{
|
|
||||||
addHole( via->GetPosition(), via->GetDrillValue() / 2, via );
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool DRC_DRILLED_HOLE_TESTER::checkMicroVia( VIA* via )
|
|
||||||
{
|
|
||||||
bool success = true;
|
|
||||||
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
|
||||||
|
|
||||||
// while microvia holes don't necessarily go all the way through, they can't be different
|
|
||||||
// sizes on different layers so we should still be safe enough using a fixed layer.
|
|
||||||
PCB_LAYER_ID layer = F_Cu;
|
|
||||||
|
|
||||||
if( !bds.Ignore( DRCE_TOO_SMALL_MICROVIA_DRILL ) )
|
|
||||||
{
|
|
||||||
int minHole;
|
|
||||||
const DRC_CONSTRAINT* constraint = GetConstraint( via, nullptr, DRC_CONSTRAINT_TYPE_HOLE_SIZE,
|
|
||||||
layer, &m_source );
|
|
||||||
|
|
||||||
if( constraint )
|
|
||||||
{
|
|
||||||
minHole = constraint->m_Value.Min();
|
|
||||||
m_source = wxString::Format( _( "'%s' rule" ), m_source );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
minHole = bds.m_MicroViasMinDrill;
|
|
||||||
m_source = _( "board minimum" );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( via->GetDrillValue() < minHole )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_MICROVIA_DRILL );
|
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
|
|
||||||
m_source,
|
|
||||||
MessageTextFromValue( m_units, minHole, true ),
|
|
||||||
MessageTextFromValue( m_units, via->GetDrillValue(), true ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( via );
|
|
||||||
|
|
||||||
HandleMarker( new MARKER_PCB( drcItem, via->GetPosition() ) );
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DRC_DRILLED_HOLE_TESTER::addHole( const wxPoint& aLocation, int aRadius, BOARD_ITEM* aOwner )
|
|
||||||
{
|
|
||||||
DRILLED_HOLE hole;
|
|
||||||
|
|
||||||
hole.m_location = aLocation;
|
|
||||||
hole.m_drillRadius = aRadius;
|
|
||||||
hole.m_owner = aOwner;
|
|
||||||
|
|
||||||
m_largestRadius = std::max( m_largestRadius, aRadius );
|
|
||||||
|
|
||||||
m_holes.push_back( hole );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool DRC_DRILLED_HOLE_TESTER::checkHoles()
|
|
||||||
{
|
|
||||||
bool success = true;
|
|
||||||
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
|
||||||
|
|
||||||
// No need to check if we're ignoring DRCE_DRILLED_HOLES_TOO_CLOSE; if we are then we
|
|
||||||
// won't have collected any holes to test.
|
|
||||||
|
|
||||||
// Sort holes by X for performance. In the nested iteration we then need to look at
|
|
||||||
// following holes only while they are within the refHole's neighborhood as defined by
|
|
||||||
// the refHole radius + the minimum hole-to-hole clearance + the largest radius any of
|
|
||||||
// the following holes can have.
|
|
||||||
std::sort( m_holes.begin(), m_holes.end(),
|
|
||||||
[]( const DRILLED_HOLE& a, const DRILLED_HOLE& b )
|
|
||||||
{
|
|
||||||
if( a.m_location.x == b.m_location.x )
|
|
||||||
return a.m_location.y < b.m_location.y;
|
|
||||||
else
|
|
||||||
return a.m_location.x < b.m_location.x;
|
|
||||||
} );
|
|
||||||
|
|
||||||
for( size_t ii = 0; ii < m_holes.size(); ++ii )
|
|
||||||
{
|
|
||||||
const DRILLED_HOLE& refHole = m_holes[ ii ];
|
|
||||||
int neighborhood = refHole.m_drillRadius + bds.m_HoleToHoleMin + m_largestRadius;
|
|
||||||
|
|
||||||
for( size_t jj = ii + 1; jj < m_holes.size(); ++jj )
|
|
||||||
{
|
|
||||||
const DRILLED_HOLE& checkHole = m_holes[ jj ];
|
|
||||||
|
|
||||||
if( refHole.m_location.x + neighborhood < checkHole.m_location.x )
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Holes with identical locations are allowable
|
|
||||||
if( checkHole.m_location == refHole.m_location )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int actual = KiROUND( GetLineLength( checkHole.m_location, refHole.m_location ) );
|
|
||||||
actual = std::max( 0, actual - checkHole.m_drillRadius - refHole.m_drillRadius );
|
|
||||||
|
|
||||||
if( actual < bds.m_HoleToHoleMin )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_DRILLED_HOLES_TOO_CLOSE );
|
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
|
|
||||||
MessageTextFromValue( m_units, bds.m_HoleToHoleMin, true ),
|
|
||||||
MessageTextFromValue( m_units, actual, true ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( refHole.m_owner, checkHole.m_owner );
|
|
||||||
|
|
||||||
HandleMarker( new MARKER_PCB( drcItem, refHole.m_location ) );
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
/*
|
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 KiCad Developers, see change_log.txt for contributors.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, you may find one here:
|
|
||||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
||||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
||||||
* or you may write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef DRC_DRILLED_HOLE_TESTER__H
|
|
||||||
#define DRC_DRILLED_HOLE_TESTER__H
|
|
||||||
|
|
||||||
#include <drc/drc_results_provider.h>
|
|
||||||
|
|
||||||
|
|
||||||
class BOARD;
|
|
||||||
class BOARD_ITEM;
|
|
||||||
|
|
||||||
|
|
||||||
class DRC_DRILLED_HOLE_TESTER : public LEGACY_DRC_TEST_PROVIDER
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DRC_DRILLED_HOLE_TESTER( MARKER_HANDLER aMarkerHandler );
|
|
||||||
|
|
||||||
virtual ~DRC_DRILLED_HOLE_TESTER() {};
|
|
||||||
|
|
||||||
bool RunDRC( EDA_UNITS aUnits, BOARD& aBoard ) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool checkPad( D_PAD* aPad );
|
|
||||||
bool checkVia( VIA* aVia );
|
|
||||||
bool checkMicroVia( VIA* aVia );
|
|
||||||
|
|
||||||
void addHole( const wxPoint& aLocation, int aRadius, BOARD_ITEM* aOwner );
|
|
||||||
bool checkHoles();
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct DRILLED_HOLE
|
|
||||||
{
|
|
||||||
wxPoint m_location;
|
|
||||||
int m_drillRadius = 0;
|
|
||||||
BOARD_ITEM* m_owner = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
EDA_UNITS m_units;
|
|
||||||
BOARD* m_board;
|
|
||||||
std::vector<DRILLED_HOLE> m_holes;
|
|
||||||
int m_largestRadius;
|
|
||||||
|
|
||||||
wxString m_source; // Construct only once for performance
|
|
||||||
wxString m_msg; // Construct only once for performance
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // DRC_DRILLED_HOLE_TESTER__H
|
|
|
@ -87,7 +87,7 @@ void DRC_ENGINE::loadImplicitRules()
|
||||||
|
|
||||||
// 1) global defaults
|
// 1) global defaults
|
||||||
|
|
||||||
DRC_RULE* rule = createImplicitRule( _( "board setup > design rules > constraints" ));
|
DRC_RULE* rule = createImplicitRule( _( "board setup constraints" ));
|
||||||
|
|
||||||
DRC_CONSTRAINT clearanceConstraint( DRC_CONSTRAINT_TYPE_CLEARANCE );
|
DRC_CONSTRAINT clearanceConstraint( DRC_CONSTRAINT_TYPE_CLEARANCE );
|
||||||
clearanceConstraint.Value().SetMin( bds.m_MinClearance );
|
clearanceConstraint.Value().SetMin( bds.m_MinClearance );
|
||||||
|
@ -123,7 +123,7 @@ void DRC_ENGINE::loadImplicitRules()
|
||||||
|
|
||||||
// 2) micro-via specific defaults (new DRC doesn't treat microvias in any special way)
|
// 2) micro-via specific defaults (new DRC doesn't treat microvias in any special way)
|
||||||
|
|
||||||
DRC_RULE* uViaRule = createImplicitRule( _( "board setup > design rules > constraints" ));
|
DRC_RULE* uViaRule = createImplicitRule( _( "board setup constraints" ));
|
||||||
|
|
||||||
uViaRule->m_Condition = new DRC_RULE_CONDITION ( "A.Via_Type == 'micro_via'" );
|
uViaRule->m_Condition = new DRC_RULE_CONDITION ( "A.Via_Type == 'micro_via'" );
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ void DRC_ENGINE::loadImplicitRules()
|
||||||
|
|
||||||
if( !bds.m_BlindBuriedViaAllowed )
|
if( !bds.m_BlindBuriedViaAllowed )
|
||||||
{
|
{
|
||||||
DRC_RULE* bbViaRule = createImplicitRule( _( "board setup > design rules > constraints" ));
|
DRC_RULE* bbViaRule = createImplicitRule( _( "board setup constraints" ));
|
||||||
|
|
||||||
bbViaRule->m_Condition = new DRC_RULE_CONDITION ( "A.Via_Type == 'buried_via'" );
|
bbViaRule->m_Condition = new DRC_RULE_CONDITION ( "A.Via_Type == 'buried_via'" );
|
||||||
|
|
||||||
|
@ -188,13 +188,6 @@ void DRC_ENGINE::loadImplicitRules()
|
||||||
ncClearanceConstraint.Value().SetMin( nc->GetClearance() );
|
ncClearanceConstraint.Value().SetMin( nc->GetClearance() );
|
||||||
netclassRule->AddConstraint( ncClearanceConstraint );
|
netclassRule->AddConstraint( ncClearanceConstraint );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( nc->GetTrackWidth() > bds.m_TrackMinWidth )
|
|
||||||
{
|
|
||||||
DRC_CONSTRAINT ncWidthConstraint( DRC_CONSTRAINT_TYPE_TRACK_WIDTH );
|
|
||||||
ncWidthConstraint.Value().SetMin( nc->GetTrackWidth() );
|
|
||||||
netclassRule->AddConstraint( ncWidthConstraint );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,23 +295,21 @@ bool DRC_ENGINE::CompileRules()
|
||||||
for( DRC_TEST_PROVIDER* provider : m_testProviders )
|
for( DRC_TEST_PROVIDER* provider : m_testProviders )
|
||||||
{
|
{
|
||||||
ReportAux( wxString::Format( "- Provider: '%s': ", provider->GetName() ) );
|
ReportAux( wxString::Format( "- Provider: '%s': ", provider->GetName() ) );
|
||||||
drc_dbg(7, "do prov %s", provider->GetName() );
|
drc_dbg( 7, "do prov %s", provider->GetName() );
|
||||||
|
|
||||||
for ( DRC_CONSTRAINT_TYPE_T id : provider->GetConstraintTypes() )
|
for( DRC_CONSTRAINT_TYPE_T id : provider->GetConstraintTypes() )
|
||||||
{
|
{
|
||||||
drc_dbg( 7, "do id %d", id );
|
drc_dbg( 7, "do id %d", id );
|
||||||
|
|
||||||
if( m_constraintMap.find( id ) == m_constraintMap.end() )
|
if( m_constraintMap.find( id ) == m_constraintMap.end() )
|
||||||
m_constraintMap[ id ] = new CONSTRAINT_SET;
|
m_constraintMap[ id ] = new std::vector<CONSTRAINT_WITH_CONDITIONS*>();
|
||||||
|
|
||||||
m_constraintMap[ id ]->provider = provider;
|
|
||||||
|
|
||||||
for( DRC_RULE* rule : m_rules )
|
for( DRC_RULE* rule : m_rules )
|
||||||
{
|
{
|
||||||
DRC_RULE_CONDITION* condition = nullptr;
|
DRC_RULE_CONDITION* condition = nullptr;
|
||||||
bool compileOk = false;
|
bool compileOk = false;
|
||||||
std::vector<DRC_CONSTRAINT> matchingConstraints;
|
std::vector<DRC_CONSTRAINT> matchingConstraints;
|
||||||
drc_dbg(7, "Scan provider %s, rule %s", provider->GetName(), rule->m_Name );
|
drc_dbg( 7, "Scan provider %s, rule %s", provider->GetName(), rule->m_Name );
|
||||||
|
|
||||||
if( rule->m_Condition && !rule->m_Condition->GetExpression().IsEmpty() )
|
if( rule->m_Condition && !rule->m_Condition->GetExpression().IsEmpty() )
|
||||||
{
|
{
|
||||||
|
@ -342,7 +333,7 @@ bool DRC_ENGINE::CompileRules()
|
||||||
|
|
||||||
rcons->constraint = constraint;
|
rcons->constraint = constraint;
|
||||||
rcons->parentRule = rule;
|
rcons->parentRule = rule;
|
||||||
m_constraintMap[ id ]->sortedConstraints.push_back( rcons );
|
m_constraintMap[ id ]->push_back( rcons );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !matchingConstraints.empty() )
|
if( !matchingConstraints.empty() )
|
||||||
|
@ -391,9 +382,22 @@ void DRC_ENGINE::InitEngine( const wxFileName& aRulePath )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DRC_ENGINE::RunTests( DRC_VIOLATION_HANDLER aViolationHandler )
|
void DRC_ENGINE::RunTests( EDA_UNITS aUnits, bool aTestTracksAgainstZones,
|
||||||
|
bool aReportAllTrackErrors, bool aTestFootprints )
|
||||||
{
|
{
|
||||||
m_violationHandler = std::move( aViolationHandler );
|
m_userUnits = aUnits;
|
||||||
|
|
||||||
|
// Note: set these first. The phase counts may be dependent on some of them.
|
||||||
|
m_testTracksAgainstZones = aTestTracksAgainstZones;
|
||||||
|
m_reportAllTrackErrors = aReportAllTrackErrors;
|
||||||
|
m_testFootprints = aTestFootprints;
|
||||||
|
|
||||||
|
int phases = 0;
|
||||||
|
|
||||||
|
for( DRC_TEST_PROVIDER* provider : m_testProviders )
|
||||||
|
phases += provider->GetNumPhases();
|
||||||
|
|
||||||
|
m_progressReporter->AddPhases( phases );
|
||||||
|
|
||||||
for( int ii = DRCE_FIRST; ii < DRCE_LAST; ++ii )
|
for( int ii = DRCE_FIRST; ii < DRCE_LAST; ++ii )
|
||||||
{
|
{
|
||||||
|
@ -405,27 +409,8 @@ void DRC_ENGINE::RunTests( DRC_VIOLATION_HANDLER aViolationHandler )
|
||||||
|
|
||||||
for( DRC_TEST_PROVIDER* provider : m_testProviders )
|
for( DRC_TEST_PROVIDER* provider : m_testProviders )
|
||||||
{
|
{
|
||||||
bool skipProvider = false;
|
drc_dbg( 0, "Running test provider: '%s'\n", provider->GetName() );
|
||||||
auto providedConstraints = provider->GetConstraintTypes();
|
|
||||||
|
|
||||||
if( providedConstraints.size() )
|
|
||||||
{
|
|
||||||
for( DRC_CONSTRAINT_TYPE_T constraintType : providedConstraints )
|
|
||||||
{
|
|
||||||
if( !HasRulesForConstraintType( constraintType ) )
|
|
||||||
{
|
|
||||||
ReportAux( wxString::Format( "DRC provider '%s' has no rules provided. Skipping run.",
|
|
||||||
provider->GetName() ) );
|
|
||||||
skipProvider = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( skipProvider )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
drc_dbg(0, "Running test provider: '%s'\n", provider->GetName() );
|
|
||||||
ReportAux( wxString::Format( "Run DRC provider: '%s'", provider->GetName() ) );
|
ReportAux( wxString::Format( "Run DRC provider: '%s'", provider->GetName() ) );
|
||||||
provider->Run();
|
provider->Run();
|
||||||
}
|
}
|
||||||
|
@ -438,39 +423,33 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRulesForItems( DRC_CONSTRAINT_TYPE_T aConstraintI
|
||||||
{
|
{
|
||||||
#define REPORT( s ) { if( aReporter ) { aReporter->Report( s ); } }
|
#define REPORT( s ) { if( aReporter ) { aReporter->Report( s ); } }
|
||||||
|
|
||||||
|
auto* connectedA = a && a->IsConnected() ? static_cast<BOARD_CONNECTED_ITEM*>( a ) : nullptr;
|
||||||
|
auto* connectedB = b && b->IsConnected() ? static_cast<BOARD_CONNECTED_ITEM*>( b ) : nullptr;
|
||||||
|
|
||||||
// Local overrides take precedence
|
// Local overrides take precedence
|
||||||
if( aConstraintId == DRC_CONSTRAINT_TYPE_CLEARANCE )
|
if( aConstraintId == DRC_CONSTRAINT_TYPE_CLEARANCE )
|
||||||
{
|
{
|
||||||
BOARD_CONNECTED_ITEM* ac = a->IsConnected() ? static_cast<BOARD_CONNECTED_ITEM*>( a )
|
|
||||||
: nullptr;
|
|
||||||
BOARD_CONNECTED_ITEM* bc = b->IsConnected() ? static_cast<BOARD_CONNECTED_ITEM*>( b )
|
|
||||||
: nullptr;
|
|
||||||
int overrideA = 0;
|
int overrideA = 0;
|
||||||
int overrideB = 0;
|
int overrideB = 0;
|
||||||
|
|
||||||
if( ac && ac->GetLocalClearanceOverrides( nullptr ) > 0 )
|
if( connectedA && connectedA->GetLocalClearanceOverrides( nullptr ) > 0 )
|
||||||
{
|
{
|
||||||
overrideA = ac->GetLocalClearanceOverrides( &m_msg );
|
overrideA = connectedA->GetLocalClearanceOverrides( &m_msg );
|
||||||
|
|
||||||
|
REPORT( "" )
|
||||||
REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
|
REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
|
||||||
a->GetSelectMenuText( aReporter->GetUnits() ),
|
a->GetSelectMenuText( aReporter->GetUnits() ),
|
||||||
StringFromValue( aReporter->GetUnits(), overrideA, true ) ) )
|
StringFromValue( aReporter->GetUnits(), overrideA, true ) ) )
|
||||||
}
|
}
|
||||||
|
|
||||||
if( bc && bc->GetLocalClearanceOverrides( nullptr ) > 0 )
|
if( connectedB && connectedB->GetLocalClearanceOverrides( nullptr ) > 0 )
|
||||||
{
|
{
|
||||||
overrideB = bc->GetLocalClearanceOverrides( &m_msg );
|
overrideB = connectedB->GetLocalClearanceOverrides( &m_msg );
|
||||||
|
|
||||||
|
REPORT( "" )
|
||||||
REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
|
REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
|
||||||
b->GetSelectMenuText( aReporter->GetUnits() ),
|
b->GetSelectMenuText( aReporter->GetUnits() ),
|
||||||
StringFromValue( aReporter->GetUnits(), overrideB, true ) ) )
|
StringFromValue( aReporter->GetUnits(), overrideB, true ) ) )
|
||||||
|
|
||||||
// If both overridden, report on which wins
|
|
||||||
if( overrideA )
|
|
||||||
{
|
|
||||||
REPORT( wxString::Format( _( "Clearance: %s." ),
|
|
||||||
std::max( overrideA, overrideB ) ) )
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( overrideA || overrideB )
|
if( overrideA || overrideB )
|
||||||
|
@ -481,17 +460,34 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRulesForItems( DRC_CONSTRAINT_TYPE_T aConstraintI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CONSTRAINT_SET* ruleset = m_constraintMap[ aConstraintId ];
|
std::vector<CONSTRAINT_WITH_CONDITIONS*>* ruleset = m_constraintMap[ aConstraintId ];
|
||||||
|
|
||||||
for( ssize_t ii = ruleset->sortedConstraints.size() - 1; ii >= 0; --ii )
|
const DRC_CONSTRAINT* constraintRef = nullptr;
|
||||||
|
bool implicit = false;
|
||||||
|
|
||||||
|
// Last matching rule wins, so process in reverse order
|
||||||
|
for( int ii = (int) ruleset->size() - 1; ii >= 0; --ii )
|
||||||
{
|
{
|
||||||
const CONSTRAINT_WITH_CONDITIONS* rcons = ruleset->sortedConstraints[ ii ];
|
const CONSTRAINT_WITH_CONDITIONS* rcons = ruleset->at( ii );
|
||||||
bool implicit = rcons->parentRule && rcons->parentRule->m_Implicit;
|
implicit = rcons->parentRule && rcons->parentRule->m_Implicit;
|
||||||
|
|
||||||
if( implicit )
|
REPORT( "" )
|
||||||
REPORT( wxString::Format( _( "Checking %s." ), rcons->parentRule->m_Name ) )
|
|
||||||
|
if( aConstraintId == DRC_CONSTRAINT_TYPE_CLEARANCE )
|
||||||
|
{
|
||||||
|
int clearance = rcons->constraint.m_Value.Min();
|
||||||
|
REPORT( wxString::Format( _( "Checking %s %s; clearance: %s." ),
|
||||||
|
implicit ? _( "" ) : _( "rule" ),
|
||||||
|
rcons->parentRule->m_Name,
|
||||||
|
StringFromValue( aReporter->GetUnits(), clearance, true ) ) )
|
||||||
|
}
|
||||||
else
|
else
|
||||||
REPORT( wxString::Format( _( "Checking rule %s." ), rcons->parentRule->m_Name ) )
|
{
|
||||||
|
REPORT( wxString::Format( _( "Checking %s %s." ),
|
||||||
|
implicit ? _( "" ) : _( "rule" ),
|
||||||
|
rcons->parentRule->m_Name ) )
|
||||||
|
}
|
||||||
|
|
||||||
if( aLayer != UNDEFINED_LAYER && !rcons->layerTest.test( aLayer ) )
|
if( aLayer != UNDEFINED_LAYER && !rcons->layerTest.test( aLayer ) )
|
||||||
{
|
{
|
||||||
REPORT( wxString::Format( _( "Rule layer \"%s\" not matched." ),
|
REPORT( wxString::Format( _( "Rule layer \"%s\" not matched." ),
|
||||||
|
@ -501,50 +497,103 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRulesForItems( DRC_CONSTRAINT_TYPE_T aConstraintI
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wxString& expression = rcons->condition->GetExpression();
|
if( !rcons->condition || rcons->condition->GetExpression().IsEmpty() )
|
||||||
|
|
||||||
if( expression.IsEmpty() )
|
|
||||||
{
|
{
|
||||||
REPORT( implicit ? _( "Unconditional constraint applied." )
|
REPORT( implicit ? _( "Unconditional constraint applied." )
|
||||||
: _( "Unconditional rule applied." ) )
|
: _( "Unconditional rule applied." ) )
|
||||||
|
|
||||||
return rcons->constraint;
|
constraintRef = &rcons->constraint;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Don't report on implicit rule conditions; they're stuff we made up.
|
// Don't report on implicit rule conditions; they're synthetic.
|
||||||
if( !implicit )
|
if( !implicit )
|
||||||
REPORT( _( "Checking rule condition \"" + expression + "\"." ) )
|
{
|
||||||
|
REPORT( wxString::Format( _( "Checking rule condition \"%s\"." ),
|
||||||
|
rcons->condition->GetExpression() ) )
|
||||||
|
}
|
||||||
|
|
||||||
if( rcons->condition->EvaluateFor( a, b, aLayer, aReporter ) )
|
if( rcons->condition->EvaluateFor( a, b, aLayer, aReporter ) )
|
||||||
{
|
{
|
||||||
REPORT( implicit ? _( "Constraint applied." )
|
REPORT( implicit ? _( "Constraint applicable." )
|
||||||
: _( "Rule applied." ) )
|
: _( "Rule applied." ) )
|
||||||
|
|
||||||
return rcons->constraint;
|
constraintRef = &rcons->constraint;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
REPORT( implicit ? _( "Membership not satisfied; constraint not applied." )
|
REPORT( implicit ? _( "Membership not satisfied; constraint not applicable." )
|
||||||
: _( "Condition not satisfied; rule not applied." ) )
|
: _( "Condition not satisfied; rule not applied." ) )
|
||||||
REPORT( "" )
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unfortunately implicit rules don't work for local clearances (such as zones) because
|
||||||
|
// they have to be max'ed with netclass values (which are already implicit rules), and our
|
||||||
|
// rule selection paradigm is "winner takes all".
|
||||||
|
if( aConstraintId == DRC_CONSTRAINT_TYPE_CLEARANCE && implicit )
|
||||||
|
{
|
||||||
|
int global = constraintRef->m_Value.Min();
|
||||||
|
int localA = connectedA ? connectedA->GetLocalClearance( nullptr ) : 0;
|
||||||
|
int localB = connectedB ? connectedB->GetLocalClearance( nullptr ) : 0;
|
||||||
|
int clearance = global;
|
||||||
|
|
||||||
|
if( localA > 0 )
|
||||||
|
{
|
||||||
|
REPORT( "" )
|
||||||
|
REPORT( wxString::Format( _( "Local clearance on %s; clearance: %s." ),
|
||||||
|
a->GetSelectMenuText( aReporter->GetUnits() ),
|
||||||
|
StringFromValue( aReporter->GetUnits(), localA, true ) ) )
|
||||||
|
|
||||||
|
if( localA > clearance )
|
||||||
|
clearance = connectedA->GetLocalClearance( &m_msg );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( localB > 0 )
|
||||||
|
{
|
||||||
|
REPORT( "" )
|
||||||
|
REPORT( wxString::Format( _( "Local clearance on %s; clearance: %s." ),
|
||||||
|
b->GetSelectMenuText( aReporter->GetUnits() ),
|
||||||
|
StringFromValue( aReporter->GetUnits(), localB, true ) ) )
|
||||||
|
|
||||||
|
if( localB > clearance )
|
||||||
|
clearance = connectedB->GetLocalClearance( &m_msg );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( localA > global || localB > global )
|
||||||
|
{
|
||||||
|
DRC_CONSTRAINT constraint( DRC_CONSTRAINT_TYPE_CLEARANCE, m_msg );
|
||||||
|
constraint.m_Value.SetMin( clearance );
|
||||||
|
return constraint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// fixme: return optional<drc_constraint>, let the particular test decide what to do if no matching constraint
|
// fixme: return optional<drc_constraint>, let the particular test decide what to do if no matching constraint
|
||||||
// is found
|
// is found
|
||||||
static DRC_CONSTRAINT nullConstraint;
|
static DRC_CONSTRAINT nullConstraint;
|
||||||
nullConstraint.m_DisallowFlags = 0;
|
nullConstraint.m_DisallowFlags = 0;
|
||||||
|
|
||||||
return nullConstraint;
|
return constraintRef ? *constraintRef : nullConstraint;
|
||||||
|
|
||||||
#undef REPORT
|
#undef REPORT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DRC_ENGINE::IsErrorLimitExceeded( int error_code )
|
||||||
|
{
|
||||||
|
return m_errorLimits[ error_code ] <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DRC_ENGINE::ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos )
|
void DRC_ENGINE::ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos )
|
||||||
{
|
{
|
||||||
|
m_errorLimits[ aItem->GetErrorCode() ] -= 1;
|
||||||
|
|
||||||
|
if( m_violationHandler )
|
||||||
|
m_violationHandler( aItem, aPos );
|
||||||
|
|
||||||
if( m_reporter )
|
if( m_reporter )
|
||||||
{
|
{
|
||||||
wxString msg = wxString::Format( "Test '%s': %s (code %d)",
|
wxString msg = wxString::Format( "Test '%s': %s (code %d)",
|
||||||
|
@ -561,12 +610,10 @@ void DRC_ENGINE::ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, wxPoin
|
||||||
|
|
||||||
wxString violatingItemsStr = "Violating items: ";
|
wxString violatingItemsStr = "Violating items: ";
|
||||||
|
|
||||||
m_reporter->Report( wxString::Format( " |- violating position (%d, %d)",
|
m_reporter->Report( wxString::Format( " |- violating position (%d, %d)",
|
||||||
aPos.x,
|
aPos.x,
|
||||||
aPos.y ) );
|
aPos.y ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
m_violationHandler( aItem, aPos );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRC_ENGINE::ReportAux ( const wxString& aStr )
|
void DRC_ENGINE::ReportAux ( const wxString& aStr )
|
||||||
|
@ -587,14 +634,12 @@ void DRC_ENGINE::ReportProgress( double aProgress )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DRC_ENGINE::ReportStage ( const wxString& aStageName, int index, int total )
|
void DRC_ENGINE::ReportStage ( const wxString& aStageName )
|
||||||
{
|
{
|
||||||
if( !m_progressReporter )
|
if( !m_progressReporter )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_progressReporter->SetNumPhases( total );
|
m_progressReporter->AdvancePhase( aStageName );
|
||||||
m_progressReporter->BeginPhase( index ); // fixme: coalesce all stages/test providers
|
|
||||||
m_progressReporter->Report( aStageName );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -623,8 +668,8 @@ std::vector<DRC_CONSTRAINT> DRC_ENGINE::QueryConstraintsById( DRC_CONSTRAINT_TYP
|
||||||
{
|
{
|
||||||
std::vector<DRC_CONSTRAINT> rv;
|
std::vector<DRC_CONSTRAINT> rv;
|
||||||
|
|
||||||
for ( CONSTRAINT_WITH_CONDITIONS* c : m_constraintMap[constraintID]->sortedConstraints )
|
for ( CONSTRAINT_WITH_CONDITIONS* c : *m_constraintMap[constraintID] )
|
||||||
rv.push_back(c->constraint);
|
rv.push_back( c->constraint );
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -633,7 +678,7 @@ std::vector<DRC_CONSTRAINT> DRC_ENGINE::QueryConstraintsById( DRC_CONSTRAINT_TYP
|
||||||
bool DRC_ENGINE::HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_T constraintID )
|
bool DRC_ENGINE::HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_T constraintID )
|
||||||
{
|
{
|
||||||
//drc_dbg(10,"hascorrect id %d size %d\n", ruleID, m_ruleMap[ruleID]->sortedRules.size( ) );
|
//drc_dbg(10,"hascorrect id %d size %d\n", ruleID, m_ruleMap[ruleID]->sortedRules.size( ) );
|
||||||
return m_constraintMap[constraintID]->sortedConstraints.size() != 0;
|
return m_constraintMap[constraintID]->size() != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,6 @@ std::function<void( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos )> DRC_
|
||||||
*/
|
*/
|
||||||
class DRC_ENGINE
|
class DRC_ENGINE
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DRC_ENGINE( BOARD* aBoard, BOARD_DESIGN_SETTINGS* aSettings );
|
DRC_ENGINE( BOARD* aBoard, BOARD_DESIGN_SETTINGS* aSettings );
|
||||||
~DRC_ENGINE();
|
~DRC_ENGINE();
|
||||||
|
@ -87,31 +86,42 @@ public:
|
||||||
void SetSchematicNetlist( NETLIST* aNetlist ) { m_schematicNetlist = aNetlist; }
|
void SetSchematicNetlist( NETLIST* aNetlist ) { m_schematicNetlist = aNetlist; }
|
||||||
NETLIST* GetSchematicNetlist() const { return m_schematicNetlist; }
|
NETLIST* GetSchematicNetlist() const { return m_schematicNetlist; }
|
||||||
|
|
||||||
// JEY TODO: why isn't this called?
|
|
||||||
void SetWorksheet( KIGFX::WS_PROXY_VIEW_ITEM* aWorksheet ) { m_worksheet = aWorksheet; }
|
void SetWorksheet( KIGFX::WS_PROXY_VIEW_ITEM* aWorksheet ) { m_worksheet = aWorksheet; }
|
||||||
KIGFX::WS_PROXY_VIEW_ITEM* GetWorksheet() const { return m_worksheet; }
|
KIGFX::WS_PROXY_VIEW_ITEM* GetWorksheet() const { return m_worksheet; }
|
||||||
|
|
||||||
// JEY TODO: rationalize old progress report style with new...
|
/*
|
||||||
|
* Receives DRC violation reports (a DRC_ITEM and a position).
|
||||||
|
*/
|
||||||
|
void SetViolationHandler( DRC_VIOLATION_HANDLER aHandler )
|
||||||
|
{
|
||||||
|
m_violationHandler = std::move( aHandler );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Receives progress information to show the user.
|
||||||
|
*/
|
||||||
void SetProgressReporter( PROGRESS_REPORTER* aProgRep ) { m_progressReporter = aProgRep; }
|
void SetProgressReporter( PROGRESS_REPORTER* aProgRep ) { m_progressReporter = aProgRep; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Receives debug information for a developer.
|
||||||
|
*/
|
||||||
void SetLogReporter( REPORTER* aReporter ) { m_reporter = aReporter; }
|
void SetLogReporter( REPORTER* aReporter ) { m_reporter = aReporter; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loads and parses a rule set from an sexpr text file.
|
||||||
|
*/
|
||||||
bool LoadRules( const wxFileName& aPath );
|
bool LoadRules( const wxFileName& aPath );
|
||||||
|
|
||||||
void InitEngine( const wxFileName& aRulePath );
|
void InitEngine( const wxFileName& aRulePath );
|
||||||
|
|
||||||
void RunTests( DRC_VIOLATION_HANDLER aDRCItemHandler );
|
void RunTests( EDA_UNITS aUnits = EDA_UNITS::MILLIMETRES, bool aTestTracksAgainstZones = true,
|
||||||
|
bool aReportAllTrackErrors = true, bool aTestFootprints = true );
|
||||||
|
|
||||||
BOARD_DESIGN_SETTINGS* GetDesignSettings() const { return m_designSettings; }
|
BOARD_DESIGN_SETTINGS* GetDesignSettings() const { return m_designSettings; }
|
||||||
|
|
||||||
BOARD* GetBoard() const { return m_board; }
|
BOARD* GetBoard() const { return m_board; }
|
||||||
|
|
||||||
bool IsErrorLimitExceeded( int error_code )
|
bool IsErrorLimitExceeded( int error_code );
|
||||||
{
|
|
||||||
m_errorLimits[ error_code ] -= 1;
|
|
||||||
|
|
||||||
return m_errorLimits[ error_code ] <= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DRC_CONSTRAINT EvalRulesForItems( DRC_CONSTRAINT_TYPE_T ruleID, BOARD_ITEM* a,
|
DRC_CONSTRAINT EvalRulesForItems( DRC_CONSTRAINT_TYPE_T ruleID, BOARD_ITEM* a,
|
||||||
BOARD_ITEM* b = nullptr,
|
BOARD_ITEM* b = nullptr,
|
||||||
|
@ -122,23 +132,16 @@ public:
|
||||||
|
|
||||||
bool HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_T constraintID );
|
bool HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_T constraintID );
|
||||||
|
|
||||||
EDA_UNITS UserUnits() const
|
EDA_UNITS UserUnits() const { return m_userUnits; }
|
||||||
{
|
bool GetTestTracksAgainstZones() const { return m_testTracksAgainstZones; }
|
||||||
// JEY TODO
|
bool GetReportAllTrackErrors() const { return m_reportAllTrackErrors; }
|
||||||
return EDA_UNITS::MILLIMETRES;
|
bool GetTestFootprints() const { return m_testFootprints; }
|
||||||
}
|
|
||||||
|
|
||||||
bool GetTestTracksAgainstZones() const
|
|
||||||
{
|
|
||||||
// JEY TODO
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CompileRules();
|
bool CompileRules();
|
||||||
|
|
||||||
void ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos );
|
void ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos );
|
||||||
void ReportProgress( double aProgress );
|
void ReportProgress( double aProgress );
|
||||||
void ReportStage ( const wxString& aStageName, int index, int total );
|
void ReportStage( const wxString& aStageName );
|
||||||
void ReportAux( const wxString& aStr );
|
void ReportAux( const wxString& aStr );
|
||||||
|
|
||||||
bool QueryWorstConstraint( DRC_CONSTRAINT_TYPE_T aRuleId, DRC_CONSTRAINT& aConstraint,
|
bool QueryWorstConstraint( DRC_CONSTRAINT_TYPE_T aRuleId, DRC_CONSTRAINT& aConstraint,
|
||||||
|
@ -160,12 +163,6 @@ private:
|
||||||
DRC_CONSTRAINT constraint;
|
DRC_CONSTRAINT constraint;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CONSTRAINT_SET
|
|
||||||
{
|
|
||||||
std::vector<CONSTRAINT_WITH_CONDITIONS*> sortedConstraints;
|
|
||||||
DRC_TEST_PROVIDER* provider;
|
|
||||||
};
|
|
||||||
|
|
||||||
void loadImplicitRules();
|
void loadImplicitRules();
|
||||||
void loadTestProviders();
|
void loadTestProviders();
|
||||||
DRC_RULE* createImplicitRule( const wxString& name );
|
DRC_RULE* createImplicitRule( const wxString& name );
|
||||||
|
@ -179,10 +176,16 @@ protected:
|
||||||
std::vector<DRC_RULE_CONDITION*> m_ruleConditions;
|
std::vector<DRC_RULE_CONDITION*> m_ruleConditions;
|
||||||
std::vector<DRC_RULE*> m_rules;
|
std::vector<DRC_RULE*> m_rules;
|
||||||
std::vector<DRC_TEST_PROVIDER*> m_testProviders;
|
std::vector<DRC_TEST_PROVIDER*> m_testProviders;
|
||||||
|
|
||||||
|
EDA_UNITS m_userUnits;
|
||||||
std::vector<int> m_errorLimits;
|
std::vector<int> m_errorLimits;
|
||||||
|
bool m_testTracksAgainstZones;
|
||||||
|
bool m_reportAllTrackErrors;
|
||||||
|
bool m_testFootprints;
|
||||||
|
|
||||||
// constraint -> rule -> provider
|
// constraint -> rule -> provider
|
||||||
std::unordered_map<DRC_CONSTRAINT_TYPE_T, CONSTRAINT_SET*> m_constraintMap;
|
std::unordered_map< DRC_CONSTRAINT_TYPE_T,
|
||||||
|
std::vector<CONSTRAINT_WITH_CONDITIONS*>* > m_constraintMap;
|
||||||
|
|
||||||
DRC_VIOLATION_HANDLER m_violationHandler;
|
DRC_VIOLATION_HANDLER m_violationHandler;
|
||||||
REPORTER* m_reporter;
|
REPORTER* m_reporter;
|
||||||
|
|
|
@ -31,6 +31,50 @@ class PCB_BASE_FRAME;
|
||||||
class DRC_RULE;
|
class DRC_RULE;
|
||||||
class DRC_TEST_PROVIDER;
|
class DRC_TEST_PROVIDER;
|
||||||
|
|
||||||
|
enum PCB_DRC_CODE {
|
||||||
|
DRCE_FIRST = 1,
|
||||||
|
DRCE_UNCONNECTED_ITEMS = DRCE_FIRST, // items are unconnected
|
||||||
|
DRCE_SHORTING_ITEMS, // items short two nets but are not a net-tie
|
||||||
|
DRCE_ALLOWED_ITEMS, // a disallowed item has been used
|
||||||
|
DRCE_CLEARANCE, // items are too close together
|
||||||
|
DRCE_TRACKS_CROSSING, // tracks are crossing
|
||||||
|
DRCE_COPPER_EDGE_CLEARANCE, // a copper item is too close to the board edge
|
||||||
|
DRCE_ZONES_INTERSECT, // copper area outlines intersect
|
||||||
|
DRCE_ZONE_HAS_EMPTY_NET, // copper area has a net but no pads in nets, which is suspicious
|
||||||
|
DRCE_DANGLING_VIA, // via which isn't connected to anything
|
||||||
|
DRCE_DANGLING_TRACK, // track with at least one end not connected to anything
|
||||||
|
DRCE_DRILLED_HOLES_TOO_CLOSE, // overlapping drilled holes break drill bits
|
||||||
|
DRCE_HOLE_CLEARANCE, //
|
||||||
|
DRCE_TRACK_WIDTH, // Track width is too small or too large
|
||||||
|
DRCE_TOO_SMALL_VIA, // Too small via size
|
||||||
|
DRCE_ANNULUS, // Via size and drill leave annulus too small or too large
|
||||||
|
DRCE_TOO_SMALL_DRILL, // Too small via or pad drill
|
||||||
|
DRCE_VIA_HOLE_BIGGER, // via's hole is bigger than its diameter
|
||||||
|
DRCE_VIA_DIAMETER, // Via diameter checks (min/max)
|
||||||
|
DRCE_PADSTACK, // something is wrong with a pad or via stackup
|
||||||
|
DRCE_TOO_SMALL_MICROVIA, // Too small micro via size
|
||||||
|
DRCE_TOO_SMALL_MICROVIA_DRILL, // Too small micro via drill
|
||||||
|
DRCE_KEEPOUT, // A disallowed object is inside a keepout
|
||||||
|
DRCE_OVERLAPPING_FOOTPRINTS, // footprint courtyards overlap
|
||||||
|
DRCE_MISSING_COURTYARD, // footprint has no courtyard defined
|
||||||
|
DRCE_MALFORMED_COURTYARD, // footprint has a courtyard but malformed
|
||||||
|
// (not convertible to a closed polygon with holes)
|
||||||
|
DRCE_PTH_IN_COURTYARD,
|
||||||
|
DRCE_NPTH_IN_COURTYARD,
|
||||||
|
DRCE_DISABLED_LAYER_ITEM, // item on a disabled layer
|
||||||
|
DRCE_INVALID_OUTLINE, // invalid board outline
|
||||||
|
|
||||||
|
DRCE_MISSING_FOOTPRINT, // footprint not found for netlist item
|
||||||
|
DRCE_DUPLICATE_FOOTPRINT, // more than one footprints found for netlist item
|
||||||
|
DRCE_EXTRA_FOOTPRINT, // netlist item not found for footprint
|
||||||
|
DRCE_NET_CONFLICT, // pad net doesn't match netlist
|
||||||
|
|
||||||
|
DRCE_UNRESOLVED_VARIABLE,
|
||||||
|
|
||||||
|
DRCE_LAST = DRCE_UNRESOLVED_VARIABLE
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class DRC_ITEM : public RC_ITEM
|
class DRC_ITEM : public RC_ITEM
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -1,328 +0,0 @@
|
||||||
/*
|
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, you may find one here:
|
|
||||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
||||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
||||||
* or you may write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <drc/drc_keepout_tester.h>
|
|
||||||
#include <geometry/shape_segment.h>
|
|
||||||
#include <class_module.h>
|
|
||||||
#include <drc/drc.h>
|
|
||||||
#include <drc/drc_item.h>
|
|
||||||
|
|
||||||
DRC_KEEPOUT_TESTER::DRC_KEEPOUT_TESTER( MARKER_HANDLER aMarkerHandler ) :
|
|
||||||
LEGACY_DRC_TEST_PROVIDER( std::move( aMarkerHandler ) ),
|
|
||||||
m_units( EDA_UNITS::MILLIMETRES ),
|
|
||||||
m_board( nullptr ),
|
|
||||||
m_zone( nullptr ),
|
|
||||||
m_keepoutFlags( 0 )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool DRC_KEEPOUT_TESTER::RunDRC( EDA_UNITS aUnits, BOARD& aBoard )
|
|
||||||
{
|
|
||||||
bool success = true;
|
|
||||||
|
|
||||||
m_units = aUnits;
|
|
||||||
m_board = &aBoard;
|
|
||||||
|
|
||||||
// Get a list of all zones to inspect, from both board and footprints
|
|
||||||
std::list<ZONE_CONTAINER*> areasToInspect = m_board->GetZoneList( true );
|
|
||||||
|
|
||||||
// Test keepout areas for vias, tracks and pads inside keepout areas
|
|
||||||
for( ZONE_CONTAINER* area : areasToInspect )
|
|
||||||
{
|
|
||||||
// JEY TODO: our existing keepout strategy needs a work-over for rules....
|
|
||||||
m_keepoutFlags = area->GetKeepouts( F_Cu, &m_sources );
|
|
||||||
|
|
||||||
if( m_keepoutFlags > 0 )
|
|
||||||
{
|
|
||||||
m_zone = area;
|
|
||||||
m_zoneBBox = area->GetBoundingBox();
|
|
||||||
|
|
||||||
success &= checkTracksAndVias();
|
|
||||||
success &= checkFootprints();
|
|
||||||
success &= checkDrawings();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool DRC_KEEPOUT_TESTER::checkTracksAndVias()
|
|
||||||
{
|
|
||||||
constexpr int VIA_MASK = DRC_DISALLOW_VIAS | DRC_DISALLOW_MICRO_VIAS | DRC_DISALLOW_BB_VIAS;
|
|
||||||
constexpr int CHECK_VIAS_MASK = VIA_MASK | DRC_DISALLOW_HOLES;
|
|
||||||
constexpr int CHECK_TRACKS_AND_VIAS_MASK = CHECK_VIAS_MASK | DRC_DISALLOW_TRACKS;
|
|
||||||
|
|
||||||
if(( m_keepoutFlags & CHECK_TRACKS_AND_VIAS_MASK ) == 0 )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
bool success = true;
|
|
||||||
|
|
||||||
for( TRACK* segm : m_board->Tracks() )
|
|
||||||
{
|
|
||||||
if( !m_zoneBBox.Intersects( segm->GetBoundingBox() ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( segm->Type() == PCB_TRACE_T && ( m_keepoutFlags & DRC_DISALLOW_TRACKS ) != 0 )
|
|
||||||
{
|
|
||||||
// Ignore if the keepout zone is not on the same layer
|
|
||||||
PCB_LAYER_ID layer = segm->GetLayer();
|
|
||||||
|
|
||||||
if( !m_zone->IsOnLayer( layer ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
SEG trackSeg( segm->GetStart(), segm->GetEnd() );
|
|
||||||
|
|
||||||
if( m_zone->Outline()->Collide( trackSeg, segm->GetWidth() / 2 ) )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_KEEPOUT );
|
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s)" ),
|
|
||||||
m_sources.at( DRC_DISALLOW_TRACKS ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( segm, m_zone );
|
|
||||||
|
|
||||||
HandleMarker( new MARKER_PCB( drcItem, DRC::GetLocation( layer, segm, m_zone ) ) );
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( segm->Type() == PCB_VIA_T && ( m_keepoutFlags & CHECK_VIAS_MASK ) != 0 )
|
|
||||||
{
|
|
||||||
VIA* via = static_cast<VIA*>( segm );
|
|
||||||
SEG seg( via->GetPosition(), via->GetPosition() );
|
|
||||||
int test = 0;
|
|
||||||
int clearance = via->GetWidth() / 2;
|
|
||||||
|
|
||||||
if( ( m_keepoutFlags & DRC_DISALLOW_VIAS ) > 0 )
|
|
||||||
{
|
|
||||||
test = DRC_DISALLOW_VIAS;
|
|
||||||
}
|
|
||||||
else if( via->GetViaType() == VIATYPE::MICROVIA
|
|
||||||
&& ( m_keepoutFlags & DRC_DISALLOW_MICRO_VIAS ) > 0 )
|
|
||||||
{
|
|
||||||
test = DRC_DISALLOW_MICRO_VIAS;
|
|
||||||
}
|
|
||||||
else if( via->GetViaType() == VIATYPE::BLIND_BURIED
|
|
||||||
&& ( m_keepoutFlags & DRC_DISALLOW_BB_VIAS ) > 0 )
|
|
||||||
{
|
|
||||||
test = DRC_DISALLOW_BB_VIAS;
|
|
||||||
}
|
|
||||||
else if( ( m_keepoutFlags & DRC_DISALLOW_HOLES ) > 0 )
|
|
||||||
{
|
|
||||||
test = DRC_DISALLOW_HOLES;
|
|
||||||
clearance = via->GetDrillValue() / 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( m_zone->Outline()->Collide( seg, clearance ) )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_KEEPOUT );
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s)" ), m_sources.at( test ) );
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( segm, m_zone );
|
|
||||||
|
|
||||||
HandleMarker( new MARKER_PCB( drcItem, via->GetPosition() ) );
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool DRC_KEEPOUT_TESTER::checkFootprints()
|
|
||||||
{
|
|
||||||
constexpr int CHECK_PADS_MASK = DRC_DISALLOW_PADS | DRC_DISALLOW_HOLES;
|
|
||||||
constexpr int CHECK_FOOTPRINTS_MASK = CHECK_PADS_MASK | DRC_DISALLOW_FOOTPRINTS;
|
|
||||||
|
|
||||||
if(( m_keepoutFlags & CHECK_FOOTPRINTS_MASK ) == 0 )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
bool success = true;
|
|
||||||
|
|
||||||
for( MODULE* fp : m_board->Modules() )
|
|
||||||
{
|
|
||||||
if( m_zone->GetParent() == fp )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( !m_zoneBBox.Intersects( fp->GetBoundingBox() ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( ( m_keepoutFlags & DRC_DISALLOW_FOOTPRINTS ) > 0
|
|
||||||
&& ( fp->IsFlipped() ? m_zone->CommonLayerExists( LSET::BackMask() )
|
|
||||||
: m_zone->CommonLayerExists( LSET::FrontMask() ) ) )
|
|
||||||
{
|
|
||||||
SHAPE_POLY_SET poly;
|
|
||||||
|
|
||||||
if( fp->BuildPolyCourtyard() )
|
|
||||||
poly = fp->IsFlipped() ? fp->GetPolyCourtyardBack() : fp->GetPolyCourtyardFront();
|
|
||||||
|
|
||||||
if( poly.OutlineCount() == 0 )
|
|
||||||
poly = fp->GetBoundingPoly();
|
|
||||||
|
|
||||||
// Build the common area between footprint and the keepout area:
|
|
||||||
poly.BooleanIntersection( *m_zone->Outline(), SHAPE_POLY_SET::PM_FAST );
|
|
||||||
|
|
||||||
// If it's not empty then we have a violation
|
|
||||||
if( poly.OutlineCount() )
|
|
||||||
{
|
|
||||||
const VECTOR2I& pt = poly.CVertex( 0, 0, -1 );
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_KEEPOUT );
|
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s)" ),
|
|
||||||
m_sources.at( DRC_DISALLOW_FOOTPRINTS ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( fp, m_zone );
|
|
||||||
|
|
||||||
HandleMarker( new MARKER_PCB( drcItem, (wxPoint) pt ) );
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ( m_keepoutFlags & CHECK_PADS_MASK ) > 0 )
|
|
||||||
{
|
|
||||||
success &= checkPads( fp );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool DRC_KEEPOUT_TESTER::checkPads( MODULE* aModule )
|
|
||||||
{
|
|
||||||
bool success = true;
|
|
||||||
|
|
||||||
for( D_PAD* pad : aModule->Pads() )
|
|
||||||
{
|
|
||||||
if( !m_zone->CommonLayerExists( pad->GetLayerSet() ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Fast test to detect a pad inside the keepout area bounding box.
|
|
||||||
EDA_RECT padBBox( pad->GetPosition(), wxSize() );
|
|
||||||
padBBox.Inflate( pad->GetBoundingRadius() );
|
|
||||||
|
|
||||||
if( !m_zoneBBox.Intersects( padBBox ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( ( m_keepoutFlags & DRC_DISALLOW_PADS ) > 0 )
|
|
||||||
{
|
|
||||||
SHAPE_POLY_SET outline = *pad->GetEffectivePolygon();
|
|
||||||
|
|
||||||
// Build the common area between pad and the keepout area:
|
|
||||||
outline.BooleanIntersection( *m_zone->Outline(), SHAPE_POLY_SET::PM_FAST );
|
|
||||||
|
|
||||||
// If it's not empty then we have a violation
|
|
||||||
if( outline.OutlineCount() )
|
|
||||||
{
|
|
||||||
const VECTOR2I& pt = outline.CVertex( 0, 0, -1 );
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_KEEPOUT );
|
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s)" ),
|
|
||||||
m_sources.at( DRC_DISALLOW_PADS ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( pad, m_zone );
|
|
||||||
|
|
||||||
HandleMarker( new MARKER_PCB( drcItem, (wxPoint) pt ) );
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( ( m_keepoutFlags & DRC_DISALLOW_HOLES ) > 0 )
|
|
||||||
{
|
|
||||||
const SHAPE_SEGMENT* slot = pad->GetEffectiveHoleShape();
|
|
||||||
|
|
||||||
if( m_zone->Outline()->Collide( slot->GetSeg(), slot->GetWidth() / 2 ) )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_KEEPOUT );
|
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s)" ),
|
|
||||||
m_sources.at( DRC_DISALLOW_HOLES ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( pad, m_zone );
|
|
||||||
|
|
||||||
HandleMarker( new MARKER_PCB( drcItem, pad->GetPosition() ) );
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool DRC_KEEPOUT_TESTER::checkDrawings()
|
|
||||||
{
|
|
||||||
constexpr int CHECK_DRAWINGS_MASK = DRC_DISALLOW_TEXTS | DRC_DISALLOW_GRAPHICS;
|
|
||||||
constexpr KICAD_T graphicTypes[] = { PCB_LINE_T, PCB_DIMENSION_T, PCB_TARGET_T, EOT };
|
|
||||||
|
|
||||||
if(( m_keepoutFlags & CHECK_DRAWINGS_MASK ) == 0 )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
bool success = true;
|
|
||||||
|
|
||||||
for( BOARD_ITEM* drawing : m_board->Drawings() )
|
|
||||||
{
|
|
||||||
if( !m_zoneBBox.Intersects( drawing->GetBoundingBox() ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int sourceId = 0;
|
|
||||||
|
|
||||||
if( drawing->IsType( graphicTypes ) && ( m_keepoutFlags & DRC_DISALLOW_GRAPHICS ) > 0 )
|
|
||||||
sourceId = DRC_DISALLOW_GRAPHICS;
|
|
||||||
else if( drawing->Type() == PCB_TEXT_T && ( m_keepoutFlags & DRC_DISALLOW_TEXTS ) > 0 )
|
|
||||||
sourceId = DRC_DISALLOW_TEXTS;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
|
|
||||||
SHAPE_POLY_SET poly;
|
|
||||||
drawing->TransformShapeWithClearanceToPolygon( poly, drawing->GetLayer(), 0 );
|
|
||||||
|
|
||||||
// Build the common area between footprint and the keepout area:
|
|
||||||
poly.BooleanIntersection( *m_zone->Outline(), SHAPE_POLY_SET::PM_FAST );
|
|
||||||
|
|
||||||
// If it's not empty then we have a violation
|
|
||||||
if( poly.OutlineCount() )
|
|
||||||
{
|
|
||||||
const VECTOR2I& pt = poly.CVertex( 0, 0, -1 );
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_KEEPOUT );
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s)" ), m_sources.at( sourceId ) );
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
|
||||||
drcItem->SetItems( drawing, m_zone );
|
|
||||||
|
|
||||||
HandleMarker( new MARKER_PCB( drcItem, (wxPoint) pt ) );
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
/*
|
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 KiCad Developers, see change_log.txt for contributors.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, you may find one here:
|
|
||||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
||||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
||||||
* or you may write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef DRC_KEEPOUT_TESTER__H
|
|
||||||
#define DRC_KEEPOUT_TESTER__H
|
|
||||||
|
|
||||||
#include <drc/drc_results_provider.h>
|
|
||||||
|
|
||||||
|
|
||||||
class BOARD;
|
|
||||||
|
|
||||||
|
|
||||||
class DRC_KEEPOUT_TESTER : public LEGACY_DRC_TEST_PROVIDER
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DRC_KEEPOUT_TESTER( MARKER_HANDLER aMarkerHandler );
|
|
||||||
|
|
||||||
virtual ~DRC_KEEPOUT_TESTER() {};
|
|
||||||
|
|
||||||
bool RunDRC( EDA_UNITS aUnits, BOARD& aBoard ) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool checkTracksAndVias();
|
|
||||||
bool checkFootprints();
|
|
||||||
bool checkPads( MODULE* aModule );
|
|
||||||
bool checkDrawings();
|
|
||||||
|
|
||||||
private:
|
|
||||||
EDA_UNITS m_units;
|
|
||||||
BOARD* m_board;
|
|
||||||
|
|
||||||
// Temp variables for use while testing:
|
|
||||||
ZONE_CONTAINER* m_zone;
|
|
||||||
EDA_RECT m_zoneBBox;
|
|
||||||
int m_keepoutFlags; // bitset of DISALLOW_* flags
|
|
||||||
std::map<int, wxString> m_sources; // map of DISALLOW_* flag to source
|
|
||||||
wxString m_msg; // avoid lots of calls to wxString's c'tor.
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // DRC_KEEPOUT_TESTER__H
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 KiCad Developers, see change_log.txt for contributors.
|
* Copyright (C) 2018-2020 KiCad Developers, see change_log.txt for contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -28,58 +28,11 @@
|
||||||
#include <class_board.h>
|
#include <class_board.h>
|
||||||
#include <class_marker_pcb.h>
|
#include <class_marker_pcb.h>
|
||||||
#include <pcb_base_frame.h>
|
#include <pcb_base_frame.h>
|
||||||
#include <drc/drc.h>
|
|
||||||
#include <drc/drc_item.h>
|
#include <drc/drc_item.h>
|
||||||
#include <widgets/ui_common.h>
|
#include <widgets/ui_common.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LEGACY_DRC_TEST_PROVIDER
|
|
||||||
* is a base class that represents a DRC "provider" which runs some DRC functions over a
|
|
||||||
* #BOARD and spits out #PCB_MARKERs as needed.
|
|
||||||
*
|
|
||||||
* JEY TODO: to remove
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class LEGACY_DRC_TEST_PROVIDER
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* A callable that can handle a single generated PCB_MARKER
|
|
||||||
*/
|
|
||||||
using MARKER_HANDLER = std::function<void( MARKER_PCB* )>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs this provider against the given PCB with configured options (if any).
|
|
||||||
*
|
|
||||||
* Note: Board is non-const, as some DRC functions modify the board (e.g. zone fill
|
|
||||||
* or polygon coalescing)
|
|
||||||
*/
|
|
||||||
virtual bool RunDRC( EDA_UNITS aUnits, BOARD& aBoard ) = 0;
|
|
||||||
|
|
||||||
virtual ~LEGACY_DRC_TEST_PROVIDER() {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
LEGACY_DRC_TEST_PROVIDER( MARKER_HANDLER aMarkerHandler ) :
|
|
||||||
m_marker_handler( std::move( aMarkerHandler ) )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pass a given marker to the marker handler
|
|
||||||
*/
|
|
||||||
void HandleMarker( MARKER_PCB* aMarker ) const
|
|
||||||
{
|
|
||||||
m_marker_handler( aMarker );
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// The handler for any generated markers
|
|
||||||
MARKER_HANDLER m_marker_handler;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BOARD_DRC_ITEMS_PROVIDER
|
* BOARD_DRC_ITEMS_PROVIDER
|
||||||
* is an implementation of the RC_ITEMS_PROVIDER interface which uses a BOARD instance
|
* is an implementation of the RC_ITEMS_PROVIDER interface which uses a BOARD instance
|
||||||
|
|
|
@ -39,27 +39,27 @@ const wxString DRC_TEST_PROVIDER::GetName() const { return "<no name test>"; }
|
||||||
const wxString DRC_TEST_PROVIDER::GetDescription() const { return ""; }
|
const wxString DRC_TEST_PROVIDER::GetDescription() const { return ""; }
|
||||||
|
|
||||||
|
|
||||||
void DRC_TEST_PROVIDER::ReportViolation( std::shared_ptr<DRC_ITEM> aItem, wxPoint aPos )
|
void DRC_TEST_PROVIDER::reportViolation( std::shared_ptr<DRC_ITEM> item, wxPoint aMarkerPos )
|
||||||
{
|
{
|
||||||
aItem->SetViolatingTest( this );
|
item->SetViolatingTest( this );
|
||||||
m_drcEngine->ReportViolation( aItem, aPos );
|
m_drcEngine->ReportViolation( item, aMarkerPos );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DRC_TEST_PROVIDER::ReportProgress( double aProgress )
|
void DRC_TEST_PROVIDER::reportProgress( double aProgress )
|
||||||
{
|
{
|
||||||
m_drcEngine->ReportProgress( aProgress );
|
m_drcEngine->ReportProgress( aProgress );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DRC_TEST_PROVIDER::ReportStage ( const wxString& aStageName, int index, int total )
|
void DRC_TEST_PROVIDER::reportStage( const wxString& aStageName )
|
||||||
{
|
{
|
||||||
m_drcEngine->ReportStage( aStageName, index, total );
|
m_drcEngine->ReportStage( aStageName );
|
||||||
ReportAux( aStageName );
|
reportAux( aStageName );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DRC_TEST_PROVIDER::ReportAux( wxString fmt, ... )
|
void DRC_TEST_PROVIDER::reportAux( wxString fmt, ... )
|
||||||
{
|
{
|
||||||
va_list vargs;
|
va_list vargs;
|
||||||
va_start( vargs, fmt );
|
va_start( vargs, fmt );
|
||||||
|
@ -83,7 +83,7 @@ void DRC_TEST_PROVIDER::accountCheck( const DRC_RULE* ruleToTest )
|
||||||
if( it == m_stats.end() )
|
if( it == m_stats.end() )
|
||||||
m_stats[ ruleToTest ] = 1;
|
m_stats[ ruleToTest ] = 1;
|
||||||
else
|
else
|
||||||
it->second++;
|
m_stats[ ruleToTest ] += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,13 +98,16 @@ void DRC_TEST_PROVIDER::reportRuleStatistics()
|
||||||
if( !m_isRuleDriven )
|
if( !m_isRuleDriven )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_drcEngine->ReportAux("Rule hit statistics: ");
|
m_drcEngine->ReportAux( "Rule hit statistics: " );
|
||||||
|
|
||||||
for( const std::pair<const DRC_RULE* const, int>& stat : m_stats )
|
for( const std::pair<const DRC_RULE* const, int>& stat : m_stats )
|
||||||
{
|
{
|
||||||
m_drcEngine->ReportAux( wxString::Format( " - rule '%s': %d hits ",
|
if( stat.first )
|
||||||
stat.first->m_Name,
|
{
|
||||||
stat.second ) );
|
m_drcEngine->ReportAux( wxString::Format( " - rule '%s': %d hits ",
|
||||||
|
stat.first->m_Name,
|
||||||
|
stat.second ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* DRC_TEST_PROVIDER
|
* DRC_TEST_PROVIDER
|
||||||
* is a base class that represents a DRC "provider" which runs some DRC functions over a
|
* is a base class that represents a DRC "provider" which runs some DRC functions over a
|
||||||
* #BOARD and spits out #PCB_MARKERs as needed.
|
* #BOARD and spits out #DRC_ITEMs and positions as needed.
|
||||||
*/
|
*/
|
||||||
class DRC_TEST_PROVIDER
|
class DRC_TEST_PROVIDER
|
||||||
{
|
{
|
||||||
|
@ -82,23 +82,16 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs this provider against the given PCB with configured options (if any).
|
* Runs this provider against the given PCB with configured options (if any).
|
||||||
*
|
|
||||||
* Note: Board is non-const, as some DRC functions modify the board (e.g. zone fill
|
|
||||||
* or polygon coalescing)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
virtual bool Run() = 0;
|
virtual bool Run() = 0;
|
||||||
|
|
||||||
virtual const wxString GetName() const;
|
virtual const wxString GetName() const;
|
||||||
virtual const wxString GetDescription() const;
|
virtual const wxString GetDescription() const;
|
||||||
|
|
||||||
virtual void ReportAux( wxString fmt, ... );
|
|
||||||
virtual void ReportViolation( std::shared_ptr<DRC_ITEM> item, wxPoint aMarkerPos );
|
|
||||||
virtual void ReportProgress( double aProgress );
|
|
||||||
virtual void ReportStage ( const wxString& aStageName, int index, int total );
|
|
||||||
|
|
||||||
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const = 0;
|
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const = 0;
|
||||||
|
|
||||||
|
virtual int GetNumPhases() const = 0;
|
||||||
|
|
||||||
virtual bool IsRuleDriven() const
|
virtual bool IsRuleDriven() const
|
||||||
{
|
{
|
||||||
return m_isRuleDriven;
|
return m_isRuleDriven;
|
||||||
|
@ -108,6 +101,11 @@ protected:
|
||||||
int forEachGeometryItem( const std::vector<KICAD_T>& aTypes, LSET aLayers,
|
int forEachGeometryItem( const std::vector<KICAD_T>& aTypes, LSET aLayers,
|
||||||
const std::function<bool(BOARD_ITEM*)>& aFunc );
|
const std::function<bool(BOARD_ITEM*)>& aFunc );
|
||||||
|
|
||||||
|
virtual void reportAux( wxString fmt, ... );
|
||||||
|
virtual void reportViolation( std::shared_ptr<DRC_ITEM> item, wxPoint aMarkerPos );
|
||||||
|
virtual void reportProgress( double aProgress );
|
||||||
|
virtual void reportStage( const wxString& aStageName );
|
||||||
|
|
||||||
virtual void reportRuleStatistics();
|
virtual void reportRuleStatistics();
|
||||||
virtual void accountCheck( const DRC_RULE* ruleToTest );
|
virtual void accountCheck( const DRC_RULE* ruleToTest );
|
||||||
virtual void accountCheck( const DRC_CONSTRAINT& constraintToTest );
|
virtual void accountCheck( const DRC_CONSTRAINT& constraintToTest );
|
||||||
|
|
|
@ -63,6 +63,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
||||||
|
|
||||||
|
int GetNumPhases() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,11 +72,11 @@ bool DRC_TEST_PROVIDER_ANNULUS::Run()
|
||||||
{
|
{
|
||||||
if( !m_drcEngine->HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_ANNULUS_WIDTH ) )
|
if( !m_drcEngine->HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_ANNULUS_WIDTH ) )
|
||||||
{
|
{
|
||||||
ReportAux( "No annulus constraints found. Skipping check." );
|
reportAux( "No annulus constraints found. Skipping check." );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportStage( _( "Testing via annular rings" ), 0, 2 );
|
reportStage( _( "Via annular rings..." ));
|
||||||
|
|
||||||
auto checkAnnulus =
|
auto checkAnnulus =
|
||||||
[&]( BOARD_ITEM* item ) -> bool
|
[&]( BOARD_ITEM* item ) -> bool
|
||||||
|
@ -117,7 +119,7 @@ bool DRC_TEST_PROVIDER_ANNULUS::Run()
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s annulus %s; actual %s)" ),
|
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s annulus %s; actual %s)" ),
|
||||||
constraint.GetName(),
|
constraint.GetName(),
|
||||||
fail_min ? _( "minimum" ) : _( "maximum" ),
|
fail_min ? _( "min" ) : _( "max" ),
|
||||||
MessageTextFromValue( userUnits(), annulus, true ),
|
MessageTextFromValue( userUnits(), annulus, true ),
|
||||||
MessageTextFromValue( userUnits(), fail_min ? v_min : v_max, true ) );
|
MessageTextFromValue( userUnits(), fail_min ? v_min : v_max, true ) );
|
||||||
|
|
||||||
|
@ -125,7 +127,7 @@ bool DRC_TEST_PROVIDER_ANNULUS::Run()
|
||||||
drcItem->SetItems( item );
|
drcItem->SetItems( item );
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
ReportViolation( drcItem, via->GetPosition() );
|
reportViolation( drcItem, via->GetPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -139,6 +141,12 @@ bool DRC_TEST_PROVIDER_ANNULUS::Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int DRC_TEST_PROVIDER_ANNULUS::GetNumPhases() const
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_ANNULUS::GetConstraintTypes() const
|
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_ANNULUS::GetConstraintTypes() const
|
||||||
{
|
{
|
||||||
return { DRC_CONSTRAINT_TYPE_ANNULUS_WIDTH };
|
return { DRC_CONSTRAINT_TYPE_ANNULUS_WIDTH };
|
||||||
|
|
|
@ -66,12 +66,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
||||||
|
|
||||||
|
int GetNumPhases() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
bool DRC_TEST_PROVIDER_CONNECTIVITY::Run()
|
bool DRC_TEST_PROVIDER_CONNECTIVITY::Run()
|
||||||
{
|
{
|
||||||
ReportStage( _( "Testing dangling pads/vias" ), 0, 2 );
|
reportStage( _( "Dangling pads/vias..." ));
|
||||||
|
|
||||||
BOARD* board = m_drcEngine->GetBoard();
|
BOARD* board = m_drcEngine->GetBoard();
|
||||||
|
|
||||||
|
@ -100,11 +102,11 @@ bool DRC_TEST_PROVIDER_CONNECTIVITY::Run()
|
||||||
{
|
{
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( code );
|
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( code );
|
||||||
drcItem->SetItems( track );
|
drcItem->SetItems( track );
|
||||||
ReportViolation( drcItem, pos );
|
reportViolation( drcItem, pos );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportStage( _( "Testing starved zones" ), 0, 2 );
|
reportStage( _( "Starved zones..." ));
|
||||||
|
|
||||||
/* test starved zones */
|
/* test starved zones */
|
||||||
for( ZONE_CONTAINER* zone : board->Zones() )
|
for( ZONE_CONTAINER* zone : board->Zones() )
|
||||||
|
@ -125,11 +127,11 @@ bool DRC_TEST_PROVIDER_CONNECTIVITY::Run()
|
||||||
{
|
{
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ZONE_HAS_EMPTY_NET );
|
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ZONE_HAS_EMPTY_NET );
|
||||||
drcItem->SetItems( zone );
|
drcItem->SetItems( zone );
|
||||||
ReportViolation( drcItem, zone->GetPosition() );
|
reportViolation( drcItem, zone->GetPosition());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportStage( _( "Testing unconnected nets" ), 0, 2 );
|
reportStage( _( "Unconnected nets..." ));
|
||||||
|
|
||||||
connectivity->RecalculateRatsnest();
|
connectivity->RecalculateRatsnest();
|
||||||
std::vector<CN_EDGE> edges;
|
std::vector<CN_EDGE> edges;
|
||||||
|
@ -142,7 +144,7 @@ bool DRC_TEST_PROVIDER_CONNECTIVITY::Run()
|
||||||
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNCONNECTED_ITEMS );
|
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNCONNECTED_ITEMS );
|
||||||
drcItem->SetItems( edge.GetSourceNode()->Parent(), edge.GetTargetNode()->Parent() );
|
drcItem->SetItems( edge.GetSourceNode()->Parent(), edge.GetTargetNode()->Parent() );
|
||||||
ReportViolation( drcItem, (wxPoint) edge.GetSourceNode()->Pos() );
|
reportViolation( drcItem, (wxPoint) edge.GetSourceNode()->Pos());
|
||||||
}
|
}
|
||||||
|
|
||||||
reportRuleStatistics();
|
reportRuleStatistics();
|
||||||
|
@ -151,6 +153,12 @@ bool DRC_TEST_PROVIDER_CONNECTIVITY::Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int DRC_TEST_PROVIDER_CONNECTIVITY::GetNumPhases() const
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_CONNECTIVITY::GetConstraintTypes() const
|
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_CONNECTIVITY::GetConstraintTypes() const
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -75,10 +75,12 @@ public:
|
||||||
|
|
||||||
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
||||||
|
|
||||||
|
int GetNumPhases() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void testPadClearances();
|
void testPadClearances();
|
||||||
|
|
||||||
void testTrackClearances( bool aTestZones );
|
void testTrackClearances();
|
||||||
|
|
||||||
void testCopperTextAndGraphics();
|
void testCopperTextAndGraphics();
|
||||||
|
|
||||||
|
@ -87,7 +89,7 @@ private:
|
||||||
void testCopperDrawItem( BOARD_ITEM* aItem );
|
void testCopperDrawItem( BOARD_ITEM* aItem );
|
||||||
|
|
||||||
void doTrackDrc( TRACK* aRefSeg, PCB_LAYER_ID aLayer, TRACKS::iterator aStartIt,
|
void doTrackDrc( TRACK* aRefSeg, PCB_LAYER_ID aLayer, TRACKS::iterator aStartIt,
|
||||||
TRACKS::iterator aEndIt, bool aTestZones );
|
TRACKS::iterator aEndIt );
|
||||||
|
|
||||||
void doPadToPadsDrc( D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd, int x_limit );
|
void doPadToPadsDrc( D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd, int x_limit );
|
||||||
};
|
};
|
||||||
|
@ -105,22 +107,22 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::Run()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ReportAux( "No Clearance constraints found..." );
|
reportAux( "No Clearance constraints found..." );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportAux( "Worst clearance : %d nm", m_largestClearance );
|
reportAux( "Worst clearance : %d nm", m_largestClearance );
|
||||||
|
|
||||||
ReportStage( _( "Testing pad copper clerances" ), 0, 2 );
|
reportStage( _( "Pad clerances..." ));
|
||||||
testPadClearances();
|
testPadClearances();
|
||||||
|
|
||||||
ReportStage( _( "Testing track/via copper clerances" ), 1, 2 );
|
reportStage( _( "Track/via clerances..." ));
|
||||||
testTrackClearances( m_drcEngine->GetTestTracksAgainstZones() );
|
testTrackClearances();
|
||||||
|
|
||||||
ReportStage( _( "Testing copper drawing/text clerances" ), 1, 2 );
|
reportStage( _( "Copper drawing/text clerances..." ));
|
||||||
testCopperTextAndGraphics();
|
testCopperTextAndGraphics();
|
||||||
|
|
||||||
ReportStage( _( "Testing copper zone clearances" ), 1, 2 );
|
reportStage( _( "Zone clearances..." ));
|
||||||
testZones();
|
testZones();
|
||||||
|
|
||||||
reportRuleStatistics();
|
reportRuleStatistics();
|
||||||
|
@ -230,7 +232,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* aItem )
|
||||||
drcItem->SetItems( track, aItem );
|
drcItem->SetItems( track, aItem );
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
ReportViolation( drcItem, pos );
|
reportViolation( drcItem, pos );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +255,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* aItem )
|
||||||
|
|
||||||
|
|
||||||
// Fast test to detect a pad candidate inside the text bounding box
|
// Fast test to detect a pad candidate inside the text bounding box
|
||||||
// Finer test (time consumming) is made only for pads near the text.
|
// Finer test (time consuming) is made only for pads near the text.
|
||||||
int bb_radius = pad->GetBoundingRadius() + minClearance;
|
int bb_radius = pad->GetBoundingRadius() + minClearance;
|
||||||
|
|
||||||
if( !bboxShape.Collide( SEG( pad->GetPosition(), pad->GetPosition() ), bb_radius ) )
|
if( !bboxShape.Collide( SEG( pad->GetPosition(), pad->GetPosition() ), bb_radius ) )
|
||||||
|
@ -273,39 +275,39 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* aItem )
|
||||||
drcItem->SetItems( pad, aItem );
|
drcItem->SetItems( pad, aItem );
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
ReportViolation( drcItem, pad->GetPosition() );
|
reportViolation( drcItem, pad->GetPosition());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances( bool aTestZones )
|
void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
|
||||||
{
|
{
|
||||||
const int delta = 500; // This is the number of tests between 2 calls to the progress bar
|
const int delta = 500; // This is the number of tests between 2 calls to the progress bar
|
||||||
int count = m_board->Tracks().size();
|
int count = m_board->Tracks().size();
|
||||||
|
|
||||||
ReportProgress( 0.0 );
|
reportProgress( 0.0 );
|
||||||
ReportAux( "Testing %d tracks...", count );
|
reportAux( "Testing %d tracks...", count );
|
||||||
|
|
||||||
int ii = 0;
|
int ii = 0;
|
||||||
|
|
||||||
for( auto seg_it = m_board->Tracks().begin(); seg_it != m_board->Tracks().end(); seg_it++ )
|
for( auto seg_it = m_board->Tracks().begin(); seg_it != m_board->Tracks().end(); seg_it++ )
|
||||||
{
|
{
|
||||||
if( (ii % delta) == 0)
|
if( (ii % delta) == 0)
|
||||||
ReportProgress( (double) ii / (double) m_board->Tracks().size() );
|
reportProgress((double) ii / (double) m_board->Tracks().size());
|
||||||
|
|
||||||
ii++;
|
ii++;
|
||||||
|
|
||||||
// Test segment against tracks and pads, optionally against copper zones
|
// Test segment against tracks and pads, optionally against copper zones
|
||||||
for( PCB_LAYER_ID layer : (*seg_it)->GetLayerSet().Seq() )
|
for( PCB_LAYER_ID layer : (*seg_it)->GetLayerSet().Seq() )
|
||||||
{
|
{
|
||||||
doTrackDrc( *seg_it, layer, seg_it + 1, m_board->Tracks().end(), aTestZones );
|
doTrackDrc( *seg_it, layer, seg_it + 1, m_board->Tracks().end() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_ID aLayer,
|
void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_ID aLayer,
|
||||||
TRACKS::iterator aStartIt,
|
TRACKS::iterator aStartIt,
|
||||||
TRACKS::iterator aEndIt, bool aTestZones )
|
TRACKS::iterator aEndIt )
|
||||||
{
|
{
|
||||||
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
||||||
|
|
||||||
|
@ -369,7 +371,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_I
|
||||||
drcItem->SetItems( aRefSeg, pad );
|
drcItem->SetItems( aRefSeg, pad );
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
ReportViolation( drcItem, pad->GetPosition() );
|
reportViolation( drcItem, pad->GetPosition());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -424,7 +426,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_I
|
||||||
drcItem->SetItems( aRefSeg, track );
|
drcItem->SetItems( aRefSeg, track );
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
ReportViolation( drcItem, (wxPoint) intersection.get() );
|
reportViolation( drcItem, (wxPoint) intersection.get());
|
||||||
}
|
}
|
||||||
else if( refSeg.Collide( &trackSeg, minClearance - bds.GetDRCEpsilon(), &actual ) )
|
else if( refSeg.Collide( &trackSeg, minClearance - bds.GetDRCEpsilon(), &actual ) )
|
||||||
{
|
{
|
||||||
|
@ -440,16 +442,19 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_I
|
||||||
drcItem->SetItems( aRefSeg, track );
|
drcItem->SetItems( aRefSeg, track );
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
ReportViolation( drcItem, pos );
|
reportViolation( drcItem, pos );
|
||||||
|
|
||||||
|
if( !m_drcEngine->GetReportAllTrackErrors() )
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************/
|
/***************************************/
|
||||||
/* Phase 3: test DRC with copper zones */
|
/* Phase 3: test DRC with copper zones */
|
||||||
/***************************************/
|
/***************************************/
|
||||||
// Can be *very* time consumming.
|
// Can be *very* time consuming.
|
||||||
|
|
||||||
if( aTestZones )
|
if( m_drcEngine->GetTestTracksAgainstZones() )
|
||||||
{
|
{
|
||||||
SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
|
SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
|
||||||
|
|
||||||
|
@ -490,7 +495,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_I
|
||||||
drcItem->SetItems( aRefSeg, zone );
|
drcItem->SetItems( aRefSeg, zone );
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
ReportViolation( drcItem, getLocation( aLayer, aRefSeg, zone ) );
|
reportViolation( drcItem, getLocation( aLayer, aRefSeg, zone ));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -503,7 +508,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( )
|
||||||
|
|
||||||
m_board->GetSortedPadListByXthenYCoord( sortedPads );
|
m_board->GetSortedPadListByXthenYCoord( sortedPads );
|
||||||
|
|
||||||
ReportAux( "Testing %d pads...", sortedPads.size() );
|
reportAux( "Testing %d pads...", sortedPads.size());
|
||||||
|
|
||||||
if( sortedPads.empty() )
|
if( sortedPads.empty() )
|
||||||
return;
|
return;
|
||||||
|
@ -533,7 +538,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( )
|
||||||
for( D_PAD* pad : sortedPads )
|
for( D_PAD* pad : sortedPads )
|
||||||
{
|
{
|
||||||
if( ii % 100 == 0 )
|
if( ii % 100 == 0 )
|
||||||
ReportProgress( (double) ii / (double) sortedPads.size() );
|
reportProgress((double) ii / (double) sortedPads.size());
|
||||||
|
|
||||||
ii++;
|
ii++;
|
||||||
int x_limit = pad->GetPosition().x + pad->GetBoundingRadius() + max_size;
|
int x_limit = pad->GetPosition().x + pad->GetBoundingRadius() + max_size;
|
||||||
|
@ -589,7 +594,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doPadToPadsDrc( D_PAD* aRefPad, D_PAD**
|
||||||
drcItem->SetErrorMessage( m_msg );
|
drcItem->SetErrorMessage( m_msg );
|
||||||
drcItem->SetItems( pad, aRefPad );
|
drcItem->SetItems( pad, aRefPad );
|
||||||
|
|
||||||
ReportViolation( drcItem, aRefPad->GetPosition() );
|
reportViolation( drcItem, aRefPad->GetPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
@ -630,7 +635,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doPadToPadsDrc( D_PAD* aRefPad, D_PAD**
|
||||||
drcItem->SetItems( aRefPad, pad );
|
drcItem->SetItems( aRefPad, pad );
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
ReportViolation( drcItem, aRefPad->GetPosition() );
|
reportViolation( drcItem, aRefPad->GetPosition());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -711,7 +716,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZones()
|
||||||
drcItem->SetItems( zoneRef, zoneToTest );
|
drcItem->SetItems( zoneRef, zoneToTest );
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
ReportViolation( drcItem, pt );
|
reportViolation( drcItem, pt );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -727,7 +732,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZones()
|
||||||
drcItem->SetItems( zoneToTest, zoneRef );
|
drcItem->SetItems( zoneToTest, zoneRef );
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
ReportViolation( drcItem, pt );
|
reportViolation( drcItem, pt );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -799,13 +804,19 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZones()
|
||||||
drcItem->SetItems( zoneRef, zoneToTest );
|
drcItem->SetItems( zoneRef, zoneToTest );
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
ReportViolation( drcItem, conflict.first );
|
reportViolation( drcItem, conflict.first );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int DRC_TEST_PROVIDER_COPPER_CLEARANCE::GetNumPhases() const
|
||||||
|
{
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_COPPER_CLEARANCE::GetConstraintTypes() const
|
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_COPPER_CLEARANCE::GetConstraintTypes() const
|
||||||
{
|
{
|
||||||
return { DRC_CONSTRAINT_TYPE_CLEARANCE };
|
return { DRC_CONSTRAINT_TYPE_CLEARANCE };
|
||||||
|
|
|
@ -65,6 +65,8 @@ public:
|
||||||
|
|
||||||
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
||||||
|
|
||||||
|
int GetNumPhases() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void testFootprintCourtyardDefinitions();
|
void testFootprintCourtyardDefinitions();
|
||||||
|
|
||||||
|
@ -75,7 +77,7 @@ private:
|
||||||
void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions()
|
void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions()
|
||||||
{
|
{
|
||||||
// Detects missing (or malformed) footprint courtyards
|
// Detects missing (or malformed) footprint courtyards
|
||||||
ReportStage( _( "Testing component courtyard definitions" ), 0, 2 );
|
reportStage( _( "Footprint courtyard definitions..." ));
|
||||||
|
|
||||||
for( MODULE* footprint : m_board->Modules() )
|
for( MODULE* footprint : m_board->Modules() )
|
||||||
{
|
{
|
||||||
|
@ -89,7 +91,7 @@ void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions()
|
||||||
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MISSING_COURTYARD );
|
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MISSING_COURTYARD );
|
||||||
drcItem->SetItems( footprint );
|
drcItem->SetItems( footprint );
|
||||||
ReportViolation( drcItem, footprint->GetPosition() );
|
reportViolation( drcItem, footprint->GetPosition());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -108,7 +110,7 @@ void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions()
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
drcItem->SetErrorMessage( m_msg );
|
||||||
drcItem->SetItems( footprint );
|
drcItem->SetItems( footprint );
|
||||||
ReportViolation( drcItem, footprint->GetPosition() );
|
reportViolation( drcItem, footprint->GetPosition());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,7 +118,7 @@ void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions()
|
||||||
|
|
||||||
void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testOverlappingComponentCourtyards()
|
void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testOverlappingComponentCourtyards()
|
||||||
{
|
{
|
||||||
ReportStage( _( "Testing component courtyard overlap" ), 0, 2 );
|
reportStage( _( "Footprint courtyard overlap..." ));
|
||||||
|
|
||||||
for( auto it1 = m_board->Modules().begin(); it1 != m_board->Modules().end(); it1++ )
|
for( auto it1 = m_board->Modules().begin(); it1 != m_board->Modules().end(); it1++ )
|
||||||
{
|
{
|
||||||
|
@ -175,7 +177,7 @@ void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testOverlappingComponentCourtyards()
|
||||||
{
|
{
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_OVERLAPPING_FOOTPRINTS );
|
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_OVERLAPPING_FOOTPRINTS );
|
||||||
drcItem->SetItems( footprint, test );
|
drcItem->SetItems( footprint, test );
|
||||||
ReportViolation( drcItem, pos );
|
reportViolation( drcItem, pos );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,6 +200,12 @@ bool DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::GetNumPhases() const
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::GetConstraintTypes() const
|
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::GetConstraintTypes() const
|
||||||
{
|
{
|
||||||
return { DRC_CONSTRAINT_TYPE_COURTYARD_CLEARANCE };
|
return { DRC_CONSTRAINT_TYPE_COURTYARD_CLEARANCE };
|
||||||
|
|
|
@ -21,11 +21,7 @@
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//#include <class_board.h>
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
|
||||||
//#include <geometry/shape.h>
|
|
||||||
|
|
||||||
#include <drc/drc_engine.h>
|
#include <drc/drc_engine.h>
|
||||||
#include <drc/drc.h>
|
#include <drc/drc.h>
|
||||||
#include <drc/drc_item.h>
|
#include <drc/drc_item.h>
|
||||||
|
@ -62,18 +58,20 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
||||||
|
|
||||||
|
int GetNumPhases() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
bool DRC_TEST_PROVIDER_DISALLOW::Run()
|
bool DRC_TEST_PROVIDER_DISALLOW::Run()
|
||||||
{
|
{
|
||||||
if( !m_drcEngine->HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_DISALLOW ) )
|
if( !m_drcEngine->HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_DISALLOW ) )
|
||||||
{
|
{
|
||||||
ReportAux( "No disallow constraints found. Skipping check." );
|
reportAux( "No disallow constraints found. Skipping check." );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportStage( _( "Testing disallow constraints" ), 0, 2 );
|
reportStage( _( "Keepouts & disallow constraints..." ));
|
||||||
|
|
||||||
auto checkItem = [&]( BOARD_ITEM *item ) -> bool
|
auto checkItem = [&]( BOARD_ITEM *item ) -> bool
|
||||||
{
|
{
|
||||||
|
@ -93,7 +91,7 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run()
|
||||||
drcItem->SetItems( item );
|
drcItem->SetItems( item );
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
ReportViolation( drcItem, item->GetPosition() );
|
reportViolation( drcItem, item->GetPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -107,6 +105,12 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int DRC_TEST_PROVIDER_DISALLOW::GetNumPhases() const
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_DISALLOW::GetConstraintTypes() const
|
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_DISALLOW::GetConstraintTypes() const
|
||||||
{
|
{
|
||||||
return { DRC_CONSTRAINT_TYPE_DISALLOW };
|
return { DRC_CONSTRAINT_TYPE_DISALLOW };
|
||||||
|
|
|
@ -66,6 +66,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
||||||
|
|
||||||
|
int GetNumPhases() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -82,13 +84,13 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ReportAux("No Clearance constraints found...");
|
reportAux( "No Clearance constraints found..." );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportAux( "Worst clearance : %d nm", m_largestClearance );
|
reportAux( "Worst clearance : %d nm", m_largestClearance );
|
||||||
|
|
||||||
ReportStage( _( "Testing all items <> Board Edge clearance" ), 0, 2 );
|
reportStage( _( "Board edge clearances..." ));
|
||||||
|
|
||||||
std::vector<DRAWSEGMENT*> boardOutline;
|
std::vector<DRAWSEGMENT*> boardOutline;
|
||||||
std::vector<BOARD_ITEM*> boardItems;
|
std::vector<BOARD_ITEM*> boardItems;
|
||||||
|
@ -108,12 +110,13 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
|
||||||
};
|
};
|
||||||
|
|
||||||
forEachGeometryItem( { PCB_LINE_T }, LSET( Edge_Cuts ), queryBoardOutlineItems );
|
forEachGeometryItem( { PCB_LINE_T }, LSET( Edge_Cuts ), queryBoardOutlineItems );
|
||||||
forEachGeometryItem( {}, LSET::AllTechMask() | LSET::AllCuMask(), queryBoardGeometryItems );
|
forEachGeometryItem( {}, LSET::AllCuMask(), queryBoardGeometryItems );
|
||||||
|
|
||||||
wxString val;
|
wxString val;
|
||||||
wxGetEnv( "WXTRACE", &val);
|
wxGetEnv( "WXTRACE", &val);
|
||||||
|
|
||||||
drc_dbg( 2,"outline: %d items, board: %d items\n", boardOutline.size(), boardItems.size() );
|
drc_dbg( 2, "outline: %d items, board: %d items\n",
|
||||||
|
(int) boardOutline.size(), (int) boardItems.size() );
|
||||||
|
|
||||||
for( DRAWSEGMENT* outlineItem : boardOutline )
|
for( DRAWSEGMENT* outlineItem : boardOutline )
|
||||||
{
|
{
|
||||||
|
@ -154,7 +157,7 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
|
||||||
drcItem->SetItems( outlineItem, boardItem );
|
drcItem->SetItems( outlineItem, boardItem );
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
ReportViolation( drcItem, (wxPoint) refShape->Centre() );
|
reportViolation( drcItem, (wxPoint) refShape->Centre());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,6 +168,12 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int DRC_TEST_PROVIDER_EDGE_CLEARANCE::GetNumPhases() const
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_EDGE_CLEARANCE::GetConstraintTypes() const
|
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_EDGE_CLEARANCE::GetConstraintTypes() const
|
||||||
{
|
{
|
||||||
return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE };
|
return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE };
|
||||||
|
|
|
@ -67,6 +67,8 @@ public:
|
||||||
|
|
||||||
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
||||||
|
|
||||||
|
int GetNumPhases() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addHole( const VECTOR2I& aLocation, int aRadius, BOARD_ITEM* aOwner );
|
void addHole( const VECTOR2I& aLocation, int aRadius, BOARD_ITEM* aOwner );
|
||||||
|
|
||||||
|
@ -103,21 +105,20 @@ bool DRC_TEST_PROVIDER_HOLE_CLEARANCE::Run()
|
||||||
worstClearanceConstraint, DRCCQ_LARGEST_MINIMUM ) )
|
worstClearanceConstraint, DRCCQ_LARGEST_MINIMUM ) )
|
||||||
{
|
{
|
||||||
m_largestClearance = worstClearanceConstraint.GetValue().Min();
|
m_largestClearance = worstClearanceConstraint.GetValue().Min();
|
||||||
|
reportAux( "Worst hole clearance : %d nm", m_largestClearance );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ReportAux( "No Clearance constraints found..." );
|
reportAux( "No hole clearance constraints found..." );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportAux( "Worst hole clearance : %d nm", m_largestClearance );
|
|
||||||
|
|
||||||
buildDrilledHoleList();
|
buildDrilledHoleList();
|
||||||
|
|
||||||
ReportStage( _( "Testing hole<->pad clearances" ), 0, 2 );
|
reportStage( _( "Hole to pad clearances..." ));
|
||||||
testPads2Holes();
|
testPads2Holes();
|
||||||
|
|
||||||
ReportStage( _( "Testing hole<->hole clearances" ), 0, 2 );
|
reportStage( _( "Hole to hole clearances..." ));
|
||||||
testHoles2Holes();
|
testHoles2Holes();
|
||||||
|
|
||||||
reportRuleStatistics();
|
reportRuleStatistics();
|
||||||
|
@ -155,7 +156,7 @@ void DRC_TEST_PROVIDER_HOLE_CLEARANCE::buildDrilledHoleList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportAux( "Total drilled holes : %d", m_drilledHoles.size() );
|
reportAux( "Total drilled holes : %d", m_drilledHoles.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRC_TEST_PROVIDER_HOLE_CLEARANCE::testPads2Holes()
|
void DRC_TEST_PROVIDER_HOLE_CLEARANCE::testPads2Holes()
|
||||||
|
@ -277,7 +278,7 @@ bool DRC_TEST_PROVIDER_HOLE_CLEARANCE::doPadToPadHoleDrc( D_PAD* aRefPad, D_PAD
|
||||||
drcItem->SetItems( pad, aRefPad );
|
drcItem->SetItems( pad, aRefPad );
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
ReportViolation( drcItem, pad->GetPosition() );
|
reportViolation( drcItem, pad->GetPosition());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,7 +311,7 @@ bool DRC_TEST_PROVIDER_HOLE_CLEARANCE::doPadToPadHoleDrc( D_PAD* aRefPad, D_PAD
|
||||||
drcItem->SetItems( aRefPad, pad );
|
drcItem->SetItems( aRefPad, pad );
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
ReportViolation( drcItem, pad->GetPosition() );
|
reportViolation( drcItem, pad->GetPosition());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -395,13 +396,19 @@ void DRC_TEST_PROVIDER_HOLE_CLEARANCE::testHoles2Holes()
|
||||||
drcItem->SetItems( refHole.m_owner, checkHole.m_owner );
|
drcItem->SetItems( refHole.m_owner, checkHole.m_owner );
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
ReportViolation( drcItem, (wxPoint) refHole.m_location );
|
reportViolation( drcItem, (wxPoint) refHole.m_location );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int DRC_TEST_PROVIDER_HOLE_CLEARANCE::GetNumPhases() const
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_HOLE_CLEARANCE::GetConstraintTypes() const
|
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_HOLE_CLEARANCE::GetConstraintTypes() const
|
||||||
{
|
{
|
||||||
return { DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE };
|
return { DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE };
|
||||||
|
|
|
@ -64,6 +64,8 @@ public:
|
||||||
|
|
||||||
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
||||||
|
|
||||||
|
int GetNumPhases() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void checkVia( VIA* via, bool aExceedMicro, bool aExceedStd );
|
void checkVia( VIA* via, bool aExceedMicro, bool aExceedStd );
|
||||||
void checkPad( D_PAD* aPad );
|
void checkPad( D_PAD* aPad );
|
||||||
|
@ -74,7 +76,7 @@ private:
|
||||||
|
|
||||||
bool DRC_TEST_PROVIDER_HOLE_SIZE::Run()
|
bool DRC_TEST_PROVIDER_HOLE_SIZE::Run()
|
||||||
{
|
{
|
||||||
ReportStage( _( "Testing pad holes" ), 0, 2 );
|
reportStage( _( "Pad holes..." ));
|
||||||
|
|
||||||
m_board = m_drcEngine->GetBoard();
|
m_board = m_drcEngine->GetBoard();
|
||||||
|
|
||||||
|
@ -92,7 +94,7 @@ bool DRC_TEST_PROVIDER_HOLE_SIZE::Run()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportStage( _( "Testing via/microvia holes" ), 0, 2 );
|
reportStage( _( "Via holes..." ));
|
||||||
|
|
||||||
std::vector<VIA*> vias;
|
std::vector<VIA*> vias;
|
||||||
|
|
||||||
|
@ -145,7 +147,7 @@ void DRC_TEST_PROVIDER_HOLE_SIZE::checkPad( D_PAD* aPad )
|
||||||
drcItem->SetItems( aPad );
|
drcItem->SetItems( aPad );
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
ReportViolation( drcItem, aPad->GetPosition() );
|
reportViolation( drcItem, aPad->GetPosition());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,11 +189,17 @@ void DRC_TEST_PROVIDER_HOLE_SIZE::checkVia( VIA* via, bool aExceedMicro, bool aE
|
||||||
drcItem->SetItems( via );
|
drcItem->SetItems( via );
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
ReportViolation( drcItem, via->GetPosition() );
|
reportViolation( drcItem, via->GetPosition());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int DRC_TEST_PROVIDER_HOLE_SIZE::GetNumPhases() const
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_HOLE_SIZE::GetConstraintTypes() const
|
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_HOLE_SIZE::GetConstraintTypes() const
|
||||||
{
|
{
|
||||||
return { DRC_CONSTRAINT_TYPE_HOLE_SIZE };
|
return { DRC_CONSTRAINT_TYPE_HOLE_SIZE };
|
||||||
|
|
|
@ -70,9 +70,9 @@ public:
|
||||||
|
|
||||||
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
||||||
|
|
||||||
private:
|
int GetNumPhases() const override;
|
||||||
|
|
||||||
bool fetchNetlistFromSchematic( NETLIST& aNetlist );
|
private:
|
||||||
void testFootprints( NETLIST& aNetlist );
|
void testFootprints( NETLIST& aNetlist );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ void DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist )
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_DUPLICATE_FOOTPRINT );
|
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_DUPLICATE_FOOTPRINT );
|
||||||
drcItem->SetItems( mod, *ins.first );
|
drcItem->SetItems( mod, *ins.first );
|
||||||
|
|
||||||
ReportViolation( drcItem, mod->GetPosition() );
|
reportViolation( drcItem, mod->GetPosition());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ void DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist )
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MISSING_FOOTPRINT );
|
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MISSING_FOOTPRINT );
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
drcItem->SetErrorMessage( m_msg );
|
||||||
ReportViolation( drcItem, wxPoint() );
|
reportViolation( drcItem, wxPoint());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -142,7 +142,7 @@ void DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist )
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
|
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
|
||||||
drcItem->SetErrorMessage( m_msg );
|
drcItem->SetErrorMessage( m_msg );
|
||||||
drcItem->SetItems( pad );
|
drcItem->SetItems( pad );
|
||||||
ReportViolation( drcItem, module->GetPosition() );
|
reportViolation( drcItem, module->GetPosition());
|
||||||
}
|
}
|
||||||
else if( pcb_netname.IsEmpty() && !sch_net.GetNetName().IsEmpty() )
|
else if( pcb_netname.IsEmpty() && !sch_net.GetNetName().IsEmpty() )
|
||||||
{
|
{
|
||||||
|
@ -152,7 +152,7 @@ void DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist )
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
|
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
|
||||||
drcItem->SetErrorMessage( m_msg );
|
drcItem->SetErrorMessage( m_msg );
|
||||||
drcItem->SetItems( pad );
|
drcItem->SetItems( pad );
|
||||||
ReportViolation( drcItem, module->GetPosition() );
|
reportViolation( drcItem, module->GetPosition());
|
||||||
}
|
}
|
||||||
else if( pcb_netname != sch_net.GetNetName() )
|
else if( pcb_netname != sch_net.GetNetName() )
|
||||||
{
|
{
|
||||||
|
@ -163,7 +163,7 @@ void DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist )
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
|
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
|
||||||
drcItem->SetErrorMessage( m_msg );
|
drcItem->SetErrorMessage( m_msg );
|
||||||
drcItem->SetItems( pad );
|
drcItem->SetItems( pad );
|
||||||
ReportViolation( drcItem, module->GetPosition() );
|
reportViolation( drcItem, module->GetPosition());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ void DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist )
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
|
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
|
||||||
drcItem->SetErrorMessage( m_msg );
|
drcItem->SetErrorMessage( m_msg );
|
||||||
drcItem->SetItems( module );
|
drcItem->SetItems( module );
|
||||||
ReportViolation( drcItem, module->GetPosition() );
|
reportViolation( drcItem, module->GetPosition());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -199,63 +199,33 @@ void DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist )
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_EXTRA_FOOTPRINT );
|
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_EXTRA_FOOTPRINT );
|
||||||
|
|
||||||
drcItem->SetItems( module );
|
drcItem->SetItems( module );
|
||||||
ReportViolation( drcItem, module->GetPosition() );
|
reportViolation( drcItem, module->GetPosition());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool DRC_TEST_PROVIDER_LVS::fetchNetlistFromSchematic( NETLIST& aNetlist )
|
|
||||||
{
|
|
||||||
// fixme: make it work without dependency on EDIT_FRAME/kiway
|
|
||||||
#if 0
|
|
||||||
std::string payload;
|
|
||||||
|
|
||||||
Kiway().ExpressMail( FRAME_SCH, MAIL_SCH_GET_NETLIST, payload, nullptr );
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
auto lineReader = new STRING_LINE_READER( payload, _( "Eeschema netlist" ) );
|
|
||||||
KICAD_NETLIST_READER netlistReader( lineReader, &aNetlist );
|
|
||||||
netlistReader.LoadNetlist();
|
|
||||||
}
|
|
||||||
catch( const IO_ERROR& )
|
|
||||||
{
|
|
||||||
assert( false ); // should never happen
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DRC_TEST_PROVIDER_LVS::Run()
|
bool DRC_TEST_PROVIDER_LVS::Run()
|
||||||
{
|
{
|
||||||
ReportStage( _( "Layout-vs-Schematic checks..." ), 0, 2 );
|
if( m_drcEngine->GetTestFootprints() )
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
if ( !Kiface().IsSingle() )
|
|
||||||
{
|
{
|
||||||
NETLIST netlist; // fixme: fetch from schematic without referring directly to the FRAME
|
reportStage( _( "Layout-vs-Schematic checks..." ));
|
||||||
|
|
||||||
if( ! fetchNetlistFromSchematic( netlist ) )
|
testFootprints( *m_drcEngine->GetSchematicNetlist() );
|
||||||
{
|
|
||||||
ReportAux( _( "Unable to fetch the schematic netlist. Skipping LVS checks. ") );
|
reportRuleStatistics();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
testFootprints( netlist );
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
reportRuleStatistics();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int DRC_TEST_PROVIDER_LVS::GetNumPhases() const
|
||||||
|
{
|
||||||
|
return m_drcEngine->GetTestFootprints() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_LVS::GetConstraintTypes() const
|
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_LVS::GetConstraintTypes() const
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -68,6 +68,8 @@ public:
|
||||||
|
|
||||||
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
||||||
|
|
||||||
|
int GetNumPhases() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void testOutline();
|
void testOutline();
|
||||||
void testDisabledLayers();
|
void testDisabledLayers();
|
||||||
|
@ -93,7 +95,7 @@ void DRC_TEST_PROVIDER_MISC::testOutline()
|
||||||
drcItem->SetErrorMessage( m_msg );
|
drcItem->SetErrorMessage( m_msg );
|
||||||
drcItem->SetItems( m_board );
|
drcItem->SetItems( m_board );
|
||||||
|
|
||||||
ReportViolation( drcItem, error_loc );
|
reportViolation( drcItem, error_loc );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -119,7 +121,7 @@ void DRC_TEST_PROVIDER_MISC::testDisabledLayers()
|
||||||
drcItem->SetErrorMessage( m_msg );
|
drcItem->SetErrorMessage( m_msg );
|
||||||
drcItem->SetItems( item );
|
drcItem->SetItems( item );
|
||||||
|
|
||||||
ReportViolation( drcItem, item->GetPosition() );
|
reportViolation( drcItem, item->GetPosition());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
@ -144,7 +146,7 @@ void DRC_TEST_PROVIDER_MISC::testTextVars()
|
||||||
std::shared_ptr<DRC_ITEM>drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE );
|
std::shared_ptr<DRC_ITEM>drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE );
|
||||||
drcItem->SetItems( item );
|
drcItem->SetItems( item );
|
||||||
|
|
||||||
ReportViolation( drcItem, item->GetPosition() );
|
reportViolation( drcItem, item->GetPosition());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
@ -179,7 +181,7 @@ void DRC_TEST_PROVIDER_MISC::testTextVars()
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE );
|
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE );
|
||||||
drcItem->SetItems( text );
|
drcItem->SetItems( text );
|
||||||
|
|
||||||
ReportViolation( drcItem, text->GetPosition() );
|
reportViolation( drcItem, text->GetPosition());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,19 +191,25 @@ bool DRC_TEST_PROVIDER_MISC::Run()
|
||||||
{
|
{
|
||||||
m_board = m_drcEngine->GetBoard();
|
m_board = m_drcEngine->GetBoard();
|
||||||
|
|
||||||
ReportStage( _( "Test board outline" ), 0, 3 );
|
reportStage( _( "Board outline..." ));
|
||||||
testOutline();
|
testOutline();
|
||||||
|
|
||||||
ReportStage( _( "Test disabled layers" ), 1, 3 );
|
reportStage( _( "Disabled layers..." ));
|
||||||
testDisabledLayers();
|
testDisabledLayers();
|
||||||
|
|
||||||
ReportStage( _( "Test text variables" ), 2, 3 );
|
reportStage( _( "Text variables..." ));
|
||||||
testTextVars();
|
testTextVars();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int DRC_TEST_PROVIDER_MISC::GetNumPhases() const
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_MISC::GetConstraintTypes() const
|
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_MISC::GetConstraintTypes() const
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -60,6 +60,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
||||||
|
|
||||||
|
int GetNumPhases() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,11 +69,11 @@ bool DRC_TEST_PROVIDER_TRACK_WIDTH::Run()
|
||||||
{
|
{
|
||||||
if( !m_drcEngine->HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_TRACK_WIDTH ) )
|
if( !m_drcEngine->HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_TRACK_WIDTH ) )
|
||||||
{
|
{
|
||||||
ReportAux( "No track width constraints found. Skipping check." );
|
reportAux( "No track width constraints found. Skipping check." );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportStage( _( "Testing track widths" ), 0, 2 );
|
reportStage( _( "Track widths..." ));
|
||||||
|
|
||||||
auto checkTrackWidth =
|
auto checkTrackWidth =
|
||||||
[&]( BOARD_ITEM* item ) -> bool
|
[&]( BOARD_ITEM* item ) -> bool
|
||||||
|
@ -117,15 +119,15 @@ bool DRC_TEST_PROVIDER_TRACK_WIDTH::Run()
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s width %s; actual %s)" ),
|
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s width %s; actual %s)" ),
|
||||||
constraint.GetName(),
|
constraint.GetName(),
|
||||||
fail_min ? _( "minimum" ) : _( "maximum" ),
|
fail_min ? _( "min" ) : _( "max" ),
|
||||||
MessageTextFromValue( userUnits(), constraintWidth, true ) );
|
MessageTextFromValue( userUnits(), constraintWidth, true ),
|
||||||
MessageTextFromValue( userUnits(), actual, true ),
|
MessageTextFromValue( userUnits(), actual, true ) );
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
drcItem->SetErrorMessage( m_msg );
|
||||||
drcItem->SetItems( item );
|
drcItem->SetItems( item );
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
ReportViolation( drcItem, p0 );
|
reportViolation( drcItem, p0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -139,6 +141,12 @@ bool DRC_TEST_PROVIDER_TRACK_WIDTH::Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int DRC_TEST_PROVIDER_TRACK_WIDTH::GetNumPhases() const
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_TRACK_WIDTH::GetConstraintTypes() const
|
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_TRACK_WIDTH::GetConstraintTypes() const
|
||||||
{
|
{
|
||||||
return { DRC_CONSTRAINT_TYPE_TRACK_WIDTH };
|
return { DRC_CONSTRAINT_TYPE_TRACK_WIDTH };
|
||||||
|
|
|
@ -61,6 +61,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
|
||||||
|
|
||||||
|
int GetNumPhases() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,11 +70,11 @@ bool DRC_TEST_PROVIDER_VIA_DIAMETER::Run()
|
||||||
{
|
{
|
||||||
if( !m_drcEngine->HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_VIA_DIAMETER ) )
|
if( !m_drcEngine->HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_VIA_DIAMETER ) )
|
||||||
{
|
{
|
||||||
ReportAux( "No diameter constraints found. Skipping check." );
|
reportAux( "No diameter constraints found. Skipping check." );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportStage( ( "Testing via diameters" ), 0, 2 );
|
reportStage(( "Via diameters..." ));
|
||||||
|
|
||||||
auto checkViaDiameter =
|
auto checkViaDiameter =
|
||||||
[&]( BOARD_ITEM* item ) -> bool
|
[&]( BOARD_ITEM* item ) -> bool
|
||||||
|
@ -111,7 +113,7 @@ bool DRC_TEST_PROVIDER_VIA_DIAMETER::Run()
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s diameter %s; actual %s)" ),
|
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s diameter %s; actual %s)" ),
|
||||||
constraint.GetName(),
|
constraint.GetName(),
|
||||||
fail_min ? _( "minimum" ) : _( "maximum" ),
|
fail_min ? _( "min" ) : _( "max" ),
|
||||||
MessageTextFromValue( userUnits(), constraintDiameter, true ) );
|
MessageTextFromValue( userUnits(), constraintDiameter, true ) );
|
||||||
MessageTextFromValue( userUnits(), actual, true ),
|
MessageTextFromValue( userUnits(), actual, true ),
|
||||||
|
|
||||||
|
@ -119,7 +121,7 @@ bool DRC_TEST_PROVIDER_VIA_DIAMETER::Run()
|
||||||
drcItem->SetItems( item );
|
drcItem->SetItems( item );
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
ReportViolation( drcItem, via->GetPosition() );
|
reportViolation( drcItem, via->GetPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -133,6 +135,12 @@ bool DRC_TEST_PROVIDER_VIA_DIAMETER::Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int DRC_TEST_PROVIDER_VIA_DIAMETER::GetNumPhases() const
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_VIA_DIAMETER::GetConstraintTypes() const
|
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_VIA_DIAMETER::GetConstraintTypes() const
|
||||||
{
|
{
|
||||||
return { DRC_CONSTRAINT_TYPE_VIA_DIAMETER };
|
return { DRC_CONSTRAINT_TYPE_VIA_DIAMETER };
|
||||||
|
|
|
@ -1,120 +0,0 @@
|
||||||
/*
|
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, you may find one here:
|
|
||||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
||||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
||||||
* or you may write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <drc/drc_textvar_tester.h>
|
|
||||||
|
|
||||||
#include <class_module.h>
|
|
||||||
#include <class_pcb_text.h>
|
|
||||||
#include <ws_draw_item.h>
|
|
||||||
#include <ws_proxy_view_item.h>
|
|
||||||
|
|
||||||
DRC_TEXTVAR_TESTER::DRC_TEXTVAR_TESTER( MARKER_HANDLER aMarkerHandler,
|
|
||||||
KIGFX::WS_PROXY_VIEW_ITEM* aWorksheet ) :
|
|
||||||
LEGACY_DRC_TEST_PROVIDER( std::move( aMarkerHandler ) ),
|
|
||||||
m_units( EDA_UNITS::MILLIMETRES ),
|
|
||||||
m_board( nullptr ),
|
|
||||||
m_worksheet( aWorksheet )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool DRC_TEXTVAR_TESTER::RunDRC( EDA_UNITS aUnits, BOARD& aBoard )
|
|
||||||
{
|
|
||||||
bool success = true;
|
|
||||||
|
|
||||||
m_units = aUnits;
|
|
||||||
m_board = &aBoard;
|
|
||||||
|
|
||||||
for( MODULE* module : m_board->Modules() )
|
|
||||||
{
|
|
||||||
module->RunOnChildren(
|
|
||||||
[&]( BOARD_ITEM* child )
|
|
||||||
{
|
|
||||||
if( child->Type() == PCB_MODULE_TEXT_T )
|
|
||||||
{
|
|
||||||
TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( child );
|
|
||||||
|
|
||||||
if( text->GetShownText().Matches( wxT( "*${*}*" ) ) )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE );
|
|
||||||
drcItem->SetItems( text );
|
|
||||||
|
|
||||||
HandleMarker( new MARKER_PCB( drcItem, text->GetPosition() ) );
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
for( BOARD_ITEM* drawing : m_board->Drawings() )
|
|
||||||
{
|
|
||||||
if( drawing->Type() == PCB_TEXT_T )
|
|
||||||
{
|
|
||||||
TEXTE_PCB* text = static_cast<TEXTE_PCB*>( drawing );
|
|
||||||
|
|
||||||
if( text->GetShownText().Matches( wxT( "*${*}*" ) ) )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE );
|
|
||||||
drcItem->SetItems( text );
|
|
||||||
|
|
||||||
HandleMarker( new MARKER_PCB( drcItem, text->GetPosition() ) );
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WS_DRAW_ITEM_LIST wsItems;
|
|
||||||
|
|
||||||
if( m_worksheet )
|
|
||||||
{
|
|
||||||
wsItems.SetMilsToIUfactor( IU_PER_MILS );
|
|
||||||
wsItems.SetSheetNumber( 1 );
|
|
||||||
wsItems.SetSheetCount( 1 );
|
|
||||||
wsItems.SetFileName( "dummyFilename" );
|
|
||||||
wsItems.SetSheetName( "dummySheet" );
|
|
||||||
wsItems.SetSheetLayer( "dummyLayer" );
|
|
||||||
wsItems.SetProject( m_board->GetProject() );
|
|
||||||
wsItems.BuildWorkSheetGraphicList( m_worksheet->GetPageInfo(),
|
|
||||||
m_worksheet->GetTitleBlock() );
|
|
||||||
|
|
||||||
for( WS_DRAW_ITEM_BASE* item = wsItems.GetFirst(); item; item = wsItems.GetNext() )
|
|
||||||
{
|
|
||||||
if( WS_DRAW_ITEM_TEXT* text = dynamic_cast<WS_DRAW_ITEM_TEXT*>( item ) )
|
|
||||||
{
|
|
||||||
if( text->GetShownText().Matches( wxT( "*${*}*" ) ) )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE );
|
|
||||||
drcItem->SetErrorMessage( _( "Unresolved text variable in worksheet." ) );
|
|
||||||
|
|
||||||
HandleMarker( new MARKER_PCB( drcItem, text->GetPosition() ) );
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
/*
|
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 KiCad Developers, see change_log.txt for contributors.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, you may find one here:
|
|
||||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
||||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
||||||
* or you may write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef DRC_TEXTVAR_TESTER__H
|
|
||||||
#define DRC_TEXTVAR_TESTER__H
|
|
||||||
|
|
||||||
#include <drc/drc_results_provider.h>
|
|
||||||
|
|
||||||
|
|
||||||
class BOARD;
|
|
||||||
|
|
||||||
|
|
||||||
class DRC_TEXTVAR_TESTER : public LEGACY_DRC_TEST_PROVIDER
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DRC_TEXTVAR_TESTER( MARKER_HANDLER aMarkerHandler, KIGFX::WS_PROXY_VIEW_ITEM* aWorksheet );
|
|
||||||
|
|
||||||
virtual ~DRC_TEXTVAR_TESTER() {};
|
|
||||||
|
|
||||||
bool RunDRC( EDA_UNITS aUnits, BOARD& aBoard ) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
EDA_UNITS m_units;
|
|
||||||
BOARD* m_board;
|
|
||||||
KIGFX::WS_PROXY_VIEW_ITEM* m_worksheet;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // DRC_TEXTVAR_TESTER__H
|
|
|
@ -1,149 +0,0 @@
|
||||||
/*
|
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 KiCad Developers, see change_log.txt for contributors.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, you may find one here:
|
|
||||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
||||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
||||||
* or you may write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <fctsys.h>
|
|
||||||
#include <netlist_reader/pcb_netlist.h>
|
|
||||||
#include <drc/footprint_tester.h>
|
|
||||||
#include <drc/drc_item.h>
|
|
||||||
|
|
||||||
void TestFootprints( NETLIST& aNetlist, BOARD* aBoard, std::vector<std::shared_ptr<DRC_ITEM> >& aDRCList )
|
|
||||||
{
|
|
||||||
wxString msg;
|
|
||||||
|
|
||||||
auto comp = []( const MODULE* x, const MODULE* y )
|
|
||||||
{
|
|
||||||
return x->GetReference().CmpNoCase( y->GetReference() ) < 0;
|
|
||||||
};
|
|
||||||
auto mods = std::set<MODULE*, decltype( comp )>( comp );
|
|
||||||
|
|
||||||
if( !aBoard->GetDesignSettings().Ignore( DRCE_DUPLICATE_FOOTPRINT ) )
|
|
||||||
{
|
|
||||||
// Search for duplicate footprints on the board
|
|
||||||
for( MODULE* mod : aBoard->Modules() )
|
|
||||||
{
|
|
||||||
auto ins = mods.insert( mod );
|
|
||||||
|
|
||||||
if( !ins.second )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> item = DRC_ITEM::Create( DRCE_DUPLICATE_FOOTPRINT );
|
|
||||||
item->SetItems( mod, *ins.first );
|
|
||||||
aDRCList.push_back( item );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search for component footprints in the netlist but not on the board.
|
|
||||||
for( unsigned ii = 0; ii < aNetlist.GetCount(); ii++ )
|
|
||||||
{
|
|
||||||
COMPONENT* component = aNetlist.GetComponent( ii );
|
|
||||||
MODULE* module = aBoard->FindModuleByReference( component->GetReference() );
|
|
||||||
|
|
||||||
if( module == nullptr )
|
|
||||||
{
|
|
||||||
if( !aBoard->GetDesignSettings().Ignore( DRCE_MISSING_FOOTPRINT ) && module == NULL )
|
|
||||||
{
|
|
||||||
msg.Printf( _( "Missing footprint %s (%s)" ),
|
|
||||||
component->GetReference(),
|
|
||||||
component->GetValue() );
|
|
||||||
|
|
||||||
std::shared_ptr<DRC_ITEM> item = DRC_ITEM::Create( DRCE_MISSING_FOOTPRINT );
|
|
||||||
item->SetErrorMessage( msg );
|
|
||||||
aDRCList.push_back( item );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( !aBoard->GetDesignSettings().Ignore( DRCE_NET_CONFLICT ) )
|
|
||||||
{
|
|
||||||
for( D_PAD* pad : module->Pads() )
|
|
||||||
{
|
|
||||||
const COMPONENT_NET& sch_net = component->GetNet( pad->GetName() );
|
|
||||||
const wxString& pcb_netname = pad->GetNetname();
|
|
||||||
|
|
||||||
if( !pcb_netname.IsEmpty() && sch_net.GetPinName().IsEmpty() )
|
|
||||||
{
|
|
||||||
msg.Printf( _( "No corresponding pin found in schematic." ) );
|
|
||||||
|
|
||||||
std::shared_ptr<DRC_ITEM> item = DRC_ITEM::Create( DRCE_NET_CONFLICT );
|
|
||||||
item->SetErrorMessage( msg );
|
|
||||||
item->SetItems( pad );
|
|
||||||
aDRCList.push_back( item );
|
|
||||||
}
|
|
||||||
else if( pcb_netname.IsEmpty() && !sch_net.GetNetName().IsEmpty() )
|
|
||||||
{
|
|
||||||
msg.Printf( _( "Pad missing net given by schematic (%s)." ),
|
|
||||||
sch_net.GetNetName() );
|
|
||||||
|
|
||||||
std::shared_ptr<DRC_ITEM> item = DRC_ITEM::Create( DRCE_NET_CONFLICT );
|
|
||||||
item->SetErrorMessage( msg );
|
|
||||||
item->SetItems( pad );
|
|
||||||
aDRCList.push_back( item );
|
|
||||||
}
|
|
||||||
else if( pcb_netname != sch_net.GetNetName() )
|
|
||||||
{
|
|
||||||
msg.Printf( _( "Pad net (%s) doesn't match net given by schematic (%s)." ),
|
|
||||||
pcb_netname,
|
|
||||||
sch_net.GetNetName() );
|
|
||||||
|
|
||||||
std::shared_ptr<DRC_ITEM> item = DRC_ITEM::Create( DRCE_NET_CONFLICT );
|
|
||||||
item->SetErrorMessage( msg );
|
|
||||||
item->SetItems( pad );
|
|
||||||
aDRCList.push_back( item );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for( unsigned jj = 0; jj < component->GetNetCount(); ++jj )
|
|
||||||
{
|
|
||||||
const COMPONENT_NET& sch_net = component->GetNet( jj );
|
|
||||||
|
|
||||||
if( !module->FindPadByName( sch_net.GetPinName() ) )
|
|
||||||
{
|
|
||||||
msg.Printf( _( "No pad found for pin %s in schematic." ),
|
|
||||||
sch_net.GetPinName() );
|
|
||||||
|
|
||||||
std::shared_ptr<DRC_ITEM> item = DRC_ITEM::Create( DRCE_NET_CONFLICT );
|
|
||||||
item->SetErrorMessage( msg );
|
|
||||||
item->SetItems( module );
|
|
||||||
aDRCList.push_back( item );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !aBoard->GetDesignSettings().Ignore( DRCE_EXTRA_FOOTPRINT ) )
|
|
||||||
{
|
|
||||||
// Search for component footprints found on board but not in netlist.
|
|
||||||
for( MODULE* module : aBoard->Modules() )
|
|
||||||
{
|
|
||||||
COMPONENT* component = aNetlist.GetComponentByReference( module->GetReference() );
|
|
||||||
|
|
||||||
if( component == NULL )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> item = DRC_ITEM::Create( DRCE_EXTRA_FOOTPRINT );
|
|
||||||
item->SetItems( module );
|
|
||||||
aDRCList.push_back( item );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
/*
|
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 KiCad Developers, see change_log.txt for contributors.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, you may find one here:
|
|
||||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
||||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
||||||
* or you may write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef FOOTPRINT_TESTER_H
|
|
||||||
#define FOOTPRINT_TESTER_H
|
|
||||||
|
|
||||||
#include <drc/drc.h>
|
|
||||||
|
|
||||||
class BOARD;
|
|
||||||
|
|
||||||
|
|
||||||
void TestFootprints( NETLIST& aNetlist, BOARD* aBoard, std::vector<std::shared_ptr<DRC_ITEM> >& aDRCList );
|
|
||||||
|
|
||||||
#endif // FOOTPRINT_TESTER_H
|
|
|
@ -64,6 +64,7 @@
|
||||||
#include <tools/pcbnew_picker_tool.h>
|
#include <tools/pcbnew_picker_tool.h>
|
||||||
#include <tools/point_editor.h>
|
#include <tools/point_editor.h>
|
||||||
#include <tools/edit_tool.h>
|
#include <tools/edit_tool.h>
|
||||||
|
#include <tools/drc_tool.h>
|
||||||
#include <tools/global_edit_tool.h>
|
#include <tools/global_edit_tool.h>
|
||||||
#include <tools/convert_tool.h>
|
#include <tools/convert_tool.h>
|
||||||
#include <tools/drawing_tool.h>
|
#include <tools/drawing_tool.h>
|
||||||
|
@ -504,6 +505,7 @@ void PCB_EDIT_FRAME::setupTools()
|
||||||
m_toolManager->RegisterTool( new ZONE_FILLER_TOOL );
|
m_toolManager->RegisterTool( new ZONE_FILLER_TOOL );
|
||||||
m_toolManager->RegisterTool( new AUTOPLACE_TOOL );
|
m_toolManager->RegisterTool( new AUTOPLACE_TOOL );
|
||||||
m_toolManager->RegisterTool( new DRC );
|
m_toolManager->RegisterTool( new DRC );
|
||||||
|
m_toolManager->RegisterTool( new DRC_TOOL );
|
||||||
m_toolManager->RegisterTool( new PCB_VIEWER_TOOLS );
|
m_toolManager->RegisterTool( new PCB_VIEWER_TOOLS );
|
||||||
m_toolManager->RegisterTool( new CONVERT_TOOL );
|
m_toolManager->RegisterTool( new CONVERT_TOOL );
|
||||||
m_toolManager->InitTools();
|
m_toolManager->InitTools();
|
||||||
|
@ -573,7 +575,7 @@ void PCB_EDIT_FRAME::setupUIConditions()
|
||||||
auto enableBoardSetupCondition =
|
auto enableBoardSetupCondition =
|
||||||
[this] ( const SELECTION& )
|
[this] ( const SELECTION& )
|
||||||
{
|
{
|
||||||
if( DRC* tool = m_toolManager->GetTool<DRC>() )
|
if( DRC_TOOL* tool = m_toolManager->GetTool<DRC_TOOL>() )
|
||||||
return !tool->IsDRCDialogShown();
|
return !tool->IsDRCDialogShown();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -0,0 +1,224 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 KiCad Developers, see change_log.txt for contributors.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fctsys.h>
|
||||||
|
#include <pcb_edit_frame.h>
|
||||||
|
#include <bitmaps.h>
|
||||||
|
#include <tool/tool_manager.h>
|
||||||
|
#include <tools/pcb_actions.h>
|
||||||
|
#include <tools/pcb_tool_base.h>
|
||||||
|
#include <tools/zone_filler_tool.h>
|
||||||
|
#include <tools/drc_tool.h>
|
||||||
|
#include <kiface_i.h>
|
||||||
|
#include <dialog_drc.h>
|
||||||
|
#include <board_commit.h>
|
||||||
|
#include <widgets/progress_reporter.h>
|
||||||
|
#include <drc/drc_engine.h>
|
||||||
|
#include <drc/drc_results_provider.h>
|
||||||
|
#include <netlist_reader/pcb_netlist.h>
|
||||||
|
|
||||||
|
|
||||||
|
DRC_TOOL::DRC_TOOL() :
|
||||||
|
PCB_TOOL_BASE( "pcbnew.DRCTool" ),
|
||||||
|
m_editFrame( nullptr ),
|
||||||
|
m_pcb( nullptr ),
|
||||||
|
m_drcDialog( nullptr )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DRC_TOOL::~DRC_TOOL()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DRC_TOOL::Reset( RESET_REASON aReason )
|
||||||
|
{
|
||||||
|
m_editFrame = getEditFrame<PCB_EDIT_FRAME>();
|
||||||
|
|
||||||
|
if( m_pcb != m_editFrame->GetBoard() )
|
||||||
|
{
|
||||||
|
if( m_drcDialog )
|
||||||
|
DestroyDRCDialog( wxID_OK );
|
||||||
|
|
||||||
|
m_pcb = m_editFrame->GetBoard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DRC_TOOL::ShowDRCDialog( wxWindow* aParent )
|
||||||
|
{
|
||||||
|
bool show_dlg_modal = true;
|
||||||
|
|
||||||
|
// the dialog needs a parent frame. if it is not specified, this is the PCB editor frame
|
||||||
|
// specified in DRC_TOOL class.
|
||||||
|
if( !aParent )
|
||||||
|
{
|
||||||
|
// if any parent is specified, the dialog is modal.
|
||||||
|
// if this is the default PCB editor frame, it is not modal
|
||||||
|
show_dlg_modal = false;
|
||||||
|
aParent = m_editFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
Activate();
|
||||||
|
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
|
||||||
|
|
||||||
|
if( !m_drcDialog )
|
||||||
|
{
|
||||||
|
m_drcDialog = new DIALOG_DRC( m_editFrame, aParent );
|
||||||
|
updatePointers();
|
||||||
|
|
||||||
|
if( show_dlg_modal )
|
||||||
|
m_drcDialog->ShowModal();
|
||||||
|
else
|
||||||
|
m_drcDialog->Show( true );
|
||||||
|
}
|
||||||
|
else // The dialog is just not visible (because the user has double clicked on an error item)
|
||||||
|
{
|
||||||
|
updatePointers();
|
||||||
|
m_drcDialog->Show( true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int DRC_TOOL::ShowDRCDialog( const TOOL_EVENT& aEvent )
|
||||||
|
{
|
||||||
|
ShowDRCDialog( nullptr );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DRC_TOOL::IsDRCDialogShown()
|
||||||
|
{
|
||||||
|
if( m_drcDialog )
|
||||||
|
return m_drcDialog->IsShown();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DRC_TOOL::DestroyDRCDialog( int aReason )
|
||||||
|
{
|
||||||
|
if( m_drcDialog )
|
||||||
|
{
|
||||||
|
m_drcDialog->Destroy();
|
||||||
|
m_drcDialog = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DRC_TOOL::RunTests( WX_PROGRESS_REPORTER* aProgressReporter, bool aTestTracksAgainstZones,
|
||||||
|
bool aRefillZones, bool aReportAllTrackErrors, bool aTestFootprints )
|
||||||
|
{
|
||||||
|
ZONE_FILLER_TOOL* zoneFiller = m_toolMgr->GetTool<ZONE_FILLER_TOOL>();
|
||||||
|
|
||||||
|
BOARD_COMMIT commit( m_editFrame );
|
||||||
|
DRC_ENGINE drcEngine( m_pcb, &m_pcb->GetDesignSettings() );
|
||||||
|
NETLIST netlist;
|
||||||
|
|
||||||
|
if( aRefillZones )
|
||||||
|
{
|
||||||
|
aProgressReporter->AdvancePhase( _( "Refilling all zones..." ) );
|
||||||
|
|
||||||
|
zoneFiller->FillAllZones( aProgressReporter->GetParent(), aProgressReporter );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
aProgressReporter->AdvancePhase( _( "Checking zone fills..." ) );
|
||||||
|
|
||||||
|
zoneFiller->CheckAllZones( aProgressReporter->GetParent(), aProgressReporter );
|
||||||
|
}
|
||||||
|
|
||||||
|
drcEngine.InitEngine( m_editFrame->Prj().AbsolutePath( "drc-rules" ) );
|
||||||
|
|
||||||
|
drcEngine.SetWorksheet( m_editFrame->GetCanvas()->GetWorksheet() );
|
||||||
|
|
||||||
|
if( aTestFootprints && !Kiface().IsSingle() )
|
||||||
|
{
|
||||||
|
m_editFrame->FetchNetlistFromSchematic( netlist, PCB_EDIT_FRAME::ANNOTATION_DIALOG );
|
||||||
|
|
||||||
|
if( m_drcDialog )
|
||||||
|
m_drcDialog->Raise();
|
||||||
|
|
||||||
|
drcEngine.SetSchematicNetlist( &netlist );
|
||||||
|
}
|
||||||
|
|
||||||
|
drcEngine.SetProgressReporter( aProgressReporter );
|
||||||
|
|
||||||
|
drcEngine.SetViolationHandler(
|
||||||
|
[&]( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos )
|
||||||
|
{
|
||||||
|
if( aItem->GetErrorCode() == DRCE_MISSING_FOOTPRINT
|
||||||
|
|| aItem->GetErrorCode() == DRCE_DUPLICATE_FOOTPRINT
|
||||||
|
|| aItem->GetErrorCode() == DRCE_EXTRA_FOOTPRINT
|
||||||
|
|| aItem->GetErrorCode() == DRCE_NET_CONFLICT )
|
||||||
|
{
|
||||||
|
m_footprints.push_back( aItem );
|
||||||
|
}
|
||||||
|
else if( aItem->GetErrorCode() == DRCE_UNCONNECTED_ITEMS )
|
||||||
|
{
|
||||||
|
m_unconnected.push_back( aItem );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MARKER_PCB* marker = new MARKER_PCB( aItem, aPos );
|
||||||
|
commit.Add( marker );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
drcEngine.RunTests( m_editFrame->GetUserUnits(), aTestTracksAgainstZones,
|
||||||
|
aReportAllTrackErrors, aTestFootprints );
|
||||||
|
|
||||||
|
commit.Push( _( "DRC" ), false );
|
||||||
|
|
||||||
|
// update the m_drcDialog listboxes
|
||||||
|
updatePointers();
|
||||||
|
|
||||||
|
aProgressReporter->AdvancePhase( _( "Done." ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DRC_TOOL::updatePointers()
|
||||||
|
{
|
||||||
|
// update my pointers, m_editFrame is the only unchangeable one
|
||||||
|
m_pcb = m_editFrame->GetBoard();
|
||||||
|
|
||||||
|
m_editFrame->ResolveDRCExclusions();
|
||||||
|
|
||||||
|
if( m_drcDialog ) // Use diag list boxes only in DRC_TOOL dialog
|
||||||
|
{
|
||||||
|
m_drcDialog->SetMarkersProvider( new BOARD_DRC_ITEMS_PROVIDER( m_pcb ) );
|
||||||
|
m_drcDialog->SetUnconnectedProvider( new RATSNEST_DRC_ITEMS_PROVIDER( m_editFrame,
|
||||||
|
&m_unconnected ) );
|
||||||
|
m_drcDialog->SetFootprintsProvider( new VECTOR_DRC_ITEMS_PROVIDER( m_editFrame,
|
||||||
|
&m_footprints ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DRC_TOOL::setTransitions()
|
||||||
|
{
|
||||||
|
Go( &DRC_TOOL::ShowDRCDialog, PCB_ACTIONS::runDRC.MakeEvent() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 KiCad Developers, see change_log.txt for contributors.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DRC_TOOL_H
|
||||||
|
#define DRC_TOOL_H
|
||||||
|
|
||||||
|
#include <board_commit.h>
|
||||||
|
#include <class_board.h>
|
||||||
|
#include <class_track.h>
|
||||||
|
#include <class_marker_pcb.h>
|
||||||
|
#include <geometry/seg.h>
|
||||||
|
#include <geometry/shape_poly_set.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <tools/pcb_tool_base.h>
|
||||||
|
|
||||||
|
|
||||||
|
class PCB_EDIT_FRAME;
|
||||||
|
class DIALOG_DRC;
|
||||||
|
class DRC_ITEM;
|
||||||
|
class WX_PROGRESS_REPORTER;
|
||||||
|
|
||||||
|
|
||||||
|
class DRC_TOOL : public PCB_TOOL_BASE
|
||||||
|
{
|
||||||
|
friend class DIALOG_DRC;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DRC_TOOL();
|
||||||
|
~DRC_TOOL();
|
||||||
|
|
||||||
|
/// @copydoc TOOL_INTERACTIVE::Reset()
|
||||||
|
void Reset( RESET_REASON aReason ) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
PCB_EDIT_FRAME* m_editFrame; // The pcb frame editor which owns the board
|
||||||
|
BOARD* m_pcb;
|
||||||
|
DIALOG_DRC* m_drcDialog;
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<DRC_ITEM>> m_unconnected; // list of unconnected pads
|
||||||
|
std::vector<std::shared_ptr<DRC_ITEM>> m_footprints; // list of footprint warnings
|
||||||
|
|
||||||
|
private:
|
||||||
|
///> Sets up handlers for various events.
|
||||||
|
void setTransitions() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update needed pointers from the one pointer which is known not to change.
|
||||||
|
*/
|
||||||
|
void updatePointers();
|
||||||
|
|
||||||
|
EDA_UNITS userUnits() const { return m_editFrame->GetUserUnits(); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Open a dialog and prompts the user, then if a test run button is
|
||||||
|
* clicked, runs the test(s) and creates the MARKERS. The dialog is only
|
||||||
|
* created if it is not already in existence.
|
||||||
|
*
|
||||||
|
* @param aParent is the parent window for wxWidgets. Usually the PCB editor frame
|
||||||
|
* but can be another dialog
|
||||||
|
* if aParent == NULL (default), the parent will be the PCB editor frame
|
||||||
|
* and the dialog will be not modal (just float on parent
|
||||||
|
* if aParent is specified, the dialog will be modal.
|
||||||
|
* The modal mode is mandatory if the dialog is created from another dialog, not
|
||||||
|
* from the PCB editor frame
|
||||||
|
*/
|
||||||
|
void ShowDRCDialog( wxWindow* aParent );
|
||||||
|
|
||||||
|
int ShowDRCDialog( const TOOL_EVENT& aEvent );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if the DRC_TOOL dialog is currently shown
|
||||||
|
*
|
||||||
|
* @return true if the dialog is shown
|
||||||
|
*/
|
||||||
|
bool IsDRCDialogShown();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes this ui dialog box and zeros out its pointer to remember
|
||||||
|
* the state of the dialog's existence.
|
||||||
|
*
|
||||||
|
* @param aReason Indication of which button was clicked to cause the destruction.
|
||||||
|
* if aReason == wxID_OK, design parameters values which can be entered from the dialog
|
||||||
|
* will bbe saved in design parameters list
|
||||||
|
*/
|
||||||
|
void DestroyDRCDialog( int aReason );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run all the tests specified with a previous call to
|
||||||
|
* SetSettings()
|
||||||
|
* @param aMessages = a wxTextControl where to display some activity messages. Can be NULL
|
||||||
|
*/
|
||||||
|
void RunTests( WX_PROGRESS_REPORTER* aProgressReporter, bool aTestTracksAgainstZones,
|
||||||
|
bool aRefillZones, bool aReportAllTrackErrors, bool aTestFootprints );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // DRC_TOOL_H
|
|
@ -194,6 +194,8 @@ void PCB_INSPECTION_TOOL::reportCopperClearance( PCB_LAYER_ID aLayer, BOARD_CONN
|
||||||
if( r )
|
if( r )
|
||||||
{
|
{
|
||||||
wxString clearance = StringFromValue( r->GetUnits(), constraint.m_Value.Min(), true );
|
wxString clearance = StringFromValue( r->GetUnits(), constraint.m_Value.Min(), true );
|
||||||
|
|
||||||
|
r->Report( "" );
|
||||||
r->Report( wxString::Format( _( "Clearance: %s." ), clearance ) );
|
r->Report( wxString::Format( _( "Clearance: %s." ), clearance ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,9 +30,7 @@
|
||||||
#include <widgets/progress_reporter.h>
|
#include <widgets/progress_reporter.h>
|
||||||
#include <wx/event.h>
|
#include <wx/event.h>
|
||||||
#include <tool/tool_manager.h>
|
#include <tool/tool_manager.h>
|
||||||
#include <bitmaps.h>
|
|
||||||
#include "pcb_actions.h"
|
#include "pcb_actions.h"
|
||||||
#include "selection_tool.h"
|
|
||||||
#include "zone_filler_tool.h"
|
#include "zone_filler_tool.h"
|
||||||
#include "zone_filler.h"
|
#include "zone_filler.h"
|
||||||
|
|
||||||
|
@ -53,7 +51,7 @@ void ZONE_FILLER_TOOL::Reset( RESET_REASON aReason )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ZONE_FILLER_TOOL::CheckAllZones( wxWindow* aCaller )
|
void ZONE_FILLER_TOOL::CheckAllZones( wxWindow* aCaller, WX_PROGRESS_REPORTER* aReporter )
|
||||||
{
|
{
|
||||||
if( !getEditFrame<PCB_EDIT_FRAME>()->m_ZoneFillsDirty )
|
if( !getEditFrame<PCB_EDIT_FRAME>()->m_ZoneFillsDirty )
|
||||||
return;
|
return;
|
||||||
|
@ -66,7 +64,11 @@ void ZONE_FILLER_TOOL::CheckAllZones( wxWindow* aCaller )
|
||||||
BOARD_COMMIT commit( this );
|
BOARD_COMMIT commit( this );
|
||||||
|
|
||||||
ZONE_FILLER filler( frame()->GetBoard(), &commit );
|
ZONE_FILLER filler( frame()->GetBoard(), &commit );
|
||||||
filler.InstallNewProgressReporter( aCaller, _( "Checking Zones" ), 4 );
|
|
||||||
|
if( aReporter )
|
||||||
|
filler.SetProgressReporter( aReporter );
|
||||||
|
else
|
||||||
|
filler.InstallNewProgressReporter( aCaller, _( "Checking Zones" ), 4 );
|
||||||
|
|
||||||
if( filler.Fill( toFill, true ) )
|
if( filler.Fill( toFill, true ) )
|
||||||
{
|
{
|
||||||
|
@ -89,7 +91,7 @@ void ZONE_FILLER_TOOL::singleShotRefocus( wxIdleEvent& )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ZONE_FILLER_TOOL::FillAllZones( wxWindow* aCaller )
|
void ZONE_FILLER_TOOL::FillAllZones( wxWindow* aCaller, WX_PROGRESS_REPORTER* aReporter )
|
||||||
{
|
{
|
||||||
std::vector<ZONE_CONTAINER*> toFill;
|
std::vector<ZONE_CONTAINER*> toFill;
|
||||||
|
|
||||||
|
@ -99,7 +101,11 @@ void ZONE_FILLER_TOOL::FillAllZones( wxWindow* aCaller )
|
||||||
toFill.push_back(zone);
|
toFill.push_back(zone);
|
||||||
|
|
||||||
ZONE_FILLER filler( board(), &commit );
|
ZONE_FILLER filler( board(), &commit );
|
||||||
filler.InstallNewProgressReporter( aCaller, _( "Fill All Zones" ), 4 );
|
|
||||||
|
if( aReporter )
|
||||||
|
filler.SetProgressReporter( aReporter );
|
||||||
|
else
|
||||||
|
filler.InstallNewProgressReporter( aCaller, _( "Fill All Zones" ), 4 );
|
||||||
|
|
||||||
if( filler.Fill( toFill ) )
|
if( filler.Fill( toFill ) )
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
|
|
||||||
|
|
||||||
class PCB_EDIT_FRAME;
|
class PCB_EDIT_FRAME;
|
||||||
|
class WX_PROGRESS_REPORTER;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ZONE_FILLER_TOOL
|
* ZONE_FILLER_TOOL
|
||||||
|
@ -44,8 +46,8 @@ public:
|
||||||
/// @copydoc TOOL_INTERACTIVE::Reset()
|
/// @copydoc TOOL_INTERACTIVE::Reset()
|
||||||
void Reset( RESET_REASON aReason ) override;
|
void Reset( RESET_REASON aReason ) override;
|
||||||
|
|
||||||
void CheckAllZones( wxWindow* aCaller );
|
void CheckAllZones( wxWindow* aCaller, WX_PROGRESS_REPORTER* aReporter = nullptr );
|
||||||
void FillAllZones( wxWindow* aCaller );
|
void FillAllZones( wxWindow* aCaller, WX_PROGRESS_REPORTER* aReporter = nullptr );
|
||||||
|
|
||||||
int ZoneFill( const TOOL_EVENT& aEvent );
|
int ZoneFill( const TOOL_EVENT& aEvent );
|
||||||
int ZoneFillAll( const TOOL_EVENT& aEvent );
|
int ZoneFillAll( const TOOL_EVENT& aEvent );
|
||||||
|
|
|
@ -96,7 +96,13 @@ void ZONE_FILLER::InstallNewProgressReporter( wxWindow* aParent, const wxString&
|
||||||
int aNumPhases )
|
int aNumPhases )
|
||||||
{
|
{
|
||||||
m_uniqueReporter = std::make_unique<WX_PROGRESS_REPORTER>( aParent, aTitle, aNumPhases );
|
m_uniqueReporter = std::make_unique<WX_PROGRESS_REPORTER>( aParent, aTitle, aNumPhases );
|
||||||
m_progressReporter = m_uniqueReporter.get();
|
SetProgressReporter( m_uniqueReporter.get() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ZONE_FILLER::SetProgressReporter( WX_PROGRESS_REPORTER* aReporter )
|
||||||
|
{
|
||||||
|
m_progressReporter = aReporter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -118,6 +124,7 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
|
||||||
m_progressReporter->Report( aCheck ? _( "Checking zone fills..." )
|
m_progressReporter->Report( aCheck ? _( "Checking zone fills..." )
|
||||||
: _( "Building zone fills..." ) );
|
: _( "Building zone fills..." ) );
|
||||||
m_progressReporter->SetMaxProgress( aZones.size() );
|
m_progressReporter->SetMaxProgress( aZones.size() );
|
||||||
|
m_progressReporter->KeepRefreshing();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The board outlines is used to clip solid areas inside the board (when outlines are valid)
|
// The board outlines is used to clip solid areas inside the board (when outlines are valid)
|
||||||
|
@ -125,9 +132,9 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
|
||||||
m_brdOutlinesValid = m_board->GetBoardPolygonOutlines( m_boardOutline );
|
m_brdOutlinesValid = m_board->GetBoardPolygonOutlines( m_boardOutline );
|
||||||
|
|
||||||
// Update the bounding box shape caches in the pads to prevent multi-threaded rebuilds
|
// Update the bounding box shape caches in the pads to prevent multi-threaded rebuilds
|
||||||
for( auto module : m_board->Modules() )
|
for( MODULE* module : m_board->Modules() )
|
||||||
{
|
{
|
||||||
for( auto pad : module->Pads() )
|
for( D_PAD* pad : module->Pads() )
|
||||||
{
|
{
|
||||||
if( pad->IsDirty() )
|
if( pad->IsDirty() )
|
||||||
pad->BuildEffectiveShapes( UNDEFINED_LAYER );
|
pad->BuildEffectiveShapes( UNDEFINED_LAYER );
|
||||||
|
@ -263,8 +270,6 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now remove insulated copper islands and islands outside the board edge
|
// Now remove insulated copper islands and islands outside the board edge
|
||||||
bool outOfDate = false;
|
|
||||||
|
|
||||||
for( auto& zone : islandsList )
|
for( auto& zone : islandsList )
|
||||||
{
|
{
|
||||||
for( PCB_LAYER_ID layer : zone.m_zone->GetLayerSet().Seq() )
|
for( PCB_LAYER_ID layer : zone.m_zone->GetLayerSet().Seq() )
|
||||||
|
@ -322,25 +327,45 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
|
||||||
zone.m_zone->SetFilledPolysList( layer, poly );
|
zone.m_zone->SetFilledPolysList( layer, poly );
|
||||||
zone.m_zone->CalculateFilledArea();
|
zone.m_zone->CalculateFilledArea();
|
||||||
|
|
||||||
if( aCheck && zone.m_zone->GetHashValue( layer ) != poly.GetHash() )
|
|
||||||
outOfDate = true;
|
|
||||||
|
|
||||||
if( m_progressReporter && m_progressReporter->IsCancelled() )
|
if( m_progressReporter && m_progressReporter->IsCancelled() )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( aCheck && outOfDate )
|
if( aCheck )
|
||||||
{
|
{
|
||||||
PROGRESS_REPORTER_HIDER raii( m_progressReporter );
|
bool outOfDate = false;
|
||||||
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 )
|
for( ZONE_CONTAINER* zone : aZones )
|
||||||
return false;
|
{
|
||||||
|
// 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 )
|
if( m_progressReporter )
|
||||||
|
@ -406,7 +431,6 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_progressReporter->AdvancePhase();
|
m_progressReporter->AdvancePhase();
|
||||||
m_progressReporter->Report( _( "Committing changes..." ) );
|
|
||||||
m_progressReporter->KeepRefreshing();
|
m_progressReporter->KeepRefreshing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ public:
|
||||||
ZONE_FILLER( BOARD* aBoard, COMMIT* aCommit );
|
ZONE_FILLER( BOARD* aBoard, COMMIT* aCommit );
|
||||||
~ZONE_FILLER();
|
~ZONE_FILLER();
|
||||||
|
|
||||||
|
void SetProgressReporter( WX_PROGRESS_REPORTER* aReporter );
|
||||||
void InstallNewProgressReporter( wxWindow* aParent, const wxString& aTitle, int aNumPhases );
|
void InstallNewProgressReporter( wxWindow* aParent, const wxString& aTitle, int aNumPhases );
|
||||||
bool Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck = false );
|
bool Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck = false );
|
||||||
|
|
||||||
|
@ -107,15 +108,15 @@ private:
|
||||||
void addHatchFillTypeOnZone( const ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer,
|
void addHatchFillTypeOnZone( const ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer,
|
||||||
SHAPE_POLY_SET& aRawPolys );
|
SHAPE_POLY_SET& aRawPolys );
|
||||||
|
|
||||||
BOARD* m_board;
|
BOARD* m_board;
|
||||||
SHAPE_POLY_SET m_boardOutline; // The board outlines, if exists
|
SHAPE_POLY_SET m_boardOutline; // the board outlines, if exists
|
||||||
bool m_brdOutlinesValid; // true if m_boardOutline can be calculated
|
bool m_brdOutlinesValid; // true if m_boardOutline is well-formed
|
||||||
// false if not (not closed outlines for instance)
|
COMMIT* m_commit;
|
||||||
COMMIT* m_commit;
|
|
||||||
WX_PROGRESS_REPORTER* m_progressReporter;
|
WX_PROGRESS_REPORTER* m_progressReporter;
|
||||||
|
|
||||||
std::unique_ptr<WX_PROGRESS_REPORTER> m_uniqueReporter;
|
std::unique_ptr<WX_PROGRESS_REPORTER> m_uniqueReporter;
|
||||||
|
|
||||||
int m_maxError;
|
int m_maxError;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -236,6 +236,12 @@ int main( int argc, char *argv[] )
|
||||||
drcEngine.SetLogReporter( new CONSOLE_MSG_REPORTER ( &consoleLog ) );
|
drcEngine.SetLogReporter( new CONSOLE_MSG_REPORTER ( &consoleLog ) );
|
||||||
drcEngine.SetProgressReporter( new CONSOLE_PROGRESS_REPORTER ( &consoleLog ) );
|
drcEngine.SetProgressReporter( new CONSOLE_PROGRESS_REPORTER ( &consoleLog ) );
|
||||||
|
|
||||||
|
drcEngine.SetViolationHandler(
|
||||||
|
[&]( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos )
|
||||||
|
{
|
||||||
|
// fixme
|
||||||
|
} );
|
||||||
|
|
||||||
wxString rulesFilepath;
|
wxString rulesFilepath;
|
||||||
|
|
||||||
if( argc > 2 )
|
if( argc > 2 )
|
||||||
|
@ -245,10 +251,7 @@ int main( int argc, char *argv[] )
|
||||||
|
|
||||||
drcEngine.InitEngine( rulesFilepath );
|
drcEngine.InitEngine( rulesFilepath );
|
||||||
|
|
||||||
drcEngine.RunTests(
|
drcEngine.RunTests();
|
||||||
[&]( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos )
|
|
||||||
{
|
|
||||||
} );
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
|
|
||||||
namespace test {
|
namespace test {
|
||||||
|
|
||||||
class DRC_TEST_PROVIDER_SILK_TO_PAD : public DRC_TEST_PROVIDER
|
class DRC_TEST_PROVIDER_SILK_TO_PAD : public ::DRC_TEST_PROVIDER
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DRC_TEST_PROVIDER_SILK_TO_PAD ()
|
DRC_TEST_PROVIDER_SILK_TO_PAD ()
|
||||||
|
@ -94,8 +94,8 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_PAD::Run()
|
||||||
m_largestClearance = worstClearanceConstraint.m_Value.Min();
|
m_largestClearance = worstClearanceConstraint.m_Value.Min();
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportAux( "Worst clearance : %d nm", m_largestClearance );
|
reportAux( "Worst clearance : %d nm", m_largestClearance );
|
||||||
ReportStage( ("Testing pads vs silkscreen clearance"), 0, 2 );
|
reportStage(( "Pad to silkscreen clearances..." ));
|
||||||
|
|
||||||
std::vector<DRAWSEGMENT*> boardOutline;
|
std::vector<DRAWSEGMENT*> boardOutline;
|
||||||
std::vector<BOARD_ITEM*> boardItems;
|
std::vector<BOARD_ITEM*> boardItems;
|
||||||
|
@ -116,7 +116,7 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_PAD::Run()
|
||||||
forEachGeometryItem( {}, LSET::AllTechMask() | LSET::AllCuMask(), queryBoardGeometryItems );
|
forEachGeometryItem( {}, LSET::AllTechMask() | LSET::AllCuMask(), queryBoardGeometryItems );
|
||||||
|
|
||||||
|
|
||||||
drc_dbg(2,"outline: %d items, board: %d items\n", boardOutline.size(), boardItems.size() );
|
drc_dbg( 2, "outline: %d items, board: %d items\n", boardOutline.size(), boardItems.size() );
|
||||||
|
|
||||||
for( auto outlineItem : boardOutline )
|
for( auto outlineItem : boardOutline )
|
||||||
{
|
{
|
||||||
|
@ -129,13 +129,14 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_PAD::Run()
|
||||||
|
|
||||||
auto shape = boardItem->GetEffectiveShape();
|
auto shape = boardItem->GetEffectiveShape();
|
||||||
|
|
||||||
test::DRC_RULE* rule = m_drcEngine->EvalRulesForItems( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE, outlineItem, boardItem );
|
auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE,
|
||||||
int minClearance = rule->GetConstraint().GetValue().Min();
|
outlineItem, boardItem );
|
||||||
int actual;
|
int minClearance = constraint.GetValue().Min();
|
||||||
|
int actual;
|
||||||
|
|
||||||
if( refShape->Collide( shape.get(), minClearance, &actual ) )
|
if( refShape->Collide( shape.get(), minClearance, &actual ) )
|
||||||
{
|
{
|
||||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_COPPER_EDGE_CLEARANCE );
|
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_COPPER_EDGE_CLEARANCE );
|
||||||
wxString msg;
|
wxString msg;
|
||||||
|
|
||||||
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
||||||
|
@ -147,7 +148,7 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_PAD::Run()
|
||||||
drcItem->SetItems( outlineItem, boardItem );
|
drcItem->SetItems( outlineItem, boardItem );
|
||||||
drcItem->SetViolatingRule( rule );
|
drcItem->SetViolatingRule( rule );
|
||||||
|
|
||||||
ReportViolation( drcItem, refShape->Centre() );
|
reportViolation( drcItem, refShape->Centre());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,13 +157,13 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_PAD::Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::set<DRC_CONSTRAINT_TYPE_T> test::DRC_TEST_PROVIDER_EDGE_CLEARANCE::GetMatchingConstraintIds() const
|
std::set<DRC_CONSTRAINT_TYPE_T> test::DRC_TEST_PROVIDER_SILK_TO_PAD::GetConstraintTypes() const
|
||||||
{
|
{
|
||||||
return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE };
|
return { DRC_CONSTRAINT_TYPE_CLEARANCE };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
static DRC_REGISTER_TEST_PROVIDER<test::DRC_TEST_PROVIDER_EDGE_CLEARANCE> dummy;
|
static DRC_REGISTER_TEST_PROVIDER<test::DRC_TEST_PROVIDER_SILK_TO_PAD> dummy;
|
||||||
}
|
}
|
|
@ -25,11 +25,11 @@
|
||||||
|
|
||||||
#include <pcbnew_utils/board_construction_utils.h>
|
#include <pcbnew_utils/board_construction_utils.h>
|
||||||
#include <pcbnew_utils/board_file_utils.h>
|
#include <pcbnew_utils/board_file_utils.h>
|
||||||
|
#include <class_board.h>
|
||||||
#include <class_module.h>
|
#include <class_module.h>
|
||||||
#include <drc/drc.h>
|
#include <class_marker_pcb.h>
|
||||||
|
#include <drc/drc_engine.h>
|
||||||
#include <drc/drc_item.h>
|
#include <drc/drc_item.h>
|
||||||
#include <drc/drc_courtyard_tester.h>
|
|
||||||
#include <widgets/ui_common.h>
|
#include <widgets/ui_common.h>
|
||||||
|
|
||||||
#include "../board_test_utils.h"
|
#include "../board_test_utils.h"
|
||||||
|
@ -294,13 +294,21 @@ void DoCourtyardInvalidTest( const COURTYARD_INVALID_CASE& aCase,
|
||||||
// list of markers to collect
|
// list of markers to collect
|
||||||
std::vector<std::unique_ptr<MARKER_PCB>> markers;
|
std::vector<std::unique_ptr<MARKER_PCB>> markers;
|
||||||
|
|
||||||
DRC_COURTYARD_TESTER drc_overlap(
|
DRC_ENGINE drcEngine( board.get(), &board->GetDesignSettings() );
|
||||||
[&]( MARKER_PCB* aMarker )
|
|
||||||
|
drcEngine.InitEngine( wxFileName() );
|
||||||
|
|
||||||
|
drcEngine.SetViolationHandler(
|
||||||
|
[&]( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos )
|
||||||
{
|
{
|
||||||
markers.push_back( std::unique_ptr<MARKER_PCB>( aMarker ) );
|
if( aItem->GetErrorCode() == DRCE_OVERLAPPING_FOOTPRINTS
|
||||||
|
|| aItem->GetErrorCode() == DRCE_MISSING_COURTYARD )
|
||||||
|
{
|
||||||
|
markers.push_back( std::make_unique<MARKER_PCB>( aItem, aPos ) );
|
||||||
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
drc_overlap.RunDRC( EDA_UNITS::MILLIMETRES, *board );
|
drcEngine.RunTests();
|
||||||
|
|
||||||
CheckInvalidsMatchExpected( *board, markers, aCase.m_exp_errors );
|
CheckInvalidsMatchExpected( *board, markers, aCase.m_exp_errors );
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,11 +25,11 @@
|
||||||
|
|
||||||
#include <pcbnew_utils/board_construction_utils.h>
|
#include <pcbnew_utils/board_construction_utils.h>
|
||||||
#include <pcbnew_utils/board_file_utils.h>
|
#include <pcbnew_utils/board_file_utils.h>
|
||||||
|
#include <class_board.h>
|
||||||
#include <class_module.h>
|
#include <class_module.h>
|
||||||
#include <drc/drc.h>
|
#include <class_marker_pcb.h>
|
||||||
#include <drc/drc_item.h>
|
#include <drc/drc_item.h>
|
||||||
#include <drc/drc_courtyard_tester.h>
|
#include <drc/drc_engine.h>
|
||||||
#include <widgets/ui_common.h>
|
#include <widgets/ui_common.h>
|
||||||
|
|
||||||
#include "../board_test_utils.h"
|
#include "../board_test_utils.h"
|
||||||
|
@ -463,13 +463,21 @@ static void DoCourtyardOverlapTest( const COURTYARD_OVERLAP_TEST_CASE& aCase,
|
||||||
// list of markers to collect
|
// list of markers to collect
|
||||||
std::vector<std::unique_ptr<MARKER_PCB>> markers;
|
std::vector<std::unique_ptr<MARKER_PCB>> markers;
|
||||||
|
|
||||||
DRC_COURTYARD_TESTER drc_overlap(
|
DRC_ENGINE drcEngine( board.get(), &board->GetDesignSettings() );
|
||||||
[&]( MARKER_PCB* aMarker )
|
|
||||||
|
drcEngine.InitEngine( wxFileName() );
|
||||||
|
|
||||||
|
drcEngine.SetViolationHandler(
|
||||||
|
[&]( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos )
|
||||||
{
|
{
|
||||||
markers.push_back( std::unique_ptr<MARKER_PCB>( aMarker ) );
|
if( aItem->GetErrorCode() == DRCE_OVERLAPPING_FOOTPRINTS
|
||||||
|
|| aItem->GetErrorCode() == DRCE_MISSING_COURTYARD )
|
||||||
|
{
|
||||||
|
markers.push_back( std::make_unique<MARKER_PCB>( aItem, aPos ) );
|
||||||
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
drc_overlap.RunDRC( EDA_UNITS::MILLIMETRES, *board );
|
drcEngine.RunTests();
|
||||||
|
|
||||||
CheckCollisionsMatchExpected( *board, markers, aCase.m_collisions );
|
CheckCollisionsMatchExpected( *board, markers, aCase.m_collisions );
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,6 @@ add_executable( qa_pcbnew_tools
|
||||||
# The main entry point
|
# The main entry point
|
||||||
pcbnew_tools.cpp
|
pcbnew_tools.cpp
|
||||||
|
|
||||||
tools/drc_tool/drc_tool.cpp
|
|
||||||
|
|
||||||
tools/pcb_parser/pcb_parser_tool.cpp
|
tools/pcb_parser/pcb_parser_tool.cpp
|
||||||
|
|
||||||
tools/polygon_generator/polygon_generator.cpp
|
tools/polygon_generator/polygon_generator.cpp
|
||||||
|
|
|
@ -1,332 +0,0 @@
|
||||||
/*
|
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018-2020 KiCad Developers, see CHANGELOG.TXT for contributors.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, you may find one here:
|
|
||||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
||||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
||||||
* or you may write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <common.h>
|
|
||||||
#include <profile.h>
|
|
||||||
|
|
||||||
#include <wx/cmdline.h>
|
|
||||||
|
|
||||||
#include <pcbnew_utils/board_file_utils.h>
|
|
||||||
#include <widgets/ui_common.h>
|
|
||||||
#include <pcbnew/drc/drc.h>
|
|
||||||
#include <drc/drc_courtyard_tester.h>
|
|
||||||
|
|
||||||
#include <qa_utils/utility_registry.h>
|
|
||||||
|
|
||||||
using DRC_DURATION = std::chrono::microseconds;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DRC runner: provides a simple framework to run some DRC checks on #BOARDS.
|
|
||||||
* The DRC_RUNNER can be set up as needed to instantiate a #DRC_TEST_PROVIDER to
|
|
||||||
* perform the desired DRC on the #BOARD and provide some basic information
|
|
||||||
* about what happened.
|
|
||||||
*/
|
|
||||||
class DRC_RUNNER
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* How the DRC runner behaves (e.g. what is printed and how)
|
|
||||||
*/
|
|
||||||
struct EXECUTION_CONTEXT
|
|
||||||
{
|
|
||||||
bool m_verbose;
|
|
||||||
bool m_print_times;
|
|
||||||
bool m_print_markers;
|
|
||||||
};
|
|
||||||
|
|
||||||
DRC_RUNNER( const EXECUTION_CONTEXT& aExecCtx ) : m_exec_context( aExecCtx )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~DRC_RUNNER()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Execute( BOARD& aBoard )
|
|
||||||
{
|
|
||||||
if( m_exec_context.m_verbose )
|
|
||||||
std::cout << "Running DRC check: " << getRunnerIntro() << std::endl;
|
|
||||||
|
|
||||||
setDesignSettings( aBoard.GetDesignSettings() );
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<MARKER_PCB>> markers;
|
|
||||||
|
|
||||||
auto marker_handler = [&]( MARKER_PCB* aMarker )
|
|
||||||
{
|
|
||||||
markers.push_back( std::unique_ptr<MARKER_PCB>( aMarker ) );
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unique_ptr<LEGACY_DRC_TEST_PROVIDER> drc_prov = createDrcProvider( aBoard, marker_handler );
|
|
||||||
|
|
||||||
DRC_DURATION duration;
|
|
||||||
{
|
|
||||||
SCOPED_PROF_COUNTER<DRC_DURATION> timer( duration );
|
|
||||||
drc_prov->RunDRC( EDA_UNITS::MILLIMETRES, aBoard );
|
|
||||||
}
|
|
||||||
|
|
||||||
// report results
|
|
||||||
if( m_exec_context.m_print_times )
|
|
||||||
reportDuration( duration );
|
|
||||||
|
|
||||||
if( m_exec_context.m_print_markers )
|
|
||||||
reportMarkers( aBoard, markers );
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* Get the introduction text for this DRC runner
|
|
||||||
*/
|
|
||||||
virtual std::string getRunnerIntro() const = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set suitable design settings for this DRC runner
|
|
||||||
* @param aSettings is a reference to the design settings object of the board under test
|
|
||||||
*/
|
|
||||||
virtual void setDesignSettings( BOARD_DESIGN_SETTINGS& aSettings ) const = 0;
|
|
||||||
|
|
||||||
virtual std::unique_ptr<LEGACY_DRC_TEST_PROVIDER> createDrcProvider(
|
|
||||||
BOARD& aBoard, LEGACY_DRC_TEST_PROVIDER::MARKER_HANDLER aHandler ) = 0;
|
|
||||||
|
|
||||||
void reportDuration( const DRC_DURATION& aDuration ) const
|
|
||||||
{
|
|
||||||
std::cout << "Took: " << aDuration.count() << "us" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reportMarkers( BOARD& aBoard,
|
|
||||||
const std::vector<std::unique_ptr<MARKER_PCB>>& aMarkers ) const
|
|
||||||
{
|
|
||||||
std::map<KIID, EDA_ITEM*> itemMap;
|
|
||||||
aBoard.FillItemMap( itemMap );
|
|
||||||
|
|
||||||
std::cout << "DRC markers: " << aMarkers.size() << std::endl;
|
|
||||||
|
|
||||||
int index = 0;
|
|
||||||
|
|
||||||
for( const auto& m : aMarkers )
|
|
||||||
{
|
|
||||||
std::cout << index++ << ": " ;
|
|
||||||
std::cout << m->GetRCItem()->ShowReport( EDA_UNITS::MILLIMETRES, itemMap );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( index )
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
const EXECUTION_CONTEXT m_exec_context;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DRC runner to run only DRC courtyard-overlap checks
|
|
||||||
*/
|
|
||||||
class DRC_COURTYARD_OVERLAP_RUNNER : public DRC_RUNNER
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DRC_COURTYARD_OVERLAP_RUNNER( const EXECUTION_CONTEXT& aCtx ) : DRC_RUNNER( aCtx )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~DRC_COURTYARD_OVERLAP_RUNNER()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string getRunnerIntro() const override
|
|
||||||
{
|
|
||||||
return "Courtyard overlap";
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDesignSettings( BOARD_DESIGN_SETTINGS& aSettings ) const override
|
|
||||||
{
|
|
||||||
aSettings.m_DRCSeverities[ DRCE_MISSING_COURTYARD ] = RPT_SEVERITY_IGNORE;
|
|
||||||
aSettings.m_DRCSeverities[ DRCE_OVERLAPPING_FOOTPRINTS ] = RPT_SEVERITY_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<LEGACY_DRC_TEST_PROVIDER> createDrcProvider(
|
|
||||||
BOARD& aBoard, LEGACY_DRC_TEST_PROVIDER::MARKER_HANDLER aHandler ) override
|
|
||||||
{
|
|
||||||
return std::make_unique<DRC_COURTYARD_TESTER>( aHandler );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DRC runner to run only DRC courtyard-missing checks
|
|
||||||
*/
|
|
||||||
class DRC_COURTYARD_MISSING_RUNNER : public DRC_RUNNER
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DRC_COURTYARD_MISSING_RUNNER( const EXECUTION_CONTEXT& aCtx ) : DRC_RUNNER( aCtx )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~DRC_COURTYARD_MISSING_RUNNER()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string getRunnerIntro() const override
|
|
||||||
{
|
|
||||||
return "Courtyard missing";
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDesignSettings( BOARD_DESIGN_SETTINGS& aSettings ) const override
|
|
||||||
{
|
|
||||||
aSettings.m_DRCSeverities[ DRCE_MISSING_COURTYARD ] = RPT_SEVERITY_ERROR;
|
|
||||||
aSettings.m_DRCSeverities[ DRCE_OVERLAPPING_FOOTPRINTS ] = RPT_SEVERITY_IGNORE;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<LEGACY_DRC_TEST_PROVIDER> createDrcProvider(
|
|
||||||
BOARD& aBoard, LEGACY_DRC_TEST_PROVIDER::MARKER_HANDLER aHandler ) override
|
|
||||||
{
|
|
||||||
return std::make_unique<DRC_COURTYARD_TESTER>( aHandler );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static const wxCmdLineEntryDesc g_cmdLineDesc[] = {
|
|
||||||
{
|
|
||||||
wxCMD_LINE_SWITCH,
|
|
||||||
"h",
|
|
||||||
"help",
|
|
||||||
_( "displays help on the command line parameters" ).mb_str(),
|
|
||||||
wxCMD_LINE_VAL_NONE,
|
|
||||||
wxCMD_LINE_OPTION_HELP,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
wxCMD_LINE_SWITCH,
|
|
||||||
"v",
|
|
||||||
"verbose",
|
|
||||||
_( "print parsing information" ).mb_str(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
wxCMD_LINE_SWITCH,
|
|
||||||
"t",
|
|
||||||
"timings",
|
|
||||||
_( "print DRC timings" ).mb_str(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
wxCMD_LINE_SWITCH,
|
|
||||||
"m",
|
|
||||||
"print-markers",
|
|
||||||
_( "print DRC marker information" ).mb_str(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
wxCMD_LINE_SWITCH,
|
|
||||||
"A",
|
|
||||||
"all-checks",
|
|
||||||
_( "perform all available DRC checks" ).mb_str(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
wxCMD_LINE_SWITCH,
|
|
||||||
"C",
|
|
||||||
"courtyard-overlap",
|
|
||||||
_( "perform courtyard-overlap (and malformation) checking" ).mb_str(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
wxCMD_LINE_SWITCH,
|
|
||||||
"c",
|
|
||||||
"courtyard-missing",
|
|
||||||
_( "perform courtyard-missing checking" ).mb_str(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
wxCMD_LINE_PARAM,
|
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
_( "input file" ).mb_str(),
|
|
||||||
wxCMD_LINE_VAL_STRING,
|
|
||||||
wxCMD_LINE_PARAM_OPTIONAL,
|
|
||||||
},
|
|
||||||
{ wxCMD_LINE_NONE }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tool=specific return codes
|
|
||||||
*/
|
|
||||||
enum PARSER_RET_CODES
|
|
||||||
{
|
|
||||||
PARSE_FAILED = KI_TEST::RET_CODES::TOOL_SPECIFIC,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int drc_main_func( int argc, char** argv )
|
|
||||||
{
|
|
||||||
#ifdef __AFL_COMPILER
|
|
||||||
__AFL_INIT();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
wxMessageOutput::Set( new wxMessageOutputStderr );
|
|
||||||
wxCmdLineParser cl_parser( argc, argv );
|
|
||||||
cl_parser.SetDesc( g_cmdLineDesc );
|
|
||||||
cl_parser.AddUsageText(
|
|
||||||
_( "This program runs DRC tools on given PCB files. "
|
|
||||||
"This can be used for debugging, fuzz testing or development, etc." ) );
|
|
||||||
|
|
||||||
int cmd_parsed_ok = cl_parser.Parse();
|
|
||||||
if( cmd_parsed_ok != 0 )
|
|
||||||
{
|
|
||||||
// Help and invalid input both stop here
|
|
||||||
return ( cmd_parsed_ok == -1 ) ? KI_TEST::RET_CODES::OK : KI_TEST::RET_CODES::BAD_CMDLINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool verbose = cl_parser.Found( "verbose" );
|
|
||||||
|
|
||||||
std::string filename;
|
|
||||||
|
|
||||||
if( cl_parser.GetParamCount() )
|
|
||||||
filename = cl_parser.GetParam( 0 ).ToStdString();
|
|
||||||
|
|
||||||
std::unique_ptr<BOARD> board = KI_TEST::ReadBoardFromFileOrStream( filename );
|
|
||||||
|
|
||||||
if( !board )
|
|
||||||
return PARSER_RET_CODES::PARSE_FAILED;
|
|
||||||
|
|
||||||
DRC_RUNNER::EXECUTION_CONTEXT exec_context{
|
|
||||||
verbose,
|
|
||||||
cl_parser.Found( "timings" ),
|
|
||||||
cl_parser.Found( "print-markers" ),
|
|
||||||
};
|
|
||||||
|
|
||||||
const bool all = cl_parser.Found( "all-checks" );
|
|
||||||
|
|
||||||
// Run the DRC on the board
|
|
||||||
if( all || cl_parser.Found( "courtyard-overlap" ) )
|
|
||||||
{
|
|
||||||
DRC_COURTYARD_OVERLAP_RUNNER runner( exec_context );
|
|
||||||
runner.Execute( *board );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( all || cl_parser.Found( "courtyard-missing" ) )
|
|
||||||
{
|
|
||||||
DRC_COURTYARD_MISSING_RUNNER runner( exec_context );
|
|
||||||
runner.Execute( *board );
|
|
||||||
}
|
|
||||||
|
|
||||||
return KI_TEST::RET_CODES::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static bool registered = UTILITY_REGISTRY::Register(
|
|
||||||
{ "drc", "Run selected DRC function on a PCB", drc_main_func } );
|
|
Loading…
Reference in New Issue