|
|
|
@ -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,39 +1041,59 @@ 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; |
|
|
|
|
|
|
|
SEG trackSeg( track->GetStart(), track->GetEnd() ); |
|
|
|
|
|
|
|
for( const auto& itemSeg : itemShape ) |
|
|
|
// 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 ); |
|
|
|
minSeg = itemSeg; |
|
|
|
center2center_squared = thisDist_squared; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
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 ); |
|
|
|
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 ); |
|
|
|
|
|
|
|
wxPoint pos = getLocation( track, itemSeg ); |
|
|
|
MARKER_PCB* marker = new MARKER_PCB( drcItem, pos ); |
|
|
|
addMarkerToPcb( marker ); |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
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 ); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -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 ); |
|
|
|
|
|
|
|
OPT<SEG> minSeg; |
|
|
|
SEG::ecoord center2center_squared = 0; |
|
|
|
|
|
|
|
for( const auto& itemSeg : itemShape ) |
|
|
|
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,39 +1183,50 @@ 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; |
|
|
|
|
|
|
|
SEG trackSeg( track->GetStart(), track->GetEnd() ); |
|
|
|
|
|
|
|
// Fast test to detect a trach segment candidate inside the text bounding box
|
|
|
|
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; |
|
|
|
|
|
|
|
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 ); |
|
|
|
minSeg = textSeg; |
|
|
|
center2center_squared = thisDist_squared; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
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 ); |
|
|
|
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 ); |
|
|
|
|
|
|
|
wxPoint pos = getLocation( track, textSeg ); |
|
|
|
MARKER_PCB* marker = new MARKER_PCB( drcItem, pos ); |
|
|
|
addMarkerToPcb( marker ); |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
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 ); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -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; |
|
|
|
|