Add DRC checks for dangling vias and tracks.
Fixes https://gitlab.com/kicad/code/kicad/issues/1999
This commit is contained in:
parent
3b84653591
commit
aedc624340
|
@ -97,14 +97,14 @@ public:
|
|||
bds.m_DRCSeverities[ DRCE_OVERLAPPING_FOOTPRINTS ] = RPT_SEVERITY_IGNORE;
|
||||
}
|
||||
|
||||
bds.m_DRCSeverities[ DRCE_SHORT ] = RPT_SEVERITY_ACTION;
|
||||
bds.m_DRCSeverities[ DRCE_REDUNDANT_VIA ] = RPT_SEVERITY_ACTION;
|
||||
bds.m_DRCSeverities[ DRCE_DUPLICATE_TRACK ] = RPT_SEVERITY_ACTION;
|
||||
bds.m_DRCSeverities[ DRCE_MERGE_TRACKS ] = RPT_SEVERITY_ACTION;
|
||||
bds.m_DRCSeverities[ DRCE_DANGLING_TRACK ] = RPT_SEVERITY_ACTION;
|
||||
bds.m_DRCSeverities[ DRCE_DANGLING_VIA ] = RPT_SEVERITY_ACTION;
|
||||
bds.m_DRCSeverities[ DRCE_ZERO_LENGTH_TRACK ] = RPT_SEVERITY_ACTION;
|
||||
bds.m_DRCSeverities[ DRCE_TRACK_IN_PAD ] = RPT_SEVERITY_ACTION;
|
||||
bds.m_DRCSeverities[ CLEANUP_SHORT ] = RPT_SEVERITY_ACTION;
|
||||
bds.m_DRCSeverities[ CLEANUP_REDUNDANT_VIA ] = RPT_SEVERITY_ACTION;
|
||||
bds.m_DRCSeverities[ CLEANUP_DUPLICATE_TRACK ] = RPT_SEVERITY_ACTION;
|
||||
bds.m_DRCSeverities[ CLEANUP_MERGE_TRACKS ] = RPT_SEVERITY_ACTION;
|
||||
bds.m_DRCSeverities[ CLEANUP_DANGLING_TRACK ] = RPT_SEVERITY_ACTION;
|
||||
bds.m_DRCSeverities[ CLEANUP_DANGLING_VIA ] = RPT_SEVERITY_ACTION;
|
||||
bds.m_DRCSeverities[ CLEANUP_ZERO_LENGTH_TRACK ] = RPT_SEVERITY_ACTION;
|
||||
bds.m_DRCSeverities[ CLEANUP_TRACK_IN_PAD ] = RPT_SEVERITY_ACTION;
|
||||
|
||||
DRC_ITEM drc( 0 );
|
||||
wxString severity;
|
||||
|
|
|
@ -598,6 +598,35 @@ void CONNECTIVITY_DATA::GetUnconnectedEdges( std::vector<CN_EDGE>& aEdges) const
|
|||
}
|
||||
|
||||
|
||||
bool CONNECTIVITY_DATA::TestTrackEndpointDangling( TRACK* aTrack, wxPoint* aPos )
|
||||
{
|
||||
auto items = GetConnectivityAlgo()->ItemEntry( aTrack ).GetItems();
|
||||
|
||||
// Not in the connectivity system. This is a bug!
|
||||
if( items.empty() )
|
||||
{
|
||||
wxFAIL_MSG( "track not in connectivity system" );
|
||||
return false;
|
||||
}
|
||||
|
||||
CN_ITEM* citem = items.front();
|
||||
|
||||
if( !citem->Valid() )
|
||||
return false;
|
||||
|
||||
for( const std::shared_ptr<CN_ANCHOR>& anchor : citem->Anchors() )
|
||||
{
|
||||
if( anchor->IsDangling() )
|
||||
{
|
||||
*aPos = (wxPoint) anchor->Pos();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const std::vector<BOARD_CONNECTED_ITEM*> CONNECTIVITY_DATA::GetConnectedItems(
|
||||
const BOARD_CONNECTED_ITEM* aItem, const VECTOR2I& aAnchor, KICAD_T aTypes[] )
|
||||
{
|
||||
|
@ -700,3 +729,5 @@ const std::vector<CN_EDGE> CONNECTIVITY_DATA::GetRatsnestForComponent( MODULE* a
|
|||
|
||||
return edges;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -183,6 +183,8 @@ public:
|
|||
|
||||
void GetUnconnectedEdges( std::vector<CN_EDGE>& aEdges ) const;
|
||||
|
||||
bool TestTrackEndpointDangling( TRACK* aTrack, wxPoint* aPos );
|
||||
|
||||
/**
|
||||
* Function ClearDynamicRatsnest()
|
||||
* Erases the temporary dynamic ratsnest (i.e. the ratsnest lines that
|
||||
|
|
|
@ -868,12 +868,11 @@ void DRC::testDrilledHoles()
|
|||
|
||||
void DRC::testTracks( wxWindow *aActiveWindow, bool aShowProgressBar )
|
||||
{
|
||||
wxProgressDialog * progressDialog = NULL;
|
||||
const int delta = 500; // This is the number of tests between 2 calls to the
|
||||
// progress bar
|
||||
int count = m_pcb->Tracks().size();
|
||||
|
||||
int deltamax = count/delta;
|
||||
wxProgressDialog* progressDialog = NULL;
|
||||
const int delta = 500; // This is the number of tests between 2 calls to the
|
||||
// progress bar
|
||||
int count = m_pcb->Tracks().size();
|
||||
int deltamax = count/delta;
|
||||
|
||||
if( aShowProgressBar && deltamax > 3 )
|
||||
{
|
||||
|
@ -885,6 +884,17 @@ void DRC::testTracks( wxWindow *aActiveWindow, bool aShowProgressBar )
|
|||
progressDialog->Update( 0, wxEmptyString );
|
||||
}
|
||||
|
||||
std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_pcb->GetConnectivity();
|
||||
BOARD_DESIGN_SETTINGS& settings = m_pcb->GetDesignSettings();
|
||||
|
||||
|
||||
if( !m_pcb->GetDesignSettings().Ignore( DRCE_DANGLING_TRACK )
|
||||
|| !m_pcb->GetDesignSettings().Ignore( DRCE_DANGLING_VIA ) )
|
||||
{
|
||||
connectivity->Clear();
|
||||
connectivity->Build( m_pcb ); // just in case. This really needs to be reliable.
|
||||
}
|
||||
|
||||
int ii = 0;
|
||||
count = 0;
|
||||
|
||||
|
@ -909,6 +919,19 @@ void DRC::testTracks( wxWindow *aActiveWindow, bool aShowProgressBar )
|
|||
|
||||
// Test new segment against tracks and pads, optionally against copper zones
|
||||
doTrackDrc( *seg_it, seg_it + 1, m_pcb->Tracks().end(), m_doZonesTest );
|
||||
|
||||
// Test for dangling items
|
||||
int code = (*seg_it)->Type() == PCB_VIA_T ? DRCE_DANGLING_VIA : DRCE_DANGLING_TRACK;
|
||||
wxPoint pos;
|
||||
|
||||
if( !settings.Ignore( code ) && connectivity->TestTrackEndpointDangling( *seg_it, &pos ) )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( code );
|
||||
drcItem->SetItems( *seg_it );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, pos );
|
||||
addMarkerToPcb( marker );
|
||||
}
|
||||
}
|
||||
|
||||
if( progressDialog )
|
||||
|
|
|
@ -56,6 +56,8 @@ enum PCB_DRC_CODE {
|
|||
DRCE_ZONES_INTERSECT, ///< copper area outlines intersect
|
||||
DRCE_ZONES_TOO_CLOSE, ///< copper area outlines are too close
|
||||
DRCE_ZONE_HAS_EMPTY_NET, ///< copper area has a net but no pads in nets, which is suspicious
|
||||
DRCE_DANGLING_VIA, ///< via which isn't connected to anything
|
||||
DRCE_DANGLING_TRACK, ///< track with at least one end not connected to anything
|
||||
DRCE_HOLE_NEAR_PAD, ///< hole too close to pad
|
||||
DRCE_HOLE_NEAR_TRACK, ///< hole too close to track
|
||||
DRCE_DRILLED_HOLES_TOO_CLOSE, ///< overlapping drilled holes break drill bits
|
||||
|
@ -96,14 +98,14 @@ enum PCB_DRC_CODE {
|
|||
DRCE_LAST = DRCE_UNRESOLVED_VARIABLE,
|
||||
|
||||
// These are actually Cleanup Tracks and Vias actions, not DRCE errors
|
||||
DRCE_SHORT,
|
||||
DRCE_REDUNDANT_VIA,
|
||||
DRCE_DUPLICATE_TRACK,
|
||||
DRCE_MERGE_TRACKS,
|
||||
DRCE_DANGLING_TRACK,
|
||||
DRCE_DANGLING_VIA,
|
||||
DRCE_ZERO_LENGTH_TRACK,
|
||||
DRCE_TRACK_IN_PAD
|
||||
CLEANUP_SHORT,
|
||||
CLEANUP_REDUNDANT_VIA,
|
||||
CLEANUP_DUPLICATE_TRACK,
|
||||
CLEANUP_MERGE_TRACKS,
|
||||
CLEANUP_DANGLING_TRACK,
|
||||
CLEANUP_DANGLING_VIA,
|
||||
CLEANUP_ZERO_LENGTH_TRACK,
|
||||
CLEANUP_TRACK_IN_PAD
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -78,9 +78,9 @@ wxString DRC_ITEM::GetErrorText( int aCode, bool aTranslate ) const
|
|||
case DRCE_DISABLED_LAYER_ITEM: msg = _HKI( "Item on a disabled layer" ); break;
|
||||
case DRCE_ZONES_INTERSECT: msg = _HKI( "Copper areas intersect" ); break;
|
||||
case DRCE_ZONES_TOO_CLOSE: msg = _HKI( "Copper areas too close" ); break;
|
||||
|
||||
case DRCE_ZONE_HAS_EMPTY_NET: msg = _HKI( "Copper zone net has no pads" ); break;
|
||||
|
||||
case DRCE_DANGLING_VIA: msg = _HKI( "Via is not connected" ); break;
|
||||
case DRCE_DANGLING_TRACK: msg = _HKI( "Track has unconnected end" ); break;
|
||||
case DRCE_HOLE_NEAR_PAD: msg = _HKI( "Hole too close to pad" ); break;
|
||||
case DRCE_HOLE_NEAR_TRACK: msg = _HKI( "Hole too close to track" ); break;
|
||||
case DRCE_TOO_SMALL_TRACK_WIDTH: msg = _HKI( "Track width too small" ); break;
|
||||
|
@ -121,14 +121,14 @@ wxString DRC_ITEM::GetErrorText( int aCode, bool aTranslate ) const
|
|||
case DRCE_EXTRA_FOOTPRINT: msg = _HKI( "Extra footprint" ); break;
|
||||
|
||||
// For cleanup tracks and vias:
|
||||
case DRCE_SHORT: msg = _HKI( "Remove track shorting two nets" ); break;
|
||||
case DRCE_REDUNDANT_VIA: msg = _HKI( "Remove redundant via" ); break;
|
||||
case DRCE_DUPLICATE_TRACK: msg = _HKI( "Remove duplicate track" ); break;
|
||||
case DRCE_MERGE_TRACKS: msg = _HKI( "Merge co-linear tracks" ); break;
|
||||
case DRCE_DANGLING_TRACK: msg = _HKI( "Remove dangling track" ); break;
|
||||
case DRCE_DANGLING_VIA: msg = _HKI( "Remove dangling via" ); break;
|
||||
case DRCE_ZERO_LENGTH_TRACK: msg = _HKI( "Remove zero-length track" ); break;
|
||||
case DRCE_TRACK_IN_PAD: msg = _HKI( "Remove track inside pad" ); break;
|
||||
case CLEANUP_SHORT: msg = _HKI( "Remove track shorting two nets" ); break;
|
||||
case CLEANUP_REDUNDANT_VIA: msg = _HKI( "Remove redundant via" ); break;
|
||||
case CLEANUP_DUPLICATE_TRACK: msg = _HKI( "Remove duplicate track" ); break;
|
||||
case CLEANUP_MERGE_TRACKS: msg = _HKI( "Merge co-linear tracks" ); break;
|
||||
case CLEANUP_DANGLING_TRACK: msg = _HKI( "Remove dangling track" ); break;
|
||||
case CLEANUP_DANGLING_VIA: msg = _HKI( "Remove dangling via" ); break;
|
||||
case CLEANUP_ZERO_LENGTH_TRACK: msg = _HKI( "Remove zero-length track" ); break;
|
||||
case CLEANUP_TRACK_IN_PAD: msg = _HKI( "Remove track inside pad" ); break;
|
||||
|
||||
case DRCE_UNRESOLVED_VARIABLE: msg = _HKI( "Unresolved text variable" ); break;
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ bool TRACKS_CLEANER::removeBadTrackSegments()
|
|||
{
|
||||
if( segment->GetNetCode() != testedPad->GetNetCode() )
|
||||
{
|
||||
DRC_ITEM* item = new DRC_ITEM( DRCE_SHORT );
|
||||
DRC_ITEM* item = new DRC_ITEM( CLEANUP_SHORT );
|
||||
item->SetItems( segment );
|
||||
m_itemsList->push_back( item );
|
||||
|
||||
|
@ -145,7 +145,7 @@ bool TRACKS_CLEANER::removeBadTrackSegments()
|
|||
{
|
||||
if( segment->GetNetCode() != testedTrack->GetNetCode() && !testedTrack->GetState( FLAG0 ) )
|
||||
{
|
||||
DRC_ITEM* item = new DRC_ITEM( DRCE_SHORT );
|
||||
DRC_ITEM* item = new DRC_ITEM( CLEANUP_SHORT );
|
||||
item->SetItems( segment );
|
||||
m_itemsList->push_back( item );
|
||||
|
||||
|
@ -190,7 +190,7 @@ bool TRACKS_CLEANER::cleanupVias()
|
|||
|
||||
if( ( pad->GetLayerSet() & all_cu ) == all_cu )
|
||||
{
|
||||
DRC_ITEM* item = new DRC_ITEM( DRCE_REDUNDANT_VIA );
|
||||
DRC_ITEM* item = new DRC_ITEM( CLEANUP_REDUNDANT_VIA );
|
||||
item->SetItems( via1, pad );
|
||||
m_itemsList->push_back( item );
|
||||
|
||||
|
@ -209,7 +209,7 @@ bool TRACKS_CLEANER::cleanupVias()
|
|||
|
||||
if( via1->GetViaType() == via2->GetViaType() )
|
||||
{
|
||||
DRC_ITEM* item = new DRC_ITEM( DRCE_REDUNDANT_VIA );
|
||||
DRC_ITEM* item = new DRC_ITEM( CLEANUP_REDUNDANT_VIA );
|
||||
item->SetItems( via1, via2 );
|
||||
m_itemsList->push_back( item );
|
||||
|
||||
|
@ -224,35 +224,6 @@ bool TRACKS_CLEANER::cleanupVias()
|
|||
}
|
||||
|
||||
|
||||
bool TRACKS_CLEANER::testTrackEndpointDangling( TRACK* aTrack )
|
||||
{
|
||||
auto connectivity = m_brd->GetConnectivity();
|
||||
auto items = connectivity->GetConnectivityAlgo()->ItemEntry( aTrack ).GetItems();
|
||||
|
||||
// Not in the connectivity system. This is a bug!
|
||||
if( items.empty() )
|
||||
{
|
||||
wxASSERT( !items.empty() );
|
||||
return false;
|
||||
}
|
||||
|
||||
auto citem = items.front();
|
||||
|
||||
if( !citem->Valid() )
|
||||
return false;
|
||||
|
||||
auto anchors = citem->Anchors();
|
||||
|
||||
for( const auto& anchor : anchors )
|
||||
{
|
||||
if( anchor->IsDangling() )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool TRACKS_CLEANER::testTrackEndpointIsNode( TRACK* aTrack, bool aTstStart )
|
||||
{
|
||||
// A node is a point where more than 2 items are connected.
|
||||
|
@ -299,15 +270,16 @@ bool TRACKS_CLEANER::deleteDanglingTracks()
|
|||
|
||||
for( TRACK* track : m_brd->Tracks() )
|
||||
{
|
||||
bool flag_erase = false; // Start without a good reason to erase it
|
||||
bool flag_erase = false; // Start without a good reason to erase it
|
||||
wxPoint pos;
|
||||
|
||||
// Tst if a track (or a via) endpoint is not connected to another track or to a zone.
|
||||
if( testTrackEndpointDangling( track ) )
|
||||
if( m_brd->GetConnectivity()->TestTrackEndpointDangling( track, &pos ) )
|
||||
flag_erase = true;
|
||||
|
||||
if( flag_erase )
|
||||
{
|
||||
int errorCode = track->IsTrack() ? DRCE_DANGLING_TRACK : DRCE_DANGLING_VIA;
|
||||
int errorCode = track->IsTrack() ? CLEANUP_DANGLING_TRACK : CLEANUP_DANGLING_VIA;
|
||||
DRC_ITEM* item = new DRC_ITEM( errorCode );
|
||||
item->SetItems( track );
|
||||
m_itemsList->push_back( item );
|
||||
|
@ -341,7 +313,7 @@ bool TRACKS_CLEANER::deleteNullSegments( TRACKS& aTracks )
|
|||
{
|
||||
if( segment->IsNull() && segment->Type() == PCB_TRACE_T && !segment->IsLocked() )
|
||||
{
|
||||
DRC_ITEM* item = new DRC_ITEM( DRCE_ZERO_LENGTH_TRACK );
|
||||
DRC_ITEM* item = new DRC_ITEM( CLEANUP_ZERO_LENGTH_TRACK );
|
||||
item->SetItems( segment );
|
||||
m_itemsList->push_back( item );
|
||||
|
||||
|
@ -367,7 +339,7 @@ bool TRACKS_CLEANER::deleteTracksInPads()
|
|||
{
|
||||
if( pad->HitTest( track->GetStart() ) && pad->HitTest( track->GetEnd() ) )
|
||||
{
|
||||
DRC_ITEM* item = new DRC_ITEM( DRCE_TRACK_IN_PAD );
|
||||
DRC_ITEM* item = new DRC_ITEM( CLEANUP_TRACK_IN_PAD );
|
||||
item->SetItems( track );
|
||||
m_itemsList->push_back( item );
|
||||
|
||||
|
@ -410,7 +382,7 @@ bool TRACKS_CLEANER::cleanupSegments()
|
|||
&& track1->GetWidth() == track2->GetWidth()
|
||||
&& track1->GetLayer() == track2->GetLayer() )
|
||||
{
|
||||
DRC_ITEM* item = new DRC_ITEM( DRCE_DUPLICATE_TRACK );
|
||||
DRC_ITEM* item = new DRC_ITEM( CLEANUP_DUPLICATE_TRACK );
|
||||
item->SetItems( track2 );
|
||||
m_itemsList->push_back( item );
|
||||
|
||||
|
@ -510,7 +482,7 @@ bool TRACKS_CLEANER::mergeCollinearSegments( TRACK* aSeg1, TRACK* aSeg2 )
|
|||
return false;
|
||||
}
|
||||
|
||||
DRC_ITEM* item = new DRC_ITEM( DRCE_MERGE_TRACKS );
|
||||
DRC_ITEM* item = new DRC_ITEM( CLEANUP_MERGE_TRACKS );
|
||||
item->SetItems( aSeg1, aSeg2 );
|
||||
m_itemsList->push_back( item );
|
||||
|
||||
|
|
|
@ -80,13 +80,6 @@ private:
|
|||
*/
|
||||
bool cleanupSegments();
|
||||
|
||||
/**
|
||||
* helper function
|
||||
* Rebuild list of tracks, and connected tracks
|
||||
* this info must be rebuilt when tracks are erased
|
||||
*/
|
||||
void buildTrackConnectionInfo();
|
||||
|
||||
/**
|
||||
* helper function
|
||||
* merge aTrackRef and aCandidate, when possible,
|
||||
|
@ -97,15 +90,6 @@ private:
|
|||
*/
|
||||
bool mergeCollinearSegments( TRACK* aSeg1, TRACK* aSeg2 );
|
||||
|
||||
/**
|
||||
* @return true if aTrack has at least one end dangling, i.e. connected
|
||||
* to nothing.
|
||||
* if aTrack is a via, it is dangling if the via is connected to nothing
|
||||
* or only one item.
|
||||
* @param aTrack is the track (or the via) to test.
|
||||
*/
|
||||
bool testTrackEndpointDangling( TRACK* aTrack );
|
||||
|
||||
/**
|
||||
* @return true if a track end position is a node, i.e. a end connected
|
||||
* to more than one item.
|
||||
|
|
Loading…
Reference in New Issue