Performance enhancements to zone filling & track DRC.

Significant improvement in fetch time for item clearances.  On large
boards with lots of nets, maybe 10% faster zone fills and about
2x speedup on track-to-track DRC.
This commit is contained in:
Jeff Young 2019-06-25 03:19:27 +01:00
parent d4054029cd
commit 7ce38ee6f8
5 changed files with 34 additions and 90 deletions

View File

@ -78,75 +78,30 @@ bool BOARD_CONNECTED_ITEM::SetNetCode( int aNetCode, bool aNoAssert )
int BOARD_CONNECTED_ITEM::GetClearance( BOARD_CONNECTED_ITEM* aItem ) const
{
NETCLASSPTR myclass = GetNetClass();
int myClearance = m_netinfo->GetClearance();
// DO NOT use wxASSERT, because GetClearance is called inside an OnPaint event
// and a call to wxASSERT can crash the application.
if( myclass )
{
int myClearance = myclass->GetClearance();
// @todo : after GetNetClass() is reliably not returning NULL, remove the
// tests for if( myclass )
if( m_netinfo->GetNet() == 0 )
myClearance = GetBoard()->GetDesignSettings().GetDefault()->GetClearance();
if( aItem )
{
int hisClearance = aItem->GetClearance();
return std::max( hisClearance, myClearance );
}
if( aItem )
return std::max( myClearance, aItem->GetClearance() );
return myClearance;
}
else
{
wxLogTrace( traceMask, "%s: NULL netclass,type %d", __func__, Type() );
}
return 0;
return myClearance;
}
NETCLASSPTR BOARD_CONNECTED_ITEM::GetNetClass() const
{
// It is important that this be implemented without any sequential searching.
// Simple array lookups should be fine, performance-wise.
BOARD* board = GetBoard();
// DO NOT use wxASSERT, because GetNetClass is called inside an OnPaint event
// and a call to wxASSERT can crash the application.
if( board == NULL ) // Should not occur
{
wxLogTrace( traceMask, "%s: NULL board,type %d", __func__, Type() );
return NETCLASSPTR();
}
NETCLASSPTR netclass;
NETINFO_ITEM* net = board->FindNet( GetNetCode() );
if( net )
{
netclass = net->GetNetClass();
//DBG( if(!netclass) printf( "%s: NULL netclass,type %d", __func__, Type() );)
}
NETCLASSPTR netclass = m_netinfo->GetNetClass();
if( netclass )
return netclass;
else
return board->GetDesignSettings().GetDefault();
return GetBoard()->GetDesignSettings().GetDefault();
}
wxString BOARD_CONNECTED_ITEM::GetNetClassName() const
{
wxString name;
NETCLASSPTR myclass = GetNetClass();
if( myclass )
name = myclass->GetName();
else
name = NETCLASS::Default;
return name;
return m_netinfo->GetClassName();
}

View File

@ -202,9 +202,8 @@ public:
/**
* Function GetClearance
* returns the clearance when routing near aBoardItem
*/
int GetClearance( BOARD_ITEM* aBoardItem )
int GetClearance()
{
wxASSERT( m_NetClass );
return m_NetClass->GetClearance();

View File

@ -795,7 +795,7 @@ void DRC::testTracks( wxWindow *aActiveWindow, bool aShowProgressBar )
}
// Test new segment against tracks and pads, optionally against copper zones
if( !doTrackDrc( *seg_it, seg_it + 1, m_pcb->Tracks().end(), true, m_doZonesTest ) )
if( !doTrackDrc( *seg_it, seg_it + 1, m_pcb->Tracks().end(), m_doZonesTest ) )
{
if( m_currentMarker )
{

View File

@ -330,13 +330,12 @@ private:
* @param aRefSeg The segment to test
* @param aStartIt the iterator to the first track to test
* @param aEndIt the marker for the iterator end
* @param aTestPads true if should do pads test
* @param aTestZones true if should do copper zones test. This can be very time consumming
* @return bool - true if no problems, else false and m_currentMarker is
* filled in with the problem information.
*/
bool doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterator aEndIt,
bool aTestPads, bool aTestZones );
bool aTestZones );
/**
* Test for footprint courtyard overlaps.

View File

@ -111,12 +111,10 @@ bool poly2segmentDRC( wxPoint* aTref, int aTrefCount, wxPoint aSegStart, wxPoint
bool DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterator aEndIt,
bool aTestPads, bool aTestZones )
bool aTestZones )
{
TRACK* track;
wxPoint delta; // length on X and Y axis of segments
LSET layerMask;
int net_code_ref;
wxPoint shape_pos;
std::vector<MARKER_PCB*> markers;
@ -156,8 +154,11 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
m_segmEnd = delta = aRefSeg->GetEnd() - origin;
m_segmAngle = 0;
layerMask = aRefSeg->GetLayerSet();
net_code_ref = aRefSeg->GetNetCode();
LSET layerMask = aRefSeg->GetLayerSet();
int net_code_ref = aRefSeg->GetNetCode();
int ref_seg_clearance = netclass->GetClearance();
int ref_seg_width = aRefSeg->GetWidth();
/******************************************/
/* Phase 0 : via DRC tests : */
@ -265,7 +266,7 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
}
else // This is a track segment
{
if( aRefSeg->GetWidth() < dsnSettings.m_TrackMinWidth )
if( ref_seg_width < dsnSettings.m_TrackMinWidth )
{
wxPoint refsegMiddle = ( aRefSeg->GetStart() + aRefSeg->GetEnd() ) / 2;
@ -308,28 +309,18 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
dummypad.SetLayerSet( LSET::AllCuMask() ); // Ensure the hole is on all layers
// Compute the min distance to pads
if( aTestPads )
for( MODULE* mod : m_pcb->Modules() )
{
unsigned pad_count = m_pcb->GetPadCount();
auto pads = m_pcb->GetPads();
for( unsigned ii = 0; ii < pad_count; ++ii )
for( D_PAD* pad : mod->Pads() )
{
D_PAD* pad = pads[ii];
SEG padSeg( pad->GetPosition(), pad->GetPosition() );
/* No problem if pads are on another layer,
* But if a drill hole exists (a pad on a single layer can have a hole!)
* we must test the hole
*/
// No problem if pads are on another layer, but if a drill hole exists (a pad on
// a single layer can have a hole!) we must test the hole
if( !( pad->GetLayerSet() & layerMask ).any() )
{
/* We must test the pad hole. In order to use the function
* checkClearanceSegmToPad(),a pseudo pad is used, with a shape and a
* size like the hole
*/
// We must test the pad hole. In order to use checkClearanceSegmToPad(), a
// pseudo pad is used, with a shape and a size like the hole
if( pad->GetDrillSize().x == 0 )
continue;
@ -341,8 +332,7 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
m_padToTestPos = dummypad.GetPosition() - origin;
if( !checkClearanceSegmToPad( &dummypad, aRefSeg->GetWidth(),
netclass->GetClearance() ) )
if( !checkClearanceSegmToPad( &dummypad, ref_seg_width, ref_seg_clearance ) )
{
markers.PUSH_NEW_MARKER_4( aRefSeg, pad, padSeg, DRCE_TRACK_NEAR_THROUGH_HOLE );
@ -362,8 +352,9 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
// DRC for the pad
shape_pos = pad->ShapePos();
m_padToTestPos = shape_pos - origin;
int segToPadClearance = std::max( ref_seg_clearance, pad->GetClearance() );
if( !checkClearanceSegmToPad( pad, aRefSeg->GetWidth(), aRefSeg->GetClearance( pad ) ) )
if( !checkClearanceSegmToPad( pad, ref_seg_width, segToPadClearance ) )
{
markers.PUSH_NEW_MARKER_4( aRefSeg, pad, padSeg, DRCE_TRACK_NEAR_PAD );
@ -396,8 +387,8 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
// the minimum distance = clearance plus half the reference track
// width plus half the other track's width
int w_dist = aRefSeg->GetClearance( track );
w_dist += ( aRefSeg->GetWidth() + track->GetWidth() ) / 2;
int w_dist = std::max( ref_seg_clearance, track->GetClearance() );
w_dist += ( ref_seg_width + track->GetWidth() ) / 2;
// Due to many double to int conversions during calculations, which
// create rounding issues,
@ -680,10 +671,10 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
if( zone->GetNetCode() && zone->GetNetCode() == net_code_ref )
continue;
int clearance = zone->GetClearance( aRefSeg );
int clearance = std::max( ref_seg_clearance, zone->GetClearance() );
SHAPE_POLY_SET* outline = const_cast<SHAPE_POLY_SET*>( &zone->GetFilledPolysList() );
if( outline->Distance( refSeg, aRefSeg->GetWidth() ) < clearance )
if( outline->Distance( refSeg, ref_seg_width ) < clearance )
addMarkerToPcb( m_markerFactory.NewMarker( aRefSeg, zone, DRCE_TRACK_NEAR_ZONE ) );
}
}
@ -694,10 +685,10 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
{
SEG test_seg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
int clearance = std::max( aRefSeg->GetClearance(), dsnSettings.m_CopperEdgeClearance );
int clearance = std::max( ref_seg_clearance, dsnSettings.m_CopperEdgeClearance );
// the minimum distance = clearance plus half the reference track width
SEG::ecoord w_dist = clearance + aRefSeg->GetWidth() / 2;
SEG::ecoord w_dist = clearance + ref_seg_width / 2;
SEG::ecoord w_dist_sq = w_dist * w_dist;
for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ )