From 32db9eb0f1817e83ea1e6ad0d79c59a62b3eacee Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Fri, 24 Apr 2020 19:56:44 +0100 Subject: [PATCH] Add some distances to a few DRC errors. --- common/dialogs/panel_setup_severities.cpp | 3 +- common/rc_item.cpp | 25 ++- common/rc_item.h | 10 +- eeschema/dialogs/dialog_erc.cpp | 22 +- eeschema/erc_item.cpp | 5 +- eeschema/erc_item.h | 4 +- eeschema/sch_marker.cpp | 4 +- pcbnew/class_marker_pcb.cpp | 7 +- pcbnew/class_marker_pcb.h | 2 +- pcbnew/dialogs/dialog_drc.cpp | 22 +- pcbnew/drc/drc.cpp | 42 +++- pcbnew/drc/drc.h | 15 +- pcbnew/drc/drc_clearance_test_functions.cpp | 217 ++++++++++++++------ pcbnew/drc/drc_item.cpp | 9 +- pcbnew/drc/drc_item.h | 2 +- 15 files changed, 273 insertions(+), 116 deletions(-) diff --git a/common/dialogs/panel_setup_severities.cpp b/common/dialogs/panel_setup_severities.cpp index 2ef6607b73..9e4f1b2c0b 100644 --- a/common/dialogs/panel_setup_severities.cpp +++ b/common/dialogs/panel_setup_severities.cpp @@ -48,8 +48,7 @@ PANEL_SETUP_SEVERITIES::PANEL_SETUP_SEVERITIES( PAGED_DIALOG* aParent, RC_ITEM& for( int errorCode = m_firstErrorCode; errorCode <= m_lastErrorCode; ++errorCode ) { - aDummyItem.SetErrorCode( errorCode ); - wxString msg = aDummyItem.GetErrorText(); + wxString msg = aDummyItem.GetErrorText( errorCode ); // When msg is empty, for some reason, the current errorCode is not supported // by the RC_ITEM aDummyItem. diff --git a/common/rc_item.cpp b/common/rc_item.cpp index b2aaff078f..3c24c1d9f6 100644 --- a/common/rc_item.cpp +++ b/common/rc_item.cpp @@ -33,6 +33,15 @@ #define WX_DATAVIEW_WINDOW_PADDING 6 +wxString RC_ITEM::GetErrorMessage() const +{ + if( m_errorMessage.IsEmpty() ) + return GetErrorText( m_errorCode ); + else + return m_errorMessage; +} + + wxString RC_ITEM::ShowCoord( EDA_UNITS aUnits, const wxPoint& aPos ) { return wxString::Format( "@(%s, %s)", @@ -52,13 +61,11 @@ wxString RC_ITEM::ShowReport( EDA_UNITS aUnits, const std::map& if( m_auxItemUuid != niluuid ) auxItem = aItemMap.at( m_auxItemUuid ); - wxString msg = m_errorMessage.IsEmpty() ? GetErrorText() : m_errorMessage; - if( mainItem && auxItem ) { return wxString::Format( wxT( "ErrType(%d): %s\n %s: %s\n %s: %s\n" ), - m_errorCode, - msg, + GetErrorCode(), + GetErrorMessage(), ShowCoord( aUnits, mainItem->GetPosition() ), mainItem->GetSelectMenuText( aUnits ), ShowCoord( aUnits, auxItem->GetPosition() ), @@ -67,16 +74,16 @@ wxString RC_ITEM::ShowReport( EDA_UNITS aUnits, const std::map& else if( mainItem ) { return wxString::Format( wxT( "ErrType(%d): %s\n %s: %s\n" ), - m_errorCode, - msg, + GetErrorCode(), + GetErrorMessage(), ShowCoord( aUnits, mainItem->GetPosition() ), mainItem->GetSelectMenuText( aUnits ) ); } else { return wxString::Format( wxT( "ErrType(%d): %s\n" ), - m_errorCode, - msg ); + GetErrorCode(), + GetErrorMessage() ); } } @@ -254,7 +261,7 @@ void RC_TREE_MODEL::GetValue( wxVariant& aVariant, excluded ? _( "Excluded " ) : wxString( "" ), error ? _( "Error: " ) : _( "Warning: " ) ); - aVariant = prefix + rcItem->GetErrorText(); + aVariant = prefix + rcItem->GetErrorMessage(); } break; diff --git a/common/rc_item.h b/common/rc_item.h index 178861a401..8e962cb19a 100644 --- a/common/rc_item.h +++ b/common/rc_item.h @@ -140,9 +140,15 @@ public: /** * Function GetErrorText - * returns the string form of a drc error code. + * returns the string form of a RC error code */ - virtual wxString GetErrorText() const = 0; + virtual wxString GetErrorText( int aCode = -1 ) const = 0; + + /** + * Function GetErrorMessage + * returns the error message of a RC_ITEM + */ + virtual wxString GetErrorMessage() const; /** * Function ShowCoord diff --git a/eeschema/dialogs/dialog_erc.cpp b/eeschema/dialogs/dialog_erc.cpp index 062b5bc58d..005369ba3f 100644 --- a/eeschema/dialogs/dialog_erc.cpp +++ b/eeschema/dialogs/dialog_erc.cpp @@ -394,6 +394,7 @@ void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent ) RC_ITEM* rcItem = node->m_RcItem; wxString listName; wxMenu menu; + wxString msg; switch( GetSeverity( rcItem->GetErrorCode() ) ) { @@ -417,20 +418,23 @@ void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent ) if( GetSeverity( rcItem->GetErrorCode() ) == RPT_SEVERITY_WARNING ) { - menu.Append( 3, wxString::Format( _( "Change severity to Error for all '%s' violations" ), - rcItem->GetErrorText(), - _( "Violation severities can also be edited in the Board Setup... dialog" ) ) ); + msg.Printf( _( "Change severity to Error for all '%s' violations" ), + rcItem->GetErrorText( rcItem->GetErrorCode() ), + _( "Violation severities can also be edited in the Board Setup... dialog" ) ); + menu.Append( 3, msg ); } else { - menu.Append( 4, wxString::Format( _( "Change severity to Warning for all '%s' violations" ), - rcItem->GetErrorText(), - _( "Violation severities can also be edited in the Board Setup... dialog" ) ) ); + msg.Printf( _( "Change severity to Warning for all '%s' violations" ), + rcItem->GetErrorText( rcItem->GetErrorCode() ), + _( "Violation severities can also be edited in the Board Setup... dialog" ) ); + menu.Append( 4, msg ); } - menu.Append( 5, wxString::Format( _( "Ignore all '%s' violations" ), - rcItem->GetErrorText() ), - _( "Violations will not be checked or reported" ) ); + msg.Printf( _( "Ignore all '%s' violations" ), + rcItem->GetErrorText( rcItem->GetErrorCode() ), + _( "Violations will not be checked or reported" ) ); + menu.Append( 5, msg ); menu.AppendSeparator(); diff --git a/eeschema/erc_item.cpp b/eeschema/erc_item.cpp index bb2ecb53e1..e3e80d3007 100644 --- a/eeschema/erc_item.cpp +++ b/eeschema/erc_item.cpp @@ -30,8 +30,11 @@ #include -wxString ERC_ITEM::GetErrorText() const +wxString ERC_ITEM::GetErrorText( int aErrorCode ) const { + if( aErrorCode < 0 ) + aErrorCode = m_errorCode; + switch( m_errorCode ) { case ERCE_UNSPECIFIED: diff --git a/eeschema/erc_item.h b/eeschema/erc_item.h index fd6e26c4ca..8d6b904fd4 100644 --- a/eeschema/erc_item.h +++ b/eeschema/erc_item.h @@ -37,9 +37,9 @@ public: /** * Function GetErrorText - * returns the string form of a drc error code. + * returns the string form of an erc error code. */ - wxString GetErrorText() const override; + wxString GetErrorText( int aErrorCode = -1 ) const override; }; diff --git a/eeschema/sch_marker.cpp b/eeschema/sch_marker.cpp index cca5d8e362..490e69f2ef 100644 --- a/eeschema/sch_marker.cpp +++ b/eeschema/sch_marker.cpp @@ -117,7 +117,7 @@ void SCH_MARKER::Print( RENDER_SETTINGS* aSettings, const wxPoint& aOffset ) bool SCH_MARKER::Matches( wxFindReplaceData& aSearchData, void* aAuxData ) { - return SCH_ITEM::Matches( m_rcItem->GetErrorText(), aSearchData ); + return SCH_ITEM::Matches( m_rcItem->GetErrorMessage(), aSearchData ); } @@ -130,7 +130,7 @@ const EDA_RECT SCH_MARKER::GetBoundingBox() const void SCH_MARKER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, MSG_PANEL_ITEMS& aList ) { aList.push_back( MSG_PANEL_ITEM( _( "Electronics Rule Check Error" ), - m_rcItem->GetErrorText(), DARKRED ) ); + m_rcItem->GetErrorMessage(), DARKRED ) ); } diff --git a/pcbnew/class_marker_pcb.cpp b/pcbnew/class_marker_pcb.cpp index 520c373dd2..aa5cf1d592 100644 --- a/pcbnew/class_marker_pcb.cpp +++ b/pcbnew/class_marker_pcb.cpp @@ -100,7 +100,7 @@ bool MARKER_PCB::IsOnLayer( PCB_LAYER_ID aLayer ) const void MARKER_PCB::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector& aList ) { aList.emplace_back( _( "Type" ), _( "Marker" ), DARKCYAN ); - aList.emplace_back( _( "Violation" ), m_rcItem->GetErrorText(), RED ); + aList.emplace_back( _( "Violation" ), m_rcItem->GetErrorMessage(), RED ); wxString mainText; wxString auxText; @@ -140,7 +140,10 @@ void MARKER_PCB::Flip(const wxPoint& aCentre, bool aFlipLeftRight ) wxString MARKER_PCB::GetSelectMenuText( EDA_UNITS aUnits ) const { - return wxString::Format( _( "Marker (%s)" ), m_rcItem->GetErrorText() ); + // m_rcItem->GetErrorMessage() could be used instead, but is probably too long + // for menu duty. + return wxString::Format( _( "Marker (%s)" ), + m_rcItem->GetErrorText( m_rcItem->GetErrorCode() ) ); } diff --git a/pcbnew/class_marker_pcb.h b/pcbnew/class_marker_pcb.h index 92062a44fb..2e37e5f2c5 100644 --- a/pcbnew/class_marker_pcb.h +++ b/pcbnew/class_marker_pcb.h @@ -84,7 +84,7 @@ public: bool Matches( wxFindReplaceData& aSearchData, void* aAuxData ) override { - return BOARD_ITEM::Matches( m_rcItem->GetErrorText(), aSearchData ); + return BOARD_ITEM::Matches( m_rcItem->GetErrorMessage(), aSearchData ); } wxString GetSelectMenuText( EDA_UNITS aUnits ) const override; diff --git a/pcbnew/dialogs/dialog_drc.cpp b/pcbnew/dialogs/dialog_drc.cpp index 37cc0b6147..64ffbbf892 100644 --- a/pcbnew/dialogs/dialog_drc.cpp +++ b/pcbnew/dialogs/dialog_drc.cpp @@ -285,6 +285,7 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent ) RC_ITEM* rcItem = node->m_RcItem; wxString listName; wxMenu menu; + wxString msg; switch( m_BrdSettings.m_DRCSeverities[ rcItem->GetErrorCode() ] ) { @@ -308,20 +309,23 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent ) if( m_BrdSettings.m_DRCSeverities[ rcItem->GetErrorCode() ] == RPT_SEVERITY_WARNING ) { - menu.Append( 3, wxString::Format( _( "Change severity to Error for all '%s' violations" ), - rcItem->GetErrorText(), - _( "Violation severities can also be edited in the Board Setup... dialog" ) ) ); + msg.Printf( _( "Change severity to Error for all '%s' violations" ), + rcItem->GetErrorText( rcItem->GetErrorCode() ), + _( "Violation severities can also be edited in the Board Setup... dialog" ) ); + menu.Append( 3, msg ); } else { - menu.Append( 4, wxString::Format( _( "Change severity to Warning for all '%s' violations" ), - rcItem->GetErrorText(), - _( "Violation severities can also be edited in the Board Setup... dialog" ) ) ); + msg.Printf( _( "Change severity to Warning for all '%s' violations" ), + rcItem->GetErrorText( rcItem->GetErrorCode() ), + _( "Violation severities can also be edited in the Board Setup... dialog" ) ); + menu.Append( 4, msg ); } - menu.Append( 5, wxString::Format( _( "Ignore all '%s' violations" ), - rcItem->GetErrorText() ), - _( "Violations will not be checked or reported" ) ); + msg.Printf( _( "Ignore all '%s' violations" ), + rcItem->GetErrorText( rcItem->GetErrorCode() ), + _( "Violations will not be checked or reported" ) ); + menu.Append( 5, msg ); menu.AppendSeparator(); diff --git a/pcbnew/drc/drc.cpp b/pcbnew/drc/drc.cpp index de0775a2f3..cd7bd5127f 100644 --- a/pcbnew/drc/drc.cpp +++ b/pcbnew/drc/drc.cpp @@ -696,6 +696,7 @@ void DRC::testDrilledHoles() std::vector holes; DRILLED_HOLE hole; + wxString msg; for( MODULE* mod : m_pcb->Modules() ) { @@ -735,10 +736,18 @@ void DRC::testDrilledHoles() if( checkHole.m_location == refHole.m_location ) continue; - if( KiROUND( GetLineLength( checkHole.m_location, refHole.m_location ) ) - < checkHole.m_drillRadius + refHole.m_drillRadius + holeToHoleMin ) + int actual = KiROUND( GetLineLength( checkHole.m_location, refHole.m_location ) ); + actual = std::max( 0, actual - checkHole.m_drillRadius - refHole.m_drillRadius ); + + if( actual < holeToHoleMin ) { DRC_ITEM* drcItem = new DRC_ITEM( DRCE_DRILLED_HOLES_TOO_CLOSE ); + + msg.Printf( drcItem->GetErrorText() + _( " (minimum %s; actual %s)" ), + MessageTextFromValue( userUnits(), holeToHoleMin, true ), + MessageTextFromValue( userUnits(), actual, true ) ); + + drcItem->SetErrorMessage( msg ); drcItem->SetItems( refHole.m_owner, checkHole.m_owner ); MARKER_PCB* marker = new MARKER_PCB( drcItem, refHole.m_location ); @@ -1319,7 +1328,10 @@ bool DRC::doPadToPadsDrc( D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd, int x_li for( D_PAD** pad_list = aStart; pad_listGetOrientation() ); - if( !checkClearancePadToPad( aRefPad, &dummypad ) ) + if( !checkClearancePadToPad( aRefPad, &dummypad, &allowed, &actual ) ) { DRC_ITEM* drcItem = new DRC_ITEM( DRCE_HOLE_NEAR_PAD ); + + msg.Printf( drcItem->GetErrorText() + _( "(minimum %s; actual %s)" ), + MessageTextFromValue( userUnits(), allowed, true ), + MessageTextFromValue( userUnits(), actual, true ) ); + + drcItem->SetErrorMessage( msg ); drcItem->SetItems( pad, aRefPad ); MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() ); @@ -1382,9 +1400,15 @@ bool DRC::doPadToPadsDrc( D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd, int x_li PAD_SHAPE_OVAL : PAD_SHAPE_CIRCLE ); dummypad.SetOrientation( aRefPad->GetOrientation() ); - if( !checkClearancePadToPad( pad, &dummypad ) ) + if( !checkClearancePadToPad( pad, &dummypad, &allowed, &actual ) ) { DRC_ITEM* drcItem = new DRC_ITEM( DRCE_HOLE_NEAR_PAD ); + + msg.Printf( drcItem->GetErrorText() + _( "(minimum %s; actual %s)" ), + MessageTextFromValue( userUnits(), allowed, true ), + MessageTextFromValue( userUnits(), actual, true ) ); + + drcItem->SetErrorMessage( msg ); drcItem->SetItems( aRefPad, pad ); MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefPad->GetPosition() ); @@ -1420,9 +1444,15 @@ bool DRC::doPadToPadsDrc( D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd, int x_li continue; } - if( !checkClearancePadToPad( aRefPad, pad ) ) + if( !checkClearancePadToPad( aRefPad, pad, &allowed, &actual ) ) { DRC_ITEM* drcItem = new DRC_ITEM( DRCE_PAD_NEAR_PAD1 ); + + msg.Printf( drcItem->GetErrorText() + _( "(minimum %s; actual %s)" ), + MessageTextFromValue( userUnits(), allowed, true ), + MessageTextFromValue( userUnits(), actual, true ) ); + + drcItem->SetErrorMessage( msg ); drcItem->SetItems( aRefPad, pad ); MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefPad->GetPosition() ); diff --git a/pcbnew/drc/drc.h b/pcbnew/drc/drc.h index 124f61e42c..02edbcfae8 100644 --- a/pcbnew/drc/drc.h +++ b/pcbnew/drc/drc.h @@ -301,9 +301,11 @@ private: /** * @param aRefPad The reference pad to check * @param aPad Another pad to check against + * @param aAllowed [out] is the allowed distance (only guaranteed to be set for violations) + * @param aActual [out] it the actual difference (only guaranteed to be set for violations) * @return bool - true if clearance between aRefPad and aPad is >= dist_min, else false */ - bool checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad ); + bool checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad, int* aAllowed, int* aActual ); /** @@ -316,11 +318,13 @@ private: * @param aPad Is the pad involved in the check * @param aSegmentWidth width of the segment to test * @param aMinDist Is the minimum clearance needed + * @param aActualDist [out] Is the actual clearance (only guarantted to be set on violations) * * @return true distance >= dist_min, * false if distance < dist_min */ - bool checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMinDist ); + bool checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMinDist, + int* aActualDist ); /** @@ -329,13 +333,14 @@ private: * The segment is expected starting at 0,0, and on the X axis * (used to test DRC between a segment and a round pad, via or round end of a track * @param aCentre The coordinate of the circle's center - * @param aRadius A "keep out" radius centered over the circle + * @param aAllowed A "keep out" radius centered over the circle * @param aLength The length of the segment (i.e. coordinate of end, because it is on * the X axis) + * @param aActual [out] is the actual distance (only guaranteed to be set on violations) * @return bool - true if distance >= radius, else - * false when distance < aRadius + * false when distance < aAllowed */ - static bool checkMarginToCircle( wxPoint aCentre, int aRadius, int aLength ); + static bool checkMarginToCircle( wxPoint aCentre, int aAllowed, int aLength, int* aActual ); /** diff --git a/pcbnew/drc/drc_clearance_test_functions.cpp b/pcbnew/drc/drc_clearance_test_functions.cpp index 3fa3b249cd..01129061e9 100644 --- a/pcbnew/drc/drc_clearance_test_functions.cpp +++ b/pcbnew/drc/drc_clearance_test_functions.cpp @@ -46,17 +46,24 @@ * i.e if for each edge of the first polygon distance from each edge of the other polygon * is >= aDist */ -bool poly2polyDRC( wxPoint* aTref, int aTrefCount, wxPoint* aTtest, int aTtestCount, int aDist ) +bool poly2polyDRC( wxPoint* aTref, int aTrefCount, wxPoint* aTtest, int aTtestCount, + int aAllowedDist, int* actualDist ) { /* Test if one polygon is contained in the other and thus the polygon overlap. * This case is not covered by the following check if one polygone is * completely contained in the other (because edges don't intersect)! */ if( TestPointInsidePolygon( aTref, aTrefCount, aTtest[0] ) ) + { + *actualDist = 0; return false; + } if( TestPointInsidePolygon( aTtest, aTtestCount, aTref[0] ) ) + { + *actualDist = 0; return false; + } for( int ii = 0, jj = aTrefCount - 1; ii < aTrefCount; jj = ii, ii++ ) { @@ -70,8 +77,17 @@ bool poly2polyDRC( wxPoint* aTref, int aTrefCount, wxPoint* aTtest, int aTtestCo aTtest[kk].x, aTtest[kk].y, aTtest[ll].x, aTtest[ll].y, nullptr, nullptr, &d ); - if( intersect || ( d < aDist ) ) + if( intersect ) + { + *actualDist = 0; return false; + } + + if( d < aAllowedDist ) + { + *actualDist = KiROUND( d ); + return false; + } } } @@ -82,25 +98,36 @@ bool poly2polyDRC( wxPoint* aTref, int aTrefCount, wxPoint* aTtest, int aTtestCo /* * compare a trapezoid (can be rectangle) and a segment and return true if distance > aDist */ -bool poly2segmentDRC( wxPoint* aTref, int aTrefCount, wxPoint aSegStart, wxPoint aSegEnd, int aDist ) +bool poly2segmentDRC( wxPoint* aTref, int aTrefCount, wxPoint aSegStart, wxPoint aSegEnd, + int aDist, int* aActual ) { /* Test if the segment is contained in the polygon. * This case is not covered by the following check if the segment is * completely contained in the polygon (because edges don't intersect)! */ if( TestPointInsidePolygon( aTref, aTrefCount, aSegStart ) ) + { + *aActual = 0; return false; + } for( int ii = 0, jj = aTrefCount-1; ii < aTrefCount; jj = ii, ii++ ) { // for all edges in polygon double d; - int intersect = TestForIntersectionOfStraightLineSegments( - aTref[ii].x, aTref[ii].y, aTref[jj].x, aTref[jj].y, - aSegStart.x, aSegStart.y, aSegEnd.x, aSegEnd.y, - NULL, NULL, &d ); - if( intersect || ( d < aDist) ) + if( TestForIntersectionOfStraightLineSegments( aTref[ii].x, aTref[ii].y, aTref[jj].x, + aTref[jj].y, aSegStart.x, aSegStart.y, + aSegEnd.x, aSegEnd.y, NULL, NULL, &d ) ) + { + *aActual = 0; return false; + } + + if( d < aDist ) + { + *aActual = KiROUND( d ); + return false; + } } return true; @@ -128,6 +155,7 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato int net_code_ref = aRefSeg->GetNetCode(); int ref_seg_clearance = netclass->GetClearance(); int ref_seg_width = aRefSeg->GetWidth(); + int actual; /******************************************/ @@ -311,7 +339,7 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato m_padToTestPos = dummypad.GetPosition() - origin; - if( !checkClearanceSegmToPad( &dummypad, ref_seg_width, ref_seg_clearance ) ) + if( !checkClearanceSegmToPad( &dummypad, ref_seg_width, ref_seg_clearance, &actual ) ) { DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_THROUGH_HOLE ); drcItem->SetItems( aRefSeg, pad ); @@ -337,7 +365,7 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato m_padToTestPos = shape_pos - origin; int segToPadClearance = std::max( ref_seg_clearance, pad->GetClearance() ); - if( !checkClearanceSegmToPad( pad, ref_seg_width, segToPadClearance ) ) + if( !checkClearanceSegmToPad( pad, ref_seg_width, segToPadClearance, &actual ) ) { DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_PAD ); drcItem->SetItems( aRefSeg, pad ); @@ -414,7 +442,7 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato RotatePoint( &delta, angle ); RotatePoint( &segStartPoint, angle ); - if( !checkMarginToCircle( segStartPoint, w_dist, delta.x ) ) + if( !checkMarginToCircle( segStartPoint, w_dist, delta.x, &actual ) ) { DRC_ITEM* drcItem = new DRC_ITEM( DRCE_VIA_NEAR_TRACK ); drcItem->SetItems( aRefSeg, track ); @@ -443,7 +471,7 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato if( track->Type() == PCB_VIA_T ) { - if( checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) ) + if( checkMarginToCircle( segStartPoint, w_dist, m_segmLength, &actual ) ) continue; DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_VIA ); @@ -488,7 +516,7 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato return; } - if( !checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) ) + if( !checkMarginToCircle( segStartPoint, w_dist, m_segmLength, &actual ) ) { DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_ENDS ); drcItem->SetItems( aRefSeg, track ); @@ -519,7 +547,7 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato return; } - if( !checkMarginToCircle( segEndPoint, w_dist, m_segmLength ) ) + if( !checkMarginToCircle( segEndPoint, w_dist, m_segmLength, &actual ) ) { DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_ENDS ); drcItem->SetItems( aRefSeg, track ); @@ -572,7 +600,7 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato } // At this point the drc error is due to an end near a reference segm end - if( !checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) ) + if( !checkMarginToCircle( segStartPoint, w_dist, m_segmLength, &actual ) ) { DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_ENDS ); drcItem->SetItems( aRefSeg, track ); @@ -583,7 +611,7 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato if( !m_reportAllTrackErrors ) return; } - if( !checkMarginToCircle( segEndPoint, w_dist, m_segmLength ) ) + if( !checkMarginToCircle( segEndPoint, w_dist, m_segmLength, &actual ) ) { DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_ENDS ); drcItem->SetItems( aRefSeg, track ); @@ -664,7 +692,7 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato RotatePoint( &relStartPos, angle ); RotatePoint( &relEndPos, angle ); - if( !checkMarginToCircle( relStartPos, w_dist, delta.x ) ) + if( !checkMarginToCircle( relStartPos, w_dist, delta.x, &actual ) ) { DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_ENDS ); drcItem->SetItems( aRefSeg, track ); @@ -676,7 +704,7 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato return; } - if( !checkMarginToCircle( relEndPos, w_dist, delta.x ) ) + if( !checkMarginToCircle( relEndPos, w_dist, delta.x, &actual ) ) { DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_ENDS ); drcItem->SetItems( aRefSeg, track ); @@ -781,13 +809,16 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato } -bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad ) +bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad, int* aAllowed, int* aActual ) { - int dist; + int dist; double pad_angle; // Get the clearance between the 2 pads. this is the min distance between aRefPad and aPad - int dist_min = aRefPad->GetClearance( aPad ); + int dist_min = aRefPad->GetClearance( aPad ); + int dist_extra = 0; + + *aAllowed = dist_min; // relativePadPos is the aPad shape position relative to the aRefPad shape position wxPoint relativePadPos = aPad->ShapePos() - aRefPad->ShapePos(); @@ -876,7 +907,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad ) m_segmEnd.x = m_segmEnd.y = 0; m_padToTestPos = relativePadPos; - diag = checkClearanceSegmToPad( aPad, aRefPad->GetSize().x, dist_min ); + diag = checkClearanceSegmToPad( aPad, aRefPad->GetSize().x, dist_min, aActual ); break; case PAD_SHAPE_TRAPEZOID: @@ -891,7 +922,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad ) if( aRefPad->GetShape() == PAD_SHAPE_ROUNDRECT ) { int padRadius = aRefPad->GetRoundRectCornerRadius(); - dist_min += padRadius; + dist_extra = padRadius; GetRoundRectCornerCenters( polyref, padRadius, wxPoint( 0, 0 ), aRefPad->GetSize(), aRefPad->GetOrientation() ); } @@ -939,7 +970,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad ) if( aPad->GetShape() == PAD_SHAPE_ROUNDRECT ) { int padRadius = aPad->GetRoundRectCornerRadius(); - dist_min += padRadius; + dist_extra = padRadius; GetRoundRectCornerCenters( polycompare, padRadius, relativePadPos, aPad->GetSize(), aPad->GetOrientation() ); } @@ -986,17 +1017,23 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad ) { const SHAPE_LINE_CHAIN& refpoly = polysetref.COutline( 0 ); // And now test polygons: - if( !poly2polyDRC( (wxPoint*) &refpoly.CPoint( 0 ), refpoly.PointCount(), - polycompare, 4, dist_min ) ) // Therefore error + if( !poly2polyDRC((wxPoint*) &refpoly.CPoint( 0 ), refpoly.PointCount(), + polycompare, 4, dist_min + dist_extra, aActual ) ) + { + *aActual = std::max( 0, *aActual - dist_extra ); diag = false; + } } else if( polysetref.OutlineCount() == 0 && polysetcompare.OutlineCount()) { const SHAPE_LINE_CHAIN& cmppoly = polysetcompare.COutline( 0 ); // And now test polygons: - if( !poly2polyDRC( (wxPoint*) &cmppoly.CPoint( 0 ), cmppoly.PointCount(), - polyref, 4, dist_min ) ) // Therefore error + if( !poly2polyDRC((wxPoint*) &cmppoly.CPoint( 0 ), cmppoly.PointCount(), + polyref, 4, dist_min + dist_extra, aActual ) ) + { + *aActual = std::max( 0, *aActual - dist_extra ); diag = false; + } } else if( polysetref.OutlineCount() && polysetcompare.OutlineCount() ) { @@ -1004,15 +1041,21 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad ) const SHAPE_LINE_CHAIN& cmppoly = polysetcompare.COutline( 0 ); // And now test polygons: - if( !poly2polyDRC( (wxPoint*) &refpoly.CPoint( 0 ), refpoly.PointCount(), - (wxPoint*) &cmppoly.CPoint( 0 ), cmppoly.PointCount(), - dist_min ) ) // Therefore error + if( !poly2polyDRC((wxPoint*) &refpoly.CPoint( 0 ), refpoly.PointCount(), + (wxPoint*) &cmppoly.CPoint( 0 ), cmppoly.PointCount(), + dist_min + dist_extra, aActual ) ) + { + *aActual = std::max( 0, *aActual - dist_extra ); diag = false; + } } else { - if( !poly2polyDRC( polyref, 4, polycompare, 4, dist_min ) ) // Therefore error + if( !poly2polyDRC( polyref, 4, polycompare, 4, dist_min + dist_extra, aActual ) ) + { + *aActual = std::max( 0, *aActual - dist_extra ); diag = false; + } } break; @@ -1060,7 +1103,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad ) m_padToTestPos = relativePadPos - segstart; // Use segment to pad check to test the second pad: - diag = checkClearanceSegmToPad( aPad, segm_width, dist_min ); + diag = checkClearanceSegmToPad( aPad, segm_width, dist_min, aActual ); break; } @@ -1078,7 +1121,8 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad ) * and its orientation is m_segmAngle (m_segmAngle must be already initialized) * and have aSegmentWidth. */ -bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMinDist ) +bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMinDist, + int* aActualDist ) { // Note: // we are using a horizontal segment for test, because we know here @@ -1119,7 +1163,15 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi * calculate pad coordinates in the X,Y axis with X axis = segment to test */ RotatePoint( &m_padToTestPos, m_segmAngle ); - return checkMarginToCircle( m_padToTestPos, distToLine + padHalfsize.x, m_segmLength ); + + if( !checkMarginToCircle( m_padToTestPos, aMinDist + segmHalfWidth + padHalfsize.x, + m_segmLength, aActualDist ) ) + { + *aActualDist = std::max( 0, *aActualDist - segmHalfWidth - padHalfsize.x ); + return false; + } + + return true; } /* calculate the bounding box of the pad, including the clearance and the segment width @@ -1196,6 +1248,7 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi // If the segment legth is zero, only check the endpoints, skip the rectangle if( m_segmLength && !checkLine( startPoint, endPoint ) ) { + // JEY TODO: set aActual return false; } @@ -1207,8 +1260,10 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi // to the segment: RotatePoint( &cstart, m_segmAngle ); - if( !checkMarginToCircle( cstart, radius + distToLine, m_segmLength ) ) + if( !checkMarginToCircle( cstart, aMinDist + radius + segmHalfWidth, m_segmLength, + aActualDist) ) { + *aActualDist = std::max( 0, *aActualDist - radius - segmHalfWidth ); return false; } @@ -1216,8 +1271,10 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi RotatePoint( &cend, m_padToTestPos, orient ); RotatePoint( &cend, m_segmAngle ); - if( !checkMarginToCircle( cend, radius + distToLine, m_segmLength ) ) + if( !checkMarginToCircle( cend, aMinDist + radius + segmHalfWidth, m_segmLength, + aActualDist ) ) { + *aActualDist = std::max( 0, *aActualDist - radius - segmHalfWidth ); return false; } } @@ -1243,7 +1300,10 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi m_ycliphi = m_padToTestPos.y + padHalfsize.y; if( !checkLine( startPoint, endPoint ) ) + { + // JEY TODO: set aActual return false; + } // Testing the second rectangle dimx , dimy + distToLine m_xcliplo = m_padToTestPos.x - padHalfsize.x; @@ -1252,7 +1312,10 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi m_ycliphi = m_padToTestPos.y + padHalfsize.y + distToLine; if( !checkLine( startPoint, endPoint ) ) + { + // JEY TODO: set aActual return false; + } // testing the 4 circles which are the clearance area of each corner: @@ -1262,8 +1325,12 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi RotatePoint( &startPoint, m_padToTestPos, orient ); RotatePoint( &startPoint, m_segmAngle ); - if( !checkMarginToCircle( startPoint, distToLine, m_segmLength ) ) + if( !checkMarginToCircle( startPoint, aMinDist + segmHalfWidth, m_segmLength, + aActualDist ) ) + { + *aActualDist = std::max( 0, *aActualDist - segmHalfWidth ); return false; + } // testing the right top corner of the rectangle startPoint.x = m_padToTestPos.x + padHalfsize.x; @@ -1271,8 +1338,12 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi RotatePoint( &startPoint, m_padToTestPos, orient ); RotatePoint( &startPoint, m_segmAngle ); - if( !checkMarginToCircle( startPoint, distToLine, m_segmLength ) ) + if( !checkMarginToCircle( startPoint, aMinDist + segmHalfWidth, m_segmLength, + aActualDist ) ) + { + *aActualDist = std::max( 0, *aActualDist - segmHalfWidth ); return false; + } // testing the left bottom corner of the rectangle startPoint.x = m_padToTestPos.x - padHalfsize.x; @@ -1280,8 +1351,12 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi RotatePoint( &startPoint, m_padToTestPos, orient ); RotatePoint( &startPoint, m_segmAngle ); - if( !checkMarginToCircle( startPoint, distToLine, m_segmLength ) ) + if( !checkMarginToCircle( startPoint, aMinDist + segmHalfWidth, m_segmLength, + aActualDist ) ) + { + *aActualDist = std::max( 0, *aActualDist - segmHalfWidth ); return false; + } // testing the right bottom corner of the rectangle startPoint.x = m_padToTestPos.x + padHalfsize.x; @@ -1289,8 +1364,12 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi RotatePoint( &startPoint, m_padToTestPos, orient ); RotatePoint( &startPoint, m_segmAngle ); - if( !checkMarginToCircle( startPoint, distToLine, m_segmLength ) ) + if( !checkMarginToCircle( startPoint, aMinDist + segmHalfWidth, m_segmLength, + aActualDist ) ) + { + *aActualDist = std::max( 0, *aActualDist - segmHalfWidth ); return false; + } break; @@ -1306,10 +1385,13 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi RotatePoint( &poly[ii], m_segmAngle ); } - if( !poly2segmentDRC( poly, 4, wxPoint( 0, 0 ), - wxPoint(m_segmLength,0), distToLine ) ) + if( !poly2segmentDRC( poly, 4, wxPoint( 0, 0 ), wxPoint( m_segmLength, 0 ), + aMinDist + segmHalfWidth, aActualDist ) ) + { + *aActualDist = std::max( 0, *aActualDist - segmHalfWidth ); return false; } + } break; case PAD_SHAPE_CUSTOM: @@ -1320,8 +1402,7 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi // relatives to the segment being tested // Note, the pad position relative to the segment origin // is m_padToTestPos - aPad->CustomShapeAsPolygonToBoardPosition( &polyset, - m_padToTestPos, orient ); + aPad->CustomShapeAsPolygonToBoardPosition( &polyset, m_padToTestPos, orient ); // Rotate all coordinates by m_segmAngle, because the segment orient // is m_segmAngle @@ -1329,17 +1410,18 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi // only the lenght and orientation+ of the segment // therefore all coordinates of the pad to test must be rotated by // m_segmAngle (they are already relative to the segment origin) - aPad->CustomShapeAsPolygonToBoardPosition( &polyset, - wxPoint( 0, 0 ), m_segmAngle ); + aPad->CustomShapeAsPolygonToBoardPosition( &polyset, wxPoint( 0, 0 ), m_segmAngle ); const SHAPE_LINE_CHAIN& refpoly = polyset.COutline( 0 ); - if( !poly2segmentDRC( (wxPoint*) &refpoly.CPoint( 0 ), - refpoly.PointCount(), + if( !poly2segmentDRC( (wxPoint*) &refpoly.CPoint( 0 ), refpoly.PointCount(), wxPoint( 0, 0 ), wxPoint(m_segmLength,0), - distToLine ) ) + aMinDist + segmHalfWidth, aActualDist ) ) + { + *aActualDist = std::max( 0, *aActualDist - segmHalfWidth ); return false; } + } break; case PAD_SHAPE_CHAMFERED_RECT: @@ -1370,12 +1452,14 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi const SHAPE_LINE_CHAIN& refpoly = polyset.COutline( 0 ); - if( !poly2segmentDRC( (wxPoint*) &refpoly.CPoint( 0 ), - refpoly.PointCount(), + if( !poly2segmentDRC( (wxPoint*) &refpoly.CPoint( 0 ), refpoly.PointCount(), wxPoint( 0, 0 ), wxPoint(m_segmLength,0), - distToLine ) ) + aMinDist + segmHalfWidth, aActualDist ) ) + { + *aActualDist = std::max( 0, *aActualDist - segmHalfWidth ); return false; } + } break; } @@ -1387,25 +1471,34 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi * Helper function checkMarginToCircle * Check the distance between a circle (round pad, via or round end of track) * and a segment. the segment is expected starting at 0,0, and on the X axis - * return true if distance >= aRadius + * return true if distance >= aAllowed */ -bool DRC::checkMarginToCircle( wxPoint aCentre, int aRadius, int aLength ) +bool DRC::checkMarginToCircle( wxPoint aCentre, int aAllowed, int aLength, int* aActual ) { - if( abs( aCentre.y ) >= aRadius ) // trivial case + if( abs( aCentre.y ) >= aAllowed ) // trivial case return true; - // Here, distance between aCentre and X axis is < aRadius - if( (aCentre.x > -aRadius ) && ( aCentre.x < (aLength + aRadius) ) ) + // Here, distance between aCentre and X axis is < aAllowed + if( ( aCentre.x > -aAllowed ) && ( aCentre.x < ( aLength + aAllowed ) ) ) { - if( (aCentre.x >= 0) && (aCentre.x <= aLength) ) - return false; // aCentre is between the starting point and the ending point of the segm + if( ( aCentre.x >= 0 ) && ( aCentre.x <= aLength ) ) + { + // aCentre is between the starting point and the ending point of the segm + *aActual = abs( aCentre.y ); + return false; + } if( aCentre.x > aLength ) // aCentre is after the ending point aCentre.x -= aLength; // move aCentre to the starting point of the segment - if( EuclideanNorm( aCentre ) < aRadius ) - // distance between aCentre and the starting point or the ending point is < aRadius + int distToOrigin = KiROUND( EuclideanNorm( aCentre ) ); + + if( distToOrigin < aAllowed ) + { + // distance between aCentre and the starting point or the ending point is < aAllowed + *aActual = distToOrigin; return false; + } } return true; diff --git a/pcbnew/drc/drc_item.cpp b/pcbnew/drc/drc_item.cpp index f2dc9ff8c5..20994d2b7a 100644 --- a/pcbnew/drc/drc_item.cpp +++ b/pcbnew/drc/drc_item.cpp @@ -32,9 +32,12 @@ #include -wxString DRC_ITEM::GetErrorText() const +wxString DRC_ITEM::GetErrorText( int aCode ) const { - switch( m_errorCode ) + if( aCode < 0 ) + aCode = m_errorCode; + + switch( aCode ) { case DRCE_UNCONNECTED_ITEMS: return wxString( _( "Unconnected items" ) ); @@ -179,7 +182,7 @@ wxString DRC_ITEM::ShowHtml( PCB_BASE_FRAME* aFrame ) const { BOARD_ITEM* mainItem = nullptr; BOARD_ITEM* auxItem = nullptr; - wxString msg = m_errorMessage.IsEmpty() ? GetErrorText() : m_errorMessage; + wxString msg = m_errorMessage.IsEmpty() ? GetErrorText( m_errorCode ) : m_errorMessage; wxString mainText; wxString auxText; diff --git a/pcbnew/drc/drc_item.h b/pcbnew/drc/drc_item.h index f1203c007e..a94a6e9d5d 100644 --- a/pcbnew/drc/drc_item.h +++ b/pcbnew/drc/drc_item.h @@ -45,7 +45,7 @@ public: * Function GetErrorText * returns the string form of a drc error code. */ - wxString GetErrorText() const override; + wxString GetErrorText( int aErrorCode = -1 ) const override; /** * Function ShowHtml