From dfe4a00d438491efaabb0fa3e77804bd6f860c63 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Tue, 28 Apr 2020 22:43:29 +0100 Subject: [PATCH] Add distance reporting for copper item DRC tests. Also adds some performance improvements. --- libs/kimath/include/geometry/seg.h | 5 + libs/kimath/include/geometry/shape_poly_set.h | 26 +- libs/kimath/src/geometry/shape_poly_set.cpp | 35 ++- pcbnew/drc/drc.cpp | 240 ++++++++++++------ pcbnew/drc/drc_clearance_test_functions.cpp | 23 +- .../geometry/test_shape_poly_set_distance.cpp | 2 +- 6 files changed, 209 insertions(+), 122 deletions(-) diff --git a/libs/kimath/include/geometry/seg.h b/libs/kimath/include/geometry/seg.h index 2e508054ef..9103db760e 100644 --- a/libs/kimath/include/geometry/seg.h +++ b/libs/kimath/include/geometry/seg.h @@ -113,6 +113,11 @@ public: return (A != aSeg.A || B != aSeg.B); } + static SEG::ecoord Square( int a ) + { + return ecoord( a ) * a; + } + /** * Function LineProject() * diff --git a/libs/kimath/include/geometry/shape_poly_set.h b/libs/kimath/include/geometry/shape_poly_set.h index 3d3de7229d..b13603bb80 100644 --- a/libs/kimath/include/geometry/shape_poly_set.h +++ b/libs/kimath/include/geometry/shape_poly_set.h @@ -1169,7 +1169,7 @@ class SHAPE_POLY_SET : public SHAPE * @return int - The minimum distance between aPoint and all the segments of the aIndex-th * polygon. If the point is contained in the polygon, the distance is zero. */ - int DistanceToPolygon( VECTOR2I aPoint, int aIndex ); + SEG::ecoord SquaredDistanceToPolygon( VECTOR2I aPoint, int aIndex ); /** * Function DistanceToPolygon @@ -1183,26 +1183,28 @@ class SHAPE_POLY_SET : public SHAPE * aIndex-th polygon. If the point is contained in the polygon, the * distance is zero. */ - int DistanceToPolygon( const SEG& aSegment, int aIndex, int aSegmentWidth = 0 ); + SEG::ecoord SquaredDistanceToPolygon( const SEG& aSegment, int aIndex ); /** - * Function DistanceToPolygon - * computes the minimum distance between aPoint and all the polygons in the set + * Function SquaredDistance + * computes the minimum distance squared between aPoint and all the polygons in the set. + * Squared distances are used because they avoid the cost of doing square-roots. * @param aPoint is the point whose distance to the set has to be measured. - * @return int - The minimum distance between aPoint and all the polygons in the set. If - * the point is contained in any of the polygons, the distance is zero. + * @return The minimum distance squared between aPoint and all the polygons in the set. + * If the point is contained in any of the polygons, the distance is zero. */ - int Distance( VECTOR2I aPoint ); + SEG::ecoord SquaredDistance( VECTOR2I aPoint ); /** - * Function DistanceToPolygon - * computes the minimum distance between aSegment and all the polygons in the set. + * Function SquaredDistance + * computes the minimum distance squared between aSegment and all the polygons in the set. + * Squared distances are used because they avoid the cost of doing square-roots. * @param aSegment is the segment whose distance to the polygon set has to be measured. * @param aSegmentWidth is the width of the segment; defaults to zero. - * @return int - The minimum distance between aSegment and all the polygons in the set. - * If the point is contained in the polygon, the distance is zero. + * @return The minimum distance squared between aSegment and all the polygons in the set. + * If the point is contained in the polygon, the distance is zero. */ - int Distance( const SEG& aSegment, int aSegmentWidth = 0 ); + SEG::ecoord SquaredDistance( const SEG& aSegment ); /** * Function IsVertexInHole. diff --git a/libs/kimath/src/geometry/shape_poly_set.cpp b/libs/kimath/src/geometry/shape_poly_set.cpp index 4525d4a535..e0dc3f485b 100644 --- a/libs/kimath/src/geometry/shape_poly_set.cpp +++ b/libs/kimath/src/geometry/shape_poly_set.cpp @@ -1557,7 +1557,7 @@ SHAPE_POLY_SET::POLYGON SHAPE_POLY_SET::FilletPolygon( unsigned int aRadius, int } -int SHAPE_POLY_SET::DistanceToPolygon( VECTOR2I aPoint, int aPolygonIndex ) +SEG::ecoord SHAPE_POLY_SET::SquaredDistanceToPolygon( VECTOR2I aPoint, int aPolygonIndex ) { // We calculate the min dist between the segment and each outline segment. However, if the // segment to test is inside the outline, and does not cross any edge, it can be seen outside @@ -1569,13 +1569,13 @@ int SHAPE_POLY_SET::DistanceToPolygon( VECTOR2I aPoint, int aPolygonIndex ) SEGMENT_ITERATOR iterator = IterateSegmentsWithHoles( aPolygonIndex ); SEG polygonEdge = *iterator; - int minDistance = polygonEdge.Distance( aPoint ); + SEG::ecoord minDistance = polygonEdge.SquaredDistance( aPoint ); for( iterator++; iterator && minDistance > 0; iterator++ ) { polygonEdge = *iterator; - int currentDistance = polygonEdge.Distance( aPoint ); + SEG::ecoord currentDistance = polygonEdge.SquaredDistance( aPoint ); if( currentDistance < minDistance ) minDistance = currentDistance; @@ -1585,7 +1585,7 @@ int SHAPE_POLY_SET::DistanceToPolygon( VECTOR2I aPoint, int aPolygonIndex ) } -int SHAPE_POLY_SET::DistanceToPolygon( const SEG& aSegment, int aPolygonIndex, int aSegmentWidth ) +SEG::ecoord SHAPE_POLY_SET::SquaredDistanceToPolygon( const SEG& aSegment, int aPolygonIndex ) { // We calculate the min dist between the segment and each outline segment. However, if the // segment to test is inside the outline, and does not cross any edge, it can be seen outside @@ -1595,38 +1595,33 @@ int SHAPE_POLY_SET::DistanceToPolygon( const SEG& aSegment, int aPolygonIndex, i return 0; SEGMENT_ITERATOR iterator = IterateSegmentsWithHoles( aPolygonIndex ); - - SEG polygonEdge = *iterator; - int minDistance = polygonEdge.Distance( aSegment ); + SEG polygonEdge = *iterator; + SEG::ecoord minDistance = polygonEdge.SquaredDistance( aSegment ); for( iterator++; iterator && minDistance > 0; iterator++ ) { polygonEdge = *iterator; - int currentDistance = polygonEdge.Distance( aSegment ); + SEG::ecoord currentDistance = polygonEdge.SquaredDistance( aSegment ); if( currentDistance < minDistance ) minDistance = currentDistance; } - // Take into account the width of the segment - if( aSegmentWidth > 0 ) - minDistance -= aSegmentWidth / 2; - // Return the maximum of minDistance and zero return minDistance < 0 ? 0 : minDistance; } -int SHAPE_POLY_SET::Distance( VECTOR2I aPoint ) +SEG::ecoord SHAPE_POLY_SET::SquaredDistance( VECTOR2I aPoint ) { - int currentDistance; - int minDistance = DistanceToPolygon( aPoint, 0 ); + SEG::ecoord currentDistance; + SEG::ecoord minDistance = SquaredDistanceToPolygon( aPoint, 0 ); // Iterate through all the polygons and get the minimum distance. for( unsigned int polygonIdx = 1; polygonIdx < m_polys.size(); polygonIdx++ ) { - currentDistance = DistanceToPolygon( aPoint, polygonIdx ); + currentDistance = SquaredDistanceToPolygon( aPoint, polygonIdx ); if( currentDistance < minDistance ) minDistance = currentDistance; @@ -1636,15 +1631,15 @@ int SHAPE_POLY_SET::Distance( VECTOR2I aPoint ) } -int SHAPE_POLY_SET::Distance( const SEG& aSegment, int aSegmentWidth ) +SEG::ecoord SHAPE_POLY_SET::SquaredDistance( const SEG& aSegment ) { - int currentDistance; - int minDistance = DistanceToPolygon( aSegment, 0, aSegmentWidth ); + SEG::ecoord currentDistance; + SEG::ecoord minDistance = SquaredDistanceToPolygon( aSegment, 0 ); // Iterate through all the polygons and get the minimum distance. for( unsigned int polygonIdx = 1; polygonIdx < m_polys.size(); polygonIdx++ ) { - currentDistance = DistanceToPolygon( aSegment, polygonIdx, aSegmentWidth ); + currentDistance = SquaredDistanceToPolygon( aSegment, polygonIdx ); if( currentDistance < minDistance ) minDistance = currentDistance; diff --git a/pcbnew/drc/drc.cpp b/pcbnew/drc/drc.cpp index 2589132d71..877e4e8bd9 100644 --- a/pcbnew/drc/drc.cpp +++ b/pcbnew/drc/drc.cpp @@ -887,7 +887,6 @@ void DRC::testKeepoutAreas() // Test keepout areas for vias, tracks and pads inside keepout areas for( ZONE_CONTAINER* area : areasToInspect ) { - if( !area->GetIsKeepout() ) continue; @@ -902,9 +901,11 @@ void DRC::testKeepoutAreas() if( !area->IsOnLayer( segm->GetLayer() ) ) continue; - SEG trackSeg( segm->GetStart(), segm->GetEnd() ); + int widths = segm->GetWidth() / 2; + SEG trackSeg( segm->GetStart(), segm->GetEnd() ); + SEG::ecoord center2center_squared = area->Outline()->SquaredDistance( trackSeg ); - if( area->Outline()->Distance( trackSeg, segm->GetWidth() ) == 0 ) + if( center2center_squared <= SEG::Square( widths) ) { DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_INSIDE_KEEPOUT ); drcItem->SetItems( segm, area ); @@ -923,7 +924,11 @@ void DRC::testKeepoutAreas() if( !area->CommonLayerExists( viaLayers ) ) continue; - if( area->Outline()->Distance( segm->GetPosition() ) < segm->GetWidth()/2 ) + int widths = segm->GetWidth() / 2; + wxPoint viaPos = segm->GetPosition(); + SEG::ecoord center2center_squared = area->Outline()->SquaredDistance( viaPos ); + + if( center2center_squared <= SEG::Square( widths) ) { DRC_ITEM* drcItem = new DRC_ITEM( DRCE_VIA_INSIDE_KEEPOUT ); drcItem->SetItems( segm, area ); @@ -984,7 +989,7 @@ void DRC::testCopperTextAndGraphics() void DRC::testCopperDrawItem( DRAWSEGMENT* aItem ) { std::vector itemShape; - int itemWidth = aItem->GetWidth(); + int itemWidth = aItem->GetWidth(); switch( aItem->GetShape() ) { @@ -1036,40 +1041,60 @@ void DRC::testCopperDrawItem( DRAWSEGMENT* aItem ) break; } + EDA_RECT bbox = aItem->GetBoundingBox(); + SHAPE_RECT rect_area( bbox.GetX(), bbox.GetY(), bbox.GetWidth(), bbox.GetHeight() ); + wxString msg; + // Test tracks and vias for( auto track : m_pcb->Tracks() ) { if( !track->IsOnLayer( aItem->GetLayer() ) ) continue; - int minDist = ( track->GetWidth() + itemWidth ) / 2 + track->GetClearance( NULL ); - SEG trackAsSeg( track->GetStart(), track->GetEnd() ); + wxString clearanceSource; + int minClearance = track->GetClearance( nullptr, &clearanceSource ); + int widths = ( track->GetWidth() + itemWidth ) / 2; + int center2centerAllowed = minClearance + widths; - for( const auto& itemSeg : itemShape ) + SEG trackSeg( track->GetStart(), track->GetEnd() ); + + // Fast test to detect a track segment candidate inside the text bounding box + if( !rect_area.Collide( trackSeg, center2centerAllowed ) ) + continue; + + OPT minSeg; + SEG::ecoord center2center_squared = 0; + + for( const SEG& itemSeg : itemShape ) { - if( trackAsSeg.Distance( itemSeg ) < minDist ) + SEG::ecoord thisDist_squared = trackSeg.SquaredDistance( itemSeg ); + + if( !minSeg || thisDist_squared < center2center_squared ) { - if( track->Type() == PCB_VIA_T ) - { - DRC_ITEM* drcItem = new DRC_ITEM( DRCE_VIA_NEAR_COPPER ); - drcItem->SetItems( track, aItem ); - - wxPoint pos = getLocation( track, itemSeg ); - MARKER_PCB* marker = new MARKER_PCB( drcItem, pos ); - addMarkerToPcb( marker ); - } - else - { - DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_COPPER ); - drcItem->SetItems( track, aItem ); - - wxPoint pos = getLocation( track, itemSeg ); - MARKER_PCB* marker = new MARKER_PCB( drcItem, pos ); - addMarkerToPcb( marker ); - } - break; + minSeg = itemSeg; + center2center_squared = thisDist_squared; } } + + if( center2center_squared < SEG::Square( center2centerAllowed ) ) + { + int actual = std::max( 0.0, sqrt( center2center_squared ) - widths ); + int errorCode = ( track->Type() == PCB_VIA_T ) ? DRCE_VIA_NEAR_COPPER + : DRCE_TRACK_NEAR_COPPER; + DRC_ITEM* drcItem = new DRC_ITEM( errorCode ); + + msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ), + clearanceSource, + MessageTextFromValue( userUnits(), minClearance, true ), + MessageTextFromValue( userUnits(), actual, true ) ); + + drcItem->SetErrorMessage( msg ); + drcItem->SetItems( track, aItem ); + + wxPoint pos = getLocation( track, minSeg.get() ); + MARKER_PCB* marker = new MARKER_PCB( drcItem, pos ); + addMarkerToPcb( marker ); + } } // Test pads @@ -1082,21 +1107,52 @@ void DRC::testCopperDrawItem( DRAWSEGMENT* aItem ) if( pad->GetParent() == aItem->GetParent() ) continue; + // Fast test to detect a pad candidate inside the text bounding box + // Finer test (time consumming) is made only for pads near the text. + int bb_radius = pad->GetBoundingRadius() + pad->GetClearance( nullptr ); + VECTOR2I shape_pos( pad->ShapePos() ); + + if( !rect_area.Collide( SEG( shape_pos, shape_pos ), bb_radius ) ) + continue; + + wxString clearanceSource; + int minClearance = pad->GetClearance( nullptr, &clearanceSource ); + int widths = itemWidth / 2; + int center2centerAllowed = minClearance + widths; + SHAPE_POLY_SET padOutline; - pad->TransformShapeWithClearanceToPolygon( padOutline, pad->GetClearance( NULL ) ); + pad->TransformShapeWithClearanceToPolygon( padOutline, 0 ); - for( const auto& itemSeg : itemShape ) + OPT minSeg; + SEG::ecoord center2center_squared = 0; + + for( const SEG& itemSeg : itemShape ) { - if( padOutline.Distance( itemSeg, itemWidth ) == 0 ) - { - DRC_ITEM* drcItem = new DRC_ITEM( DRCE_PAD_NEAR_COPPER ); - drcItem->SetItems( pad, aItem ); + SEG::ecoord thisCenter2center_squared = padOutline.SquaredDistance( itemSeg ); - MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() ); - addMarkerToPcb( marker ); - break; + if( !minSeg || thisCenter2center_squared < center2center_squared ) + { + minSeg = itemSeg; + center2center_squared = thisCenter2center_squared; } } + + if( center2center_squared < SEG::Square( center2centerAllowed ) ) + { + int actual = std::max( 0.0, sqrt( center2center_squared ) - widths ); + DRC_ITEM* drcItem = new DRC_ITEM( DRCE_PAD_NEAR_COPPER ); + + msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ), + clearanceSource, + MessageTextFromValue( userUnits(), minClearance, true ), + MessageTextFromValue( userUnits(), actual, true ) ); + + drcItem->SetErrorMessage( msg ); + drcItem->SetItems( pad, aItem ); + + MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() ); + addMarkerToPcb( marker ); + } } } @@ -1109,7 +1165,7 @@ void DRC::testCopperTextItem( BOARD_ITEM* aTextItem ) return; std::vector textShape; // a buffer to store the text shape (set of segments) - int penWidth = text->GetEffectiveTextPenWidth(); + int penWidth = text->GetEffectiveTextPenWidth(); // So far the bounding box makes up the text-area text->TransformTextShapeToSegmentList( textShape ); @@ -1117,8 +1173,9 @@ void DRC::testCopperTextItem( BOARD_ITEM* aTextItem ) if( textShape.size() == 0 ) // Should not happen (empty text?) return; - EDA_RECT bbox = text->GetTextBox(); + EDA_RECT bbox = text->GetTextBox(); SHAPE_RECT rect_area( bbox.GetX(), bbox.GetY(), bbox.GetWidth(), bbox.GetHeight() ); + wxString msg; // Test tracks and vias for( auto track : m_pcb->Tracks() ) @@ -1126,40 +1183,51 @@ void DRC::testCopperTextItem( BOARD_ITEM* aTextItem ) if( !track->IsOnLayer( aTextItem->GetLayer() ) ) continue; - int minDist = ( track->GetWidth() + penWidth ) / 2 + track->GetClearance( NULL ); - SEG trackAsSeg( track->GetStart(), track->GetEnd() ); + wxString clearanceSource; + int minClearance = track->GetClearance( nullptr, &clearanceSource ); + int widths = ( track->GetWidth() + penWidth ) / 2; + int center2centerAllowed = minClearance + widths; - // Fast test to detect a trach segment candidate inside the text bounding box - if( !rect_area.Collide( trackAsSeg, minDist ) ) + SEG trackSeg( track->GetStart(), track->GetEnd() ); + + // Fast test to detect a track segment candidate inside the text bounding box + if( !rect_area.Collide( trackSeg, center2centerAllowed ) ) continue; + OPT minSeg; + SEG::ecoord center2center_squared = 0; + for( unsigned jj = 0; jj < textShape.size(); jj += 2 ) { - SEG textSeg( textShape[jj], textShape[jj+1] ); + SEG textSeg( textShape[jj], textShape[jj+1] ); + SEG::ecoord thisDist_squared = trackSeg.SquaredDistance( textSeg ); - if( trackAsSeg.Distance( textSeg ) < minDist ) + if( !minSeg || thisDist_squared < center2center_squared ) { - if( track->Type() == PCB_VIA_T ) - { - DRC_ITEM* drcItem = new DRC_ITEM( DRCE_VIA_NEAR_COPPER ); - drcItem->SetItems( track, aTextItem ); - - wxPoint pos = getLocation( track, textSeg ); - MARKER_PCB* marker = new MARKER_PCB( drcItem, pos ); - addMarkerToPcb( marker ); - } - else - { - DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_COPPER ); - drcItem->SetItems( track, aTextItem ); - - wxPoint pos = getLocation( track, textSeg ); - MARKER_PCB* marker = new MARKER_PCB( drcItem, pos ); - addMarkerToPcb( marker ); - } - break; + minSeg = textSeg; + center2center_squared = thisDist_squared; } } + + if( center2center_squared < SEG::Square( center2centerAllowed ) ) + { + int actual = std::max( 0.0, sqrt( center2center_squared ) - widths ); + int errorCode = ( track->Type() == PCB_VIA_T ) ? DRCE_VIA_NEAR_COPPER + : DRCE_TRACK_NEAR_COPPER; + DRC_ITEM* drcItem = new DRC_ITEM( errorCode ); + + msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ), + clearanceSource, + MessageTextFromValue( userUnits(), minClearance, true ), + MessageTextFromValue( userUnits(), actual, true ) ); + + drcItem->SetErrorMessage( msg ); + drcItem->SetItems( track, aTextItem ); + + wxPoint pos = getLocation( track, minSeg.get() ); + MARKER_PCB* marker = new MARKER_PCB( drcItem, pos ); + addMarkerToPcb( marker ); + } } // Test pads @@ -1176,25 +1244,45 @@ void DRC::testCopperTextItem( BOARD_ITEM* aTextItem ) if( !rect_area.Collide( SEG( shape_pos, shape_pos ), bb_radius ) ) continue; - SHAPE_POLY_SET padOutline; + wxString clearanceSource; + int minClearance = pad->GetClearance( nullptr, &clearanceSource ); + int widths = penWidth / 2; + int center2centerAllowed = minClearance + widths; - int minDist = penWidth / 2 + pad->GetClearance( NULL ); + SHAPE_POLY_SET padOutline; pad->TransformShapeWithClearanceToPolygon( padOutline, 0 ); + OPT minSeg; + SEG::ecoord center2center_squared = 0; + for( unsigned jj = 0; jj < textShape.size(); jj += 2 ) { - SEG textSeg( textShape[jj], textShape[jj+1] ); + SEG textSeg( textShape[jj], textShape[jj+1] ); + SEG::ecoord thisCenter2center_squared = padOutline.SquaredDistance( textSeg ); - if( padOutline.Distance( textSeg, 0 ) <= minDist ) + if( !minSeg || thisCenter2center_squared < center2center_squared ) { - DRC_ITEM* drcItem = new DRC_ITEM( DRCE_PAD_NEAR_COPPER ); - drcItem->SetItems( pad, aTextItem ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() ); - addMarkerToPcb( marker ); - break; + minSeg = textSeg; + center2center_squared = thisCenter2center_squared; } } + + if( center2center_squared < SEG::Square( center2centerAllowed ) ) + { + int actual = std::max( 0.0, sqrt( center2center_squared ) - widths ); + DRC_ITEM* drcItem = new DRC_ITEM( DRCE_PAD_NEAR_COPPER ); + + msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ), + clearanceSource, + MessageTextFromValue( userUnits(), minClearance, true ), + MessageTextFromValue( userUnits(), actual, true ) ); + + drcItem->SetErrorMessage( msg ); + drcItem->SetItems( pad, aTextItem ); + + MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() ); + addMarkerToPcb( marker ); + } } } @@ -1568,7 +1656,7 @@ wxPoint DRC::getLocation( TRACK* aTrack, ZONE_CONTAINER* aConflictZone ) const wxPoint pt2 = aTrack->GetEnd(); // If the mid-point is in the zone, then that's a fine place for the marker - if( conflictOutline->Distance( ( pt1 + pt2 ) / 2 ) == 0 ) + if( conflictOutline->SquaredDistance( ( pt1 + pt2 ) / 2 ) == 0 ) return ( pt1 + pt2 ) / 2; // Otherwise do a binary search for a "good enough" marker location @@ -1576,7 +1664,7 @@ wxPoint DRC::getLocation( TRACK* aTrack, ZONE_CONTAINER* aConflictZone ) const { while( GetLineLength( pt1, pt2 ) > EPSILON ) { - if( conflictOutline->Distance( pt1 ) < conflictOutline->Distance( pt2 ) ) + if( conflictOutline->SquaredDistance( pt1 ) < conflictOutline->SquaredDistance( pt2 ) ) pt2 = ( pt1 + pt2 ) / 2; else pt1 = ( pt1 + pt2 ) / 2; diff --git a/pcbnew/drc/drc_clearance_test_functions.cpp b/pcbnew/drc/drc_clearance_test_functions.cpp index 85f014f917..7fa325f014 100644 --- a/pcbnew/drc/drc_clearance_test_functions.cpp +++ b/pcbnew/drc/drc_clearance_test_functions.cpp @@ -43,12 +43,6 @@ #include -static SEG::ecoord square( int a ) -{ - return SEG::ecoord( a ) * a; -} - - /** * compare 2 convex polygons and return true if distance > aDist (if no error DRC) * i.e if for each edge of the first polygon distance from each edge of the other polygon @@ -366,7 +360,7 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato // Avoid square-roots if possible (for performance) SEG::ecoord center2center_squared = refSeg.SquaredDistance( slotSeg ); - if( center2center_squared < square( center2centerAllowed ) ) + if( center2center_squared < SEG::Square( center2centerAllowed ) ) { int actual = std::max( 0.0, sqrt( center2center_squared ) - widths ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_THROUGH_HOLE ); @@ -460,7 +454,7 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato if( !m_reportAllTrackErrors ) return; } - else if( center2center_squared < square( center2centerAllowed ) ) + else if( center2center_squared < SEG::Square( center2centerAllowed ) ) { int errorCode = DRCE_TRACK_ENDS; @@ -511,23 +505,26 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato wxString clearanceSource; int minClearance = aRefSeg->GetClearance( zone, &clearanceSource ); + int widths = refSegWidth / 2; + int center2centerAllowed = minClearance + widths; SHAPE_POLY_SET* outline = const_cast( &zone->GetFilledPolysList() ); - int error = minClearance - outline->Distance( testSeg, refSegWidth ); + SEG::ecoord center2center_squared = outline->SquaredDistance( testSeg ); // to avoid false positive, due to rounding issues and approxiamtions // in distance and clearance calculations, use a small threshold for distance // (1 micron) #define THRESHOLD_DIST Millimeter2iu( 0.001 ) - if( error > THRESHOLD_DIST ) + if( center2center_squared + THRESHOLD_DIST < SEG::Square( center2centerAllowed ) ) { + int actual = std::max( 0.0, sqrt( center2center_squared ) - widths ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_ZONE ); msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ), clearanceSource, MessageTextFromValue( userUnits(), minClearance, true ), - MessageTextFromValue( userUnits(), minClearance - error, true ) ); + MessageTextFromValue( userUnits(), actual, true ) ); drcItem->SetErrorMessage( msg ); drcItem->SetItems( aRefSeg, zone ); @@ -560,7 +557,7 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato { SEG::ecoord center2center_squared = testSeg.SquaredDistance( *it ); - if( center2center_squared < square( center2centerAllowed ) ) + if( center2center_squared < SEG::Square( center2centerAllowed ) ) { VECTOR2I pt = testSeg.NearestPoint( *it ); @@ -861,7 +858,7 @@ bool DRC::checkClearanceSegmToPad( const SEG& refSeg, int refSegWidth, const D_P // Avoid square-roots if possible (for performance) SEG::ecoord center2center_squared = refSeg.SquaredDistance( padSeg ); - if( center2center_squared < square( center2centerAllowed ) ) + if( center2center_squared < SEG::Square( center2centerAllowed ) ) { *aActualDist = std::max( 0.0, sqrt( center2center_squared ) - widths ); return false; diff --git a/qa/common/geometry/test_shape_poly_set_distance.cpp b/qa/common/geometry/test_shape_poly_set_distance.cpp index 5917a9a59f..2a29e13659 100644 --- a/qa/common/geometry/test_shape_poly_set_distance.cpp +++ b/qa/common/geometry/test_shape_poly_set_distance.cpp @@ -140,7 +140,7 @@ BOOST_AUTO_TEST_CASE( SegDistance ) { SHAPE_POLY_SET polyset = c.m_polyset; - int dist = polyset.Distance( c.m_seg, c.m_seg_width ); + int dist = sqrt( polyset.SquaredDistance( c.m_seg ) ) - c.m_seg_width; // right answer? BOOST_CHECK_PREDICATE( KI_TEST::IsWithin, ( dist )( c.m_exp_dist )( 1 ) );