Add distance reporting for copper item DRC tests.

Also adds some performance improvements.
This commit is contained in:
Jeff Young 2020-04-28 22:43:29 +01:00
parent 932fdf8674
commit dfe4a00d43
6 changed files with 209 additions and 122 deletions

View File

@ -113,6 +113,11 @@ public:
return (A != aSeg.A || B != aSeg.B); return (A != aSeg.A || B != aSeg.B);
} }
static SEG::ecoord Square( int a )
{
return ecoord( a ) * a;
}
/** /**
* Function LineProject() * Function LineProject()
* *

View File

@ -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 * @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. * 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 * Function DistanceToPolygon
@ -1183,26 +1183,28 @@ class SHAPE_POLY_SET : public SHAPE
* aIndex-th polygon. If the point is contained in the polygon, the * aIndex-th polygon. If the point is contained in the polygon, the
* distance is zero. * distance is zero.
*/ */
int DistanceToPolygon( const SEG& aSegment, int aIndex, int aSegmentWidth = 0 ); SEG::ecoord SquaredDistanceToPolygon( const SEG& aSegment, int aIndex );
/** /**
* Function DistanceToPolygon * Function SquaredDistance
* computes the minimum distance between aPoint and all the polygons in the set * 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. * @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 * @return The minimum distance squared between aPoint and all the polygons in the set.
* the point is contained in any of the polygons, the distance is zero. * 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 * Function SquaredDistance
* computes the minimum distance between aSegment and all the polygons in the set. * 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 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. * @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. * @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. * 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. * Function IsVertexInHole.

View File

@ -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 // 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 // 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 ); SEGMENT_ITERATOR iterator = IterateSegmentsWithHoles( aPolygonIndex );
SEG polygonEdge = *iterator; SEG polygonEdge = *iterator;
int minDistance = polygonEdge.Distance( aPoint ); SEG::ecoord minDistance = polygonEdge.SquaredDistance( aPoint );
for( iterator++; iterator && minDistance > 0; iterator++ ) for( iterator++; iterator && minDistance > 0; iterator++ )
{ {
polygonEdge = *iterator; polygonEdge = *iterator;
int currentDistance = polygonEdge.Distance( aPoint ); SEG::ecoord currentDistance = polygonEdge.SquaredDistance( aPoint );
if( currentDistance < minDistance ) if( currentDistance < minDistance )
minDistance = currentDistance; 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 // 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 // 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; return 0;
SEGMENT_ITERATOR iterator = IterateSegmentsWithHoles( aPolygonIndex ); SEGMENT_ITERATOR iterator = IterateSegmentsWithHoles( aPolygonIndex );
SEG polygonEdge = *iterator; SEG polygonEdge = *iterator;
int minDistance = polygonEdge.Distance( aSegment ); SEG::ecoord minDistance = polygonEdge.SquaredDistance( aSegment );
for( iterator++; iterator && minDistance > 0; iterator++ ) for( iterator++; iterator && minDistance > 0; iterator++ )
{ {
polygonEdge = *iterator; polygonEdge = *iterator;
int currentDistance = polygonEdge.Distance( aSegment ); SEG::ecoord currentDistance = polygonEdge.SquaredDistance( aSegment );
if( currentDistance < minDistance ) if( currentDistance < minDistance )
minDistance = currentDistance; minDistance = currentDistance;
} }
// Take into account the width of the segment
if( aSegmentWidth > 0 )
minDistance -= aSegmentWidth / 2;
// Return the maximum of minDistance and zero // Return the maximum of minDistance and zero
return minDistance < 0 ? 0 : minDistance; return minDistance < 0 ? 0 : minDistance;
} }
int SHAPE_POLY_SET::Distance( VECTOR2I aPoint ) SEG::ecoord SHAPE_POLY_SET::SquaredDistance( VECTOR2I aPoint )
{ {
int currentDistance; SEG::ecoord currentDistance;
int minDistance = DistanceToPolygon( aPoint, 0 ); SEG::ecoord minDistance = SquaredDistanceToPolygon( aPoint, 0 );
// Iterate through all the polygons and get the minimum distance. // Iterate through all the polygons and get the minimum distance.
for( unsigned int polygonIdx = 1; polygonIdx < m_polys.size(); polygonIdx++ ) for( unsigned int polygonIdx = 1; polygonIdx < m_polys.size(); polygonIdx++ )
{ {
currentDistance = DistanceToPolygon( aPoint, polygonIdx ); currentDistance = SquaredDistanceToPolygon( aPoint, polygonIdx );
if( currentDistance < minDistance ) if( currentDistance < minDistance )
minDistance = currentDistance; 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; SEG::ecoord currentDistance;
int minDistance = DistanceToPolygon( aSegment, 0, aSegmentWidth ); SEG::ecoord minDistance = SquaredDistanceToPolygon( aSegment, 0 );
// Iterate through all the polygons and get the minimum distance. // Iterate through all the polygons and get the minimum distance.
for( unsigned int polygonIdx = 1; polygonIdx < m_polys.size(); polygonIdx++ ) for( unsigned int polygonIdx = 1; polygonIdx < m_polys.size(); polygonIdx++ )
{ {
currentDistance = DistanceToPolygon( aSegment, polygonIdx, aSegmentWidth ); currentDistance = SquaredDistanceToPolygon( aSegment, polygonIdx );
if( currentDistance < minDistance ) if( currentDistance < minDistance )
minDistance = currentDistance; minDistance = currentDistance;

View File

@ -887,7 +887,6 @@ void DRC::testKeepoutAreas()
// Test keepout areas for vias, tracks and pads inside keepout areas // Test keepout areas for vias, tracks and pads inside keepout areas
for( ZONE_CONTAINER* area : areasToInspect ) for( ZONE_CONTAINER* area : areasToInspect )
{ {
if( !area->GetIsKeepout() ) if( !area->GetIsKeepout() )
continue; continue;
@ -902,9 +901,11 @@ void DRC::testKeepoutAreas()
if( !area->IsOnLayer( segm->GetLayer() ) ) if( !area->IsOnLayer( segm->GetLayer() ) )
continue; continue;
int widths = segm->GetWidth() / 2;
SEG trackSeg( segm->GetStart(), segm->GetEnd() ); 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 ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_INSIDE_KEEPOUT );
drcItem->SetItems( segm, area ); drcItem->SetItems( segm, area );
@ -923,7 +924,11 @@ void DRC::testKeepoutAreas()
if( !area->CommonLayerExists( viaLayers ) ) if( !area->CommonLayerExists( viaLayers ) )
continue; 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 ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_VIA_INSIDE_KEEPOUT );
drcItem->SetItems( segm, area ); drcItem->SetItems( segm, area );
@ -1036,40 +1041,60 @@ void DRC::testCopperDrawItem( DRAWSEGMENT* aItem )
break; break;
} }
EDA_RECT bbox = aItem->GetBoundingBox();
SHAPE_RECT rect_area( bbox.GetX(), bbox.GetY(), bbox.GetWidth(), bbox.GetHeight() );
wxString msg;
// Test tracks and vias // Test tracks and vias
for( auto track : m_pcb->Tracks() ) for( auto track : m_pcb->Tracks() )
{ {
if( !track->IsOnLayer( aItem->GetLayer() ) ) if( !track->IsOnLayer( aItem->GetLayer() ) )
continue; continue;
int minDist = ( track->GetWidth() + itemWidth ) / 2 + track->GetClearance( NULL ); wxString clearanceSource;
SEG trackAsSeg( track->GetStart(), track->GetEnd() ); 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<SEG> 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 ) minSeg = itemSeg;
center2center_squared = thisDist_squared;
}
}
if( center2center_squared < SEG::Square( center2centerAllowed ) )
{ {
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_VIA_NEAR_COPPER ); 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 ); drcItem->SetItems( track, aItem );
wxPoint pos = getLocation( track, itemSeg ); wxPoint pos = getLocation( track, minSeg.get() );
MARKER_PCB* marker = new MARKER_PCB( drcItem, pos ); MARKER_PCB* marker = new MARKER_PCB( drcItem, pos );
addMarkerToPcb( marker ); 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;
}
}
} }
// Test pads // Test pads
@ -1082,20 +1107,51 @@ void DRC::testCopperDrawItem( DRAWSEGMENT* aItem )
if( pad->GetParent() == aItem->GetParent() ) if( pad->GetParent() == aItem->GetParent() )
continue; continue;
SHAPE_POLY_SET padOutline; // Fast test to detect a pad candidate inside the text bounding box
pad->TransformShapeWithClearanceToPolygon( padOutline, pad->GetClearance( NULL ) ); // 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() );
for( const auto& itemSeg : itemShape ) 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, 0 );
OPT<SEG> minSeg;
SEG::ecoord center2center_squared = 0;
for( const SEG& itemSeg : itemShape )
{ {
if( padOutline.Distance( itemSeg, itemWidth ) == 0 ) SEG::ecoord thisCenter2center_squared = padOutline.SquaredDistance( itemSeg );
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 ); 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 ); drcItem->SetItems( pad, aItem );
MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() ); MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() );
addMarkerToPcb( marker ); addMarkerToPcb( marker );
break;
}
} }
} }
} }
@ -1119,6 +1175,7 @@ void DRC::testCopperTextItem( BOARD_ITEM* aTextItem )
EDA_RECT bbox = text->GetTextBox(); EDA_RECT bbox = text->GetTextBox();
SHAPE_RECT rect_area( bbox.GetX(), bbox.GetY(), bbox.GetWidth(), bbox.GetHeight() ); SHAPE_RECT rect_area( bbox.GetX(), bbox.GetY(), bbox.GetWidth(), bbox.GetHeight() );
wxString msg;
// Test tracks and vias // Test tracks and vias
for( auto track : m_pcb->Tracks() ) for( auto track : m_pcb->Tracks() )
@ -1126,40 +1183,51 @@ void DRC::testCopperTextItem( BOARD_ITEM* aTextItem )
if( !track->IsOnLayer( aTextItem->GetLayer() ) ) if( !track->IsOnLayer( aTextItem->GetLayer() ) )
continue; continue;
int minDist = ( track->GetWidth() + penWidth ) / 2 + track->GetClearance( NULL ); wxString clearanceSource;
SEG trackAsSeg( track->GetStart(), track->GetEnd() ); 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 SEG trackSeg( track->GetStart(), track->GetEnd() );
if( !rect_area.Collide( trackAsSeg, minDist ) )
// Fast test to detect a track segment candidate inside the text bounding box
if( !rect_area.Collide( trackSeg, center2centerAllowed ) )
continue; continue;
OPT<SEG> minSeg;
SEG::ecoord center2center_squared = 0;
for( unsigned jj = 0; jj < textShape.size(); jj += 2 ) 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 ) minSeg = textSeg;
center2center_squared = thisDist_squared;
}
}
if( center2center_squared < SEG::Square( center2centerAllowed ) )
{ {
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_VIA_NEAR_COPPER ); 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 ); drcItem->SetItems( track, aTextItem );
wxPoint pos = getLocation( track, textSeg ); wxPoint pos = getLocation( track, minSeg.get() );
MARKER_PCB* marker = new MARKER_PCB( drcItem, pos ); MARKER_PCB* marker = new MARKER_PCB( drcItem, pos );
addMarkerToPcb( marker ); 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;
}
}
} }
// Test pads // Test pads
@ -1176,24 +1244,44 @@ void DRC::testCopperTextItem( BOARD_ITEM* aTextItem )
if( !rect_area.Collide( SEG( shape_pos, shape_pos ), bb_radius ) ) if( !rect_area.Collide( SEG( shape_pos, shape_pos ), bb_radius ) )
continue; 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 ); pad->TransformShapeWithClearanceToPolygon( padOutline, 0 );
OPT<SEG> minSeg;
SEG::ecoord center2center_squared = 0;
for( unsigned jj = 0; jj < textShape.size(); jj += 2 ) 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 )
{ {
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 ); 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 ); drcItem->SetItems( pad, aTextItem );
MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() ); MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() );
addMarkerToPcb( marker ); addMarkerToPcb( marker );
break;
}
} }
} }
} }
@ -1568,7 +1656,7 @@ wxPoint DRC::getLocation( TRACK* aTrack, ZONE_CONTAINER* aConflictZone ) const
wxPoint pt2 = aTrack->GetEnd(); wxPoint pt2 = aTrack->GetEnd();
// If the mid-point is in the zone, then that's a fine place for the marker // 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; return ( pt1 + pt2 ) / 2;
// Otherwise do a binary search for a "good enough" marker location // 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 ) while( GetLineLength( pt1, pt2 ) > EPSILON )
{ {
if( conflictOutline->Distance( pt1 ) < conflictOutline->Distance( pt2 ) ) if( conflictOutline->SquaredDistance( pt1 ) < conflictOutline->SquaredDistance( pt2 ) )
pt2 = ( pt1 + pt2 ) / 2; pt2 = ( pt1 + pt2 ) / 2;
else else
pt1 = ( pt1 + pt2 ) / 2; pt1 = ( pt1 + pt2 ) / 2;

View File

@ -43,12 +43,6 @@
#include <macros.h> #include <macros.h>
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) * 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 * 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) // Avoid square-roots if possible (for performance)
SEG::ecoord center2center_squared = refSeg.SquaredDistance( slotSeg ); 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 ); int actual = std::max( 0.0, sqrt( center2center_squared ) - widths );
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_THROUGH_HOLE ); 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 ) if( !m_reportAllTrackErrors )
return; return;
} }
else if( center2center_squared < square( center2centerAllowed ) ) else if( center2center_squared < SEG::Square( center2centerAllowed ) )
{ {
int errorCode = DRCE_TRACK_ENDS; int errorCode = DRCE_TRACK_ENDS;
@ -511,23 +505,26 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
wxString clearanceSource; wxString clearanceSource;
int minClearance = aRefSeg->GetClearance( zone, &clearanceSource ); int minClearance = aRefSeg->GetClearance( zone, &clearanceSource );
int widths = refSegWidth / 2;
int center2centerAllowed = minClearance + widths;
SHAPE_POLY_SET* outline = const_cast<SHAPE_POLY_SET*>( &zone->GetFilledPolysList() ); SHAPE_POLY_SET* outline = const_cast<SHAPE_POLY_SET*>( &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 // to avoid false positive, due to rounding issues and approxiamtions
// in distance and clearance calculations, use a small threshold for distance // in distance and clearance calculations, use a small threshold for distance
// (1 micron) // (1 micron)
#define THRESHOLD_DIST Millimeter2iu( 0.001 ) #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 ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_ZONE );
msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ), msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
clearanceSource, clearanceSource,
MessageTextFromValue( userUnits(), minClearance, true ), MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), minClearance - error, true ) ); MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( msg );
drcItem->SetItems( aRefSeg, zone ); 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 ); SEG::ecoord center2center_squared = testSeg.SquaredDistance( *it );
if( center2center_squared < square( center2centerAllowed ) ) if( center2center_squared < SEG::Square( center2centerAllowed ) )
{ {
VECTOR2I pt = testSeg.NearestPoint( *it ); 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) // Avoid square-roots if possible (for performance)
SEG::ecoord center2center_squared = refSeg.SquaredDistance( padSeg ); 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 ); *aActualDist = std::max( 0.0, sqrt( center2center_squared ) - widths );
return false; return false;

View File

@ -140,7 +140,7 @@ BOOST_AUTO_TEST_CASE( SegDistance )
{ {
SHAPE_POLY_SET polyset = c.m_polyset; 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? // right answer?
BOOST_CHECK_PREDICATE( KI_TEST::IsWithin<int>, ( dist )( c.m_exp_dist )( 1 ) ); BOOST_CHECK_PREDICATE( KI_TEST::IsWithin<int>, ( dist )( c.m_exp_dist )( 1 ) );