From 73408f3f21b12376999a421d0fc426561f07416a Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Mon, 19 Mar 2018 22:07:34 -0700 Subject: [PATCH] Correct DRC calculation on segments If objects are at the clearance limit, they qualify as passing DRC. Therefore, all comparison functions that indicate failure should be strictly greater than or less than while all comparison functions that indicate success (in the DRC) should be greater/equal or less/equal. This also corrects a rounding error at the nm scale and handles scaling zero-length and large segments correctly. Fixes: lp:1756403 * https://bugs.launchpad.net/kicad/+bug/1756403 Fixes: lp:1593373 * https://bugs.launchpad.net/kicad/+bug/1593373 --- pcbnew/drc_clearance_test_functions.cpp | 48 ++++++++++++++++--------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/pcbnew/drc_clearance_test_functions.cpp b/pcbnew/drc_clearance_test_functions.cpp index 2288cd30d0..4643065cf8 100644 --- a/pcbnew/drc_clearance_test_functions.cpp +++ b/pcbnew/drc_clearance_test_functions.cpp @@ -988,8 +988,7 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi } else { - padHalfsize.x = aPad->GetSize().x >> 1; - padHalfsize.y = aPad->GetSize().y >> 1; + padHalfsize = aPad->GetSize() / 2; } if( aPad->GetShape() == PAD_SHAPE_TRAPEZOID ) // The size is bigger, due to GetDelta() extra size @@ -1017,7 +1016,7 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi m_xcliphi = m_padToTestPos.x + distToLine + padHalfsize.x; m_ycliphi = m_padToTestPos.y + distToLine + padHalfsize.y; - wxPoint startPoint; + wxPoint startPoint( 0, 0 ); wxPoint endPoint = m_segmEnd; double orient = aPad->GetOrientation(); @@ -1073,12 +1072,13 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi // is (radius + distToLine)*2 m_xcliplo = cstart.x - distToLine - radius; m_ycliplo = cstart.y; - m_xcliphi = cend.x + distToLine +radius; + m_xcliphi = cend.x + distToLine + radius; m_ycliphi = cend.y; } // Test the rectangular clearance area between the two circles (the rounded ends) - if( !checkLine( startPoint, endPoint ) ) + // If the segment legth is zero, only check the endpoints, skip the rectangle + if( m_segmLength && !checkLine( startPoint, endPoint ) ) { return false; } @@ -1264,6 +1264,21 @@ bool DRC::checkMarginToCircle( wxPoint aCentre, int aRadius, int aLength ) static inline int USCALE( unsigned arg, unsigned num, unsigned den ) { int ii; + double result; + + // Trivial check first + if( !arg || !num) + return 0; + + // If arg and num are both non-zero but den is zero, we return effective infinite + if( !den ) + return INT_MAX; + + result = ( (double) arg * num ) / den; + + // Ensure that our result doesn't overflow into the sign bit + if( result > INT_MAX ) + return INT_MAX; ii = KiROUND( ( (double) arg * num ) / den ); return ii; @@ -1284,14 +1299,14 @@ bool DRC::checkLine( wxPoint aSegStart, wxPoint aSegEnd ) if( aSegStart.x > aSegEnd.x ) std::swap( aSegStart, aSegEnd ); - if( (aSegEnd.x < m_xcliplo) || (aSegStart.x > m_xcliphi) ) + if( (aSegEnd.x <= m_xcliplo) || (aSegStart.x >= m_xcliphi) ) { WHEN_OUTSIDE; } if( aSegStart.y < aSegEnd.y ) { - if( (aSegEnd.y < m_ycliplo) || (aSegStart.y > m_ycliphi) ) + if( (aSegEnd.y <= m_ycliplo) || (aSegStart.y >= m_ycliphi) ) { WHEN_OUTSIDE; } @@ -1301,7 +1316,7 @@ bool DRC::checkLine( wxPoint aSegStart, wxPoint aSegEnd ) temp = USCALE( (aSegEnd.x - aSegStart.x), (m_ycliplo - aSegStart.y), (aSegEnd.y - aSegStart.y) ); - if( (aSegStart.x += temp) > m_xcliphi ) + if( (aSegStart.x += temp) >= m_xcliphi ) { WHEN_OUTSIDE; } @@ -1315,7 +1330,7 @@ bool DRC::checkLine( wxPoint aSegStart, wxPoint aSegEnd ) temp = USCALE( (aSegEnd.x - aSegStart.x), (aSegEnd.y - m_ycliphi), (aSegEnd.y - aSegStart.y) ); - if( (aSegEnd.x -= temp) < m_xcliplo ) + if( (aSegEnd.x -= temp) <= m_xcliplo ) { WHEN_OUTSIDE; } @@ -1344,7 +1359,7 @@ bool DRC::checkLine( wxPoint aSegStart, wxPoint aSegEnd ) } else { - if( (aSegStart.y < m_ycliplo) || (aSegEnd.y > m_ycliphi) ) + if( (aSegStart.y <= m_ycliplo) || (aSegEnd.y >= m_ycliphi) ) { WHEN_OUTSIDE; } @@ -1354,7 +1369,7 @@ bool DRC::checkLine( wxPoint aSegStart, wxPoint aSegEnd ) temp = USCALE( (aSegEnd.x - aSegStart.x), (aSegStart.y - m_ycliphi), (aSegStart.y - aSegEnd.y) ); - if( (aSegStart.x += temp) > m_xcliphi ) + if( (aSegStart.x += temp) >= m_xcliphi ) { WHEN_OUTSIDE; } @@ -1368,7 +1383,7 @@ bool DRC::checkLine( wxPoint aSegStart, wxPoint aSegEnd ) temp = USCALE( (aSegEnd.x - aSegStart.x), (m_ycliplo - aSegEnd.y), (aSegStart.y - aSegEnd.y) ); - if( (aSegEnd.x -= temp) < m_xcliplo ) + if( (aSegEnd.x -= temp) <= m_xcliplo ) { WHEN_OUTSIDE; } @@ -1396,10 +1411,11 @@ bool DRC::checkLine( wxPoint aSegStart, wxPoint aSegEnd ) } } - if( ( (aSegEnd.x + aSegStart.x) / 2 <= m_xcliphi ) - && ( (aSegEnd.x + aSegStart.x) / 2 >= m_xcliplo ) \ - && ( (aSegEnd.y + aSegStart.y) / 2 <= m_ycliphi ) - && ( (aSegEnd.y + aSegStart.y) / 2 >= m_ycliplo ) ) + // Do not divide here to avoid rounding errors + if( ( (aSegEnd.x + aSegStart.x) < m_xcliphi * 2 ) + && ( (aSegEnd.x + aSegStart.x) > m_xcliplo * 2) \ + && ( (aSegEnd.y + aSegStart.y) < m_ycliphi * 2 ) + && ( (aSegEnd.y + aSegStart.y) > m_ycliplo * 2 ) ) { return false; }