Move rest of DRC to SHAPE collision architecture.
This commit is contained in:
parent
2a1550d1d2
commit
d85a707385
|
@ -430,7 +430,7 @@ COBJECT2D *BOARD_ADAPTER::createNewPadDrill( const D_PAD* aPad, int aInflateValu
|
||||||
}
|
}
|
||||||
else // Oblong hole
|
else // Oblong hole
|
||||||
{
|
{
|
||||||
const std::shared_ptr<SHAPE_SEGMENT>& seg = aPad->GetEffectiveHoleShape();
|
const SHAPE_SEGMENT* seg = aPad->GetEffectiveHoleShape();
|
||||||
float width = seg->GetWidth() + aInflateValue * 2;
|
float width = seg->GetWidth() + aInflateValue * 2;
|
||||||
|
|
||||||
SFVEC2F start3DU( seg->GetSeg().A.x * m_biuTo3Dunits,
|
SFVEC2F start3DU( seg->GetSeg().A.x * m_biuTo3Dunits,
|
||||||
|
|
|
@ -90,6 +90,16 @@ public:
|
||||||
return VECTOR2I( m_w, m_h ).EuclideanNorm();
|
return VECTOR2I( m_w, m_h ).EuclideanNorm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Collide( const SHAPE* aShape, int aClearance, VECTOR2I* aMTV ) const override
|
||||||
|
{
|
||||||
|
return SHAPE::Collide( aShape, aClearance, aMTV );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Collide( const SHAPE* aShape, int aClearance = 0, int* aActual = nullptr ) const override
|
||||||
|
{
|
||||||
|
return SHAPE::Collide( aShape, aClearance, aActual );
|
||||||
|
}
|
||||||
|
|
||||||
/// @copydoc SHAPE::Collide()
|
/// @copydoc SHAPE::Collide()
|
||||||
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override;
|
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override;
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,16 @@ public:
|
||||||
return BOX2I( m_seg.A, m_seg.B - m_seg.A ).Inflate( aClearance + ( m_width + 1 ) / 2 );
|
return BOX2I( m_seg.A, m_seg.B - m_seg.A ).Inflate( aClearance + ( m_width + 1 ) / 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Collide( const SHAPE* aShape, int aClearance, VECTOR2I* aMTV ) const override
|
||||||
|
{
|
||||||
|
return SHAPE::Collide( aShape, aClearance, aMTV );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Collide( const SHAPE* aShape, int aClearance = 0, int* aActual = nullptr ) const override
|
||||||
|
{
|
||||||
|
return SHAPE::Collide( aShape, aClearance, aActual );
|
||||||
|
}
|
||||||
|
|
||||||
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override
|
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override
|
||||||
{
|
{
|
||||||
int min_dist = ( m_width + 1 ) / 2 + aClearance;
|
int min_dist = ( m_width + 1 ) / 2 + aClearance;
|
||||||
|
|
|
@ -651,7 +651,7 @@ bool D_PAD::TransformHoleWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
||||||
if( !drillsize.x || !drillsize.y )
|
if( !drillsize.x || !drillsize.y )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const std::shared_ptr<SHAPE_SEGMENT>& seg = GetEffectiveHoleShape();
|
const SHAPE_SEGMENT* seg = GetEffectiveHoleShape();
|
||||||
|
|
||||||
TransformSegmentToPolygon( aCornerBuffer, (wxPoint) seg->GetSeg().A, (wxPoint) seg->GetSeg().B,
|
TransformSegmentToPolygon( aCornerBuffer, (wxPoint) seg->GetSeg().A, (wxPoint) seg->GetSeg().B,
|
||||||
aError, seg->GetWidth() + aInflateValue * 2 );
|
aError, seg->GetWidth() + aInflateValue * 2 );
|
||||||
|
|
|
@ -200,12 +200,12 @@ const std::vector<std::shared_ptr<SHAPE>>& D_PAD::GetEffectiveShapes() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const std::shared_ptr<SHAPE_SEGMENT>& D_PAD::GetEffectiveHoleShape() const
|
const SHAPE_SEGMENT* D_PAD::GetEffectiveHoleShape() const
|
||||||
{
|
{
|
||||||
if( m_shapesDirty )
|
if( m_shapesDirty )
|
||||||
BuildEffectiveShapes();
|
BuildEffectiveShapes();
|
||||||
|
|
||||||
return m_effectiveHoleShape;
|
return m_effectiveHoleShape.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -761,39 +761,6 @@ void D_PAD::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void D_PAD::GetOblongGeometry( const wxSize& aDrillOrPadSize,
|
|
||||||
wxPoint* aStartPoint, wxPoint* aEndPoint, int* aWidth ) const
|
|
||||||
{
|
|
||||||
// calculates the start point, end point and width
|
|
||||||
// of an equivalent segment which have the same position and width as the pad or hole
|
|
||||||
int delta_cx, delta_cy;
|
|
||||||
|
|
||||||
wxSize halfsize = aDrillOrPadSize / 2;
|
|
||||||
wxPoint offset;
|
|
||||||
|
|
||||||
if( aDrillOrPadSize.x > aDrillOrPadSize.y ) // horizontal
|
|
||||||
{
|
|
||||||
delta_cx = halfsize.x - halfsize.y;
|
|
||||||
delta_cy = 0;
|
|
||||||
*aWidth = aDrillOrPadSize.y;
|
|
||||||
}
|
|
||||||
else // vertical
|
|
||||||
{
|
|
||||||
delta_cx = 0;
|
|
||||||
delta_cy = halfsize.y - halfsize.x;
|
|
||||||
*aWidth = aDrillOrPadSize.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
RotatePoint( &delta_cx, &delta_cy, m_Orient );
|
|
||||||
|
|
||||||
aStartPoint->x = delta_cx + offset.x;
|
|
||||||
aStartPoint->y = delta_cy + offset.y;
|
|
||||||
|
|
||||||
aEndPoint->x = - delta_cx + offset.x;
|
|
||||||
aEndPoint->y = - delta_cy + offset.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool D_PAD::HitTest( const wxPoint& aPosition, int aAccuracy ) const
|
bool D_PAD::HitTest( const wxPoint& aPosition, int aAccuracy ) const
|
||||||
{
|
{
|
||||||
VECTOR2I delta = aPosition - GetPosition();
|
VECTOR2I delta = aPosition - GetPosition();
|
||||||
|
@ -846,6 +813,64 @@ bool D_PAD::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) con
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool D_PAD::Collide( const D_PAD* aPad, int aMinClearance, int* aActual )
|
||||||
|
{
|
||||||
|
int center2center = KiROUND( EuclideanNorm( aPad->ShapePos() - ShapePos() ) );
|
||||||
|
|
||||||
|
// Quick test: Clearance is OK if the bounding circles are further away than aMinClearance
|
||||||
|
if( center2center - GetBoundingRadius() - aPad->GetBoundingRadius() >= aMinClearance )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int actual = INT_MAX;
|
||||||
|
|
||||||
|
for( const std::shared_ptr<SHAPE>& aShape : GetEffectiveShapes() )
|
||||||
|
{
|
||||||
|
for( const std::shared_ptr<SHAPE>& bShape : aPad->GetEffectiveShapes() )
|
||||||
|
{
|
||||||
|
int this_dist;
|
||||||
|
|
||||||
|
if( aShape->Collide( bShape.get(), aMinClearance, &this_dist ) )
|
||||||
|
actual = std::min( actual, this_dist );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( actual < INT_MAX )
|
||||||
|
{
|
||||||
|
// returns the actual clearance (clearance < aMinClearance) for diags:
|
||||||
|
if( aActual )
|
||||||
|
*aActual = std::max( 0, actual );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool D_PAD::Collide( const SHAPE_SEGMENT* aSeg, int aMinClearance, int* aActual )
|
||||||
|
{
|
||||||
|
int actual = INT_MAX;
|
||||||
|
|
||||||
|
for( const std::shared_ptr<SHAPE>& shape : GetEffectiveShapes() )
|
||||||
|
{
|
||||||
|
int this_dist;
|
||||||
|
|
||||||
|
if( shape->Collide( aSeg, aMinClearance, &this_dist ) )
|
||||||
|
actual = std::min( actual, this_dist );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( actual < INT_MAX )
|
||||||
|
{
|
||||||
|
if( aActual )
|
||||||
|
*aActual = std::max( 0, actual );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int D_PAD::Compare( const D_PAD* padref, const D_PAD* padcmp )
|
int D_PAD::Compare( const D_PAD* padref, const D_PAD* padcmp )
|
||||||
{
|
{
|
||||||
int diff;
|
int diff;
|
||||||
|
|
|
@ -321,12 +321,6 @@ public:
|
||||||
|
|
||||||
bool IsDirty() const { return m_shapesDirty; }
|
bool IsDirty() const { return m_shapesDirty; }
|
||||||
|
|
||||||
/**
|
|
||||||
* JEY TODO: temporary until Tom is done with DRC stuff....
|
|
||||||
*/
|
|
||||||
void GetOblongGeometry( const wxSize& aDrillOrPadSize,
|
|
||||||
wxPoint* aStartPoint, wxPoint* aEndPoint, int* aWidth ) const;
|
|
||||||
|
|
||||||
void SetLayerSet( LSET aLayerMask ) { m_layerMask = aLayerMask; }
|
void SetLayerSet( LSET aLayerMask ) { m_layerMask = aLayerMask; }
|
||||||
LSET GetLayerSet() const override { return m_layerMask; }
|
LSET GetLayerSet() const override { return m_layerMask; }
|
||||||
|
|
||||||
|
@ -394,7 +388,7 @@ public:
|
||||||
* Function GetEffectiveHoleShape
|
* Function GetEffectiveHoleShape
|
||||||
* Returns a list of SHAPE objects representing the pad's hole.
|
* Returns a list of SHAPE objects representing the pad's hole.
|
||||||
*/
|
*/
|
||||||
const std::shared_ptr<SHAPE_SEGMENT>& GetEffectiveHoleShape() const;
|
const SHAPE_SEGMENT* GetEffectiveHoleShape() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function GetBoundingRadius
|
* Function GetBoundingRadius
|
||||||
|
@ -513,6 +507,9 @@ public:
|
||||||
bool HitTest( const wxPoint& aPosition, int aAccuracy = 0 ) const override;
|
bool HitTest( const wxPoint& aPosition, int aAccuracy = 0 ) const override;
|
||||||
bool HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy = 0 ) const override;
|
bool HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy = 0 ) const override;
|
||||||
|
|
||||||
|
bool Collide( const SHAPE_SEGMENT* aSeg, int aMinClearance, int* aActual = nullptr );
|
||||||
|
bool Collide( const D_PAD* aPad, int aMinClearance, int* aActual = nullptr );
|
||||||
|
|
||||||
wxString GetClass() const override
|
wxString GetClass() const override
|
||||||
{
|
{
|
||||||
return wxT( "PAD" );
|
return wxT( "PAD" );
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include <dialog_drc.h>
|
#include <dialog_drc.h>
|
||||||
#include <wx/progdlg.h>
|
#include <wx/progdlg.h>
|
||||||
#include <board_commit.h>
|
#include <board_commit.h>
|
||||||
|
#include <geometry/shape_segment.h>
|
||||||
#include <geometry/shape_arc.h>
|
#include <geometry/shape_arc.h>
|
||||||
#include <drc/drc.h>
|
#include <drc/drc.h>
|
||||||
#include <drc/drc_rule_parser.h>
|
#include <drc/drc_rule_parser.h>
|
||||||
|
@ -61,6 +62,7 @@
|
||||||
#include <drc/footprint_tester.h>
|
#include <drc/footprint_tester.h>
|
||||||
#include <dialogs/panel_setup_rules.h>
|
#include <dialogs/panel_setup_rules.h>
|
||||||
|
|
||||||
|
|
||||||
DRC::DRC() :
|
DRC::DRC() :
|
||||||
PCB_TOOL_BASE( "pcbnew.DRCTool" ),
|
PCB_TOOL_BASE( "pcbnew.DRCTool" ),
|
||||||
m_editFrame( nullptr ),
|
m_editFrame( nullptr ),
|
||||||
|
@ -538,11 +540,11 @@ void DRC::testPadClearances( BOARD_COMMIT& aCommit )
|
||||||
|
|
||||||
for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ )
|
for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ )
|
||||||
{
|
{
|
||||||
|
SHAPE_SEGMENT edge( *it );
|
||||||
int actual;
|
int actual;
|
||||||
|
|
||||||
if( !checkClearanceSegmToPad( *it, 0, pad, minClearance, &actual ) )
|
if( pad->Collide( &edge, minClearance, &actual ) )
|
||||||
{
|
{
|
||||||
actual = std::max( 0, actual );
|
|
||||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_COPPER_EDGE_CLEARANCE );
|
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_COPPER_EDGE_CLEARANCE );
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
||||||
|
@ -907,100 +909,25 @@ void DRC::testCopperTextAndGraphics( BOARD_COMMIT& aCommit )
|
||||||
void DRC::testCopperDrawItem( BOARD_COMMIT& aCommit, BOARD_ITEM* aItem )
|
void DRC::testCopperDrawItem( BOARD_COMMIT& aCommit, BOARD_ITEM* aItem )
|
||||||
{
|
{
|
||||||
EDA_RECT bbox;
|
EDA_RECT bbox;
|
||||||
std::vector<SEG> itemShape;
|
std::vector<SHAPE*> itemShapes;
|
||||||
int itemWidth;
|
|
||||||
DRAWSEGMENT* drawItem = dynamic_cast<DRAWSEGMENT*>( aItem );
|
DRAWSEGMENT* drawItem = dynamic_cast<DRAWSEGMENT*>( aItem );
|
||||||
EDA_TEXT* textItem = dynamic_cast<EDA_TEXT*>( aItem );
|
EDA_TEXT* textItem = dynamic_cast<EDA_TEXT*>( aItem );
|
||||||
|
|
||||||
if( drawItem )
|
if( drawItem )
|
||||||
{
|
{
|
||||||
bbox = drawItem->GetBoundingBox();
|
bbox = drawItem->GetBoundingBox();
|
||||||
itemWidth = drawItem->GetWidth();
|
itemShapes = drawItem->MakeEffectiveShapes();
|
||||||
|
|
||||||
switch( drawItem->GetShape() )
|
|
||||||
{
|
|
||||||
case S_ARC:
|
|
||||||
{
|
|
||||||
SHAPE_ARC arc( drawItem->GetCenter(), drawItem->GetArcStart(),
|
|
||||||
(double) drawItem->GetAngle() / 10.0 );
|
|
||||||
|
|
||||||
SHAPE_LINE_CHAIN l = arc.ConvertToPolyline();
|
|
||||||
|
|
||||||
for( int i = 0; i < l.SegmentCount(); i++ )
|
|
||||||
itemShape.push_back( l.Segment( i ) );
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case S_SEGMENT:
|
|
||||||
itemShape.emplace_back( SEG( drawItem->GetStart(), drawItem->GetEnd() ) );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case S_RECT:
|
|
||||||
{
|
|
||||||
std::vector<wxPoint> pts;
|
|
||||||
drawItem->GetRectCorners( &pts );
|
|
||||||
|
|
||||||
itemShape.emplace_back( SEG( pts[0], pts[1] ) );
|
|
||||||
itemShape.emplace_back( SEG( pts[1], pts[2] ) );
|
|
||||||
itemShape.emplace_back( SEG( pts[2], pts[3] ) );
|
|
||||||
itemShape.emplace_back( SEG( pts[3], pts[0] ) );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case S_CIRCLE:
|
|
||||||
{
|
|
||||||
// SHAPE_CIRCLE has no ConvertToPolyline() method, so use a 360.0 SHAPE_ARC
|
|
||||||
SHAPE_ARC circle( drawItem->GetCenter(), drawItem->GetEnd(), 360.0 );
|
|
||||||
|
|
||||||
SHAPE_LINE_CHAIN l = circle.ConvertToPolyline();
|
|
||||||
|
|
||||||
for( int i = 0; i < l.SegmentCount(); i++ )
|
|
||||||
itemShape.push_back( l.Segment( i ) );
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case S_CURVE:
|
|
||||||
{
|
|
||||||
drawItem->RebuildBezierToSegmentsPointsList( drawItem->GetWidth() );
|
|
||||||
wxPoint start_pt = drawItem->GetBezierPoints()[0];
|
|
||||||
|
|
||||||
for( unsigned int jj = 1; jj < drawItem->GetBezierPoints().size(); jj++ )
|
|
||||||
{
|
|
||||||
wxPoint end_pt = drawItem->GetBezierPoints()[jj];
|
|
||||||
itemShape.emplace_back( SEG( start_pt, end_pt ) );
|
|
||||||
start_pt = end_pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case S_POLYGON:
|
|
||||||
{
|
|
||||||
SHAPE_LINE_CHAIN l = drawItem->GetPolyShape().Outline( 0 );
|
|
||||||
|
|
||||||
for( int i = 0; i < l.SegmentCount(); i++ )
|
|
||||||
itemShape.push_back( l.Segment( i ) );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
wxFAIL_MSG( "DRC::testCopperDrawItem unsupported DRAWSEGMENT shape: "
|
|
||||||
+ STROKE_T_asString( drawItem->GetShape() ) );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if( textItem )
|
else if( textItem )
|
||||||
{
|
{
|
||||||
bbox = textItem->GetTextBox();
|
bbox = textItem->GetTextBox();
|
||||||
itemWidth = textItem->GetEffectiveTextPenWidth();
|
|
||||||
|
|
||||||
std::vector<wxPoint> textShape;
|
int penWidth = textItem->GetEffectiveTextPenWidth();
|
||||||
textItem->TransformTextShapeToSegmentList( textShape );
|
std::vector<wxPoint> pts;
|
||||||
|
textItem->TransformTextShapeToSegmentList( pts );
|
||||||
|
|
||||||
for( unsigned jj = 0; jj < textShape.size(); jj += 2 )
|
for( unsigned jj = 0; jj < pts.size(); jj += 2 )
|
||||||
itemShape.emplace_back( SEG( textShape[jj], textShape[jj+1] ) );
|
itemShapes.push_back( new SHAPE_SEGMENT( pts[jj], pts[jj+1], penWidth ) );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1008,10 +935,7 @@ void DRC::testCopperDrawItem( BOARD_COMMIT& aCommit, BOARD_ITEM* aItem )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHAPE_RECT rect_area( bbox.GetX(), bbox.GetY(), bbox.GetWidth(), bbox.GetHeight() );
|
SHAPE_RECT bboxShape( bbox.GetX(), bbox.GetY(), bbox.GetWidth(), bbox.GetHeight() );
|
||||||
|
|
||||||
if( itemShape.empty() )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Test tracks and vias
|
// Test tracks and vias
|
||||||
for( auto track : m_pcb->Tracks() )
|
for( auto track : m_pcb->Tracks() )
|
||||||
|
@ -1020,43 +944,41 @@ void DRC::testCopperDrawItem( BOARD_COMMIT& aCommit, BOARD_ITEM* aItem )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int minClearance = track->GetClearance( aItem, &m_clearanceSource );
|
int minClearance = track->GetClearance( aItem, &m_clearanceSource );
|
||||||
int widths = ( track->GetWidth() + itemWidth ) / 2;
|
int actual = INT_MAX;
|
||||||
int center2centerAllowed = minClearance + widths;
|
wxPoint pos;
|
||||||
|
|
||||||
SEG trackSeg( track->GetStart(), track->GetEnd() );
|
SHAPE_SEGMENT trackSeg( track->GetStart(), track->GetEnd(), track->GetWidth() );
|
||||||
|
|
||||||
// Fast test to detect a track segment candidate inside the text bounding box
|
// Fast test to detect a track segment candidate inside the text bounding box
|
||||||
if( !rect_area.Collide( trackSeg, center2centerAllowed ) )
|
if( !bboxShape.Collide( &trackSeg, 0 ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
OPT<SEG> minSeg;
|
for( const SHAPE* shape : itemShapes )
|
||||||
SEG::ecoord center2center_squared = 0;
|
|
||||||
|
|
||||||
for( const SEG& itemSeg : itemShape )
|
|
||||||
{
|
{
|
||||||
SEG::ecoord thisDist_squared = trackSeg.SquaredDistance( itemSeg );
|
int this_dist;
|
||||||
|
|
||||||
if( !minSeg || thisDist_squared < center2center_squared )
|
if( shape->Collide( &trackSeg, minClearance, &this_dist ) )
|
||||||
{
|
{
|
||||||
minSeg = itemSeg;
|
if( this_dist < actual )
|
||||||
center2center_squared = thisDist_squared;
|
{
|
||||||
|
actual = this_dist;
|
||||||
|
pos = (wxPoint) shape->Centre();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( center2center_squared < SEG::Square( center2centerAllowed ) )
|
if( actual < INT_MAX )
|
||||||
{
|
{
|
||||||
int actual = std::max( 0.0, sqrt( center2center_squared ) - widths );
|
|
||||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
||||||
m_clearanceSource,
|
m_clearanceSource,
|
||||||
MessageTextFromValue( userUnits(), minClearance, true ),
|
MessageTextFromValue( userUnits(), minClearance, true ),
|
||||||
MessageTextFromValue( userUnits(), actual, true ) );
|
MessageTextFromValue( userUnits(), std::max( 0, actual ), true ) );
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
drcItem->SetErrorMessage( m_msg );
|
||||||
drcItem->SetItems( track, aItem );
|
drcItem->SetItems( track, aItem );
|
||||||
|
|
||||||
wxPoint pos = GetLocation( track, minSeg.get() );
|
|
||||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, pos );
|
MARKER_PCB* marker = new MARKER_PCB( drcItem, pos );
|
||||||
addMarkerToPcb( aCommit, marker );
|
addMarkerToPcb( aCommit, marker );
|
||||||
}
|
}
|
||||||
|
@ -1073,42 +995,34 @@ void DRC::testCopperDrawItem( BOARD_COMMIT& aCommit, BOARD_ITEM* aItem )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int minClearance = pad->GetClearance( aItem, &m_clearanceSource );
|
int minClearance = pad->GetClearance( aItem, &m_clearanceSource );
|
||||||
int widths = itemWidth / 2;
|
int actual = INT_MAX;
|
||||||
int center2centerAllowed = minClearance + widths;
|
|
||||||
|
|
||||||
// Fast test to detect a pad candidate inside the text bounding box
|
// Fast test to detect a pad candidate inside the text bounding box
|
||||||
// Finer test (time consumming) is made only for pads near the text.
|
// Finer test (time consumming) is made only for pads near the text.
|
||||||
int bb_radius = pad->GetBoundingRadius() + minClearance;
|
int bb_radius = pad->GetBoundingRadius() + minClearance;
|
||||||
|
|
||||||
if( !rect_area.Collide( SEG( pad->GetPosition(), pad->GetPosition() ), bb_radius ) )
|
if( !bboxShape.Collide( SEG( pad->GetPosition(), pad->GetPosition() ), bb_radius ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
SHAPE_POLY_SET padOutline;
|
for( const std::shared_ptr<SHAPE>& aShape : pad->GetEffectiveShapes() )
|
||||||
pad->TransformShapeWithClearanceToPolygon( padOutline, 0 );
|
|
||||||
|
|
||||||
OPT<SEG> minSeg;
|
|
||||||
SEG::ecoord center2center_squared = 0;
|
|
||||||
|
|
||||||
for( const SEG& itemSeg : itemShape )
|
|
||||||
{
|
{
|
||||||
SEG::ecoord thisCenter2center_squared = padOutline.SquaredDistance( itemSeg );
|
for( const SHAPE* bShape : itemShapes )
|
||||||
|
|
||||||
if( !minSeg || thisCenter2center_squared < center2center_squared )
|
|
||||||
{
|
{
|
||||||
minSeg = itemSeg;
|
int this_dist;
|
||||||
center2center_squared = thisCenter2center_squared;
|
|
||||||
|
if( aShape->Collide( bShape, minClearance, &this_dist ) )
|
||||||
|
actual = std::min( actual, this_dist );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( center2center_squared < SEG::Square( center2centerAllowed ) )
|
if( actual < INT_MAX )
|
||||||
{
|
{
|
||||||
int actual = std::max( 0.0, sqrt( center2center_squared ) - widths );
|
|
||||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
||||||
m_clearanceSource,
|
m_clearanceSource,
|
||||||
MessageTextFromValue( userUnits(), minClearance, true ),
|
MessageTextFromValue( userUnits(), minClearance, true ),
|
||||||
MessageTextFromValue( userUnits(), actual, true ) );
|
MessageTextFromValue( userUnits(), std::max( 0, actual ), true ) );
|
||||||
|
|
||||||
drcItem->SetErrorMessage( m_msg );
|
drcItem->SetErrorMessage( m_msg );
|
||||||
drcItem->SetItems( pad, aItem );
|
drcItem->SetItems( pad, aItem );
|
||||||
|
@ -1117,6 +1031,9 @@ void DRC::testCopperDrawItem( BOARD_COMMIT& aCommit, BOARD_ITEM* aItem )
|
||||||
addMarkerToPcb( aCommit, marker );
|
addMarkerToPcb( aCommit, marker );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for( SHAPE* shape : itemShapes )
|
||||||
|
delete shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1217,15 +1134,6 @@ bool DRC::doPadToPadsDrc( BOARD_COMMIT& aCommit, D_PAD* aRefPad, D_PAD** aStart,
|
||||||
|
|
||||||
LSET layerMask = aRefPad->GetLayerSet() & all_cu;
|
LSET layerMask = aRefPad->GetLayerSet() & all_cu;
|
||||||
|
|
||||||
// For hole testing we use a dummy pad which is given the shape of the hole. Note that
|
|
||||||
// this pad must have a parent because some functions expect a non-null parent to find
|
|
||||||
// the pad's board.
|
|
||||||
MODULE dummymodule( m_pcb ); // Creates a dummy parent
|
|
||||||
D_PAD dummypad( &dummymodule );
|
|
||||||
|
|
||||||
// Ensure the hole is on all copper layers
|
|
||||||
dummypad.SetLayerSet( all_cu | dummypad.GetLayerSet() );
|
|
||||||
|
|
||||||
for( D_PAD** pad_list = aStart; pad_list<aEnd; ++pad_list )
|
for( D_PAD** pad_list = aStart; pad_list<aEnd; ++pad_list )
|
||||||
{
|
{
|
||||||
D_PAD* pad = *pad_list;
|
D_PAD* pad = *pad_list;
|
||||||
|
@ -1260,22 +1168,12 @@ bool DRC::doPadToPadsDrc( BOARD_COMMIT& aCommit, D_PAD* aRefPad, D_PAD** aStart,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Here, we must test clearance between holes and pads
|
|
||||||
* dummy pad size and shape is adjusted to pad drill size and shape
|
|
||||||
*/
|
|
||||||
if( pad->GetDrillSize().x )
|
if( pad->GetDrillSize().x )
|
||||||
{
|
{
|
||||||
// pad under testing has a hole, test this hole against pad reference
|
|
||||||
dummypad.SetPosition( pad->GetPosition() );
|
|
||||||
dummypad.SetSize( pad->GetDrillSize() );
|
|
||||||
dummypad.SetShape( pad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG ?
|
|
||||||
PAD_SHAPE_OVAL : PAD_SHAPE_CIRCLE );
|
|
||||||
dummypad.SetOrientation( pad->GetOrientation() );
|
|
||||||
|
|
||||||
int minClearance = aRefPad->GetClearance( nullptr, &m_clearanceSource );
|
int minClearance = aRefPad->GetClearance( nullptr, &m_clearanceSource );
|
||||||
int actual;
|
int actual;
|
||||||
|
|
||||||
if( !checkClearancePadToPad( aRefPad, &dummypad, minClearance, &actual ) )
|
if( aRefPad->Collide( pad->GetEffectiveHoleShape(), minClearance, &actual ) )
|
||||||
{
|
{
|
||||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
||||||
|
|
||||||
|
@ -1293,18 +1191,12 @@ bool DRC::doPadToPadsDrc( BOARD_COMMIT& aCommit, D_PAD* aRefPad, D_PAD** aStart,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( aRefPad->GetDrillSize().x ) // pad reference has a hole
|
if( aRefPad->GetDrillSize().x )
|
||||||
{
|
{
|
||||||
dummypad.SetPosition( aRefPad->GetPosition() );
|
|
||||||
dummypad.SetSize( aRefPad->GetDrillSize() );
|
|
||||||
dummypad.SetShape( aRefPad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG ?
|
|
||||||
PAD_SHAPE_OVAL : PAD_SHAPE_CIRCLE );
|
|
||||||
dummypad.SetOrientation( aRefPad->GetOrientation() );
|
|
||||||
|
|
||||||
int minClearance = pad->GetClearance( nullptr, &m_clearanceSource );
|
int minClearance = pad->GetClearance( nullptr, &m_clearanceSource );
|
||||||
int actual;
|
int actual;
|
||||||
|
|
||||||
if( !checkClearancePadToPad( pad, &dummypad, minClearance, &actual ) )
|
if( pad->Collide( aRefPad->GetEffectiveHoleShape(), minClearance, &actual ) )
|
||||||
{
|
{
|
||||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
||||||
|
|
||||||
|
@ -1353,7 +1245,7 @@ bool DRC::doPadToPadsDrc( BOARD_COMMIT& aCommit, D_PAD* aRefPad, D_PAD** aStart,
|
||||||
int clearanceAllowed = minClearance - m_pcb->GetDesignSettings().GetDRCEpsilon();
|
int clearanceAllowed = minClearance - m_pcb->GetDesignSettings().GetDRCEpsilon();
|
||||||
int actual;
|
int actual;
|
||||||
|
|
||||||
if( !checkClearancePadToPad( aRefPad, pad, clearanceAllowed, &actual ) )
|
if( aRefPad->Collide( pad, clearanceAllowed, &actual ) )
|
||||||
{
|
{
|
||||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
||||||
|
|
||||||
|
|
|
@ -219,38 +219,6 @@ private:
|
||||||
void doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
|
void doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
|
||||||
TRACKS::iterator aEndIt, bool aTestZones );
|
TRACKS::iterator aEndIt, bool aTestZones );
|
||||||
|
|
||||||
//-----<single tests>----------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param aRefPad The reference pad to check
|
|
||||||
* @param aPad Another pad to check against
|
|
||||||
* @param aMinClearance is the minimum allowed distance between the pads
|
|
||||||
* @param aActualDist [out] it the actual distance
|
|
||||||
* (only guaranteed to be set for violations)
|
|
||||||
* @return true if clearance between aRefPad and aPad is >= aMinClearance, else false
|
|
||||||
*/
|
|
||||||
bool checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad,
|
|
||||||
int aMinClearance, int* aActualDist );
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check the distance from a pad to segment. This function uses several
|
|
||||||
* instance variable not passed in:
|
|
||||||
* @param aPad Is the pad involved in the check
|
|
||||||
* @param aSegmentWidth width of the segment to test
|
|
||||||
* @param aMinDist Is the minimum clearance needed
|
|
||||||
* @param aActualDist [out] Is the actual clearance (only guarantted to be set on violations)
|
|
||||||
*
|
|
||||||
* @return true distance >= dist_min,
|
|
||||||
* false if distance < dist_min
|
|
||||||
*/
|
|
||||||
bool checkClearanceSegmToPad( const SEG& seg, int segWidth, const D_PAD* pad,
|
|
||||||
int minClearance, int* aActualDist );
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//-----</single tests>---------------------------------------------
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Load the DRC rules. Must be called after the netclasses have been read.
|
* Load the DRC rules. Must be called after the netclasses have been read.
|
||||||
|
|
|
@ -30,49 +30,10 @@
|
||||||
#include <class_track.h>
|
#include <class_track.h>
|
||||||
#include <class_drawsegment.h>
|
#include <class_drawsegment.h>
|
||||||
#include <class_marker_pcb.h>
|
#include <class_marker_pcb.h>
|
||||||
#include <math_for_graphics.h>
|
|
||||||
#include <geometry/polygon_test_point_inside.h>
|
#include <geometry/polygon_test_point_inside.h>
|
||||||
#include <convert_basic_shapes_to_polygon.h>
|
|
||||||
#include <geometry/shape_rect.h>
|
#include <geometry/shape_rect.h>
|
||||||
|
#include <geometry/shape_segment.h>
|
||||||
|
#include <convert_basic_shapes_to_polygon.h>
|
||||||
/*
|
|
||||||
* compare a trapezoid (can be rectangle) and a segment and return true if distance > aDist
|
|
||||||
*/
|
|
||||||
bool poly2segmentDRC( wxPoint* aTref, int aTrefCount, wxPoint aSegStart, wxPoint aSegEnd,
|
|
||||||
int aDist, int* aActual )
|
|
||||||
{
|
|
||||||
/* Test if the segment is contained in the polygon.
|
|
||||||
* This case is not covered by the following check if the segment is
|
|
||||||
* completely contained in the polygon (because edges don't intersect)!
|
|
||||||
*/
|
|
||||||
if( TestPointInsidePolygon( aTref, aTrefCount, aSegStart ) )
|
|
||||||
{
|
|
||||||
*aActual = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for( int ii = 0, jj = aTrefCount-1; ii < aTrefCount; jj = ii, ii++ )
|
|
||||||
{ // for all edges in polygon
|
|
||||||
double d;
|
|
||||||
|
|
||||||
if( TestForIntersectionOfStraightLineSegments( aTref[ii].x, aTref[ii].y, aTref[jj].x,
|
|
||||||
aTref[jj].y, aSegStart.x, aSegStart.y,
|
|
||||||
aSegEnd.x, aSegEnd.y, NULL, NULL, &d ) )
|
|
||||||
{
|
|
||||||
*aActual = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( d < aDist )
|
|
||||||
{
|
|
||||||
*aActual = KiROUND( d );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
|
void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
|
||||||
|
@ -80,7 +41,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
||||||
{
|
{
|
||||||
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
|
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
|
||||||
|
|
||||||
SEG refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
|
SHAPE_SEGMENT refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd(), aRefSeg->GetWidth() );
|
||||||
PCB_LAYER_ID refLayer = aRefSeg->GetLayer();
|
PCB_LAYER_ID refLayer = aRefSeg->GetLayer();
|
||||||
LSET refLayerSet = aRefSeg->GetLayerSet();
|
LSET refLayerSet = aRefSeg->GetLayerSet();
|
||||||
|
|
||||||
|
@ -319,18 +280,11 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
||||||
|
|
||||||
if( pad->GetDrillSize().x > 0 )
|
if( pad->GetDrillSize().x > 0 )
|
||||||
{
|
{
|
||||||
// For hole testing we use a dummy pad which is a copy of the current pad
|
const SHAPE_SEGMENT* slot = pad->GetEffectiveHoleShape();
|
||||||
// shrunk down to nothing but its hole.
|
DRC_RULE* rule = GetRule( aRefSeg, pad, CLEARANCE_CONSTRAINT );
|
||||||
D_PAD dummypad( *pad );
|
|
||||||
dummypad.SetSize( pad->GetDrillSize() );
|
|
||||||
dummypad.SetShape( pad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG ?
|
|
||||||
PAD_SHAPE_OVAL : PAD_SHAPE_CIRCLE );
|
|
||||||
// Ensure the hole is on all copper layers
|
|
||||||
const static LSET all_cu = LSET::AllCuMask();
|
|
||||||
dummypad.SetLayerSet( all_cu | dummypad.GetLayerSet() );
|
|
||||||
|
|
||||||
int minClearance;
|
int minClearance;
|
||||||
DRC_RULE* rule = GetRule( aRefSeg, &dummypad, CLEARANCE_CONSTRAINT );
|
int actual;
|
||||||
|
|
||||||
if( rule )
|
if( rule )
|
||||||
{
|
{
|
||||||
|
@ -342,27 +296,8 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
||||||
minClearance = aRefSeg->GetClearance( nullptr, &m_clearanceSource );
|
minClearance = aRefSeg->GetClearance( nullptr, &m_clearanceSource );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Treat an oval hole as a line segment along the hole's major axis,
|
if( slot->Collide( &refSeg, minClearance + bds.GetDRCEpsilon(), &actual ) )
|
||||||
* shortened by half its minor axis.
|
|
||||||
* A circular hole is just a degenerate case of an oval hole.
|
|
||||||
*/
|
|
||||||
wxPoint slotStart, slotEnd;
|
|
||||||
int slotWidth;
|
|
||||||
|
|
||||||
pad->GetOblongGeometry( pad->GetDrillSize(), &slotStart, &slotEnd, &slotWidth );
|
|
||||||
slotStart += pad->GetPosition();
|
|
||||||
slotEnd += pad->GetPosition();
|
|
||||||
|
|
||||||
SEG slotSeg( slotStart, slotEnd );
|
|
||||||
int widths = ( slotWidth + refSegWidth ) / 2;
|
|
||||||
int center2centerAllowed = minClearance + widths + bds.GetDRCEpsilon();
|
|
||||||
|
|
||||||
// Avoid square-roots if possible (for performance)
|
|
||||||
SEG::ecoord center2center_squared = refSeg.SquaredDistance( slotSeg );
|
|
||||||
|
|
||||||
if( center2center_squared < SEG::Square( center2centerAllowed ) )
|
|
||||||
{
|
{
|
||||||
int actual = std::max( 0.0, sqrt( center2center_squared ) - widths );
|
|
||||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
||||||
|
@ -373,7 +308,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
||||||
drcItem->SetErrorMessage( m_msg );
|
drcItem->SetErrorMessage( m_msg );
|
||||||
drcItem->SetItems( aRefSeg, pad );
|
drcItem->SetItems( aRefSeg, pad );
|
||||||
|
|
||||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, GetLocation( aRefSeg, slotSeg ) );
|
MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() );
|
||||||
addMarkerToPcb( aCommit, marker );
|
addMarkerToPcb( aCommit, marker );
|
||||||
|
|
||||||
if( !m_reportAllTrackErrors )
|
if( !m_reportAllTrackErrors )
|
||||||
|
@ -382,13 +317,10 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
||||||
}
|
}
|
||||||
|
|
||||||
int minClearance = aRefSeg->GetClearance( pad, &m_clearanceSource );
|
int minClearance = aRefSeg->GetClearance( pad, &m_clearanceSource );
|
||||||
int clearanceAllowed = minClearance - bds.GetDRCEpsilon();
|
|
||||||
int actual;
|
int actual;
|
||||||
|
|
||||||
if( !checkClearanceSegmToPad( refSeg, refSegWidth, pad, clearanceAllowed, &actual ) )
|
if( pad->Collide( &refSeg, minClearance - bds.GetDRCEpsilon(), &actual ) )
|
||||||
{
|
{
|
||||||
actual = std::max( 0, actual );
|
|
||||||
SEG padSeg( pad->GetPosition(), pad->GetPosition() );
|
|
||||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
||||||
|
@ -399,7 +331,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
||||||
drcItem->SetErrorMessage( m_msg );
|
drcItem->SetErrorMessage( m_msg );
|
||||||
drcItem->SetItems( aRefSeg, pad );
|
drcItem->SetItems( aRefSeg, pad );
|
||||||
|
|
||||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, GetLocation( aRefSeg, padSeg ) );
|
MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() );
|
||||||
addMarkerToPcb( aCommit, marker );
|
addMarkerToPcb( aCommit, marker );
|
||||||
|
|
||||||
if( !m_reportAllTrackErrors )
|
if( !m_reportAllTrackErrors )
|
||||||
|
@ -452,16 +384,11 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int minClearance = aRefSeg->GetClearance( track, &m_clearanceSource );
|
int minClearance = aRefSeg->GetClearance( track, &m_clearanceSource );
|
||||||
SEG trackSeg( track->GetStart(), track->GetEnd() );
|
int actual;
|
||||||
int widths = ( refSegWidth + track->GetWidth() ) / 2;
|
SHAPE_SEGMENT trackSeg( track->GetStart(), track->GetEnd(), track->GetWidth() );
|
||||||
int center2centerAllowed = minClearance + widths;
|
|
||||||
|
|
||||||
// Avoid square-roots if possible (for performance)
|
|
||||||
SEG::ecoord center2center_squared = refSeg.SquaredDistance( trackSeg );
|
|
||||||
OPT_VECTOR2I intersection = refSeg.Intersect( trackSeg );
|
|
||||||
|
|
||||||
// Check two tracks crossing first as it reports a DRCE without distances
|
// Check two tracks crossing first as it reports a DRCE without distances
|
||||||
if( intersection )
|
if( OPT_VECTOR2I intersection = refSeg.GetSeg().Intersect( trackSeg.GetSeg() ) )
|
||||||
{
|
{
|
||||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TRACKS_CROSSING );
|
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TRACKS_CROSSING );
|
||||||
drcItem->SetErrorMessage( m_msg );
|
drcItem->SetErrorMessage( m_msg );
|
||||||
|
@ -473,9 +400,9 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
||||||
if( !m_reportAllTrackErrors )
|
if( !m_reportAllTrackErrors )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if( center2center_squared < SEG::Square( center2centerAllowed ) )
|
else if( refSeg.Collide( &trackSeg, minClearance, &actual ) )
|
||||||
{
|
{
|
||||||
int actual = std::max( 0.0, sqrt( center2center_squared ) - widths );
|
wxPoint pos = GetLocation( aRefSeg, trackSeg.GetSeg() );
|
||||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
||||||
|
@ -486,7 +413,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
||||||
drcItem->SetErrorMessage( m_msg );
|
drcItem->SetErrorMessage( m_msg );
|
||||||
drcItem->SetItems( aRefSeg, track );
|
drcItem->SetItems( aRefSeg, track );
|
||||||
|
|
||||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, GetLocation( aRefSeg, trackSeg ) );
|
MARKER_PCB* marker = new MARKER_PCB( drcItem, pos );
|
||||||
addMarkerToPcb( aCommit, marker );
|
addMarkerToPcb( aCommit, marker );
|
||||||
|
|
||||||
if( !m_reportAllTrackErrors )
|
if( !m_reportAllTrackErrors )
|
||||||
|
@ -515,22 +442,19 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
||||||
if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() )
|
if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int minClearance = aRefSeg->GetClearance( zone, &m_clearanceSource );
|
|
||||||
int widths = refSegWidth / 2;
|
|
||||||
int center2centerAllowed = minClearance + widths;
|
|
||||||
SHAPE_POLY_SET* outline =
|
|
||||||
const_cast<SHAPE_POLY_SET*>( &zone->GetFilledPolysList( layer ) );
|
|
||||||
|
|
||||||
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( center2center_squared + THRESHOLD_DIST < SEG::Square( center2centerAllowed ) )
|
int minClearance = aRefSeg->GetClearance( zone, &m_clearanceSource );
|
||||||
|
int widths = refSegWidth / 2;
|
||||||
|
int allowedDist = minClearance + widths + THRESHOLD_DIST;
|
||||||
|
int actual;
|
||||||
|
|
||||||
|
if( zone->GetFilledPolysList( layer ).Collide( testSeg, allowedDist, &actual ) )
|
||||||
{
|
{
|
||||||
int actual = std::max( 0.0, sqrt( center2center_squared ) - widths );
|
actual = std::max( 0, actual - widths );
|
||||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
||||||
|
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
||||||
|
@ -616,119 +540,3 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad, int aMinClearance, int* aActual )
|
|
||||||
{
|
|
||||||
int center2center = KiROUND( EuclideanNorm( aPad->ShapePos() - aRefPad->ShapePos() ) );
|
|
||||||
|
|
||||||
// Quick test: Clearance is OK if the bounding circles are further away than aMinClearance
|
|
||||||
if( center2center - aRefPad->GetBoundingRadius() - aPad->GetBoundingRadius() >= aMinClearance )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
int actual = INT_MAX;
|
|
||||||
|
|
||||||
for( const std::shared_ptr<SHAPE>& aShape : aRefPad->GetEffectiveShapes() )
|
|
||||||
{
|
|
||||||
for( const std::shared_ptr<SHAPE>& bShape : aPad->GetEffectiveShapes() )
|
|
||||||
{
|
|
||||||
int this_dist;
|
|
||||||
|
|
||||||
if( aShape->Collide( bShape.get(), aMinClearance, &this_dist ) )
|
|
||||||
actual = std::min( actual, this_dist );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( actual < INT_MAX )
|
|
||||||
{
|
|
||||||
// returns the actual clearance (clearance < aMinClearance) for diags:
|
|
||||||
if( aActual )
|
|
||||||
*aActual = std::max( 0, actual );
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test if distance between a segment and a pad is > minClearance. Return the actual
|
|
||||||
* distance if it is less.
|
|
||||||
*/
|
|
||||||
bool DRC::checkClearanceSegmToPad( const SEG& refSeg, int refSegWidth, const D_PAD* pad,
|
|
||||||
int minClearance, int* aActualDist )
|
|
||||||
{
|
|
||||||
if( ( pad->GetShape() == PAD_SHAPE_CIRCLE || pad->GetShape() == PAD_SHAPE_OVAL ) )
|
|
||||||
{
|
|
||||||
/* Treat an oval pad as a line segment along the hole's major axis,
|
|
||||||
* shortened by half its minor axis.
|
|
||||||
* A circular pad is just a degenerate case of an oval hole.
|
|
||||||
*/
|
|
||||||
wxPoint padStart, padEnd;
|
|
||||||
int padWidth;
|
|
||||||
|
|
||||||
pad->GetOblongGeometry( pad->GetSize(), &padStart, &padEnd, &padWidth );
|
|
||||||
padStart += pad->ShapePos();
|
|
||||||
padEnd += pad->ShapePos();
|
|
||||||
|
|
||||||
SEG padSeg( padStart, padEnd );
|
|
||||||
int widths = ( padWidth + refSegWidth ) / 2;
|
|
||||||
int center2centerAllowed = minClearance + widths;
|
|
||||||
|
|
||||||
// Avoid square-roots if possible (for performance)
|
|
||||||
SEG::ecoord center2center_squared = refSeg.SquaredDistance( padSeg );
|
|
||||||
|
|
||||||
if( center2center_squared < SEG::Square( center2centerAllowed ) )
|
|
||||||
{
|
|
||||||
*aActualDist = std::max( 0.0, sqrt( center2center_squared ) - widths );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( ( pad->GetShape() == PAD_SHAPE_RECT || pad->GetShape() == PAD_SHAPE_ROUNDRECT )
|
|
||||||
&& ( (int) pad->GetOrientation() % 900 == 0 ) )
|
|
||||||
{
|
|
||||||
EDA_RECT padBBox = pad->GetBoundingBox();
|
|
||||||
int widths = refSegWidth / 2;
|
|
||||||
|
|
||||||
// Note a ROUNDRECT pad with a corner radius = r can be treated as a smaller
|
|
||||||
// RECT (size - 2*r) with a clearance increased by r
|
|
||||||
if( pad->GetShape() == PAD_SHAPE_ROUNDRECT )
|
|
||||||
{
|
|
||||||
padBBox.Inflate( - pad->GetRoundRectCornerRadius() );
|
|
||||||
widths += pad->GetRoundRectCornerRadius();
|
|
||||||
}
|
|
||||||
|
|
||||||
SHAPE_RECT padShape( padBBox.GetPosition(), padBBox.GetWidth(), padBBox.GetHeight() );
|
|
||||||
int actual;
|
|
||||||
|
|
||||||
if( padShape.Collide( refSeg, minClearance + widths, &actual ) )
|
|
||||||
{
|
|
||||||
*aActualDist = std::max( 0, actual - widths );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // Convert the rest to polygons
|
|
||||||
{
|
|
||||||
SHAPE_POLY_SET polyset;
|
|
||||||
|
|
||||||
BOARD* board = pad->GetBoard();
|
|
||||||
int maxError = board ? board->GetDesignSettings().m_MaxError : ARC_HIGH_DEF;
|
|
||||||
|
|
||||||
pad->TransformShapeWithClearanceToPolygon( polyset, 0, maxError );
|
|
||||||
|
|
||||||
const SHAPE_LINE_CHAIN& refpoly = polyset.COutline( 0 );
|
|
||||||
int widths = refSegWidth / 2;
|
|
||||||
int actual;
|
|
||||||
|
|
||||||
if( !poly2segmentDRC( (wxPoint*) &refpoly.CPoint( 0 ), refpoly.PointCount(),
|
|
||||||
(wxPoint) refSeg.A, (wxPoint) refSeg.B,
|
|
||||||
minClearance + widths, &actual ) )
|
|
||||||
{
|
|
||||||
*aActualDist = std::max( 0, actual - widths );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -23,12 +23,11 @@
|
||||||
|
|
||||||
|
|
||||||
#include <drc/drc_keepout_tester.h>
|
#include <drc/drc_keepout_tester.h>
|
||||||
|
#include <geometry/shape_segment.h>
|
||||||
#include <class_module.h>
|
#include <class_module.h>
|
||||||
#include <drc/drc.h>
|
#include <drc/drc.h>
|
||||||
#include <drc/drc_item.h>
|
#include <drc/drc_item.h>
|
||||||
|
|
||||||
|
|
||||||
DRC_KEEPOUT_TESTER::DRC_KEEPOUT_TESTER( MARKER_HANDLER aMarkerHandler ) :
|
DRC_KEEPOUT_TESTER::DRC_KEEPOUT_TESTER( MARKER_HANDLER aMarkerHandler ) :
|
||||||
DRC_TEST_PROVIDER( std::move( aMarkerHandler ) ),
|
DRC_TEST_PROVIDER( std::move( aMarkerHandler ) ),
|
||||||
m_units( EDA_UNITS::MILLIMETRES ),
|
m_units( EDA_UNITS::MILLIMETRES ),
|
||||||
|
@ -91,11 +90,9 @@ bool DRC_KEEPOUT_TESTER::checkTracksAndVias()
|
||||||
if( !m_zone->IsOnLayer( segm->GetLayer() ) )
|
if( !m_zone->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 = m_zone->Outline()->SquaredDistance( trackSeg );
|
|
||||||
|
|
||||||
if( center2center_squared <= SEG::Square( widths) )
|
if( m_zone->Outline()->Collide( trackSeg, segm->GetWidth() / 2 ) )
|
||||||
{
|
{
|
||||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_KEEPOUT );
|
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_KEEPOUT );
|
||||||
|
|
||||||
|
@ -112,41 +109,36 @@ bool DRC_KEEPOUT_TESTER::checkTracksAndVias()
|
||||||
else if( segm->Type() == PCB_VIA_T && ( m_keepoutFlags & CHECK_VIAS_MASK ) != 0 )
|
else if( segm->Type() == PCB_VIA_T && ( m_keepoutFlags & CHECK_VIAS_MASK ) != 0 )
|
||||||
{
|
{
|
||||||
VIA* via = static_cast<VIA*>( segm );
|
VIA* via = static_cast<VIA*>( segm );
|
||||||
int sourceId = 0;
|
SEG seg( via->GetPosition(), via->GetPosition() );
|
||||||
|
int test = 0;
|
||||||
|
int clearance = via->GetWidth() / 2;
|
||||||
|
|
||||||
if( ( m_keepoutFlags & DISALLOW_VIAS ) > 0 )
|
if( ( m_keepoutFlags & DISALLOW_VIAS ) > 0 )
|
||||||
{
|
{
|
||||||
sourceId = DISALLOW_VIAS;
|
test = DISALLOW_VIAS;
|
||||||
}
|
}
|
||||||
else if( via->GetViaType() == VIATYPE::MICROVIA
|
else if( via->GetViaType() == VIATYPE::MICROVIA
|
||||||
&& ( m_keepoutFlags & DISALLOW_MICRO_VIAS ) > 0 )
|
&& ( m_keepoutFlags & DISALLOW_MICRO_VIAS ) > 0 )
|
||||||
{
|
{
|
||||||
sourceId = DISALLOW_MICRO_VIAS;
|
test = DISALLOW_MICRO_VIAS;
|
||||||
}
|
}
|
||||||
else if( via->GetViaType() == VIATYPE::BLIND_BURIED
|
else if( via->GetViaType() == VIATYPE::BLIND_BURIED
|
||||||
&& ( m_keepoutFlags & DISALLOW_BB_VIAS ) > 0 )
|
&& ( m_keepoutFlags & DISALLOW_BB_VIAS ) > 0 )
|
||||||
{
|
{
|
||||||
sourceId = DISALLOW_BB_VIAS;
|
test = DISALLOW_BB_VIAS;
|
||||||
}
|
}
|
||||||
else if( ( m_keepoutFlags & DISALLOW_HOLES ) > 0 )
|
else if( ( m_keepoutFlags & DISALLOW_HOLES ) > 0 )
|
||||||
{
|
{
|
||||||
sourceId = DISALLOW_HOLES;
|
test = DISALLOW_HOLES;
|
||||||
|
clearance = via->GetDrillValue() / 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int widths = via->GetWidth() / 2;
|
if( m_zone->Outline()->Collide( seg, clearance ) )
|
||||||
wxPoint viaPos = via->GetPosition();
|
|
||||||
|
|
||||||
if( sourceId == DISALLOW_HOLES )
|
|
||||||
widths = via->GetDrillValue() / 2;
|
|
||||||
|
|
||||||
SEG::ecoord center2center_squared = m_zone->Outline()->SquaredDistance( viaPos );
|
|
||||||
|
|
||||||
if( center2center_squared <= SEG::Square( widths ) )
|
|
||||||
{
|
{
|
||||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_KEEPOUT );
|
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_KEEPOUT );
|
||||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s)" ), m_sources.at( sourceId ) );
|
m_msg.Printf( drcItem->GetErrorText() + _( " (%s)" ), m_sources.at( test ) );
|
||||||
drcItem->SetErrorMessage( m_msg );
|
drcItem->SetErrorMessage( m_msg );
|
||||||
drcItem->SetItems( segm, m_zone );
|
drcItem->SetItems( segm, m_zone );
|
||||||
|
|
||||||
|
@ -259,18 +251,9 @@ bool DRC_KEEPOUT_TESTER::checkPads( MODULE* aModule )
|
||||||
}
|
}
|
||||||
else if( ( m_keepoutFlags & DISALLOW_HOLES ) > 0 )
|
else if( ( m_keepoutFlags & DISALLOW_HOLES ) > 0 )
|
||||||
{
|
{
|
||||||
wxPoint slotStart, slotEnd;
|
const SHAPE_SEGMENT* slot = pad->GetEffectiveHoleShape();
|
||||||
int slotWidth;
|
|
||||||
|
|
||||||
pad->GetOblongGeometry( pad->GetDrillSize(), &slotStart, &slotEnd, &slotWidth );
|
if( m_zone->Outline()->Collide( slot->GetSeg(), slot->GetWidth() / 2 ) )
|
||||||
slotStart += pad->GetPosition();
|
|
||||||
slotEnd += pad->GetPosition();
|
|
||||||
|
|
||||||
SEG slotSeg( slotStart, slotEnd );
|
|
||||||
SHAPE_POLY_SET* outline = m_zone->Outline();
|
|
||||||
SEG::ecoord center2center_sq = outline->SquaredDistance( slotSeg );
|
|
||||||
|
|
||||||
if( center2center_sq <= SEG::Square( slotWidth) )
|
|
||||||
{
|
{
|
||||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_KEEPOUT );
|
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_KEEPOUT );
|
||||||
|
|
||||||
|
|
|
@ -765,8 +765,7 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
|
||||||
// Choose drawing settings depending on if we are drawing a pad itself or a hole
|
// Choose drawing settings depending on if we are drawing a pad itself or a hole
|
||||||
if( aLayer == LAYER_PADS_PLATEDHOLES || aLayer == LAYER_NON_PLATEDHOLES )
|
if( aLayer == LAYER_PADS_PLATEDHOLES || aLayer == LAYER_NON_PLATEDHOLES )
|
||||||
{
|
{
|
||||||
const std::shared_ptr<SHAPE_SEGMENT>& seg = aPad->GetEffectiveHoleShape();
|
const SHAPE_SEGMENT* seg = aPad->GetEffectiveHoleShape();
|
||||||
|
|
||||||
m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B, seg->GetWidth() );
|
m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B, seg->GetWidth() );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -698,7 +698,7 @@ void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Note: small drill marks have no significance when applied to slots
|
// Note: small drill marks have no significance when applied to slots
|
||||||
const std::shared_ptr<SHAPE_SEGMENT>& seg = pad->GetEffectiveHoleShape();
|
const SHAPE_SEGMENT* seg = pad->GetEffectiveHoleShape();
|
||||||
aPlotter->ThickSegment( (wxPoint) seg->GetSeg().A,
|
aPlotter->ThickSegment( (wxPoint) seg->GetSeg().A,
|
||||||
(wxPoint) seg->GetSeg().B,
|
(wxPoint) seg->GetSeg().B,
|
||||||
seg->GetWidth(), SKETCH, NULL );
|
seg->GetWidth(), SKETCH, NULL );
|
||||||
|
|
Loading…
Reference in New Issue