From 7ce38ee6f88806182408e88698735a5bbf47438b Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Tue, 25 Jun 2019 03:19:27 +0100 Subject: [PATCH] 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. --- pcbnew/board_connected_item.cpp | 63 +++---------------- pcbnew/netinfo.h | 3 +- pcbnew/tools/drc.cpp | 2 +- pcbnew/tools/drc.h | 3 +- pcbnew/tools/drc_clearance_test_functions.cpp | 53 +++++++--------- 5 files changed, 34 insertions(+), 90 deletions(-) diff --git a/pcbnew/board_connected_item.cpp b/pcbnew/board_connected_item.cpp index 32637cb675..3bd7fc37a0 100644 --- a/pcbnew/board_connected_item.cpp +++ b/pcbnew/board_connected_item.cpp @@ -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(); } diff --git a/pcbnew/netinfo.h b/pcbnew/netinfo.h index 25b5250491..1cbe8b143f 100644 --- a/pcbnew/netinfo.h +++ b/pcbnew/netinfo.h @@ -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(); diff --git a/pcbnew/tools/drc.cpp b/pcbnew/tools/drc.cpp index 837f19a30f..c134d6fbe0 100644 --- a/pcbnew/tools/drc.cpp +++ b/pcbnew/tools/drc.cpp @@ -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 ) { diff --git a/pcbnew/tools/drc.h b/pcbnew/tools/drc.h index 6bea3311ce..de0e4c1e0c 100644 --- a/pcbnew/tools/drc.h +++ b/pcbnew/tools/drc.h @@ -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. diff --git a/pcbnew/tools/drc_clearance_test_functions.cpp b/pcbnew/tools/drc_clearance_test_functions.cpp index 91fac15e88..f569bf2db9 100644 --- a/pcbnew/tools/drc_clearance_test_functions.cpp +++ b/pcbnew/tools/drc_clearance_test_functions.cpp @@ -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 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( &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++ )