Updating DRC to handle vias with differing layers
This commit is contained in:
parent
9a66a5acad
commit
41edf5c5bf
|
@ -592,7 +592,15 @@ void DRC::testTracks( BOARD_COMMIT& aCommit, wxWindow *aActiveWindow, bool aShow
|
|||
}
|
||||
|
||||
// Test new segment against tracks and pads, optionally against copper zones
|
||||
doTrackDrc( aCommit, *seg_it, seg_it + 1, m_pcb->Tracks().end(), m_testTracksAgainstZones );
|
||||
LSEQ layer_seq = ( *seg_it )->GetLayerSet().Seq();
|
||||
|
||||
if( ( *seg_it )->Type() == PCB_VIA_T )
|
||||
doSingleViaDRC( aCommit, static_cast<VIA*>( *seg_it ) );
|
||||
else
|
||||
doSingleTrackDRC( aCommit, *seg_it );
|
||||
|
||||
for( PCB_LAYER_ID layer : layer_seq )
|
||||
doTrackDrc( aCommit, *seg_it, seg_it + 1, m_pcb->Tracks().end(), m_testTracksAgainstZones, layer );
|
||||
|
||||
// Test for dangling items
|
||||
int code = (*seg_it)->Type() == PCB_VIA_T ? DRCE_DANGLING_VIA : DRCE_DANGLING_TRACK;
|
||||
|
|
|
@ -213,11 +213,28 @@ private:
|
|||
* @param aStartIt the iterator to the first track to test
|
||||
* @param aEndIt the marker for the iterator end
|
||||
* @param aTestZones true if should do copper zones test. This can be very time consumming
|
||||
* @param aLayer sets the layer to test against
|
||||
* @return bool - true if no problems, else false and m_currentMarker is
|
||||
* filled in with the problem information.
|
||||
*/
|
||||
void doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
|
||||
TRACKS::iterator aEndIt, bool aTestZones );
|
||||
TRACKS::iterator aEndIt, bool aTestZones, PCB_LAYER_ID aLayer );
|
||||
|
||||
/**
|
||||
* Test a single via for DRC errors
|
||||
*
|
||||
* @param aCommit The board commit to add DRC errors
|
||||
* @param aRefVia The via to test against design settings
|
||||
*/
|
||||
void doSingleViaDRC( BOARD_COMMIT& aCommit, VIA* aRefVia );
|
||||
|
||||
/**
|
||||
* Test a single track segment for DRC errors
|
||||
*
|
||||
* @param aCommit The board commit to add DRC errors
|
||||
* @param aRefSeg The track to test against design settings
|
||||
*/
|
||||
void doSingleTrackDRC( BOARD_COMMIT& aCommit, TRACK* aRefSeg );
|
||||
|
||||
public:
|
||||
/**
|
||||
|
|
|
@ -35,20 +35,178 @@
|
|||
#include <geometry/shape_segment.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
|
||||
|
||||
void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
|
||||
TRACKS::iterator aEndIt, bool aTestZones )
|
||||
void DRC::doSingleViaDRC( BOARD_COMMIT& aCommit, VIA* aRefVia )
|
||||
{
|
||||
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
|
||||
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
|
||||
|
||||
// test if the via size is smaller than minimum
|
||||
if( aRefVia->GetViaType() == VIATYPE::MICROVIA )
|
||||
{
|
||||
if( aRefVia->GetWidth() < bds.m_MicroViasMinSize )
|
||||
{
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_MICROVIA );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
|
||||
MessageTextFromValue( userUnits(), bds.m_MicroViasMinSize, true ),
|
||||
MessageTextFromValue( userUnits(), aRefVia->GetWidth(), true ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( aRefVia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( aRefVia->GetWidth() < bds.m_ViasMinSize )
|
||||
{
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_VIA );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
|
||||
MessageTextFromValue( userUnits(), bds.m_ViasMinSize, true ),
|
||||
MessageTextFromValue( userUnits(), aRefVia->GetWidth(), true ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( aRefVia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
}
|
||||
|
||||
// test if via's hole is bigger than its diameter
|
||||
// This test is necessary since the via hole size and width can be modified
|
||||
// and a default via hole can be bigger than some vias sizes
|
||||
if( aRefVia->GetDrillValue() > aRefVia->GetWidth() )
|
||||
{
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_VIA_HOLE_BIGGER );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (diameter %s; drill %s)" ),
|
||||
MessageTextFromValue( userUnits(), aRefVia->GetWidth(), true ),
|
||||
MessageTextFromValue( userUnits(), aRefVia->GetDrillValue(), true ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( aRefVia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
|
||||
// test if the type of via is allowed due to design rules
|
||||
if( aRefVia->GetViaType() == VIATYPE::MICROVIA && !bds.m_MicroViasAllowed )
|
||||
{
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_ALLOWED_ITEMS );
|
||||
|
||||
m_msg.Printf( _( "Microvia not allowed (board design rule constraints)" ) );
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( aRefVia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
|
||||
// test if the type of via is allowed due to design rules
|
||||
if( aRefVia->GetViaType() == VIATYPE::BLIND_BURIED && !bds.m_BlindBuriedViaAllowed )
|
||||
{
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_ALLOWED_ITEMS );
|
||||
|
||||
m_msg.Printf( _( "Blind/buried via not allowed (board design rule constraints)" ) );
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( aRefVia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
|
||||
// For microvias: test if they are blind vias and only between 2 layers
|
||||
// because they are used for very small drill size and are drill by laser
|
||||
// and **only one layer** can be drilled
|
||||
if( aRefVia->GetViaType() == VIATYPE::MICROVIA )
|
||||
{
|
||||
PCB_LAYER_ID layer1, layer2;
|
||||
bool err = true;
|
||||
|
||||
aRefVia->LayerPair( &layer1, &layer2 );
|
||||
|
||||
if( layer1 > layer2 )
|
||||
std::swap( layer1, layer2 );
|
||||
|
||||
if( layer2 == B_Cu && layer1 == bds.GetCopperLayerCount() - 2 )
|
||||
err = false;
|
||||
else if( layer1 == F_Cu && layer2 == In1_Cu )
|
||||
err = false;
|
||||
|
||||
if( err )
|
||||
{
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_PADSTACK );
|
||||
|
||||
m_msg.Printf( _( "Microvia through too many layers (%s and %s not adjacent)" ),
|
||||
m_pcb->GetLayerName( layer1 ),
|
||||
m_pcb->GetLayerName( layer2 ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( aRefVia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DRC::doSingleTrackDRC( BOARD_COMMIT& aCommit, TRACK* aRefSeg )
|
||||
{
|
||||
SHAPE_SEGMENT refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd(), aRefSeg->GetWidth() );
|
||||
PCB_LAYER_ID refLayer = aRefSeg->GetLayer();
|
||||
LSET refLayerSet = aRefSeg->GetLayerSet();
|
||||
|
||||
EDA_RECT refSegBB = aRefSeg->GetBoundingBox();
|
||||
int refSegWidth = aRefSeg->GetWidth();
|
||||
|
||||
int minWidth, maxWidth;
|
||||
aRefSeg->GetWidthConstraints( &minWidth, &maxWidth, &m_clearanceSource );
|
||||
|
||||
int errorCode = 0;
|
||||
int constraintWidth;
|
||||
|
||||
if( refSegWidth < minWidth )
|
||||
{
|
||||
errorCode = DRCE_TRACK_WIDTH;
|
||||
constraintWidth = minWidth;
|
||||
}
|
||||
else if( refSegWidth > maxWidth )
|
||||
{
|
||||
errorCode = DRCE_TRACK_WIDTH;
|
||||
constraintWidth = maxWidth;
|
||||
}
|
||||
|
||||
if( errorCode )
|
||||
{
|
||||
wxPoint refsegMiddle = ( aRefSeg->GetStart() + aRefSeg->GetEnd() ) / 2;
|
||||
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( errorCode );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
|
||||
m_clearanceSource,
|
||||
MessageTextFromValue( userUnits(), constraintWidth, true ),
|
||||
MessageTextFromValue( userUnits(), refSegWidth, true ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( aRefSeg );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refsegMiddle );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
|
||||
TRACKS::iterator aEndIt, bool aTestZones, PCB_LAYER_ID aLayer )
|
||||
{
|
||||
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
|
||||
SHAPE_SEGMENT refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd(), aRefSeg->GetWidth() );
|
||||
|
||||
EDA_RECT refSegBB = aRefSeg->GetBoundingBox();
|
||||
SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
|
||||
int halfWidth = ( aRefSeg->GetWidth() + 1 ) / 2;
|
||||
|
||||
/******************************************/
|
||||
/* Phase 0 : via DRC tests : */
|
||||
|
@ -56,9 +214,16 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
|
||||
if( aRefSeg->Type() == PCB_VIA_T )
|
||||
{
|
||||
VIA *refvia = static_cast<VIA*>( aRefSeg );
|
||||
VIA* refvia = static_cast<VIA*>( aRefSeg );
|
||||
int viaAnnulus = ( refvia->GetWidth() - refvia->GetDrill() ) / 2;
|
||||
int minAnnulus = refvia->GetMinAnnulus( refvia->GetLayer(), &m_clearanceSource );
|
||||
int minAnnulus = refvia->GetMinAnnulus( aLayer, &m_clearanceSource );
|
||||
|
||||
if( !refvia->IsPadOnLayer( aLayer ) )
|
||||
{
|
||||
halfWidth = ( refvia->GetDrillValue() + 1 ) / 2;
|
||||
refSegBB = EDA_RECT( refvia->GetStart(),
|
||||
wxSize( refvia->GetDrillValue(), refvia->GetDrillValue() ) );
|
||||
}
|
||||
|
||||
// test if the via size is smaller than minimum
|
||||
if( refvia->GetViaType() == VIATYPE::MICROVIA )
|
||||
|
@ -78,21 +243,6 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
|
||||
if( refvia->GetWidth() < bds.m_MicroViasMinSize )
|
||||
{
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_MICROVIA );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
|
||||
MessageTextFromValue( userUnits(), bds.m_MicroViasMinSize, true ),
|
||||
MessageTextFromValue( userUnits(), refvia->GetWidth(), true ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( refvia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -117,140 +267,9 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
|
||||
if( refvia->GetWidth() < bds.m_ViasMinSize )
|
||||
{
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_VIA );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
|
||||
MessageTextFromValue( userUnits(), bds.m_ViasMinSize, true ),
|
||||
MessageTextFromValue( userUnits(), refvia->GetWidth(), true ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( refvia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
}
|
||||
|
||||
// test if via's hole is bigger than its diameter
|
||||
// This test is necessary since the via hole size and width can be modified
|
||||
// and a default via hole can be bigger than some vias sizes
|
||||
if( refvia->GetDrillValue() > refvia->GetWidth() )
|
||||
{
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_VIA_HOLE_BIGGER );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (diameter %s; drill %s)" ),
|
||||
MessageTextFromValue( userUnits(), refvia->GetWidth(), true ),
|
||||
MessageTextFromValue( userUnits(), refvia->GetDrillValue(), true ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( refvia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
|
||||
// test if the type of via is allowed due to design rules
|
||||
if( refvia->GetViaType() == VIATYPE::MICROVIA && !bds.m_MicroViasAllowed )
|
||||
{
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_ALLOWED_ITEMS );
|
||||
|
||||
m_msg.Printf( _( "Microvia not allowed (board design rule constraints)" ) );
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( refvia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
|
||||
// test if the type of via is allowed due to design rules
|
||||
if( refvia->GetViaType() == VIATYPE::BLIND_BURIED && !bds.m_BlindBuriedViaAllowed )
|
||||
{
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_ALLOWED_ITEMS );
|
||||
|
||||
m_msg.Printf( _( "Blind/buried via not allowed (board design rule constraints)" ) );
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( refvia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
|
||||
// For microvias: test if they are blind vias and only between 2 layers
|
||||
// because they are used for very small drill size and are drill by laser
|
||||
// and **only one layer** can be drilled
|
||||
if( refvia->GetViaType() == VIATYPE::MICROVIA )
|
||||
{
|
||||
PCB_LAYER_ID layer1, layer2;
|
||||
bool err = true;
|
||||
|
||||
refvia->LayerPair( &layer1, &layer2 );
|
||||
|
||||
if( layer1 > layer2 )
|
||||
std::swap( layer1, layer2 );
|
||||
|
||||
if( layer2 == B_Cu && layer1 == bds.GetCopperLayerCount() - 2 )
|
||||
err = false;
|
||||
else if( layer1 == F_Cu && layer2 == In1_Cu )
|
||||
err = false;
|
||||
|
||||
if( err )
|
||||
{
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_PADSTACK );
|
||||
|
||||
m_msg.Printf( _( "Microvia through too many layers (%s and %s not adjacent)" ),
|
||||
m_pcb->GetLayerName( layer1 ),
|
||||
m_pcb->GetLayerName( layer2 ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( refvia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else // This is a track segment
|
||||
{
|
||||
int minWidth, maxWidth;
|
||||
aRefSeg->GetWidthConstraints( &minWidth, &maxWidth, &m_clearanceSource );
|
||||
|
||||
int errorCode = 0;
|
||||
int constraintWidth;
|
||||
|
||||
if( refSegWidth < minWidth )
|
||||
{
|
||||
errorCode = DRCE_TRACK_WIDTH;
|
||||
constraintWidth = minWidth;
|
||||
}
|
||||
else if( refSegWidth > maxWidth )
|
||||
{
|
||||
errorCode = DRCE_TRACK_WIDTH;
|
||||
constraintWidth = maxWidth;
|
||||
}
|
||||
|
||||
if( errorCode )
|
||||
{
|
||||
wxPoint refsegMiddle = ( aRefSeg->GetStart() + aRefSeg->GetEnd() ) / 2;
|
||||
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( errorCode );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
|
||||
m_clearanceSource,
|
||||
MessageTextFromValue( userUnits(), constraintWidth, true ),
|
||||
MessageTextFromValue( userUnits(), refSegWidth, true ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( aRefSeg );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refsegMiddle );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************/
|
||||
/* Phase 1 : test DRC track to pads : */
|
||||
|
@ -269,20 +288,10 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
EDA_RECT inflatedBB = refSegBB;
|
||||
inflatedBB.Inflate( pad->GetBoundingRadius() + m_largestClearance );
|
||||
|
||||
/// We setup the dummy pad to use in case we need to only draw the hole outline rather
|
||||
/// than the pad itself
|
||||
D_PAD dummypad( pad->GetParent() );
|
||||
dummypad.SetNetCode( pad->GetNetCode() );
|
||||
dummypad.SetSize( pad->GetDrillSize() );
|
||||
dummypad.SetOrientation( pad->GetOrientation() );
|
||||
dummypad.SetShape( pad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG ? PAD_SHAPE_OVAL
|
||||
: PAD_SHAPE_CIRCLE );
|
||||
dummypad.SetPosition( pad->GetPosition() );
|
||||
|
||||
if( !inflatedBB.Contains( pad->GetPosition() ) )
|
||||
continue;
|
||||
|
||||
if( !( pad->GetLayerSet() & refLayerSet ).any() )
|
||||
if( !( pad->IsOnLayer( aLayer ) ) )
|
||||
continue;
|
||||
|
||||
// No need to check pads with the same net as the refSeg.
|
||||
|
@ -293,7 +302,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
{
|
||||
const SHAPE_SEGMENT* slot = pad->GetEffectiveHoleShape();
|
||||
const DRC_CONSTRAINT* constraint = GetConstraint( aRefSeg, pad,
|
||||
DRC_RULE_ID_CLEARANCE, refLayer,
|
||||
DRC_RULE_ID_CLEARANCE, aLayer,
|
||||
&m_clearanceSource );
|
||||
int minClearance;
|
||||
int actual;
|
||||
|
@ -305,7 +314,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
}
|
||||
else
|
||||
{
|
||||
minClearance = aRefSeg->GetClearance( refLayer, nullptr,
|
||||
minClearance = aRefSeg->GetClearance( aLayer, nullptr,
|
||||
&m_clearanceSource );
|
||||
}
|
||||
|
||||
|
@ -330,7 +339,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
}
|
||||
|
||||
/// Skip checking pad copper when it has been removed
|
||||
if( !pad->IsPadOnLayer( refLayer ) )
|
||||
if( !pad->IsPadOnLayer( aLayer ) )
|
||||
continue;
|
||||
|
||||
int minClearance = aRefSeg->GetClearance( aRefSeg->GetLayer(), pad,
|
||||
|
@ -371,27 +380,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
if( aRefSeg->GetNetCode() == track->GetNetCode() )
|
||||
continue;
|
||||
|
||||
// No problem if tracks are on different layers:
|
||||
// Note that while the general case of GetLayerSet intersection always works,
|
||||
// the others are much faster.
|
||||
bool sameLayers;
|
||||
|
||||
if( aRefSeg->Type() == PCB_VIA_T )
|
||||
{
|
||||
if( track->Type() == PCB_VIA_T )
|
||||
sameLayers = ( refLayerSet & track->GetLayerSet() ).any();
|
||||
else
|
||||
sameLayers = refLayerSet.test( track->GetLayer() );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( track->Type() == PCB_VIA_T )
|
||||
sameLayers = track->GetLayerSet().test( refLayer );
|
||||
else
|
||||
sameLayers = track->GetLayer() == refLayer;
|
||||
}
|
||||
|
||||
if( !sameLayers )
|
||||
if( !track->GetLayerSet().test( aLayer ) )
|
||||
continue;
|
||||
|
||||
// Preflight based on worst-case inflated bounding boxes:
|
||||
|
@ -406,6 +395,15 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
int actual;
|
||||
SHAPE_SEGMENT trackSeg( track->GetStart(), track->GetEnd(), track->GetWidth() );
|
||||
|
||||
/// Check to see if the via has a pad on this layer
|
||||
if( track->Type() == PCB_VIA_T )
|
||||
{
|
||||
VIA* via = static_cast<VIA*>( track );
|
||||
|
||||
if( !via->IsPadOnLayer( aLayer ) )
|
||||
trackSeg.SetWidth( via->GetDrillValue() );
|
||||
}
|
||||
|
||||
// Check two tracks crossing first as it reports a DRCE without distances
|
||||
if( OPT_VECTOR2I intersection = refSeg.GetSeg().Intersect( trackSeg.GetSeg() ) )
|
||||
{
|
||||
|
@ -446,50 +444,43 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
// Can be *very* time consumming.
|
||||
if( aTestZones )
|
||||
{
|
||||
SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
|
||||
|
||||
for( ZONE_CONTAINER* zone : m_pcb->Zones() )
|
||||
{
|
||||
if( zone->GetIsKeepout() )
|
||||
if( !zone->GetLayerSet().test( aLayer ) || zone->GetIsKeepout() )
|
||||
continue;
|
||||
|
||||
if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() )
|
||||
continue;
|
||||
|
||||
for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
|
||||
if( zone->GetFilledPolysList( aLayer ).IsEmpty() )
|
||||
continue;
|
||||
|
||||
// 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 )
|
||||
|
||||
|
||||
int minClearance = aRefSeg->GetClearance( aLayer, zone, &m_clearanceSource );
|
||||
int allowedDist = minClearance + halfWidth + THRESHOLD_DIST;
|
||||
int actual;
|
||||
|
||||
if( zone->GetFilledPolysList( aLayer ).Collide( testSeg, allowedDist, &actual ) )
|
||||
{
|
||||
if( !refLayerSet.test( layer ) )
|
||||
continue;
|
||||
actual = std::max( 0, actual - halfWidth );
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
||||
|
||||
if( zone->GetFilledPolysList( layer ).IsEmpty() )
|
||||
continue;
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
||||
m_clearanceSource,
|
||||
MessageTextFromValue( userUnits(), minClearance, true ),
|
||||
MessageTextFromValue( userUnits(), actual, true ) );
|
||||
|
||||
// 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 )
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( aRefSeg, zone );
|
||||
|
||||
int minClearance = aRefSeg->GetClearance( layer, zone, &m_clearanceSource );
|
||||
int widths = refSegWidth / 2;
|
||||
int allowedDist = minClearance + widths + THRESHOLD_DIST;
|
||||
int actual;
|
||||
|
||||
if( zone->GetFilledPolysList( layer ).Collide( testSeg, allowedDist, &actual ) )
|
||||
{
|
||||
actual = std::max( 0, actual - widths );
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
||||
m_clearanceSource,
|
||||
MessageTextFromValue( userUnits(), minClearance, true ),
|
||||
MessageTextFromValue( userUnits(), actual, true ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( aRefSeg, zone );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, GetLocation( aRefSeg, zone ) );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, GetLocation( aRefSeg, zone ) );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -508,8 +499,6 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
aRefSeg->GetRuleClearance( &dummyEdge, aRefSeg->GetLayer(), &minClearance,
|
||||
&m_clearanceSource );
|
||||
|
||||
SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
|
||||
int halfWidth = refSegWidth / 2;
|
||||
int center2centerAllowed = minClearance + halfWidth;
|
||||
|
||||
for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ )
|
||||
|
|
|
@ -625,7 +625,16 @@ void DRC::testTracks( BOARD_COMMIT& aCommit, wxWindow *aActiveWindow, bool aShow
|
|||
}
|
||||
|
||||
// Test new segment against tracks and pads, optionally against copper zones
|
||||
doTrackDrc( aCommit, *seg_it, seg_it + 1, m_pcb->Tracks().end(), m_testTracksAgainstZones );
|
||||
LSEQ layer_seq = ( *seg_it )->GetLayerSet().Seq();
|
||||
|
||||
if( ( *seg_it )->Type() == PCB_VIA_T )
|
||||
doSingleViaDRC( aCommit, static_cast<VIA*>( *seg_it ) );
|
||||
else
|
||||
doSingleTrackDRC( aCommit, *seg_it );
|
||||
|
||||
for( PCB_LAYER_ID layer : layer_seq )
|
||||
doTrackDrc( aCommit, *seg_it, seg_it + 1, m_pcb->Tracks().end(), m_testTracksAgainstZones, layer );
|
||||
|
||||
|
||||
// Test for dangling items
|
||||
int code = (*seg_it)->Type() == PCB_VIA_T ? DRCE_DANGLING_VIA : DRCE_DANGLING_TRACK;
|
||||
|
|
|
@ -140,7 +140,7 @@ class wxTextCtrl;
|
|||
|
||||
class DRC_ENGINE
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -262,11 +262,28 @@ private:
|
|||
* @param aStartIt the iterator to the first track to test
|
||||
* @param aEndIt the marker for the iterator end
|
||||
* @param aTestZones true if should do copper zones test. This can be very time consumming
|
||||
* @param aLayer sets the layer to test against
|
||||
* @return bool - true if no problems, else false and m_currentMarker is
|
||||
* filled in with the problem information.
|
||||
*/
|
||||
void doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
|
||||
TRACKS::iterator aEndIt, bool aTestZones );
|
||||
TRACKS::iterator aEndIt, bool aTestZones, PCB_LAYER_ID aLayer );
|
||||
|
||||
/**
|
||||
* Test a single via for DRC errors
|
||||
*
|
||||
* @param aCommit The board commit to add DRC errors
|
||||
* @param aRefVia The via to test against design settings
|
||||
*/
|
||||
void doSingleViaDRC( BOARD_COMMIT& aCommit, VIA* aRefVia );
|
||||
|
||||
/**
|
||||
* Test a single track segment for DRC errors
|
||||
*
|
||||
* @param aCommit The board commit to add DRC errors
|
||||
* @param aRefSeg The track to test against design settings
|
||||
*/
|
||||
void doSingleTrackDRC( BOARD_COMMIT& aCommit, TRACK* aRefSeg );
|
||||
|
||||
//-----<single tests>----------------------------------------------
|
||||
|
||||
|
|
|
@ -136,18 +136,178 @@ bool poly2segmentDRC( wxPoint* aTref, int aTrefCount, wxPoint aSegStart, wxPoint
|
|||
}
|
||||
|
||||
|
||||
void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
|
||||
TRACKS::iterator aEndIt, bool aTestZones )
|
||||
void DRC::doSingleViaDRC( BOARD_COMMIT& aCommit, VIA* aRefVia )
|
||||
{
|
||||
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
|
||||
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
|
||||
|
||||
SEG refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
|
||||
PCB_LAYER_ID refLayer = aRefSeg->GetLayer();
|
||||
LSET refLayerSet = aRefSeg->GetLayerSet();
|
||||
// test if the via size is smaller than minimum
|
||||
if( aRefVia->GetViaType() == VIATYPE::MICROVIA )
|
||||
{
|
||||
if( aRefVia->GetWidth() < bds.m_MicroViasMinSize )
|
||||
{
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_MICROVIA );
|
||||
|
||||
EDA_RECT refSegBB = aRefSeg->GetBoundingBox();
|
||||
int refSegWidth = aRefSeg->GetWidth();
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
|
||||
MessageTextFromValue( userUnits(), bds.m_MicroViasMinSize, true ),
|
||||
MessageTextFromValue( userUnits(), aRefVia->GetWidth(), true ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( aRefVia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( aRefVia->GetWidth() < bds.m_ViasMinSize )
|
||||
{
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_VIA );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
|
||||
MessageTextFromValue( userUnits(), bds.m_ViasMinSize, true ),
|
||||
MessageTextFromValue( userUnits(), aRefVia->GetWidth(), true ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( aRefVia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
}
|
||||
|
||||
// test if via's hole is bigger than its diameter
|
||||
// This test is necessary since the via hole size and width can be modified
|
||||
// and a default via hole can be bigger than some vias sizes
|
||||
if( aRefVia->GetDrillValue() > aRefVia->GetWidth() )
|
||||
{
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_VIA_HOLE_BIGGER );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (diameter %s; drill %s)" ),
|
||||
MessageTextFromValue( userUnits(), aRefVia->GetWidth(), true ),
|
||||
MessageTextFromValue( userUnits(), aRefVia->GetDrillValue(), true ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( aRefVia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
|
||||
// test if the type of via is allowed due to design rules
|
||||
if( aRefVia->GetViaType() == VIATYPE::MICROVIA && !bds.m_MicroViasAllowed )
|
||||
{
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_ALLOWED_ITEMS );
|
||||
|
||||
m_msg.Printf( _( "Microvia not allowed (board design rule constraints)" ) );
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( aRefVia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
|
||||
// test if the type of via is allowed due to design rules
|
||||
if( aRefVia->GetViaType() == VIATYPE::BLIND_BURIED && !bds.m_BlindBuriedViaAllowed )
|
||||
{
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_ALLOWED_ITEMS );
|
||||
|
||||
m_msg.Printf( _( "Blind/buried via not allowed (board design rule constraints)" ) );
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( aRefVia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
|
||||
// For microvias: test if they are blind vias and only between 2 layers
|
||||
// because they are used for very small drill size and are drill by laser
|
||||
// and **only one layer** can be drilled
|
||||
if( aRefVia->GetViaType() == VIATYPE::MICROVIA )
|
||||
{
|
||||
PCB_LAYER_ID layer1, layer2;
|
||||
bool err = true;
|
||||
|
||||
aRefVia->LayerPair( &layer1, &layer2 );
|
||||
|
||||
if( layer1 > layer2 )
|
||||
std::swap( layer1, layer2 );
|
||||
|
||||
if( layer2 == B_Cu && layer1 == bds.GetCopperLayerCount() - 2 )
|
||||
err = false;
|
||||
else if( layer1 == F_Cu && layer2 == In1_Cu )
|
||||
err = false;
|
||||
|
||||
if( err )
|
||||
{
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_PADSTACK );
|
||||
|
||||
m_msg.Printf( _( "Microvia through too many layers (%s and %s not adjacent)" ),
|
||||
m_pcb->GetLayerName( layer1 ),
|
||||
m_pcb->GetLayerName( layer2 ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( aRefVia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DRC::doSingleTrackDRC( BOARD_COMMIT& aCommit, TRACK* aRefSeg )
|
||||
{
|
||||
SHAPE_SEGMENT refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd(), aRefSeg->GetWidth() );
|
||||
EDA_RECT refSegBB = aRefSeg->GetBoundingBox();
|
||||
int refSegWidth = aRefSeg->GetWidth();
|
||||
|
||||
int minWidth, maxWidth;
|
||||
aRefSeg->GetWidthConstraints( &minWidth, &maxWidth, &m_clearanceSource );
|
||||
|
||||
int errorCode = 0;
|
||||
int constraintWidth;
|
||||
|
||||
if( refSegWidth < minWidth )
|
||||
{
|
||||
errorCode = DRCE_TRACK_WIDTH;
|
||||
constraintWidth = minWidth;
|
||||
}
|
||||
else if( refSegWidth > maxWidth )
|
||||
{
|
||||
errorCode = DRCE_TRACK_WIDTH;
|
||||
constraintWidth = maxWidth;
|
||||
}
|
||||
|
||||
if( errorCode )
|
||||
{
|
||||
wxPoint refsegMiddle = ( aRefSeg->GetStart() + aRefSeg->GetEnd() ) / 2;
|
||||
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( errorCode );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
|
||||
m_clearanceSource,
|
||||
MessageTextFromValue( userUnits(), constraintWidth, true ),
|
||||
MessageTextFromValue( userUnits(), refSegWidth, true ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( aRefSeg );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refsegMiddle );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
|
||||
TRACKS::iterator aEndIt, bool aTestZones, PCB_LAYER_ID aLayer )
|
||||
{
|
||||
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
|
||||
SHAPE_SEGMENT refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd(), aRefSeg->GetWidth() );
|
||||
|
||||
EDA_RECT refSegBB = aRefSeg->GetBoundingBox();
|
||||
SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
|
||||
int halfWidth = ( aRefSeg->GetWidth() + 1 ) / 2;
|
||||
|
||||
/******************************************/
|
||||
/* Phase 0 : via DRC tests : */
|
||||
|
@ -155,18 +315,25 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
|
||||
if( aRefSeg->Type() == PCB_VIA_T )
|
||||
{
|
||||
VIA *refvia = static_cast<VIA*>( aRefSeg );
|
||||
VIA* refvia = static_cast<VIA*>( aRefSeg );
|
||||
int viaAnnulus = ( refvia->GetWidth() - refvia->GetDrill() ) / 2;
|
||||
int minAnnulus = refvia->GetMinAnnulus( &m_clearanceSource );
|
||||
int minAnnulus = refvia->GetMinAnnulus( aLayer, &m_clearanceSource );
|
||||
|
||||
if( !refvia->IsPadOnLayer( aLayer ) )
|
||||
{
|
||||
halfWidth = ( refvia->GetDrillValue() + 1 ) / 2;
|
||||
refSegBB = EDA_RECT( refvia->GetStart(),
|
||||
wxSize( refvia->GetDrillValue(), refvia->GetDrillValue() ) );
|
||||
}
|
||||
|
||||
// test if the via size is smaller than minimum
|
||||
if( refvia->GetViaType() == VIATYPE::MICROVIA )
|
||||
{
|
||||
if( viaAnnulus < minAnnulus )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_VIA_ANNULUS );
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_VIA_ANNULUS );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
|
||||
m_msg.Printf( _( "Via annulus too small (%s %s; actual %s)" ),
|
||||
m_clearanceSource,
|
||||
MessageTextFromValue( userUnits(), minAnnulus, true ),
|
||||
MessageTextFromValue( userUnits(), viaAnnulus, true ) );
|
||||
|
@ -177,21 +344,6 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
|
||||
if( refvia->GetWidth() < bds.m_MicroViasMinSize )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_MICROVIA );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
|
||||
MessageTextFromValue( userUnits(), bds.m_MicroViasMinSize, true ),
|
||||
MessageTextFromValue( userUnits(), refvia->GetWidth(), true ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( refvia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -203,9 +355,9 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
|
||||
if( viaAnnulus < minAnnulus )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_VIA_ANNULUS );
|
||||
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_VIA_ANNULUS );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
|
||||
m_msg.Printf( _( "Via annulus too small (%s %s; actual %s)" ),
|
||||
m_clearanceSource,
|
||||
MessageTextFromValue( userUnits(), minAnnulus, true ),
|
||||
MessageTextFromValue( userUnits(), viaAnnulus, true ) );
|
||||
|
@ -216,138 +368,8 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
|
||||
if( refvia->GetWidth() < bds.m_ViasMinSize )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_VIA );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
|
||||
MessageTextFromValue( userUnits(), bds.m_ViasMinSize, true ),
|
||||
MessageTextFromValue( userUnits(), refvia->GetWidth(), true ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( refvia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
}
|
||||
|
||||
// test if via's hole is bigger than its diameter
|
||||
// This test is necessary since the via hole size and width can be modified
|
||||
// and a default via hole can be bigger than some vias sizes
|
||||
if( refvia->GetDrillValue() > refvia->GetWidth() )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_VIA_HOLE_BIGGER );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (diameter %s; drill %s)" ),
|
||||
MessageTextFromValue( userUnits(), refvia->GetWidth(), true ),
|
||||
MessageTextFromValue( userUnits(), refvia->GetDrillValue(), true ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( refvia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
|
||||
// test if the type of via is allowed due to design rules
|
||||
if( refvia->GetViaType() == VIATYPE::MICROVIA && !bds.m_MicroViasAllowed )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_MICROVIA_NOT_ALLOWED );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (board design rule constraints)" ) );
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( refvia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
|
||||
// test if the type of via is allowed due to design rules
|
||||
if( refvia->GetViaType() == VIATYPE::BLIND_BURIED && !bds.m_BlindBuriedViaAllowed )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_BURIED_VIA_NOT_ALLOWED );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (board design rule constraints)" ) );
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( refvia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
|
||||
// For microvias: test if they are blind vias and only between 2 layers
|
||||
// because they are used for very small drill size and are drill by laser
|
||||
// and **only one layer** can be drilled
|
||||
if( refvia->GetViaType() == VIATYPE::MICROVIA )
|
||||
{
|
||||
PCB_LAYER_ID layer1, layer2;
|
||||
bool err = true;
|
||||
|
||||
refvia->LayerPair( &layer1, &layer2 );
|
||||
|
||||
if( layer1 > layer2 )
|
||||
std::swap( layer1, layer2 );
|
||||
|
||||
if( layer2 == B_Cu && layer1 == bds.GetCopperLayerCount() - 2 )
|
||||
err = false;
|
||||
else if( layer1 == F_Cu && layer2 == In1_Cu )
|
||||
err = false;
|
||||
|
||||
if( err )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_MICROVIA_TOO_MANY_LAYERS );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s and %s not adjacent)" ),
|
||||
m_pcb->GetLayerName( layer1 ),
|
||||
m_pcb->GetLayerName( layer2 ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( refvia );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else // This is a track segment
|
||||
{
|
||||
int minWidth, maxWidth;
|
||||
aRefSeg->GetWidthConstraints( &minWidth, &maxWidth, &m_clearanceSource );
|
||||
|
||||
int errorCode = 0;
|
||||
int constraintWidth;
|
||||
|
||||
if( refSegWidth < minWidth )
|
||||
{
|
||||
errorCode = DRCE_TOO_SMALL_TRACK_WIDTH;
|
||||
constraintWidth = minWidth;
|
||||
}
|
||||
else if( refSegWidth > maxWidth )
|
||||
{
|
||||
errorCode = DRCE_TOO_LARGE_TRACK_WIDTH;
|
||||
constraintWidth = maxWidth;
|
||||
}
|
||||
|
||||
if( errorCode )
|
||||
{
|
||||
wxPoint refsegMiddle = ( aRefSeg->GetStart() + aRefSeg->GetEnd() ) / 2;
|
||||
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( errorCode );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
|
||||
m_clearanceSource,
|
||||
MessageTextFromValue( userUnits(), constraintWidth, true ),
|
||||
MessageTextFromValue( userUnits(), refSegWidth, true ) );
|
||||
|
||||
drcItem->SetErrorMessage( m_msg );
|
||||
drcItem->SetItems( aRefSeg );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refsegMiddle );
|
||||
addMarkerToPcb( aCommit, marker );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -371,7 +393,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
if( !inflatedBB.Contains( pad->GetPosition() ) )
|
||||
continue;
|
||||
|
||||
if( !( pad->GetLayerSet() & refLayerSet ).any() )
|
||||
if( !pad->IsOnLayer( aLayer ) )
|
||||
continue;
|
||||
|
||||
// No need to check pads with the same net as the refSeg.
|
||||
|
@ -415,15 +437,14 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
slotEnd += pad->GetPosition();
|
||||
|
||||
SEG slotSeg( slotStart, slotEnd );
|
||||
int widths = ( slotWidth + refSegWidth ) / 2;
|
||||
int center2centerAllowed = minClearance + widths + bds.GetDRCEpsilon();
|
||||
int center2centerAllowed = minClearance + halfWidth + 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 );
|
||||
int actual = std::max( 0.0, sqrt( center2center_squared ) - halfWidth );
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_HOLE );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
||||
|
@ -442,11 +463,11 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
}
|
||||
}
|
||||
|
||||
int minClearance = aRefSeg->GetClearance( pad, &m_clearanceSource );
|
||||
int minClearance = aRefSeg->GetClearance( aLayer, pad, &m_clearanceSource );
|
||||
int clearanceAllowed = minClearance - bds.GetDRCEpsilon();
|
||||
int actual;
|
||||
|
||||
if( !checkClearanceSegmToPad( refSeg, refSegWidth, pad, clearanceAllowed, &actual ) )
|
||||
if( !checkClearanceSegmToPad( refSeg, refSeg.GetWidth(), pad, clearanceAllowed, &actual ) )
|
||||
{
|
||||
actual = std::max( 0, actual );
|
||||
SEG padSeg( pad->GetPosition(), pad->GetPosition() );
|
||||
|
@ -482,27 +503,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
if( aRefSeg->GetNetCode() == track->GetNetCode() )
|
||||
continue;
|
||||
|
||||
// No problem if tracks are on different layers:
|
||||
// Note that while the general case of GetLayerSet intersection always works,
|
||||
// the others are much faster.
|
||||
bool sameLayers;
|
||||
|
||||
if( aRefSeg->Type() == PCB_VIA_T )
|
||||
{
|
||||
if( track->Type() == PCB_VIA_T )
|
||||
sameLayers = ( refLayerSet & track->GetLayerSet() ).any();
|
||||
else
|
||||
sameLayers = refLayerSet.test( track->GetLayer() );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( track->Type() == PCB_VIA_T )
|
||||
sameLayers = track->GetLayerSet().test( refLayer );
|
||||
else
|
||||
sameLayers = track->GetLayer() == refLayer;
|
||||
}
|
||||
|
||||
if( !sameLayers )
|
||||
if( !track->GetLayerSet().test( aLayer ) )
|
||||
continue;
|
||||
|
||||
// Preflight based on worst-case inflated bounding boxes:
|
||||
|
@ -512,9 +513,19 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
if( !trackBB.Intersects( refSegBB ) )
|
||||
continue;
|
||||
|
||||
int minClearance = aRefSeg->GetClearance( track, &m_clearanceSource );
|
||||
int minClearance = aRefSeg->GetClearance( aLayer, track, &m_clearanceSource );
|
||||
SEG trackSeg( track->GetStart(), track->GetEnd() );
|
||||
int widths = ( refSegWidth + track->GetWidth() ) / 2;
|
||||
int widths = ( track->GetWidth() / 2 ) + halfWidth;
|
||||
|
||||
/// Check to see if the via has a pad on this layer
|
||||
if( track->Type() == PCB_VIA_T )
|
||||
{
|
||||
VIA* via = static_cast<VIA*>( track );
|
||||
|
||||
if( !via->IsPadOnLayer( aLayer ) )
|
||||
widths = ( via->GetDrillValue() / 2 ) + halfWidth;
|
||||
}
|
||||
|
||||
int center2centerAllowed = minClearance + widths;
|
||||
|
||||
// Avoid square-roots if possible (for performance)
|
||||
|
@ -574,19 +585,16 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
|
||||
for( ZONE_CONTAINER* zone : m_pcb->Zones() )
|
||||
{
|
||||
if( zone->GetFilledPolysList().IsEmpty() || zone->GetIsKeepout() )
|
||||
continue;
|
||||
|
||||
if( !( refLayerSet & zone->GetLayerSet() ).any() )
|
||||
if( !zone->GetLayerSet().test( aLayer ) || zone->GetFilledPolysList( aLayer ).IsEmpty()
|
||||
|| zone->GetIsKeepout() )
|
||||
continue;
|
||||
|
||||
if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() )
|
||||
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() );
|
||||
int minClearance = aRefSeg->GetClearance( aLayer, zone, &m_clearanceSource );
|
||||
int center2centerAllowed = minClearance + halfWidth;
|
||||
SHAPE_POLY_SET* outline = const_cast<SHAPE_POLY_SET*>( &zone->GetFilledPolysList( aLayer ) );
|
||||
|
||||
SEG::ecoord center2center_squared = outline->SquaredDistance( testSeg );
|
||||
|
||||
|
@ -597,7 +605,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
|
||||
if( center2center_squared + THRESHOLD_DIST < SEG::Square( center2centerAllowed ) )
|
||||
{
|
||||
int actual = std::max( 0.0, sqrt( center2center_squared ) - widths );
|
||||
int actual = std::max( 0.0, sqrt( center2center_squared ) - halfWidth );
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_ZONE );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
||||
|
@ -625,11 +633,10 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
static DRAWSEGMENT dummyEdge;
|
||||
dummyEdge.SetLayer( Edge_Cuts );
|
||||
|
||||
if( aRefSeg->GetRuleClearance( &dummyEdge, &minClearance, &m_clearanceSource ) )
|
||||
if( aRefSeg->GetRuleClearance( &dummyEdge, aLayer, &minClearance, &m_clearanceSource ) )
|
||||
/* minClearance and m_clearanceSource set in GetRuleClearance() */;
|
||||
|
||||
SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
|
||||
int halfWidth = refSegWidth / 2;
|
||||
int center2centerAllowed = minClearance + halfWidth;
|
||||
|
||||
for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ )
|
||||
|
|
Loading…
Reference in New Issue