Add distance reporting for copper item DRC tests.
Also adds some performance improvements.
This commit is contained in:
parent
932fdf8674
commit
dfe4a00d43
|
@ -113,6 +113,11 @@ public:
|
|||
return (A != aSeg.A || B != aSeg.B);
|
||||
}
|
||||
|
||||
static SEG::ecoord Square( int a )
|
||||
{
|
||||
return ecoord( a ) * a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function LineProject()
|
||||
*
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<SEG> 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<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 )
|
||||
{
|
||||
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<SEG> 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<wxPoint> 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<SEG> 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<SEG> 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;
|
||||
|
|
|
@ -43,12 +43,6 @@
|
|||
#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)
|
||||
* 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<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
|
||||
// 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;
|
||||
|
|
|
@ -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<int>, ( dist )( c.m_exp_dist )( 1 ) );
|
||||
|
|
Loading…
Reference in New Issue