From c78171d01fc8f28d5fe5789fed8ddef65723dcc5 Mon Sep 17 00:00:00 2001 From: Jon Evans Date: Mon, 19 Mar 2018 22:54:16 -0400 Subject: [PATCH] DRC: Add an optional mode to report all track errors Fixes: lp:1754442 * https://bugs.launchpad.net/kicad/+bug/1754442 --- pcbnew/dialogs/dialog_drc.cpp | 2 + pcbnew/dialogs/dialog_drc_base.cpp | 9 +- pcbnew/dialogs/dialog_drc_base.fbp | 89 ++++++++- pcbnew/dialogs/dialog_drc_base.h | 6 +- pcbnew/drc.cpp | 13 +- pcbnew/drc.h | 4 + pcbnew/drc_clearance_test_functions.cpp | 236 ++++++++++++++++-------- 7 files changed, 271 insertions(+), 88 deletions(-) diff --git a/pcbnew/dialogs/dialog_drc.cpp b/pcbnew/dialogs/dialog_drc.cpp index 06718f41da..370c149796 100644 --- a/pcbnew/dialogs/dialog_drc.cpp +++ b/pcbnew/dialogs/dialog_drc.cpp @@ -220,6 +220,7 @@ void DIALOG_DRC_CONTROL::OnStartdrcClick( wxCommandEvent& event ) m_cbRefillZones->GetValue(), m_cbCourtyardOverlap->GetValue(), m_cbCourtyardMissing->GetValue(), + m_cbReportAllTrackErrors->GetValue(), reportName, make_report ); DelDRCMarkers(); @@ -294,6 +295,7 @@ void DIALOG_DRC_CONTROL::OnListUnconnectedClick( wxCommandEvent& event ) m_cbRefillZones->GetValue(), m_cbCourtyardOverlap->GetValue(), m_cbCourtyardMissing->GetValue(), + m_cbReportAllTrackErrors->GetValue(), reportName, make_report ); DelDRCMarkers(); diff --git a/pcbnew/dialogs/dialog_drc_base.cpp b/pcbnew/dialogs/dialog_drc_base.cpp index 5a746642c1..9db5e08362 100644 --- a/pcbnew/dialogs/dialog_drc_base.cpp +++ b/pcbnew/dialogs/dialog_drc_base.cpp @@ -1,8 +1,8 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Feb 9 2018) +// C++ code generated with wxFormBuilder (version Nov 30 2016) // http://www.wxformbuilder.org/ // -// PLEASE DO *NOT* EDIT THIS FILE! +// PLEASE DO "NOT" EDIT THIS FILE! /////////////////////////////////////////////////////////////////////////// #include "dialog_drclistbox.h" @@ -108,6 +108,11 @@ DIALOG_DRC_CONTROL_BASE::DIALOG_DRC_CONTROL_BASE( wxWindow* parent, wxWindowID i m_cbRefillZones = new wxCheckBox( this, wxID_ANY, _("Refill all zones before performing DRC"), wxDefaultPosition, wxDefaultSize, 0 ); bSizerOptSettings->Add( m_cbRefillZones, 0, wxLEFT|wxRIGHT, 5 ); + m_cbReportAllTrackErrors = new wxCheckBox( this, wxID_ANY, _("Report all errors for tracks (slower)"), wxDefaultPosition, wxDefaultSize, 0 ); + m_cbReportAllTrackErrors->SetToolTip( _("If selected, all DRC violations for tracks will be reported. This can be slow for complicated designs.\n\nIf unselected, only the first DRC violation will be reported for each track connection.") ); + + bSizerOptSettings->Add( m_cbReportAllTrackErrors, 0, wxALL, 5 ); + m_cbCourtyardOverlap = new wxCheckBox( this, wxID_ANY, _("Check footprint courtyard overlap"), wxDefaultPosition, wxDefaultSize, 0 ); bSizerOptSettings->Add( m_cbCourtyardOverlap, 0, wxLEFT|wxRIGHT, 5 ); diff --git a/pcbnew/dialogs/dialog_drc_base.fbp b/pcbnew/dialogs/dialog_drc_base.fbp index abb6bc657c..6a0b603924 100644 --- a/pcbnew/dialogs/dialog_drc_base.fbp +++ b/pcbnew/dialogs/dialog_drc_base.fbp @@ -14,7 +14,6 @@ dialog_drc_base 1000 none - 1 dialog_drc_base @@ -1284,6 +1283,94 @@ + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Report all errors for tracks (slower) + + 0 + + + 0 + + 1 + m_cbReportAllTrackErrors + 1 + + + protected + 1 + + Resizable + 1 + + + ; forward_declare + 0 + If selected, all DRC violations for tracks will be reported. This can be slow for complicated designs. If unselected, only the first DRC violation will be reported for each track connection. + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 wxLEFT|wxRIGHT diff --git a/pcbnew/dialogs/dialog_drc_base.h b/pcbnew/dialogs/dialog_drc_base.h index 871d8551b5..f5b7ce2c26 100644 --- a/pcbnew/dialogs/dialog_drc_base.h +++ b/pcbnew/dialogs/dialog_drc_base.h @@ -1,8 +1,8 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Feb 9 2018) +// C++ code generated with wxFormBuilder (version Nov 30 2016) // http://www.wxformbuilder.org/ // -// PLEASE DO *NOT* EDIT THIS FILE! +// PLEASE DO "NOT" EDIT THIS FILE! /////////////////////////////////////////////////////////////////////////// #ifndef __DIALOG_DRC_BASE_H__ @@ -11,6 +11,7 @@ #include #include #include +class DIALOG_SHIM; class DRCLISTBOX; #include "dialog_shim.h" @@ -63,6 +64,7 @@ class DIALOG_DRC_CONTROL_BASE : public DIALOG_SHIM wxStaticText* m_MicroViaMinTitle; wxStaticText* m_MicroViaMinUnit; wxCheckBox* m_cbRefillZones; + wxCheckBox* m_cbReportAllTrackErrors; wxCheckBox* m_cbCourtyardOverlap; wxCheckBox* m_cbCourtyardMissing; wxStaticText* m_staticTextRpt; diff --git a/pcbnew/drc.cpp b/pcbnew/drc.cpp index f66e39ce70..c3d618ac06 100644 --- a/pcbnew/drc.cpp +++ b/pcbnew/drc.cpp @@ -135,6 +135,7 @@ DRC::DRC( PCB_EDIT_FRAME* aPcbWindow ) m_abortDRC = false; m_drcInProgress = false; m_refillZones = false; // Only fill zones if requested by user. + m_reportAllTrackErrors = false; m_doCreateRptFile = false; // m_rptFilename set to empty by its constructor @@ -165,9 +166,9 @@ int DRC::Drc( TRACK* aRefSegm, TRACK* aList ) if( !doTrackDrc( aRefSegm, aList, true ) ) { - wxASSERT( m_currentMarker ); + if( m_currentMarker ) + m_pcbEditorFrame->SetMsgPanel( m_currentMarker ); - m_pcbEditorFrame->SetMsgPanel( m_currentMarker ); return BAD_DRC; } @@ -711,9 +712,11 @@ void DRC::testTracks( wxWindow *aActiveWindow, bool aShowProgressBar ) if( !doTrackDrc( segm, segm->Next(), true ) ) { - wxASSERT( m_currentMarker ); - addMarkerToPcb ( m_currentMarker ); - m_currentMarker = nullptr; + if( m_currentMarker ) + { + addMarkerToPcb ( m_currentMarker ); + m_currentMarker = nullptr; + } } } diff --git a/pcbnew/drc.h b/pcbnew/drc.h index 663f2a8de6..0c46aa8730 100644 --- a/pcbnew/drc.h +++ b/pcbnew/drc.h @@ -174,6 +174,7 @@ private: bool m_doFootprintOverlapping; bool m_doNoCourtyardDefined; bool m_refillZones; + bool m_reportAllTrackErrors; wxString m_rptFilename; @@ -501,12 +502,14 @@ public: * @param aKeepoutTest Tells whether to test keepout areas. * @param aCourtyardTest Tells whether to test footprint courtyard overlap. * @param aCourtyardMissingTest Tells whether to test missing courtyard definition in footprint. + * @param aReportAllTrackErrors Tells whether or not to stop checking track connections after the first error. * @param aReportName A string telling the disk file report name entered. * @param aSaveReport A boolean telling whether to generate disk file report. */ void SetSettings( bool aPad2PadTest, bool aUnconnectedTest, bool aZonesTest, bool aKeepoutTest, bool aRefillZones, bool aCourtyardTest, bool aCourtyardMissingTest, + bool aReportAllTrackErrors, const wxString& aReportName, bool aSaveReport ) { m_doPad2PadTest = aPad2PadTest; @@ -518,6 +521,7 @@ public: m_doFootprintOverlapping = aCourtyardTest; m_doNoCourtyardDefined = aCourtyardMissingTest; m_refillZones = aRefillZones; + m_reportAllTrackErrors = aReportAllTrackErrors; } diff --git a/pcbnew/drc_clearance_test_functions.cpp b/pcbnew/drc_clearance_test_functions.cpp index 4643065cf8..3f5d531550 100644 --- a/pcbnew/drc_clearance_test_functions.cpp +++ b/pcbnew/drc_clearance_test_functions.cpp @@ -141,6 +141,7 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) LSET layerMask; int net_code_ref; wxPoint shape_pos; + bool success = true; NETCLASSPTR netclass = aRefSeg->GetNetClass(); BOARD_DESIGN_SETTINGS& dsnSettings = m_pcb->GetDesignSettings(); @@ -165,30 +166,44 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) { if( refvia->GetWidth() < dsnSettings.m_MicroViasMinSize ) { - m_currentMarker = fillMarker( refvia, NULL, - DRCE_TOO_SMALL_MICROVIA, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( refvia, NULL, + DRCE_TOO_SMALL_MICROVIA, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } + if( refvia->GetDrillValue() < dsnSettings.m_MicroViasMinDrill ) { - m_currentMarker = fillMarker( refvia, NULL, - DRCE_TOO_SMALL_MICROVIA_DRILL, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( refvia, NULL, + DRCE_TOO_SMALL_MICROVIA_DRILL, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } } else { if( refvia->GetWidth() < dsnSettings.m_ViasMinSize ) { - m_currentMarker = fillMarker( refvia, NULL, - DRCE_TOO_SMALL_VIA, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( refvia, NULL, + DRCE_TOO_SMALL_VIA, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } + if( refvia->GetDrillValue() < dsnSettings.m_ViasMinDrill ) { - m_currentMarker = fillMarker( refvia, NULL, - DRCE_TOO_SMALL_VIA_DRILL, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( refvia, NULL, + DRCE_TOO_SMALL_VIA_DRILL, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } } @@ -197,27 +212,36 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) // and a default via hole can be bigger than some vias sizes if( refvia->GetDrillValue() > refvia->GetWidth() ) { - m_currentMarker = fillMarker( refvia, NULL, - DRCE_VIA_HOLE_BIGGER, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( refvia, NULL, + DRCE_VIA_HOLE_BIGGER, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } // test if the type of via is allowed due to design rules if( ( refvia->GetViaType() == VIA_MICROVIA ) && ( m_pcb->GetDesignSettings().m_MicroViasAllowed == false ) ) { - m_currentMarker = fillMarker( refvia, NULL, - DRCE_MICRO_VIA_NOT_ALLOWED, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( refvia, NULL, + DRCE_MICRO_VIA_NOT_ALLOWED, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } // test if the type of via is allowed due to design rules if( ( refvia->GetViaType() == VIA_BLIND_BURIED ) && ( m_pcb->GetDesignSettings().m_BlindBuriedViaAllowed == false ) ) { - m_currentMarker = fillMarker( refvia, NULL, - DRCE_BURIED_VIA_NOT_ALLOWED, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( refvia, NULL, + DRCE_BURIED_VIA_NOT_ALLOWED, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } // For microvias: test if they are blind vias and only between 2 layers @@ -242,9 +266,12 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) if( err ) { - m_currentMarker = fillMarker( refvia, NULL, - DRCE_MICRO_VIA_INCORRECT_LAYER_PAIR, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( refvia, NULL, + DRCE_MICRO_VIA_INCORRECT_LAYER_PAIR, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } } @@ -253,9 +280,12 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) { if( aRefSeg->GetWidth() < dsnSettings.m_TrackMinWidth ) { - m_currentMarker = fillMarker( aRefSeg, NULL, - DRCE_TOO_SMALL_TRACK_WIDTH, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( aRefSeg, NULL, + DRCE_TOO_SMALL_TRACK_WIDTH, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } } @@ -325,9 +355,12 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) if( !checkClearanceSegmToPad( &dummypad, aRefSeg->GetWidth(), netclass->GetClearance() ) ) { - m_currentMarker = fillMarker( aRefSeg, pad, - DRCE_TRACK_NEAR_THROUGH_HOLE, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( aRefSeg, pad, + DRCE_TRACK_NEAR_THROUGH_HOLE, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } continue; @@ -343,11 +376,15 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) shape_pos = pad->ShapePos(); m_padToTestPos = shape_pos - origin; - if( !checkClearanceSegmToPad( pad, aRefSeg->GetWidth(), aRefSeg->GetClearance( pad ) ) ) + if( !checkClearanceSegmToPad( pad, aRefSeg->GetWidth(), + aRefSeg->GetClearance( pad ) ) ) { - m_currentMarker = fillMarker( aRefSeg, pad, - DRCE_TRACK_NEAR_PAD, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( aRefSeg, pad, + DRCE_TRACK_NEAR_PAD, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } } } @@ -361,6 +398,7 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) // Test the reference segment with other track segments wxPoint segStartPoint; wxPoint segEndPoint; + for( track = aStart; track; track = track->Next() ) { // No problem if segments have the same net code: @@ -394,9 +432,12 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) // Test distance between two vias, i.e. two circles, trivial case if( EuclideanNorm( segStartPoint ) < w_dist ) { - m_currentMarker = fillMarker( aRefSeg, track, - DRCE_VIA_NEAR_VIA, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( aRefSeg, track, + DRCE_VIA_NEAR_VIA, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } } else // test via to segment @@ -410,9 +451,12 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) if( !checkMarginToCircle( segStartPoint, w_dist, delta.x ) ) { - m_currentMarker = fillMarker( track, aRefSeg, - DRCE_VIA_NEAR_TRACK, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( track, aRefSeg, + DRCE_VIA_NEAR_TRACK, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } } @@ -432,9 +476,12 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) if( checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) ) continue; - m_currentMarker = fillMarker( aRefSeg, track, - DRCE_TRACK_NEAR_VIA, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( aRefSeg, track, + DRCE_TRACK_NEAR_VIA, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } /* We have changed axis: @@ -459,16 +506,22 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) // Fine test : we consider the rounded shape of each end of the track segment: if( segStartPoint.x >= 0 && segStartPoint.x <= m_segmLength ) { - m_currentMarker = fillMarker( aRefSeg, track, - DRCE_TRACK_ENDS1, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( aRefSeg, track, + DRCE_TRACK_ENDS1, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } if( !checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) ) { - m_currentMarker = fillMarker( aRefSeg, track, - DRCE_TRACK_ENDS2, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( aRefSeg, track, + DRCE_TRACK_ENDS2, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } } @@ -480,16 +533,22 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) // Fine test : we consider the rounded shape of the ends if( segEndPoint.x >= 0 && segEndPoint.x <= m_segmLength ) { - m_currentMarker = fillMarker( aRefSeg, track, - DRCE_TRACK_ENDS3, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( aRefSeg, track, + DRCE_TRACK_ENDS3, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } if( !checkMarginToCircle( segEndPoint, w_dist, m_segmLength ) ) { - m_currentMarker = fillMarker( aRefSeg, track, - DRCE_TRACK_ENDS4, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( aRefSeg, track, + DRCE_TRACK_ENDS4, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } } @@ -500,9 +559,12 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) // handled) // X.............X // O--REF--+ - m_currentMarker = fillMarker( aRefSeg, track, - DRCE_TRACK_SEGMENTS_TOO_CLOSE, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( aRefSeg, track, + DRCE_TRACK_SEGMENTS_TOO_CLOSE, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } } else if( segStartPoint.x == segEndPoint.x ) // perpendicular segments @@ -514,25 +576,34 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) if( segStartPoint.y > segEndPoint.y ) std::swap( segStartPoint.y, segEndPoint.y ); - if( (segStartPoint.y < 0) && (segEndPoint.y > 0) ) + if( ( segStartPoint.y < 0 ) && ( segEndPoint.y > 0 ) ) { - m_currentMarker = fillMarker( aRefSeg, track, - DRCE_TRACKS_CROSSING, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( aRefSeg, track, + DRCE_TRACKS_CROSSING, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } // At this point the drc error is due to an end near a reference segm end if( !checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) ) { - m_currentMarker = fillMarker( aRefSeg, track, - DRCE_ENDS_PROBLEM1, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( aRefSeg, track, + DRCE_ENDS_PROBLEM1, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } if( !checkMarginToCircle( segEndPoint, w_dist, m_segmLength ) ) { - m_currentMarker = fillMarker( aRefSeg, track, - DRCE_ENDS_PROBLEM2, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( aRefSeg, track, + DRCE_ENDS_PROBLEM2, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } } else // segments quelconques entre eux @@ -558,9 +629,12 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) if( !checkLine( segStartPoint, segEndPoint ) ) { - m_currentMarker = fillMarker( aRefSeg, track, - DRCE_ENDS_PROBLEM3, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( aRefSeg, track, + DRCE_ENDS_PROBLEM3, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } else // The drc error is due to the starting or the ending point of the reference segment { @@ -586,23 +660,29 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) if( !checkMarginToCircle( relStartPos, w_dist, delta.x ) ) { - m_currentMarker = fillMarker( aRefSeg, track, - DRCE_ENDS_PROBLEM4, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( aRefSeg, track, + DRCE_ENDS_PROBLEM4, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } if( !checkMarginToCircle( relEndPos, w_dist, delta.x ) ) { - m_currentMarker = fillMarker( aRefSeg, track, - DRCE_ENDS_PROBLEM5, m_currentMarker ); - return false; + addMarkerToPcb( fillMarker( aRefSeg, track, + DRCE_ENDS_PROBLEM5, nullptr ) ); + success = false; + + if( !m_reportAllTrackErrors ) + return false; } } } } } - return true; + return success; }