diff --git a/3d-viewer/3d_canvas/create_layer_items.cpp b/3d-viewer/3d_canvas/create_layer_items.cpp index 6ded7deb2e..a9b5fb184e 100644 --- a/3d-viewer/3d_canvas/create_layer_items.cpp +++ b/3d-viewer/3d_canvas/create_layer_items.cpp @@ -166,9 +166,9 @@ void CINFO3D_VISU::createLayers( REPORTER *aStatusTextReporter ) // ///////////////////////////////////////////////////////////////////////// std::vector< const TRACK *> trackList; trackList.clear(); - trackList.reserve( m_board->m_Track.GetCount() ); + trackList.reserve( m_board->Tracks().size() ); - for( const TRACK* track = m_board->m_Track; track; track = track->Next() ) + for( auto track : m_board->Tracks() ) { if( !Is3DLayerEnabled( track->GetLayer() ) ) // Skip non enabled layers continue; diff --git a/3d-viewer/3d_rendering/3d_render_ogl_legacy/c3d_render_createscene_ogl_legacy.cpp b/3d-viewer/3d_rendering/3d_render_ogl_legacy/c3d_render_createscene_ogl_legacy.cpp index a83c9c51d3..9cc512694e 100644 --- a/3d-viewer/3d_rendering/3d_render_ogl_legacy/c3d_render_createscene_ogl_legacy.cpp +++ b/3d-viewer/3d_rendering/3d_render_ogl_legacy/c3d_render_createscene_ogl_legacy.cpp @@ -745,9 +745,7 @@ void C3D_RENDER_OGL_LEGACY::generate_3D_Vias_and_Pads() // ///////////////////////////////////////////////////////////////////////// // Insert vias holes (vertical cylinders) - for( const TRACK* track = m_settings.GetBoard()->m_Track; - track; - track = track->Next() ) + for( auto track : m_settings.GetBoard()->Tracks() ) { if( track->Type() == PCB_VIA_T ) { diff --git a/3d-viewer/3d_rendering/3d_render_raytracing/c3d_render_createscene.cpp b/3d-viewer/3d_rendering/3d_render_raytracing/c3d_render_createscene.cpp index f008aedd9b..f031033755 100644 --- a/3d-viewer/3d_rendering/3d_render_raytracing/c3d_render_createscene.cpp +++ b/3d-viewer/3d_rendering/3d_render_raytracing/c3d_render_createscene.cpp @@ -1171,9 +1171,7 @@ void C3D_RENDER_RAYTRACING::add_3D_vias_and_pads_to_container() // ///////////////////////////////////////////////////////////////////////// // Insert vias holes (vertical cylinders) - for( const TRACK* track = m_settings.GetBoard()->m_Track; - track; - track = track->Next() ) + for( auto track : m_settings.GetBoard()->Tracks() ) { if( track->Type() == PCB_VIA_T ) { diff --git a/common/base_struct.cpp b/common/base_struct.cpp index 988f086f99..f319665c78 100644 --- a/common/base_struct.cpp +++ b/common/base_struct.cpp @@ -131,6 +131,7 @@ EDA_ITEM* EDA_ITEM::Clone() const // see base_struct.h // many classes inherit this method, be careful: +//TODO(snh): Fix this to use std::set instead of C-style vector SEARCH_RESULT EDA_ITEM::Visit( INSPECTOR inspector, void* testData, const KICAD_T scanTypes[] ) { #if 0 && defined(DEBUG) diff --git a/pcbnew/board_items_to_polygon_shape_transform.cpp b/pcbnew/board_items_to_polygon_shape_transform.cpp index e07cfec434..2003a9bdbe 100644 --- a/pcbnew/board_items_to_polygon_shape_transform.cpp +++ b/pcbnew/board_items_to_polygon_shape_transform.cpp @@ -74,7 +74,7 @@ static void addTextSegmToPoly( int x0, int y0, int xf, int yf, void* aData ) void BOARD::ConvertBrdLayerToPolygonalContours( PCB_LAYER_ID aLayer, SHAPE_POLY_SET& aOutlines ) { // convert tracks and vias: - for( TRACK* track = m_Track; track != NULL; track = track->Next() ) + for( auto track : m_tracks ) { if( !track->IsOnLayer( aLayer ) ) continue; diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index 27ef2d57c0..bd1fe76a73 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -234,327 +234,6 @@ TRACKS BOARD::TracksInNet( int aNetCode ) } -/** - * Function removeTrack - * removes aOneToRemove from aList, which is a non-owning std::vector - */ -static void removeTrack( TRACKS* aList, TRACK* aOneToRemove ) -{ - aList->erase( std::remove( aList->begin(), aList->end(), aOneToRemove ), aList->end() ); -} - - -static void otherEnd( const TRACK& aTrack, const wxPoint& aNotThisEnd, wxPoint* aOtherEnd ) -{ - if( aTrack.GetStart() == aNotThisEnd ) - { - *aOtherEnd = aTrack.GetEnd(); - } - else - { - wxASSERT( aTrack.GetEnd() == aNotThisEnd ); - *aOtherEnd = aTrack.GetStart(); - } -} - - -/** - * Function find_vias_and_tracks_at - * collects TRACKs and VIAs at aPos and returns the @a track_count which excludes vias. - */ -static int find_vias_and_tracks_at( TRACKS& at_next, TRACKS& in_net, LSET& lset, const wxPoint& next ) -{ - // first find all vias (in this net) at 'next' location, and expand LSET with each - for( TRACKS::iterator it = in_net.begin(); it != in_net.end(); ) - { - TRACK* t = *it; - - if( t->Type() == PCB_VIA_T && (t->GetLayerSet() & lset).any() && - ( t->GetStart() == next || t->GetEnd() == next ) ) - { - lset |= t->GetLayerSet(); - at_next.push_back( t ); - it = in_net.erase( it ); - } - else - ++it; - } - - int track_count = 0; - - // with expanded lset, find all tracks with an end on any of the layers in lset - for( TRACKS::iterator it = in_net.begin(); it != in_net.end(); /* iterates in the loop body */ ) - { - TRACK* t = *it; - - if( ( t->GetLayerSet() & lset ).any() && ( t->GetStart() == next || t->GetEnd() == next ) ) - { - at_next.push_back( t ); - it = in_net.erase( it ); - ++track_count; - } - else - { - ++it; - } - } - - return track_count; -} - - -/** - * Function checkConnectedTo - * returns if aTracksInNet contains a copper pathway to aGoal when starting with - * aFirstTrack. aFirstTrack should have one end situated on aStart, and the - * traversal testing begins from the other end of aFirstTrack. - *

- * The function throws an exception instead of returning bool so that detailed - * information can be provided about a possible failure in the track layout. - * - * @throw IO_ERROR - if points are not connected, with text saying why. - */ -static void checkConnectedTo( BOARD* aBoard, TRACKS* aList, const TRACKS& aTracksInNet, - const wxPoint& aGoal, const wxPoint& aStart, TRACK* aFirstTrack ) -{ - TRACKS in_net = aTracksInNet; // copy source list so the copy can be modified - wxPoint next; - - otherEnd( *aFirstTrack, aStart, &next ); - - aList->push_back( aFirstTrack ); - removeTrack( &in_net, aFirstTrack ); - - LSET lset( aFirstTrack->GetLayer() ); - - while( in_net.size() ) - { - if( next == aGoal ) - return; // success - - // Want an exact match on the position of next, i.e. pad at next, - // not a forgiving HitTest() with tolerance type of match, otherwise the overall - // algorithm will not work. GetPadFast() is an exact match as I write this. - if( aBoard->GetPadFast( next, lset ) ) - { - std::string m = StrPrintf( - "intervening pad at:(xy %s) between start:(xy %s) and goal:(xy %s)", - FormatInternalUnits( next ).c_str(), - FormatInternalUnits( aStart ).c_str(), - FormatInternalUnits( aGoal ).c_str() - ); - THROW_IO_ERROR( m ); - } - - int track_count = find_vias_and_tracks_at( *aList, in_net, lset, next ); - - if( track_count != 1 ) - { - std::string m = StrPrintf( - "found %d tracks intersecting at (xy %s), exactly 2 would be acceptable.", - track_count + aList->size() == 1 ? 1 : 0, - FormatInternalUnits( next ).c_str() - ); - THROW_IO_ERROR( m ); - } - - // reduce lset down to the layer that the last track at 'next' is on. - lset = aList->back()->GetLayerSet(); - - otherEnd( *aList->back(), next, &next ); - } - - std::string m = StrPrintf( - "not enough tracks connecting start:(xy %s) and goal:(xy %s).", - FormatInternalUnits( aStart ).c_str(), - FormatInternalUnits( aGoal ).c_str() - ); - THROW_IO_ERROR( m ); -} - - -TRACKS BOARD::TracksInNetBetweenPoints( const wxPoint& aStartPos, const wxPoint& aGoalPos, int aNetCode ) -{ - TRACKS in_between_pts; - TRACKS on_start_point; - TRACKS in_net = TracksInNet( aNetCode ); // a small subset of TRACKs and VIAs - - for( auto t : in_net ) - { - if( t->Type() == PCB_TRACE_T && ( t->GetStart() == aStartPos || t->GetEnd() == aStartPos ) ) - on_start_point.push_back( t ); - } - - wxString per_path_problem_text; - - for( auto t : on_start_point ) // explore each trace (path) leaving aStartPos - { - // checkConnectedTo() fills in_between_pts on every attempt. For failures - // this set needs to be cleared. - in_between_pts.clear(); - - try - { - checkConnectedTo( this, &in_between_pts, in_net, aGoalPos, aStartPos, t ); - } - catch( const IO_ERROR& ioe ) // means not connected - { - per_path_problem_text += "\n\t"; - per_path_problem_text += ioe.Problem(); - continue; // keep trying, there may be other paths leaving from aStartPos - } - - // success, no exception means a valid connection, - // return this set of TRACKS without throwing. - return in_between_pts; - } - - wxString m = wxString::Format( - "no clean path connecting start:(xy %s) with goal:(xy %s)", - FormatInternalUnits( aStartPos ).c_str(), - FormatInternalUnits( aGoalPos ).c_str() - ); - - THROW_IO_ERROR( m + per_path_problem_text ); -} - - -void BOARD::chainMarkedSegments( TRACK* aTrackList, wxPoint aPosition, - const LSET& aLayerSet, TRACKS* aList ) -{ - LSET layer_set = aLayerSet; - - if( !aTrackList ) // no tracks at all in board - return; - - D_PAD* pad = NULL; - double distanceToPadCenter = std::numeric_limits::max(); - - /* Set the BUSY flag of all connected segments, first search starting at - * aPosition. The search ends when a pad is found (end of a track), a - * segment end has more than one other segment end connected, or when no - * connected item found. - * - * Vias are a special case because they can connect segments - * on other layers and they change the layer mask. They can be a track - * end or not. They will be analyzed later, and vias on terminal points - * of the track will be considered as part of this track if they do not - * connect segments on a other track together and will be considered as - * part of a other track when removing the via, the segments of that other - * track are disconnected. - */ - for( ; ; ) - { - if( !pad ) - pad = GetPad( aPosition, layer_set ); - - if( pad ) - distanceToPadCenter = GetLineLength( aPosition, pad->GetCenter() ); - - /* Test for a via: a via changes the layer mask and can connect a lot - * of segments at location aPosition. When found, the via is just - * pushed in list. Vias will be examined later, when all connected - * segment are found and push in list. This is because when a via - * is found we do not know at this time the number of connected items - * and we do not know if this via is on the track or finish the track - */ - TRACK* via = aTrackList->GetVia( NULL, aPosition, layer_set ); - - if( via ) - { - layer_set = via->GetLayerSet(); - aList->push_back( via ); - } - - int seg_count = 0; - TRACK* candidate = NULL; - - /* Search all segments connected to point aPosition. - * if only 1 segment at aPosition: then this segment is "candidate" - * if > 1 segment: - * then end of "track" (because more than 2 segments are connected at aPosition) - */ - TRACK* segment = aTrackList; - - while( ( segment = ::GetTrack( segment, NULL, aPosition, layer_set ) ) != NULL ) - { - if( segment->GetState( BUSY ) ) // already found and selected: skip it - { - segment = segment->Next(); - continue; - } - - if( segment == via ) // just previously found: skip it - { - segment = segment->Next(); - continue; - } - - if( ++seg_count == 1 ) // if first connected item: then segment is candidate - { - candidate = segment; - segment = segment->Next(); - } - else // More than 1 segment connected -> location is end of track - { - return; - } - } - - if( candidate ) // A candidate is found: flag it and push it in list - { - /* Initialize parameters to search items connected to this - * candidate: - * we must analyze connections to its other end - */ - if( aPosition == candidate->GetStart() ) - { - aPosition = candidate->GetEnd(); - } - else - { - aPosition = candidate->GetStart(); - } - - /* If we are in a pad, only candidates approaching the pad center - * are accepted. - */ - if( pad ) - { - if( GetPad( aPosition, layer_set ) != pad ) - return; - - if( GetLineLength( aPosition, pad->GetCenter() ) > distanceToPadCenter ) - return; - } - - layer_set = candidate->GetLayerSet(); - - // flag this item and push it in list of selected items - aList->push_back( candidate ); - candidate->SetState( BUSY, true ); - } - else - { - return; - } - } -} - - -void BOARD::PushHighLight() -{ - m_highLightPrevious = m_highLight; -} - - -void BOARD::PopHighLight() -{ - m_highLight = m_highLightPrevious; - m_highLightPrevious.Clear(); -} - - bool BOARD::SetLayerDescr( PCB_LAYER_ID aIndex, const LAYER& aLayer ) { if( unsigned( aIndex ) < arrayDim( m_Layer ) ) @@ -566,7 +245,6 @@ bool BOARD::SetLayerDescr( PCB_LAYER_ID aIndex, const LAYER& aLayer ) return false; } -#include const PCB_LAYER_ID BOARD::GetLayerID( const wxString& aLayerName ) const { @@ -888,15 +566,9 @@ void BOARD::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode ) case PCB_TRACE_T: case PCB_VIA_T: if( aMode == ADD_APPEND ) - { - m_Track.PushBack( (TRACK*) aBoardItem ); - } + m_tracks.push_back( static_cast( aBoardItem ) ); else - { - TRACK* insertAid; - insertAid = ( (TRACK*) aBoardItem )->GetBestInsertPoint( this ); - m_Track.Insert( (TRACK*) aBoardItem, insertAid ); - } + m_tracks.push_front( static_cast( aBoardItem ) ); break; @@ -983,7 +655,8 @@ void BOARD::Remove( BOARD_ITEM* aBoardItem ) case PCB_TRACE_T: case PCB_VIA_T: - m_Track.Remove( (TRACK*) aBoardItem ); + m_tracks.erase( std::remove_if( m_tracks.begin(), m_tracks.end(), + [aBoardItem]( BOARD_ITEM* aItem ) { return aItem == aBoardItem; } ) ); break; case PCB_DIMENSION_T: @@ -1070,12 +743,6 @@ BOARD_ITEM* BOARD::GetItem( void* aWeakReference ) } -int BOARD::GetNumSegmTrack() const -{ - return m_Track.GetCount(); -} - - unsigned BOARD::GetNodesCount( int aNet ) { unsigned retval = 0; @@ -1138,7 +805,7 @@ EDA_RECT BOARD::ComputeBoundingBox( bool aBoardEdgesOnly ) const } // Check tracks - for( TRACK* track = m_Track; track; track = track->Next() ) + for( auto track : m_tracks ) { if( !( track->GetLayerSet() & visible ).any() ) continue; @@ -1177,7 +844,7 @@ void BOARD::GetMsgPanelInfo( EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM >& int viasCount = 0; int trackSegmentsCount = 0; - for( BOARD_ITEM* item = m_Track; item; item = item->Next() ) + for( auto item : m_tracks ) { if( item->Type() == PCB_VIA_T ) viasCount++; @@ -1331,12 +998,12 @@ SEARCH_RESULT BOARD::Visit( INSPECTOR inspector, void* testData, const KICAD_T s #else case PCB_VIA_T: - result = IterateForward( m_Track, inspector, testData, p ); + result = IterateForward( m_tracks, inspector, testData, p ); ++p; break; case PCB_TRACE_T: - result = IterateForward( m_Track, inspector, testData, p ); + result = IterateForward( m_tracks, inspector, testData, p ); ++p; break; #endif @@ -1587,20 +1254,6 @@ int BOARD::SetAreasNetCodesFromNetNames() } -VIA* BOARD::GetViaByPosition( const wxPoint& aPosition, PCB_LAYER_ID aLayer) const -{ - for( VIA *via = GetFirstVia( m_Track); via; via = GetFirstVia( via->Next() ) ) - { - if( (via->GetStart() == aPosition) && - (via->GetState( BUSY | IS_DELETED ) == 0) && - ((aLayer == UNDEFINED_LAYER) || (via->IsOnLayer( aLayer ))) ) - return via; - } - - return NULL; -} - - D_PAD* BOARD::GetPad( const wxPoint& aPosition, LSET aLayerSet ) { if( !aLayerSet.any() ) @@ -1631,23 +1284,6 @@ D_PAD* BOARD::GetPad( TRACK* aTrace, ENDPOINT_T aEndPoint ) } -std::list BOARD::GetTracksByPosition( const wxPoint& aPosition, PCB_LAYER_ID aLayer ) const -{ - std::list tracks; - - for( TRACK* track = GetFirstTrack( m_Track ); track; track = GetFirstTrack( track->Next() ) ) - { - if( ( ( track->GetStart() == aPosition ) || track->GetEnd() == aPosition ) && - ( track->GetState( BUSY | IS_DELETED ) == 0 ) && - ( ( aLayer == UNDEFINED_LAYER ) || ( track->IsOnLayer( aLayer ) ) ) ) - - tracks.push_back( track ); - } - - return tracks; -} - - D_PAD* BOARD::GetPadFast( const wxPoint& aPosition, LSET aLayerSet ) { for( auto mod : Modules() ) @@ -1798,340 +1434,44 @@ void BOARD::PadDelete( D_PAD* aPad ) } -TRACK* BOARD::GetVisibleTrack( TRACK* aStartingTrace, const wxPoint& aPosition, - LSET aLayerSet ) const +std::tuple BOARD::GetTrackLength( const TRACK& aTrack ) const { - for( TRACK* track = aStartingTrace; track; track = track->Next() ) + int count = 0; + double length = 0.0; + double package_length = 0.0; + + constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_VIA_T, PCB_PAD_T, EOT }; + auto connectivity = GetBoard()->GetConnectivity(); + + for( auto item : connectivity->GetConnectedItems( + static_cast( &aTrack ), types ) ) { - PCB_LAYER_ID layer = track->GetLayer(); + count++; - if( track->GetState( BUSY | IS_DELETED ) ) - continue; - - // track's layer is not visible - if( m_designSettings.IsLayerVisible( layer ) == false ) - continue; - - if( track->Type() == PCB_VIA_T ) // VIA encountered. + if( auto track = dyn_cast( item ) ) { - if( track->HitTest( aPosition ) ) - return track; - } - else - { - if( !aLayerSet[layer] ) - continue; // track's layer is not in aLayerSet + bool inPad = false; - if( track->HitTest( aPosition ) ) - return track; - } - } - - return NULL; -} - - -TRACK* BOARD::MarkTrace( TRACK* aTrackList, TRACK* aTrace, int* aCount, - double* aTraceLength, double* aPadToDieLength, - bool aReorder ) -{ - TRACKS trackList; - - if( aCount ) - *aCount = 0; - - if( aTraceLength ) - *aTraceLength = 0; - - if( aTrace == NULL ) - return NULL; - - // Ensure the flag BUSY of all tracks of the board is cleared - // because we use it to mark segments of the track - for( TRACK* track = aTrackList; track; track = track->Next() ) - track->SetState( BUSY, false ); - - // Set flags of the initial track segment - aTrace->SetState( BUSY, true ); - LSET layer_set = aTrace->GetLayerSet(); - - trackList.push_back( aTrace ); - - /* Examine the initial track segment : if it is really a segment, this is - * easy. - * If it is a via, one must search for connected segments. - * If <=2, this via connect 2 segments (or is connected to only one - * segment) and this via and these 2 segments are a part of a track. - * If > 2 only this via is flagged (the track has only this via) - */ - if( aTrace->Type() == PCB_VIA_T ) - { - TRACK* segm1 = ::GetTrack( aTrackList, NULL, aTrace->GetStart(), layer_set ); - TRACK* segm2 = NULL; - TRACK* segm3 = NULL; - - if( segm1 ) - { - segm2 = ::GetTrack( segm1->Next(), NULL, aTrace->GetStart(), layer_set ); - } - - if( segm2 ) - { - segm3 = ::GetTrack( segm2->Next(), NULL, aTrace->GetStart(), layer_set ); - } - - if( segm3 ) - { - // More than 2 segments are connected to this via. - // The "track" is only this via. - - if( aCount ) - *aCount = 1; - - return aTrace; - } - - if( segm1 ) // search for other segments connected to the initial segment start point - { - layer_set = segm1->GetLayerSet(); - chainMarkedSegments( aTrackList, aTrace->GetStart(), layer_set, &trackList ); - } - - if( segm2 ) // search for other segments connected to the initial segment end point - { - layer_set = segm2->GetLayerSet(); - chainMarkedSegments( aTrackList, aTrace->GetStart(), layer_set, &trackList ); - } - } - else // mark the chain using both ends of the initial segment - { - TRACKS from_start; - TRACKS from_end; - - chainMarkedSegments( aTrackList, aTrace->GetStart(), layer_set, &from_start ); - chainMarkedSegments( aTrackList, aTrace->GetEnd(), layer_set, &from_end ); - - // combine into one trackList: - trackList.insert( trackList.end(), from_start.begin(), from_start.end() ); - trackList.insert( trackList.end(), from_end.begin(), from_end.end() ); - } - - // Now examine selected vias and flag them if they are on the track - // If a via is connected to only one or 2 segments, it is flagged (is on the track) - // If a via is connected to more than 2 segments, it is a track end, and it - // is removed from the list. - // Go through the list backwards. - for( int i = trackList.size() - 1; i>=0; --i ) - { - ::VIA* via = dynamic_cast< ::VIA* >( trackList[i] ); - - if( !via ) - continue; - - if( via == aTrace ) - continue; - - via->SetState( BUSY, true ); // Try to flag it. the flag will be cleared later if needed - - layer_set = via->GetLayerSet(); - - TRACK* track = ::GetTrack( aTrackList, NULL, via->GetStart(), layer_set ); - - // GetTrace does not consider tracks flagged BUSY. - // So if no connected track found, this via is on the current track - // only: keep it - if( track == NULL ) - continue; - - /* If a track is found, this via connects also other segments of - * the other track. This case happens when a via ends the selected - * track but must we consider this via is on the selected track, or - * on a other track. - * (this is important when selecting a track for deletion: must this - * via be deleted or not?) - * We consider this via to be on our track if other segments connected - * to this via remain connected when removing this via. - * We search for all other segments connected together: - * if they are on the same layer, then the via is on the selected track; - * if they are on different layers, the via is on a other track. - */ - LAYER_NUM layer = track->GetLayer(); - - while( ( track = ::GetTrack( track->Next(), NULL, via->GetStart(), layer_set ) ) != NULL ) - { - if( layer != track->GetLayer() ) + for( auto pad_it : connectivity->GetConnectedPads( item ) ) { - // The via connects segments of a other track: it is removed - // from list because it is member of a other track - via->SetState( BUSY, false ); - break; + auto pad = static_cast( pad_it ); + + if( pad->HitTest( track->GetStart(), track->GetWidth() / 2 ) + && pad->HitTest( track->GetEnd(), track->GetWidth() / 2 ) ) + { + inPad = true; + break; + } } + + if( !inPad ) + length += track->GetLength(); } + else if( auto pad = dyn_cast( item ) ) + package_length += pad->GetPadToDieLength(); } - /* Rearrange the track list in order to have flagged segments linked - * from firstTrack so the NbSegmBusy segments are consecutive segments - * in list, the first item in the full track list is firstTrack, and - * the NbSegmBusy-1 next items (NbSegmBusy when including firstTrack) - * are the flagged segments - */ - int busy_count = 0; - TRACK* firstTrack; - - for( firstTrack = aTrackList; firstTrack; firstTrack = firstTrack->Next() ) - { - // Search for the first flagged BUSY segments - if( firstTrack->GetState( BUSY ) ) - { - busy_count = 1; - break; - } - } - - if( firstTrack == NULL ) - return NULL; - - // First step: calculate the track length and find the pads (when exist) - // at each end of the trace. - double full_len = 0; - double lenPadToDie = 0; - // Because we have a track (a set of track segments between 2 nodes), - // only 2 pads (maximum) will be taken in account: - // that are on each end of the track, if any. - // keep trace of them, to know the die length and the track length ibside each pad. - D_PAD* s_pad = NULL; // the pad on one end of the trace - D_PAD* e_pad = NULL; // the pad on the other end of the trace - int dist_fromstart = INT_MAX; - int dist_fromend = INT_MAX; - - for( TRACK* track = firstTrack; track; track = track->Next() ) - { - if( !track->GetState( BUSY ) ) - continue; - - layer_set = track->GetLayerSet(); - D_PAD * pad_on_start = GetPad( track->GetStart(), layer_set ); - D_PAD * pad_on_end = GetPad( track->GetEnd(), layer_set ); - - // a segment fully inside a pad does not contribute to the track len - // (another track end inside this pad will contribute to this lenght) - if( pad_on_start && ( pad_on_start == pad_on_end ) ) - continue; - - full_len += track->GetLength(); - - if( pad_on_start == NULL && pad_on_end == NULL ) - // This most of time the case - continue; - - // At this point, we can have one track end on a pad, or the 2 track ends on - // 2 different pads. - // We don't know what pad (s_pad or e_pad) must be used to store the - // start point and the end point of the track, so if a pad is already set, - // use the other - if( pad_on_start ) - { - SEG segm( track->GetStart(), pad_on_start->GetPosition() ); - int dist = segm.Length(); - - if( s_pad == NULL ) - { - dist_fromstart = dist; - s_pad = pad_on_start; - } - else if( e_pad == NULL ) - { - dist_fromend = dist; - e_pad = pad_on_start; - } - else // Should not occur, at least for basic pads - { - wxLogWarning( "Unexpected BOARD::MarkTrace: multiple pad_on_start" ); - } - } - - if( pad_on_end ) - { - SEG segm( track->GetEnd(), pad_on_end->GetPosition() ); - int dist = segm.Length(); - - if( s_pad == NULL ) - { - dist_fromstart = dist; - s_pad = pad_on_end; - } - else if( e_pad == NULL ) - { - dist_fromend = dist; - e_pad = pad_on_end; - } - else // Should not occur, at least for basic pads - { - wxLogWarning( "Unexpected BOARD::MarkTrace: multiple pad_on_end" ); - } - } - } - - if( aReorder ) - { - DLIST* list = (DLIST*)firstTrack->GetList(); - wxASSERT( list ); - - /* Rearrange the chain starting at firstTrack - * All other BUSY flagged items are moved from their position to the end - * of the flagged list - */ - TRACK* next; - - for( TRACK* track = firstTrack->Next(); track; track = next ) - { - next = track->Next(); - - if( track->GetState( BUSY ) ) // move it! - { - busy_count++; - track->UnLink(); - list->Insert( track, firstTrack->Next() ); - - } - } - } - else if( aTraceLength ) - { - busy_count = 0; - - for( TRACK* track = firstTrack; track; track = track->Next() ) - { - if( track->GetState( BUSY ) ) - { - busy_count++; - track->SetState( BUSY, false ); - } - } - } - - if( s_pad ) - { - full_len += dist_fromstart; - lenPadToDie += (double) s_pad->GetPadToDieLength(); - } - - if( e_pad ) - { - full_len += dist_fromend; - lenPadToDie += (double) e_pad->GetPadToDieLength(); - } - - if( aTraceLength ) - *aTraceLength = full_len; - - if( aPadToDieLength ) - *aPadToDieLength = lenPadToDie; - - if( aCount ) - *aCount = busy_count; - - return firstTrack; + return std::make_tuple( count, length, package_length ); } @@ -2203,104 +1543,6 @@ MODULE* BOARD::GetFootprint( const wxPoint& aPosition, PCB_LAYER_ID aActiveLayer } -BOARD_CONNECTED_ITEM* BOARD::GetLockPoint( const wxPoint& aPosition, LSET aLayerSet ) -{ - for( auto module : m_modules ) - { - D_PAD* pad = module->GetPad( aPosition, aLayerSet ); - - if( pad ) - return pad; - } - - // No pad has been located so check for a segment of the trace. - TRACK* segment = ::GetTrack( m_Track, NULL, aPosition, aLayerSet ); - - if( !segment ) - segment = GetVisibleTrack( m_Track, aPosition, aLayerSet ); - - return segment; -} - - -TRACK* BOARD::CreateLockPoint( wxPoint& aPosition, TRACK* aSegment, PICKED_ITEMS_LIST* aList ) -{ - /* creates an intermediate point on aSegment and break it into two segments - * at aPosition. - * The new segment starts from aPosition and ends at the end point of - * aSegment. The original segment now ends at aPosition. - */ - if( aSegment->GetStart() == aPosition || aSegment->GetEnd() == aPosition ) - return NULL; - - // A via is a good lock point - if( aSegment->Type() == PCB_VIA_T ) - { - aPosition = aSegment->GetStart(); - return aSegment; - } - - // Calculation coordinate of intermediate point relative to the start point of aSegment - wxPoint delta = aSegment->GetEnd() - aSegment->GetStart(); - - // calculate coordinates of aPosition relative to aSegment->GetStart() - wxPoint lockPoint = aPosition - aSegment->GetStart(); - - // lockPoint must be on aSegment: - // Ensure lockPoint.y/lockPoint.y = delta.y/delta.x - if( delta.x == 0 ) - lockPoint.x = 0; // horizontal segment - else - lockPoint.y = KiROUND( ( (double)lockPoint.x * delta.y ) / delta.x ); - - /* Create the intermediate point (that is to say creation of a new - * segment, beginning at the intermediate point. - */ - lockPoint += aSegment->GetStart(); - - TRACK* newTrack = (TRACK*)aSegment->Clone(); - // The new segment begins at the new point, - newTrack->SetStart(lockPoint); - newTrack->start = aSegment; - newTrack->SetState( BEGIN_ONPAD, false ); - - DLIST* list = (DLIST*)aSegment->GetList(); - wxASSERT( list ); - list->Insert( newTrack, aSegment->Next() ); - - if( aList ) - { - // Prepare the undo command for the now track segment - ITEM_PICKER picker( newTrack, UR_NEW ); - aList->PushItem( picker ); - // Prepare the undo command for the old track segment - // before modifications - picker.SetItem( aSegment ); - picker.SetStatus( UR_CHANGED ); - picker.SetLink( aSegment->Clone() ); - aList->PushItem( picker ); - } - - // Old track segment now ends at new point. - aSegment->SetEnd(lockPoint); - aSegment->end = newTrack; - aSegment->SetState( END_ONPAD, false ); - - D_PAD * pad = GetPad( newTrack, ENDPOINT_START ); - - if( pad ) - { - newTrack->start = pad; - newTrack->SetState( BEGIN_ONPAD, true ); - aSegment->end = pad; - aSegment->SetState( END_ONPAD, true ); - } - - aPosition = lockPoint; - return newTrack; -} - - ZONE_CONTAINER* BOARD::AddArea( PICKED_ITEMS_LIST* aNewZonesList, int aNetcode, PCB_LAYER_ID aLayer, wxPoint aStartPointPosition, int aHatch ) { diff --git a/pcbnew/class_board.h b/pcbnew/class_board.h index 394ed151a6..b36156c799 100644 --- a/pcbnew/class_board.h +++ b/pcbnew/class_board.h @@ -30,6 +30,7 @@ #ifndef CLASS_BOARD_H_ #define CLASS_BOARD_H_ +#include #include #include @@ -161,7 +162,7 @@ protected: DECL_VEC_FOR_SWIG( MARKERS, MARKER_PCB* ) DECL_VEC_FOR_SWIG( ZONE_CONTAINERS, ZONE_CONTAINER* ) -DECL_VEC_FOR_SWIG( TRACKS, TRACK* ) +DECL_DEQ_FOR_SWIG( TRACKS, TRACK* ) DECL_DEQ_FOR_SWIG( DRAWINGS, BOARD_ITEM* ) DECL_DEQ_FOR_SWIG( MODULES, MODULE* ) @@ -187,6 +188,9 @@ private: /// MODULES for components on the board, owned by pointer. MODULES m_modules; + /// TRACKS for traces on the board, owned by pointer. + TRACKS m_tracks; + /// edge zone descriptors, owned by pointer. ZONE_CONTAINERS m_ZoneDescriptorList; @@ -208,18 +212,6 @@ private: PCB_PLOT_PARAMS m_plotOptions; NETINFO_LIST m_NetInfo; ///< net info list (name, design constraints .. - /** - * Function chainMarkedSegments - * is used by MarkTrace() to set the BUSY flag of connected segments of the trace - * segment located at \a aPosition on aLayerMask. - * Vias are put in list but their flags BUSY is not set - * @param aTrackList is the beginning of the track list (usually the board track list). - * @param aPosition A wxPoint object containing the position of the starting search. - * @param aLayerSet The allowed layers for segments to search. - * @param aList The track list to fill with points of flagged segments. - */ - void chainMarkedSegments( TRACK* aTrackList, wxPoint aPosition, - const LSET& aLayerSet, TRACKS* aList ); // The default copy constructor & operator= are inadequate, // either write one or do not use it at all @@ -245,15 +237,16 @@ public: const wxString &GetFileName() const { return m_fileName; } - /// Flags used in ratsnest calculation and update. - int m_Status_Pcb; + TRACKS& Tracks() + { + return m_tracks; + } + const TRACKS& Tracks() const + { + return m_tracks; + } -public: - - DLIST m_Track; // linked list of TRACKs and VIAs - - DLIST_ITERATOR_WRAPPER Tracks() { return DLIST_ITERATOR_WRAPPER(m_Track); } - MODULES& Modules() + MODULES& Modules() { return m_modules; } @@ -261,8 +254,17 @@ public: { return m_modules; } - DRAWINGS& Drawings() { return m_drawings; } - ZONE_CONTAINERS& Zones() { return m_ZoneDescriptorList; } + + DRAWINGS& Drawings() + { + return m_drawings; + } + + ZONE_CONTAINERS& Zones() + { + return m_ZoneDescriptorList; + } + const std::vector AllConnectedItems(); /// zone contour currently in progress @@ -276,7 +278,7 @@ public: bool IsEmpty() const { - return m_drawings.empty() && m_modules.empty() && m_Track.GetCount() == 0; + return m_drawings.empty() && m_modules.empty() && m_tracks.empty(); } void Move( const wxPoint& aMoveVector ) override; @@ -423,18 +425,6 @@ public: */ void HighLightON() { m_highLight.m_highLightOn = true; } - /** - * Function PushHighLight - * save current high light info for later use - */ - void PushHighLight(); - - /** - * Function PopHighLight - * retrieve a previously saved high light info - */ - void PopHighLight(); - /** * Function GetCopperLayerCount * @return int - The number of copper layers in the BOARD. @@ -715,9 +705,6 @@ public: */ bool SetLayerType( PCB_LAYER_ID aLayer, LAYER_T aLayerType ); - /** Functions to get some items count */ - int GetNumSegmTrack() const; - /** * Function GetNodesCount * @param aNet Only count nodes belonging to this net @@ -1091,31 +1078,6 @@ public: ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combine ); - /** - * Function GetViaByPosition - * finds the first via at \a aPosition on \a aLayer. - *

- * This function does not use the normal hit test to locate a via which which tests - * if a position is within the via's bounding box. It tests for the actual locate - * of the via. - *

- * @param aPosition The wxPoint to HitTest() against. - * @param aLayer The layer to search. Use -1 (PCB_LAYER_ID::UNDEFINED_LAYER) for a don't care. - * @return VIA* A point a to the VIA object if found, else NULL. - */ - VIA* GetViaByPosition( const wxPoint& aPosition, - PCB_LAYER_ID aLayer = PCB_LAYER_ID( -1 ) ) const; - - /** - * Function GetTracksByPosition - * finds the list of tracks that starts or ends at \a aPosition on \a aLayer. - * - * @param aPosition The wxPoint to check start agains against. - * @param aLayer The layer to search. Use -1 (::UNDEFINED_LAYER) for a don't care. - * @return std::list A list of TRACK* items that can be zero if no track is found. - */ - std::list GetTracksByPosition( const wxPoint& aPosition, PCB_LAYER_ID aLayer = PCB_LAYER_ID( -1 ) ) const; - /** * Function GetPad * finds a pad \a aPosition on \a aLayer. @@ -1192,48 +1154,13 @@ public: void GetSortedPadListByXthenYCoord( std::vector& aVector, int aNetCode = -1 ); /** - * Function GetVisibleTrack - * finds the neighboring visible segment of \a aTrace at \a aPosition that is - * on a layer in \a aLayerSet. - * Traces that are flagged as deleted or busy are ignored. + * Returns data on the length and number of track segments connected to a given track. + * This uses the connectivity data for the board to calculate connections * - * @param aStartingTrace is the first TRACK to test, testing continues to end of m_Track list from - * this starting point. - * @param aPosition A wxPoint object containing the position to test. - * @param aLayerSet A set of layers; returned TRACK must be on one of these. - * May pass a full set to request any layer. - * @return A TRACK object pointer if found otherwise NULL. + * @param aTrack Starting track (can also be a via) to check against for connection. + * @return a tuple containing */ - TRACK* GetVisibleTrack( TRACK* aStartingTrace, const wxPoint& aPosition, LSET aLayerSet ) const; - - /** - * Function MarkTrace - * marks a chain of trace segments, connected to \a aTrace. - *

- * Each segment is marked by setting the BUSY bit into m_Flags. Electrical - * continuity is detected by walking each segment, and finally the segments - * are rearranged into a contiguous chain within the given list. - *

- * - * @param aTrackList The list of available track segments. - * usually tracks on board, but can be a list of segments currently created. - * @param aTrace The segment within a list of trace segments to test. - * @param aCount A pointer to an integer where to return the number of - * marked segments (can be NULL). - * @param aTraceLength A pointer to an double where to return the length of the - * trace (can be NULL). - * @param aInPackageLength A pointer to an double where to return the extra lengths inside - * integrated circuits from the pads connected to this track to the - * die (if any) (can be NULL). - * @param aReorder true for reorder the interesting segments (useful for - * track editing/deleting) in this case the flag BUSY is - * set (the user is responsible of flag clearing). False - * for no reorder : useful when we want just calculate the - * track length in this case, flags are reset - * @return TRACK* - The first in the chain of interesting segments. - */ - TRACK* MarkTrace( TRACK* aTrackList, TRACK* aTrace, int* aCount, double* aTraceLength, - double* aInPackageLength, bool aReorder ); + std::tuple GetTrackLength( const TRACK& aTrack ) const; /** * Function TrackInNet @@ -1244,25 +1171,6 @@ public: */ TRACKS TracksInNet( int aNetCode ); - /** - * Function TrackInNetBetweenPoints - * collects all the TRACKs and VIAs that are members of a net given by aNetCode and that - * make up a path between two end points. The end points must be carefully chosen, - * and are typically the locations of two neighboring pads. The function fails if there - * is an intervening pad or a 3 way intersection at a track or via. The seeking starts - * at @a aStartPos and strives to travel to @a aGoalPos. - * Used from python. - * @param aStartPos must correspond to a point on the BOARD which has a TRACK end or start, - * typically the location of either a via or pad. - * @param aGoalPos must correspond to a point on the BOARD which has a TRACK end or start, - * typically the location of either a via or pad. - * @param aNetCode gives the id of the net. - * @return TRACKS - non empty if success, empty if your aStartPos or aEndPos are bad or - * the net is interrupted along the way by an intervening D_PAD or a 3 way path. - * @throw IO_ERROR in order to convey detailed error reason upon failure. - */ - TRACKS TracksInNetBetweenPoints( const wxPoint& aStartPos, const wxPoint& aGoalPos, int aNetCode ); - /** * Function GetFootprint * get a footprint by its bounding rectangle at \a aPosition on \a aLayer. @@ -1280,40 +1188,6 @@ public: MODULE* GetFootprint( const wxPoint& aPosition, PCB_LAYER_ID aActiveLayer, bool aVisibleOnly, bool aIgnoreLocked = false ); - /** - * Function GetLockPoint - * returns the item at the "attachment" point at the end of a trace at \a aPosition - * on \a aLayerMask. - *

- * This may be a PAD or another trace segment. - *

- * - * @param aPosition A wxPoint object containing the position to test. - * @param aLayerMask A layer or layers to mask the hit test. Use -1 to ignore - * layer mask. - * @return A pointer to a BOARD_ITEM object if found otherwise NULL. - */ - BOARD_CONNECTED_ITEM* GetLockPoint( const wxPoint& aPosition, LSET aLayerMask ); - - /** - * Function CreateLockPoint - * creates an intermediate point on \a aSegment and break it into two segments - * at \a aPosition. - *

- * The new segment starts from \a aPosition and ends at the end point of \a - * aSegment. The original segment now ends at \a aPosition. - *

- * - * @param aPosition A wxPoint object containing the position to test and the new - * segment start position if the return value is not NULL. - * @param aSegment The trace segment to create the lock point on. - * @param aList The pick list to add the created items to. - * @return NULL if no new point was created or a pointer to a TRACK object of the - * created segment. If \a aSegment points to a via the exact value of \a - * aPosition and a pointer to the via are returned. - */ - TRACK* CreateLockPoint( wxPoint& aPosition, TRACK* aSegment, PICKED_ITEMS_LIST* aList ); - /** * Function ClearAllNetCodes() * Resets all items' netcodes to 0 (no net). diff --git a/pcbnew/class_track.cpp b/pcbnew/class_track.cpp index 92e43b4af2..8a98575efe 100644 --- a/pcbnew/class_track.cpp +++ b/pcbnew/class_track.cpp @@ -58,40 +58,10 @@ static bool ShowClearance( PCB_DISPLAY_OPTIONS* aDisplOpts, const TRACK* aTrack } -TRACK* GetTrack( TRACK* aStartTrace, const TRACK* aEndTrace, - const wxPoint& aPosition, LSET aLayerMask ) -{ - for( TRACK* seg = aStartTrace; seg; seg = seg->Next() ) - { - if( seg->GetState( IS_DELETED | BUSY ) == 0 ) - { - if( aPosition == seg->GetStart() ) - { - if( ( aLayerMask & seg->GetLayerSet() ).any() ) - return seg; - } - - if( aPosition == seg->GetEnd() ) - { - if( ( aLayerMask & seg->GetLayerSet() ).any() ) - return seg; - } - } - - if( seg == aEndTrace ) - break; - } - - return NULL; -} - - TRACK::TRACK( BOARD_ITEM* aParent, KICAD_T idtype ) : BOARD_CONNECTED_ITEM( aParent, idtype ) { m_Width = Millimeter2iu( 0.2 ); - start = end = NULL; - m_Param = 0; } @@ -188,16 +158,7 @@ int VIA::GetDrillValue() const } -bool TRACK::IsNull() -{ - if( ( Type() != PCB_VIA_T ) && ( m_Start == m_End ) ) - return true; - else - return false; -} - - -STATUS_FLAGS TRACK::IsPointOnEnds( const wxPoint& point, int min_dist ) +STATUS_FLAGS TRACK::IsPointOnEnds( const wxPoint& point, int min_dist ) const { STATUS_FLAGS result = 0; @@ -419,21 +380,6 @@ void VIA::SanitizeLayers() } -TRACK* TRACK::GetBestInsertPoint( BOARD* aPcb ) -{ - // When reading from a file most of the items will already be in the correct order. - // Searching from the back therefore takes us from n^2 to essentially 0. - - for( TRACK* track = aPcb->m_Track.GetLast(); track; track = track->Back() ) - { - if( GetNetCode() >= track->GetNetCode() ) - return track->Next(); - } - - return aPcb->m_Track.GetFirst(); -} - - TRACK* TRACK::GetStartNetCode( int NetCode ) { TRACK* Track = this; @@ -794,17 +740,12 @@ void TRACK::GetMsgPanelInfo( EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM >& // Display full track length (in Pcbnew) if( board ) { - double trackLen = 0; - double lenPadToDie = 0; + int count; + double trackLen; + double lenPadToDie; - // Find the beginning of the track buffer containing this, because it is not - // always the track list on board, but can be a "private" list - TRACK* track_buffer_start = this; + std::tie( count, trackLen, lenPadToDie ) = board->GetTrackLength( *this ); - while( track_buffer_start->Back() ) - track_buffer_start = track_buffer_start->Back(); - - board->MarkTrace( track_buffer_start, this, NULL, &trackLen, &lenPadToDie, false ); msg = MessageTextFromValue( aUnits, trackLen ); aList.push_back( MSG_PANEL_ITEM( _( "Length" ), msg, DARKCYAN ) ); @@ -1059,248 +1000,6 @@ bool VIA::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const } -VIA* TRACK::GetVia( const wxPoint& aPosition, PCB_LAYER_ID aLayer) -{ - for( VIA* via = GetFirstVia( this ); via; via = GetFirstVia( via->Next() ) ) - { - if( via->HitTest( aPosition ) && - !via->GetState( BUSY | IS_DELETED ) && - ((aLayer == UNDEFINED_LAYER) || (via->IsOnLayer( aLayer ))) ) - return via; - } - - return NULL; -} - - -VIA* TRACK::GetVia( TRACK* aEndTrace, const wxPoint& aPosition, LSET aLayerMask ) -{ - for( VIA* via = GetFirstVia( this, aEndTrace ); via; via = GetFirstVia( via->Next() ) ) - { - if( via->HitTest( aPosition ) && - !via->GetState( BUSY | IS_DELETED ) && - ( aLayerMask & via->GetLayerSet() ).any() - ) - { - return via; - } - } - - return NULL; -} - - -TRACK* TRACK::GetTrack( TRACK* aStartTrace, TRACK* aEndTrace, ENDPOINT_T aEndPoint, - bool aSameNetOnly, bool aSequential ) -{ - const wxPoint& position = GetEndPoint( aEndPoint ); - LSET refLayers = GetLayerSet(); - TRACK* previousSegment; - TRACK* nextSegment; - - if( aSequential ) - { - // Simple sequential search: from aStartTrace forward to aEndTrace - previousSegment = NULL; - nextSegment = aStartTrace; - } - else - { - /* Local bidirectional search: from this backward to aStartTrace - * AND forward to aEndTrace. The idea is that nearest segments - * are found (on average) faster in this way. In fact same-net - * segments are almost guaranteed to be found faster, in a global - * search, since they are grouped together in the track list */ - previousSegment = this; - nextSegment = this; - } - - while( nextSegment || previousSegment ) - { - // Terminate the search in the direction if the netcode mis-matches - if( aSameNetOnly ) - { - if( nextSegment && (nextSegment->GetNetCode() != GetNetCode()) ) - nextSegment = NULL; - if( previousSegment && (previousSegment->GetNetCode() != GetNetCode()) ) - previousSegment = NULL; - } - - if( nextSegment ) - { - if ( (nextSegment != this) && - !nextSegment->GetState( BUSY | IS_DELETED ) && - ( refLayers & nextSegment->GetLayerSet() ).any() ) - { - if( (position == nextSegment->m_Start) || - (position == nextSegment->m_End) ) - return nextSegment; - } - - // Keep looking forward - if( nextSegment == aEndTrace ) - nextSegment = NULL; - else - nextSegment = nextSegment->Next(); - } - - // Same as above, looking back. During sequential search this branch is inactive - if( previousSegment ) - { - if( (previousSegment != this) && - !previousSegment->GetState( BUSY | IS_DELETED ) && - ( refLayers & previousSegment->GetLayerSet() ).any() - ) - { - if( (position == previousSegment->m_Start) || - (position == previousSegment->m_End) ) - return previousSegment; - } - - if( previousSegment == aStartTrace ) - previousSegment = NULL; - else - previousSegment = previousSegment->Back(); - } - } - - return NULL; -} - - -int TRACK::GetEndSegments( int aCount, TRACK** aStartTrace, TRACK** aEndTrace ) -{ - TRACK* Track, * via, * segm, * TrackListEnd; - int NbEnds, ii, ok = 0; - LSET layerMask; - - if( aCount <= 1 ) - { - *aStartTrace = *aEndTrace = this; - return 1; - } - - // Calculation of the limit analysis. - *aStartTrace = *aEndTrace = NULL; - TrackListEnd = Track = this; - ii = 0; - - for( ; ( Track != NULL ) && ( ii < aCount ); ii++, Track = Track->Next() ) - { - TrackListEnd = Track; - Track->m_Param = 0; - } - - // Calculate the extremes. - NbEnds = 0; - Track = this; - ii = 0; - - for( ; ( Track != NULL ) && ( ii < aCount ); ii++, Track = Track->Next() ) - { - if( Track->Type() == PCB_VIA_T ) - continue; - - layerMask = Track->GetLayerSet(); - via = GetVia( TrackListEnd, Track->m_Start, layerMask ); - - if( via ) - { - layerMask |= via->GetLayerSet(); - via->SetState( BUSY, true ); - } - - Track->SetState( BUSY, true ); - segm = ::GetTrack( this, TrackListEnd, Track->m_Start, layerMask ); - Track->SetState( BUSY, false ); - - if( via ) - via->SetState( BUSY, false ); - - if( segm == NULL ) - { - switch( NbEnds ) - { - case 0: - *aStartTrace = Track; NbEnds++; - break; - - case 1: - int BeginPad, EndPad; - *aEndTrace = Track; - - // Swap ox, oy with fx, fy - BeginPad = Track->GetState( BEGIN_ONPAD ); - EndPad = Track->GetState( END_ONPAD ); - - Track->SetState( BEGIN_ONPAD | END_ONPAD, false ); - - if( BeginPad ) - Track->SetState( END_ONPAD, true ); - - if( EndPad ) - Track->SetState( BEGIN_ONPAD, true ); - - std::swap( Track->m_Start, Track->m_End ); - std::swap( Track->start, Track->end ); - ok = 1; - return ok; - } - } - - layerMask = Track->GetLayerSet(); - via = GetVia( TrackListEnd, Track->m_End, layerMask ); - - if( via ) - { - layerMask |= via->GetLayerSet(); - via->SetState( BUSY, true ); - } - - Track->SetState( BUSY, true ); - segm = ::GetTrack( this, TrackListEnd, Track->m_End, layerMask ); - Track->SetState( BUSY, false ); - - if( via ) - via->SetState( BUSY, false ); - - if( segm == NULL ) - { - switch( NbEnds ) - { - case 0: - int BeginPad, EndPad; - *aStartTrace = Track; - NbEnds++; - - // Swap ox, oy with fx, fy - BeginPad = Track->GetState( BEGIN_ONPAD ); - EndPad = Track->GetState( END_ONPAD ); - - Track->SetState( BEGIN_ONPAD | END_ONPAD, false ); - - if( BeginPad ) - Track->SetState( END_ONPAD, true ); - - if( EndPad ) - Track->SetState( BEGIN_ONPAD, true ); - - std::swap( Track->m_Start, Track->m_End ); - std::swap( Track->start, Track->end ); - break; - - case 1: - *aEndTrace = Track; - ok = 1; - return ok; - } - } - } - - return ok; -} - - wxString TRACK::GetSelectMenuText( EDA_UNITS_T aUnits ) const { return wxString::Format( _("Track %s %s on %s, length: %s" ), diff --git a/pcbnew/class_track.h b/pcbnew/class_track.h index 60efb8c8c2..2243c02c79 100644 --- a/pcbnew/class_track.h +++ b/pcbnew/class_track.h @@ -37,6 +37,8 @@ #include #include +#include + #include @@ -72,25 +74,6 @@ enum VIATYPE_T #define GEOMETRY_MIN_SIZE ( int )( 0.001 * IU_PER_MM ) -/** - * Function GetTrack - * is a helper function to locate a trace segment having an end point at \a aPosition - * on \a aLayerMask starting at \a aStartTrace and end at \a aEndTrace. - *

- * The segments of track that are flagged as deleted or busy are ignored. Layer - * visibility is also ignored. - *

- * @param aStartTrace A pointer to the TRACK object to begin searching. - * @param aEndTrace A pointer to the TRACK object to stop the search. A NULL value - * searches to the end of the list. - * @param aPosition A wxPoint object containing the position to test. - * @param aLayerMask A layer or layers to mask the hit test. Use -1 to ignore - * layer mask. - * @return A TRACK object pointer if found otherwise NULL. - */ -TRACK* GetTrack( TRACK* aStartTrace, const TRACK* aEndTrace, - const wxPoint& aPosition, LSET aLayerMask ); - class TRACK : public BOARD_CONNECTED_ITEM { public: @@ -99,18 +82,10 @@ public: return aItem && PCB_TRACE_T == aItem->Type(); } - BOARD_CONNECTED_ITEM* start; // pointers to a connected item (pad or track) - BOARD_CONNECTED_ITEM* end; - - double m_Param; // Auxiliary variable ( used in some computations ) - TRACK( BOARD_ITEM* aParent, KICAD_T idtype = PCB_TRACE_T ); // Do not create a copy constructor. The one generated by the compiler is adequate. - TRACK* Next() const { return static_cast( Pnext ); } - TRACK* Back() const { return static_cast( Pback ); } - virtual void Move( const wxPoint& aMoveVector ) override { m_Start += aMoveVector; @@ -156,19 +131,6 @@ public: return SetState( TRACK_LOCKED, aLocked ); } - /** - * Function GetBestInsertPoint - * searches the "best" insertion point within the track linked list. - * The best point is currently the end of the corresponding net code section. - * (The BOARD::m_Track and BOARD::m_Zone lists are sorted by netcode.) - * @param aPcb The BOARD to search for the insertion point. - * @return TRACK* - the insertion point in the linked list. - * this is the next item after the last item having my net code. - * therefore the track to insert must be inserted before the insertion point. - * if the best insertion point is the end of list, the returned value is NULL - */ - TRACK* GetBestInsertPoint( BOARD* aPcb ); - /* Search (within the track linked list) the first segment matching the netcode * ( the linked list is always sorted by net codes ) */ @@ -211,13 +173,16 @@ public: * (dist = min_dist) both ends, or 0 if none of the above. * if min_dist < 0: min_dist = track_width/2 */ - STATUS_FLAGS IsPointOnEnds( const wxPoint& point, int min_dist = 0 ); + STATUS_FLAGS IsPointOnEnds( const wxPoint& point, int min_dist = 0 ) const; /** * Function IsNull * returns true if segment length is zero. */ - bool IsNull(); + bool IsNull() const + { + return ( Type() == PCB_VIA_T ) || ( m_Start == m_End ); + } void GetMsgPanelInfo( EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM >& aList ) override; @@ -226,57 +191,12 @@ public: bool HitTest( const wxPoint& aPosition, int aAccuracy = 0 ) const override; bool HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy = 0 ) const override; - /** - * Function GetVia - * finds the first VIA object at \a aPosition on \a aLayer starting at the trace. - * - * @param aPosition The wxPoint to HitTest() against. - * @param aLayer The layer to match, pass -1 for a don't care. - * @return A pointer to a VIA object if found, else NULL. - */ - VIA* GetVia( const wxPoint& aPosition, PCB_LAYER_ID aLayer = UNDEFINED_LAYER ); - - /** - * Function GetVia - * finds the first VIA object at \a aPosition on \a aLayer starting at the trace - * and ending at \a aEndTrace. - * - * @param aEndTrace Pointer to the last TRACK object to end search. - * @param aPosition The wxPoint to HitTest() against. - * @param aLayerMask The layers to match, pass -1 for a don't care. - * @return A pointer to a VIA object if found, else NULL. - */ - VIA* GetVia( TRACK* aEndTrace, const wxPoint& aPosition, LSET aLayerMask ); - - /** - * Function GetTrack - * returns the trace segment connected to the segment at \a aEndPoint from \a - * aStartTrace to \a aEndTrace. - * - * @param aStartTrace A pointer to the TRACK object to begin searching. - * @param aEndTrace A pointer to the TRACK object to stop the search. A NULL value - * searches to the end of the list. - * @param aEndPoint The start or end point of the segment to test against. - * @param aSameNetOnly if true stop searching when the netcode changes - * @param aSequential If true, forces a forward sequential search, - * which is restartable; the default search can be faster but the - * position of the returned track in the list is unpredictable - * @return A TRACK object pointer if found otherwise NULL. - */ - TRACK* GetTrack( TRACK* aStartTrace, TRACK* aEndTrace, ENDPOINT_T aEndPoint, - bool aSameNetOnly, bool aSequential ); - - /** - * Function GetEndSegments - * get the segments connected to the end point of the track. - * return 1 if OK, 0 when a track is a closed loop - * and the beginning and the end of the track in *StartTrack and *EndTrack - * Modify *StartTrack en *EndTrack : - * (*StartTrack)->m_Start coordinate is the beginning of the track - * (*EndTrack)->m_End coordinate is the end of the track - * Segments connected must be consecutive in list - */ - int GetEndSegments( int NbSegm, TRACK** StartTrack, TRACK** EndTrack ); + bool ApproxCollinear( const TRACK& aTrack ) + { + SEG a( m_Start, m_End ); + SEG b( aTrack.GetStart(), aTrack.GetEnd() ); + return a.ApproxCollinear( b ); + } wxString GetClass() const override { @@ -336,11 +256,6 @@ protected: wxPoint m_Start; ///< Line start point wxPoint m_End; ///< Line end point -private: - // make SetNext() and SetBack() private so that they may not be called from anywhere. - // list management is done on TRACKs using DLIST only. - void SetNext( EDA_ITEM* aNext ) { Pnext = aNext; } - void SetBack( EDA_ITEM* aBack ) { Pback = aBack; } }; @@ -472,31 +387,4 @@ private: }; -/// Scan a track list for the first VIA o NULL if not found (or NULL passed) -inline VIA* GetFirstVia( TRACK* aTrk, const TRACK* aStopPoint = NULL ) -{ - while( aTrk && (aTrk != aStopPoint) && (aTrk->Type() != PCB_VIA_T) ) - aTrk = aTrk->Next(); - - // It could stop because of the stop point, not on a via - if( aTrk && (aTrk->Type() == PCB_VIA_T) ) - return static_cast( aTrk ); - else - return NULL; -} - - -/// Scan a track list for the first TRACK object. Returns NULL if not found (or NULL passed) -inline TRACK* GetFirstTrack( TRACK* aTrk, const TRACK* aStopPoint = NULL ) -{ - while( aTrk && ( aTrk != aStopPoint ) && ( aTrk->Type() != PCB_TRACE_T ) ) - aTrk = aTrk->Next(); - - // It could stop because of the stop point, not on a via - if( aTrk && ( aTrk->Type() == PCB_TRACE_T ) ) - return static_cast( aTrk ); - else - return NULL; -} - #endif // CLASS_TRACK_H diff --git a/pcbnew/dialogs/dialog_gendrill.cpp b/pcbnew/dialogs/dialog_gendrill.cpp index 8364320e1c..63a814982c 100644 --- a/pcbnew/dialogs/dialog_gendrill.cpp +++ b/pcbnew/dialogs/dialog_gendrill.cpp @@ -180,7 +180,7 @@ void DIALOG_GENDRILL::InitDisplayParams() } } - for( TRACK* track = m_board->m_Track; track != NULL; track = track->Next() ) + for( auto track : m_board->Tracks() ) { const VIA *via = dynamic_cast( track ); if( via ) diff --git a/pcbnew/dialogs/dialog_global_deletion.cpp b/pcbnew/dialogs/dialog_global_deletion.cpp index 5321fee26a..099bfc5211 100644 --- a/pcbnew/dialogs/dialog_global_deletion.cpp +++ b/pcbnew/dialogs/dialog_global_deletion.cpp @@ -196,12 +196,8 @@ void DIALOG_GLOBAL_DELETION::AcceptPcbDelete() if( !m_TrackFilterAR->GetValue() ) track_mask_filter |= TRACK_AR; - TRACK* nexttrack; - - for( TRACK *track = pcb->m_Track; track; track = nexttrack ) + for( auto track : pcb->Tracks() ) { - nexttrack = track->Next(); - if( !delAll ) { if( ( track->GetState( TRACK_LOCKED | TRACK_AR ) & track_mask_filter ) != 0 ) diff --git a/pcbnew/dialogs/dialog_global_edit_tracks_and_vias.cpp b/pcbnew/dialogs/dialog_global_edit_tracks_and_vias.cpp index 21daf39f99..9db981d937 100644 --- a/pcbnew/dialogs/dialog_global_edit_tracks_and_vias.cpp +++ b/pcbnew/dialogs/dialog_global_edit_tracks_and_vias.cpp @@ -329,7 +329,7 @@ bool DIALOG_GLOBAL_EDIT_TRACKS_AND_VIAS::TransferDataFromWindow() wxBusyCursor dummy; // Examine segments - for( TRACK* segment = m_brd->m_Track; segment != nullptr; segment = segment->Next() ) + for( auto segment : m_brd->Tracks() ) { if( m_tracks->GetValue() && segment->Type() == PCB_TRACE_T ) visitItem( &itemsListPicker, segment ); @@ -341,7 +341,7 @@ bool DIALOG_GLOBAL_EDIT_TRACKS_AND_VIAS::TransferDataFromWindow() { m_parent->SaveCopyInUndoList( itemsListPicker, UR_CHANGED ); - for( TRACK* segment = m_brd->m_Track; segment != nullptr; segment = segment->Next() ) + for( auto segment : m_brd->Tracks() ) m_parent->GetGalCanvas()->GetView()->Update( segment ); } diff --git a/pcbnew/dialogs/dialog_pad_properties.cpp b/pcbnew/dialogs/dialog_pad_properties.cpp index 2ea6217216..4747084dc3 100644 --- a/pcbnew/dialogs/dialog_pad_properties.cpp +++ b/pcbnew/dialogs/dialog_pad_properties.cpp @@ -1434,7 +1434,6 @@ bool DIALOG_PAD_PROPERTIES::TransferDataFromWindow() if( !padValuesOK() ) return false; - bool rastnestIsChanged = false; int isign = m_isFlipped ? -1 : 1; transferDataToPad( m_padMaster ); @@ -1454,12 +1453,7 @@ bool DIALOG_PAD_PROPERTIES::TransferDataFromWindow() // Update values m_currentPad->SetShape( m_padMaster->GetShape() ); m_currentPad->SetAttribute( m_padMaster->GetAttribute() ); - - if( m_currentPad->GetPosition() != m_padMaster->GetPosition() ) - { - m_currentPad->SetPosition( m_padMaster->GetPosition() ); - rastnestIsChanged = true; - } + m_currentPad->SetPosition( m_padMaster->GetPosition() ); wxSize size; MODULE* footprint = m_currentPad->GetParent(); @@ -1505,11 +1499,7 @@ bool DIALOG_PAD_PROPERTIES::TransferDataFromWindow() m_currentPad->FlipPrimitives(); } - if( m_currentPad->GetLayerSet() != m_padMaster->GetLayerSet() ) - { - rastnestIsChanged = true; - m_currentPad->SetLayerSet( m_padMaster->GetLayerSet() ); - } + m_currentPad->SetLayerSet( m_padMaster->GetLayerSet() ); if( m_isFlipped ) { @@ -1524,12 +1514,7 @@ bool DIALOG_PAD_PROPERTIES::TransferDataFromWindow() if( m_padMaster->GetAttribute() != PAD_ATTRIB_HOLE_NOT_PLATED ) padNetcode = m_PadNetSelector->GetSelectedNetcode(); - if( m_currentPad->GetNetCode() != padNetcode ) - { - rastnestIsChanged = true; - m_currentPad->SetNetCode( padNetcode ); - } - + m_currentPad->SetNetCode( padNetcode ); m_currentPad->SetLocalClearance( m_padMaster->GetLocalClearance() ); m_currentPad->SetLocalSolderMaskMargin( m_padMaster->GetLocalSolderMaskMargin() ); m_currentPad->SetLocalSolderPasteMargin( m_padMaster->GetLocalSolderPasteMargin() ); diff --git a/pcbnew/dialogs/dialog_swap_layers.cpp b/pcbnew/dialogs/dialog_swap_layers.cpp index dff1ae0ee8..e904899724 100644 --- a/pcbnew/dialogs/dialog_swap_layers.cpp +++ b/pcbnew/dialogs/dialog_swap_layers.cpp @@ -213,7 +213,7 @@ void PCB_EDIT_FRAME::Swap_Layers( wxCommandEvent& event ) bool hasChanges = false; // Change tracks. - for( TRACK* segm = GetBoard()->m_Track; segm; segm = segm->Next() ) + for( auto segm : GetBoard()->Tracks() ) { if( segm->Type() == PCB_VIA_T ) { diff --git a/pcbnew/drc.cpp b/pcbnew/drc.cpp index 7380d452dc..ed169ea8ad 100644 --- a/pcbnew/drc.cpp +++ b/pcbnew/drc.cpp @@ -179,7 +179,7 @@ DRC::~DRC() } -int DRC::DrcOnCreatingTrack( TRACK* aRefSegm, TRACK* aList ) +int DRC::DrcOnCreatingTrack( TRACK* aRefSegm, TRACKS& aList ) { updatePointers(); @@ -190,7 +190,7 @@ int DRC::DrcOnCreatingTrack( TRACK* aRefSegm, TRACK* aList ) m_reportAllTrackErrors = false; // Test new segment against tracks and pads, not against copper zones - if( !doTrackDrc( aRefSegm, aList, true, false ) ) + if( !doTrackDrc( aRefSegm, aList.begin(), aList.end(), true, false ) ) { if( m_currentMarker ) { @@ -833,10 +833,7 @@ 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 = 0; - - for( TRACK* segm = m_pcb->m_Track; segm && segm->Next(); segm = segm->Next() ) - count++; + int count = m_pcb->Tracks().size(); int deltamax = count/delta; @@ -853,7 +850,7 @@ void DRC::testTracks( wxWindow *aActiveWindow, bool aShowProgressBar ) int ii = 0; count = 0; - for( TRACK* segm = m_pcb->m_Track; segm; segm = segm->Next() ) + for( auto seg_it = m_pcb->Tracks().begin(); seg_it != m_pcb->Tracks().end(); seg_it++ ) { if( ii++ > delta ) { @@ -873,7 +870,7 @@ void DRC::testTracks( wxWindow *aActiveWindow, bool aShowProgressBar ) } // Test new segment against tracks and pads, optionally against copper zones - if( !doTrackDrc( segm, segm->Next(), true, m_doZonesTest ) ) + if( !doTrackDrc( *seg_it, seg_it + 1, m_pcb->Tracks().end(), true, m_doZonesTest ) ) { if( m_currentMarker ) { @@ -968,7 +965,7 @@ void DRC::testKeepoutAreas() continue; } - for( TRACK* segm = m_pcb->m_Track; segm != NULL; segm = segm->Next() ) + for( auto segm : m_pcb->Tracks() ) { if( segm->Type() == PCB_TRACE_T ) { @@ -1104,7 +1101,7 @@ void DRC::testCopperDrawItem( DRAWSEGMENT* aItem ) } // Test tracks and vias - for( TRACK* track = m_pcb->m_Track; track != NULL; track = track->Next() ) + for( auto track : m_pcb->Tracks() ) { if( !track->IsOnLayer( aItem->GetLayer() ) ) continue; @@ -1172,7 +1169,7 @@ void DRC::testCopperTextItem( BOARD_ITEM* aTextItem ) SHAPE_RECT rect_area( bbox.GetX(), bbox.GetY(), bbox.GetWidth(), bbox.GetHeight() ); // Test tracks and vias - for( TRACK* track = m_pcb->m_Track; track != NULL; track = track->Next() ) + for( auto track : m_pcb->Tracks() ) { if( !track->IsOnLayer( aTextItem->GetLayer() ) ) continue; diff --git a/pcbnew/drc.h b/pcbnew/drc.h index e7a7a8d96a..7798269b78 100644 --- a/pcbnew/drc.h +++ b/pcbnew/drc.h @@ -29,10 +29,12 @@ #ifndef DRC_H #define DRC_H -#include -#include +#include +#include #include #include +#include +#include #include @@ -327,14 +329,15 @@ private: * Test the current segment. * * @param aRefSeg The segment to test - * @param aStart the first item of track list to test against (usually BOARD::m_Track) + * @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, TRACK* aStart, - bool aTestPads, bool aTestZones ); + bool doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterator aEndIt, + bool aTestPads, bool aTestZones ); /** * Test the current segment or via. @@ -428,10 +431,10 @@ public: * No marker created or added to the board. Must be used only during track * creation in legacy canvas * @param aRefSeg The current segment to test. - * @param aList The track list to test (usually m_Pcb->m_Track) + * @param aList The track list to test (usually m_Pcb->Tracks()) * @return int - BAD_DRC (1) if DRC error or OK_DRC (0) if OK */ - int DrcOnCreatingTrack( TRACK* aRefSeg, TRACK* aList ); + int DrcOnCreatingTrack( TRACK* aRefSeg, TRACKS& aList ); /** * Function Drc diff --git a/pcbnew/drc_clearance_test_functions.cpp b/pcbnew/drc_clearance_test_functions.cpp index 03f450c52e..8f784003b9 100644 --- a/pcbnew/drc_clearance_test_functions.cpp +++ b/pcbnew/drc_clearance_test_functions.cpp @@ -135,7 +135,8 @@ bool convex2pointDRC( wxPoint* aTref, int aTrefCount, wxPoint aPcompare, int aDi } -bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool aTestPads, bool aTestZones ) +bool DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterator aEndIt, + bool aTestPads, bool aTestZones ) { TRACK* track; wxPoint delta; // length on X and Y axis of segments @@ -431,8 +432,9 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool aTestPads, bool aTestZ wxPoint segStartPoint; wxPoint segEndPoint; - for( track = aStart; track; track = track->Next() ) + for( auto it = aStartIt; it != aEndIt; it++ ) { + track = *it; // No problem if segments have the same net code: if( net_code_ref == track->GetNetCode() ) continue; diff --git a/pcbnew/eagle_plugin.cpp b/pcbnew/eagle_plugin.cpp index 71b8dbd616..89b9ae92be 100644 --- a/pcbnew/eagle_plugin.cpp +++ b/pcbnew/eagle_plugin.cpp @@ -2107,7 +2107,7 @@ void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals ) t->SetLayer( layer ); t->SetNetCode( netCode ); - m_board->m_Track.PushBack( t ); + m_board->Add( t ); start = end; angle -= delta_angle; @@ -2122,7 +2122,7 @@ void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals ) t->SetLayer( layer ); t->SetNetCode( netCode ); - m_board->m_Track.PushBack( t ); + m_board->Add( t ); } else { @@ -2146,7 +2146,7 @@ void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals ) int kidiam; int drillz = v.drill.ToPcbUnits(); VIA* via = new VIA( m_board ); - m_board->m_Track.PushBack( via ); + m_board->Add( via ); via->SetLayerPair( layer_front_most, layer_back_most ); diff --git a/pcbnew/exporters/export_d356.cpp b/pcbnew/exporters/export_d356.cpp index 2dc1c5188c..eb54599e99 100644 --- a/pcbnew/exporters/export_d356.cpp +++ b/pcbnew/exporters/export_d356.cpp @@ -189,7 +189,7 @@ static void build_via_testpoints( BOARD *aPcb, wxPoint origin = aPcb->GetAuxOrigin(); // Enumerate all the track segments and keep the vias - for( TRACK *track = aPcb->m_Track; track; track = track->Next() ) + for( auto track : aPcb->Tracks() ) { if( track->Type() == PCB_VIA_T ) { diff --git a/pcbnew/exporters/export_gencad.cpp b/pcbnew/exporters/export_gencad.cpp index 1d42a6e8e3..3af38ead64 100644 --- a/pcbnew/exporters/export_gencad.cpp +++ b/pcbnew/exporters/export_gencad.cpp @@ -363,31 +363,25 @@ void PCB_EDIT_FRAME::ExportToGenCAD( wxCommandEvent& aEvent ) // Comparator for sorting pads with qsort -static int PadListSortByShape( const void* aRefptr, const void* aObjptr ) +static int PadListSortByShape( const D_PAD* aRefptr, const D_PAD* aObjptr ) { - const D_PAD* padref = *(D_PAD**) aRefptr; - const D_PAD* padcmp = *(D_PAD**) aObjptr; - - return D_PAD::Compare( padref, padcmp ); + return D_PAD::Compare( aRefptr, aObjptr ) < 0; } // Sort vias for uniqueness -static int ViaSort( const void* aRefptr, const void* aObjptr ) +static bool ViaSort( const VIA* aPadref, const VIA* aPadcmp ) { - VIA* padref = *(VIA**) aRefptr; - VIA* padcmp = *(VIA**) aObjptr; + if( aPadref->GetWidth() != aPadcmp->GetWidth() ) + return aPadref->GetWidth() < aPadcmp->GetWidth(); - if( padref->GetWidth() != padcmp->GetWidth() ) - return padref->GetWidth() - padcmp->GetWidth(); + if( aPadref->GetDrillValue() != aPadcmp->GetDrillValue() ) + return aPadref->GetDrillValue() < aPadcmp->GetDrillValue(); - if( padref->GetDrillValue() != padcmp->GetDrillValue() ) - return padref->GetDrillValue() - padcmp->GetDrillValue(); + if( aPadref->GetLayerSet() != aPadcmp->GetLayerSet() ) + return aPadref->GetLayerSet().FmtBin().compare( aPadcmp->GetLayerSet().FmtBin() ) < 0; - if( padref->GetLayerSet() != padcmp->GetLayerSet() ) - return padref->GetLayerSet().FmtBin().compare( padcmp->GetLayerSet().FmtBin() ); - - return 0; + return false; } @@ -418,33 +412,28 @@ static void CreatePadsShapesSection( FILE* aFile, BOARD* aPcb ) fputs( "$PADS\n", aFile ); // Enumerate and sort the pads - if( aPcb->GetPadCount() > 0 ) - { - pads = aPcb->GetPads(); - qsort( &pads[0], aPcb->GetPadCount(), sizeof( D_PAD* ), - PadListSortByShape ); - } + pads = aPcb->GetPads(); + std::sort( pads.begin(), pads.end(), PadListSortByShape ); + // The same for vias - for( VIA* via = GetFirstVia( aPcb->m_Track ); via; - via = GetFirstVia( via->Next() ) ) + for( auto track : aPcb->Tracks() ) { - vias.push_back( via ); + if( auto via = dyn_cast( track ) ) + vias.push_back( via ); } - qsort( &vias[0], vias.size(), sizeof(VIA*), ViaSort ); + std::sort( vias.begin(), vias.end(), ViaSort ); + vias.erase( std::unique( vias.begin(), vias.end(), + []( const VIA* a, const VIA* b ) { return ViaSort( a, b ) == 0; } ), + vias.end() ); // Emit vias pads - TRACK* old_via = 0; - for( unsigned i = 0; i < vias.size(); i++ ) + for( auto item : vias ) { - VIA* via = vias[i]; + VIA* via = static_cast( item ); - if( old_via && 0 == ViaSort( &old_via, &via ) ) - continue; - - old_via = via; viastacks.push_back( via ); fprintf( aFile, "PAD V%d.%d.%s ROUND %g\nCIRCLE 0 0 %g\n", via->GetWidth(), via->GetDrillValue(), @@ -1043,39 +1032,21 @@ static int TrackListSortByNetcode( const void* refptr, const void* objptr ) */ static void CreateRoutesSection( FILE* aFile, BOARD* aPcb ) { - TRACK* track, ** tracklist; int vianum = 1; int old_netcode, old_width, old_layer; - int nbitems, ii; LSET master_layermask = aPcb->GetDesignSettings().GetEnabledLayers(); int cu_count = aPcb->GetCopperLayerCount(); - // Count items - nbitems = 0; - - for( track = aPcb->m_Track; track; track = track->Next() ) - nbitems++; - - tracklist = (TRACK**) operator new( (nbitems + 1)* sizeof( TRACK* ) ); - - nbitems = 0; - - for( track = aPcb->m_Track; track; track = track->Next() ) - tracklist[nbitems++] = track; - - tracklist[nbitems] = NULL; - - qsort( tracklist, nbitems, sizeof(TRACK*), TrackListSortByNetcode ); + TRACKS tracks = aPcb->Tracks(); + std::sort( tracks.begin(), tracks.end(), TrackListSortByNetcode ); fputs( "$ROUTES\n", aFile ); old_netcode = -1; old_width = -1; old_layer = -1; - for( ii = 0; ii < nbitems; ii++ ) + for( auto track : tracks ) { - track = tracklist[ii]; - if( old_netcode != track->GetNetCode() ) { old_netcode = track->GetNetCode(); @@ -1125,8 +1096,6 @@ static void CreateRoutesSection( FILE* aFile, BOARD* aPcb ) } fputs( "$ENDROUTES\n\n", aFile ); - - delete tracklist; } @@ -1208,41 +1177,18 @@ static void CreateBoardSection( FILE* aFile, BOARD* aPcb ) */ static void CreateTracksInfoData( FILE* aFile, BOARD* aPcb ) { - TRACK* track; - int last_width = -1; - // Find thickness used for traces - // XXX could use the same sorting approach used for pads - std::vector trackinfo; + std::set trackinfo; - unsigned ii; - - for( track = aPcb->m_Track; track; track = track->Next() ) - { - if( last_width != track->GetWidth() ) // Find a thickness already used. - { - for( ii = 0; ii < trackinfo.size(); ii++ ) - { - if( trackinfo[ii] == track->GetWidth() ) - break; - } - - if( ii == trackinfo.size() ) // not found - trackinfo.push_back( track->GetWidth() ); - - last_width = track->GetWidth(); - } - } + for( auto track : aPcb->Tracks() ) + trackinfo.insert( track->GetWidth() ); // Write data fputs( "$TRACKS\n", aFile ); - for( ii = 0; ii < trackinfo.size(); ii++ ) - { - fprintf( aFile, "TRACK TRACK%d %g\n", trackinfo[ii], - trackinfo[ii] / SCALE_FACTOR ); - } + for( auto size : trackinfo ) + fprintf( aFile, "TRACK TRACK%d %g\n", size, size / SCALE_FACTOR ); fputs( "$ENDTRACKS\n\n", aFile ); } diff --git a/pcbnew/exporters/export_vrml.cpp b/pcbnew/exporters/export_vrml.cpp index ac056e94d7..bac08e652d 100644 --- a/pcbnew/exporters/export_vrml.cpp +++ b/pcbnew/exporters/export_vrml.cpp @@ -961,7 +961,7 @@ static void export_vrml_via( MODEL_VRML& aModel, BOARD* aPcb, const VIA* aVia ) static void export_vrml_tracks( MODEL_VRML& aModel, BOARD* pcb ) { - for( TRACK* track = pcb->m_Track; track; track = track->Next() ) + for( auto track : pcb->Tracks() ) { if( track->Type() == PCB_VIA_T ) { diff --git a/pcbnew/exporters/gendrill_file_writer_base.cpp b/pcbnew/exporters/gendrill_file_writer_base.cpp index dbdfe98316..3404d24f24 100644 --- a/pcbnew/exporters/gendrill_file_writer_base.cpp +++ b/pcbnew/exporters/gendrill_file_writer_base.cpp @@ -82,8 +82,12 @@ void GENDRILL_WRITER_BASE::buildHolesList( DRILL_LAYER_PAIR aLayerPair, // build hole list for vias if( ! aGenerateNPTH_list ) // vias are always plated ! { - for( VIA* via = GetFirstVia( m_pcb->m_Track ); via; via = GetFirstVia( via->Next() ) ) + for( auto track : m_pcb->Tracks() ) { + if( track->Type() != PCB_VIA_T ) + continue; + + auto via = static_cast( track ); int hole_sz = via->GetDrillValue(); if( hole_sz == 0 ) // Should not occur. diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp index 495241994b..1acfff3a0d 100644 --- a/pcbnew/kicad_plugin.cpp +++ b/pcbnew/kicad_plugin.cpp @@ -602,7 +602,7 @@ void PCB_IO::formatGeneral( BOARD* aBoard, int aNestLevel ) const FormatInternalUnits( dsnSettings.GetBoardThickness() ).c_str() ); m_out->Print( aNestLevel+1, "(drawings %zu)\n", aBoard->Drawings().size() ); - m_out->Print( aNestLevel+1, "(tracks %d)\n", aBoard->GetNumSegmTrack() ); + m_out->Print( aNestLevel + 1, "(tracks %zu)\n", aBoard->Tracks().size() ); m_out->Print( aNestLevel + 1, "(modules %zu)\n", aBoard->Modules().size() ); m_out->Print( aNestLevel+1, "(nets %d)\n", m_mapping->GetSize() ); m_out->Print( aNestLevel, ")\n\n" ); @@ -733,10 +733,10 @@ void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const // Do not save MARKER_PCBs, they can be regenerated easily. // Save the tracks and vias. - for( TRACK* track = aBoard->m_Track; track; track = track->Next() ) + for( auto track : aBoard->Tracks() ) Format( track, aNestLevel ); - if( aBoard->m_Track.GetCount() ) + if( aBoard->Tracks().size() ) m_out->Print( 0, "\n" ); /// @todo Add warning here that the old segment filed zones are no longer supported and diff --git a/pcbnew/netinfo.h b/pcbnew/netinfo.h index 00bc0329d9..9729a252e7 100644 --- a/pcbnew/netinfo.h +++ b/pcbnew/netinfo.h @@ -554,15 +554,6 @@ private: */ void buildListOfNets(); - /** - * Function buildPadsFullList - * creates the pad list, and initializes: - * m_Pads (list of pads) - * and clear for all pads in list the m_SubRatsnest member; - * clear m_Pcb->m_FullRatsnest - */ - void buildPadsFullList(); - /** * Function getFreeNetCode * returns the first available net code that is not used by any other net. @@ -586,6 +577,4 @@ private: #define START_ON_TRACK 0x40 #define END_ON_TRACK 0x80 - - #endif // CLASS_NETINFO_ diff --git a/pcbnew/netinfo_item.cpp b/pcbnew/netinfo_item.cpp index 512884677d..7480b7982f 100644 --- a/pcbnew/netinfo_item.cpp +++ b/pcbnew/netinfo_item.cpp @@ -119,7 +119,7 @@ void NETINFO_ITEM::GetMsgPanelInfo( EDA_UNITS_T aUnits, std::vector< MSG_PANEL_I count = 0; - for( const TRACK *track = board->m_Track; track != NULL; track = track->Next() ) + for( auto track : board->Tracks() ) { if( track->Type() == PCB_VIA_T ) { diff --git a/pcbnew/netinfo_list.cpp b/pcbnew/netinfo_list.cpp index 1b659cb784..e02dd61d1c 100644 --- a/pcbnew/netinfo_list.cpp +++ b/pcbnew/netinfo_list.cpp @@ -208,7 +208,7 @@ void NETINFO_MAPPING::Update() nets.insert( m_board->GetArea( i )->GetNetCode() ); // Tracks - for( TRACK* track = m_board->m_Track; track; track = track->Next() ) + for( auto track : m_board->Tracks() ) nets.insert( track->GetNetCode() ); // Modules/pads diff --git a/pcbnew/pcad2kicadpcb_plugin/pcb_line.cpp b/pcbnew/pcad2kicadpcb_plugin/pcb_line.cpp index 7bcd1d7805..c2b83abe08 100644 --- a/pcbnew/pcad2kicadpcb_plugin/pcb_line.cpp +++ b/pcbnew/pcad2kicadpcb_plugin/pcb_line.cpp @@ -138,7 +138,7 @@ void PCB_LINE::AddToBoard() if( IsCopperLayer( m_KiCadLayer ) ) { TRACK* track = new TRACK( m_board ); - m_board->m_Track.Append( track ); + m_board->Add( track ); track->SetTimeStamp( m_timestamp ); diff --git a/pcbnew/pcad2kicadpcb_plugin/pcb_pad.cpp b/pcbnew/pcad2kicadpcb_plugin/pcb_pad.cpp index 0d0923733b..a0083f3b22 100644 --- a/pcbnew/pcad2kicadpcb_plugin/pcb_pad.cpp +++ b/pcbnew/pcad2kicadpcb_plugin/pcb_pad.cpp @@ -341,7 +341,7 @@ void PCB_PAD::AddToBoard() if( IsCopperLayer( m_KiCadLayer ) ) { VIA* via = new VIA( m_board ); - m_board->m_Track.Append( via ); + m_board->Add( via ); via->SetTimeStamp( 0 ); diff --git a/pcbnew/pcb_draw_panel_gal.cpp b/pcbnew/pcb_draw_panel_gal.cpp index ae4e66724a..2dd734f40f 100644 --- a/pcbnew/pcb_draw_panel_gal.cpp +++ b/pcbnew/pcb_draw_panel_gal.cpp @@ -170,7 +170,7 @@ void PCB_DRAW_PANEL_GAL::DisplayBoard( BOARD* aBoard ) m_view->Add( drawing ); // Load tracks - for( TRACK* track = aBoard->m_Track; track; track = track->Next() ) + for( auto track : aBoard->Tracks() ) m_view->Add( track ); // Load modules and its additional elements @@ -344,7 +344,7 @@ void PCB_DRAW_PANEL_GAL::GetMsgPanelInfo( EDA_UNITS_T aUnits, std::vectorm_Track; item; item = item->Next() ) + for( auto item : board->Tracks() ) { if( item->Type() == PCB_VIA_T ) viasCount++; diff --git a/pcbnew/pcb_edit_frame.h b/pcbnew/pcb_edit_frame.h index 02b2faa9e5..9484eda2ef 100644 --- a/pcbnew/pcb_edit_frame.h +++ b/pcbnew/pcb_edit_frame.h @@ -1064,15 +1064,6 @@ public: */ void OnNetlistChanged( BOARD_NETLIST_UPDATER& aUpdater, bool* aRunDragCommand ); - /** - * Function RemoveMisConnectedTracks - * finds all track segments which are mis-connected (to more than one net). - * When such a bad segment is found, it is flagged to be removed. - * All tracks having at least one flagged segment are removed. - * @return true if any change is made - */ - bool RemoveMisConnectedTracks(); - // Autoplacement: void OnPlaceOrRouteFootprints( wxCommandEvent& event ); diff --git a/pcbnew/pcb_legacy_draw_utils.cpp b/pcbnew/pcb_legacy_draw_utils.cpp index 123511f8f3..88cbf018e5 100644 --- a/pcbnew/pcb_legacy_draw_utils.cpp +++ b/pcbnew/pcb_legacy_draw_utils.cpp @@ -66,7 +66,7 @@ void BOARD::Print( PCB_BASE_FRAME* aFrame, wxDC* DC, const wxPoint& offset ) * tracks. But a white track will cover any other color since it has * more bits to OR in. */ - for( TRACK* track = m_Track; track; track = track->Next() ) + for( auto track : m_tracks ) { if( track->IsMoving() ) continue; diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index 58af3fb149..c33fec7f5a 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -617,7 +617,7 @@ BOARD* PCB_PARSER::parseBOARD_unchecked() } }; - for( TRACK* segm = m_board->m_Track; segm; segm = segm->Next() ) + for( auto segm : m_board->Tracks() ) { if( segm->Type() == PCB_VIA_T ) { diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp index 9e365305be..0343bb35ac 100644 --- a/pcbnew/plot_board_layers.cpp +++ b/pcbnew/plot_board_layers.cpp @@ -489,7 +489,7 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter, aPlotter->StartBlock( NULL ); - for( TRACK* track = aBoard->m_Track; track; track = track->Next() ) + for( auto track : aBoard->Tracks() ) { const VIA* Via = dyn_cast( track ); @@ -548,7 +548,7 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter, gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CONDUCTOR ); // Plot tracks (not vias) : - for( TRACK* track = aBoard->m_Track; track; track = track->Next() ) + for( auto track : aBoard->Tracks() ) { if( track->Type() == PCB_VIA_T ) continue; @@ -723,7 +723,7 @@ void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, } // Plot vias holes - for( TRACK* track = aBoard->m_Track; track; track = track->Next() ) + for( auto track : aBoard->Tracks() ) { const VIA* via = dyn_cast( track ); @@ -820,7 +820,7 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, int via_clearance = aBoard->GetDesignSettings().m_SolderMaskMargin; int via_margin = via_clearance + inflate; - for( TRACK* track = aBoard->m_Track; track; track = track->Next() ) + for( auto track : aBoard->Tracks() ) { const VIA* via = dyn_cast( track ); diff --git a/pcbnew/plot_brditems_plotter.cpp b/pcbnew/plot_brditems_plotter.cpp index 16bfac364d..3f269bd5cc 100644 --- a/pcbnew/plot_brditems_plotter.cpp +++ b/pcbnew/plot_brditems_plotter.cpp @@ -831,7 +831,7 @@ void BRDITEMS_PLOTTER::PlotDrillMarks() if( GetPlotMode() == FILLED ) m_plotter->SetColor( WHITE ); - for( TRACK* pts = m_board->m_Track; pts != NULL; pts = pts->Next() ) + for( auto pts : m_board->Tracks() ) { const VIA* via = dyn_cast( pts ); diff --git a/pcbnew/ratsnest.cpp b/pcbnew/ratsnest.cpp index 1204b211c2..2ae188affc 100644 --- a/pcbnew/ratsnest.cpp +++ b/pcbnew/ratsnest.cpp @@ -44,7 +44,6 @@ void PCB_BASE_FRAME::Compile_Ratsnest( bool aDisplayStatus ) { GetBoard()->GetConnectivity()->RecalculateRatsnest(); - ClearMsgPanel(); if( aDisplayStatus ) @@ -62,4 +61,3 @@ void PCB_BASE_FRAME::Compile_Ratsnest( bool aDisplayStatus ) } } - diff --git a/pcbnew/specctra_import_export/specctra_import.cpp b/pcbnew/specctra_import_export/specctra_import.cpp index d7b22593cf..515b4c454a 100644 --- a/pcbnew/specctra_import_export/specctra_import.cpp +++ b/pcbnew/specctra_import_export/specctra_import.cpp @@ -132,7 +132,7 @@ bool PCB_EDIT_FRAME::ImportSpecctraSession( const wxString& fullFileName ) view->RecacheAllItems(); // add imported tracks (previous tracks are removed, therfore all are new) - for( TRACK* track = GetBoard()->m_Track; track; track = track->Next() ) + for( auto track : GetBoard()->Tracks() ) { view->Add( track ); } @@ -384,7 +384,7 @@ void SPECCTRA_DB::FromSESSION( BOARD* aBoard ) THROW_IO_ERROR( _("Session file is missing the \"library_out\" section") ); // delete all the old tracks and vias - aBoard->m_Track.DeleteAll(); + aBoard->Tracks().clear(); aBoard->DeleteMARKERs(); diff --git a/pcbnew/swig/board.i b/pcbnew/swig/board.i index 736de92c9e..dfd2f84477 100644 --- a/pcbnew/swig/board.i +++ b/pcbnew/swig/board.i @@ -116,9 +116,9 @@ HANDLE_EXCEPTIONS(BOARD::TracksInNetBetweenPoints) %pythoncode %{ - def GetModules(self): return self.m_Modules - def GetDrawings(self): return self.DrawingsList() - def GetTracks(self): return self.m_Track + def GetModules(self): return self.Modules() + def GetDrawings(self): return self.Drawings() + def GetTracks(self): return self.Tracks() def Save(self,filename): return SaveBoard(filename,self) diff --git a/pcbnew/swig/pcbnew_action_plugins.cpp b/pcbnew/swig/pcbnew_action_plugins.cpp index e774487d47..e7ebc0b718 100644 --- a/pcbnew/swig/pcbnew_action_plugins.cpp +++ b/pcbnew/swig/pcbnew_action_plugins.cpp @@ -218,7 +218,7 @@ void PCB_EDIT_FRAME::RunActionPlugin( ACTION_PLUGIN* aActionPlugin ) OnModify(); // Append tracks: - for( BOARD_ITEM* item = currentPcb->m_Track; item != NULL; item = item->Next() ) + for( auto item : currentPcb->Tracks() ) { ITEM_PICKER picker( item, UR_CHANGED ); itemsList.PushItem( picker ); @@ -345,7 +345,7 @@ void PCB_EDIT_FRAME::RunActionPlugin( ACTION_PLUGIN* aActionPlugin ) } } - for( BOARD_ITEM* item = currentPcb->m_Track; item != NULL; item = item->Next() ) + for( auto item : currentPcb->Tracks() ) { if( !oldBuffer->ContainsItem( item ) ) { diff --git a/pcbnew/tools/pcbnew_control.cpp b/pcbnew/tools/pcbnew_control.cpp index 39289bc067..2025c9aa5b 100644 --- a/pcbnew/tools/pcbnew_control.cpp +++ b/pcbnew/tools/pcbnew_control.cpp @@ -838,7 +838,7 @@ int PCBNEW_CONTROL::placeBoardItems( BOARD* aBoard ) bool isNew = board() != aBoard; std::vector items; - moveNoFlagToVector( aBoard->m_Track, items, isNew ); + moveNoFlagToVector( aBoard->Tracks(), items, isNew ); moveNoFlagToVector( aBoard->Modules(), items, isNew ); moveNoFlagToVector( aBoard->Drawings(), items, isNew ); moveNoFlagToVector( aBoard->Zones(), items, isNew ); diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index a2e9f81668..bfd2870e24 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -858,7 +858,7 @@ int SELECTION_TOOL::expandConnection( const TOOL_EVENT& aEvent ) // Track items marked BUSY have already been visited // therefore their connections have already been marked if( trackItem && !trackItem->GetState( BUSY ) ) - selectAllItemsConnectedToTrack( *trackItem ); + selectAllItemsConnectedToItem( *trackItem ); } // Inform other potentially interested tools @@ -923,15 +923,12 @@ int SELECTION_TOOL::selectCopper( const TOOL_EVENT& aEvent ) void SELECTION_TOOL::selectAllItemsConnectedToTrack( TRACK& aSourceTrack ) { - int segmentCount; - TRACK* trackList = board()->MarkTrace( board()->m_Track, &aSourceTrack, &segmentCount, - nullptr, nullptr, true ); + constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_VIA_T, EOT }; + auto connectivity = board()->GetConnectivity(); - for( int i = 0; i < segmentCount; ++i ) - { - select( trackList ); - trackList = trackList->Next(); - } + for( auto item : connectivity->GetConnectedItems( + static_cast( &aSourceTrack ), types ) ) + select( item ); } @@ -1026,12 +1023,7 @@ void SELECTION_TOOL::selectAllItemsOnSheet( wxString& aSheetpath ) for( auto pad : padList ) { - launchTracks = board()->GetTracksByPosition( pad->GetPosition() ); - - for( auto track : launchTracks ) - { - selectAllItemsConnectedToTrack( *track ); - } + selectAllItemsConnectedToItem( *pad ); } // now we need to find all modules that are connected to each of these nets diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index b007a8ad0d..bffae6e918 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -209,11 +209,13 @@ private: /** * Selects all items connected by copper tracks to the given TRACK + * This selects tracks and vias but stops at pads */ void selectAllItemsConnectedToTrack( TRACK& aSourceTrack ); /** * Selects all items connected (by copper) to the given item + * This selects tracks and vias _and_ continues through pads without selecting */ void selectAllItemsConnectedToItem( BOARD_CONNECTED_ITEM& aSourceItem ); diff --git a/pcbnew/tracks_cleaner.cpp b/pcbnew/tracks_cleaner.cpp index 7b120d7e47..d6e5488140 100644 --- a/pcbnew/tracks_cleaner.cpp +++ b/pcbnew/tracks_cleaner.cpp @@ -118,7 +118,7 @@ bool TRACKS_CLEANER::CleanupBoard( bool aDryRun, DRC_LIST* aItemsList, if( aMergeSegments ) modified |= cleanupSegments(); else if( aRemoveMisConnected ) - modified |= deleteNullSegments(); + modified |= deleteNullSegments( m_brd->Tracks() ); buildTrackConnectionInfo(); @@ -189,96 +189,89 @@ bool TRACKS_CLEANER::removeBadTrackSegments() } -void TRACKS_CLEANER::removeDuplicatesOfVia( const VIA *aVia, std::set& aToRemove ) -{ - VIA* next_via; - - for( VIA* alt_via = GetFirstVia( aVia->Next() ); alt_via != NULL; alt_via = next_via ) - { - next_via = GetFirstVia( alt_via->Next() ); - - if( ( alt_via->GetViaType() == VIA_THROUGH ) && alt_via->GetStart() == aVia->GetStart() ) - { - if( m_itemsList ) - { - m_itemsList->emplace_back( new DRC_ITEM( m_units, DRCE_REDUNDANT_VIA, - alt_via, alt_via->GetPosition(), - nullptr, wxPoint() ) ); - } - - aToRemove.insert ( alt_via ); - } - } -} - - bool TRACKS_CLEANER::cleanupVias() { std::set toRemove; + std::vector vias; - for( VIA* via = GetFirstVia( m_brd->m_Track ); via != NULL; via = GetFirstVia( via->Next() ) ) + for( auto track : m_brd->Tracks() ) { - if( via->GetFlags() & TRACK_LOCKED ) + if( auto via = dyn_cast( track ) ) + vias.push_back( via ); + } + + for( auto via1_it = vias.begin(); via1_it != vias.end(); via1_it++ ) + { + auto via1 = *via1_it; + + if( via1->IsLocked() ) continue; - // Correct via m_End defects (if any), should never happen - if( via->GetStart() != via->GetEnd() ) + if( via1->GetStart() != via1->GetEnd() ) + via1->SetEnd( via1->GetStart() ); + + /* To delete through Via on THT pads at same location + * Examine the list of connected pads: + * if one through pad is found, the via can be removed */ + + const auto pads = m_brd->GetConnectivity()->GetConnectedPads( via1 ); + for( const auto pad : pads ) { - wxFAIL_MSG( "Malformed via with mismatching ends" ); - via->SetEnd( via->GetStart() ); + const LSET all_cu = LSET::AllCuMask(); + + if( ( pad->GetLayerSet() & all_cu ) == all_cu ) + { + if( m_itemsList ) + { + m_itemsList->emplace_back( new DRC_ITEM( m_units, DRCE_REDUNDANT_VIA, via1, + via1->GetPosition(), pad, pad->GetPosition() ) ); + } + + // redundant: delete the via + toRemove.insert( via1 ); + break; + } } - /* Important: these cleanups only do thru hole vias, they don't - * (yet) handle high density interconnects */ - if( via->GetViaType() == VIA_THROUGH ) + for( auto via2_it = via1_it + 1; via2_it != vias.end(); via2_it++ ) { - removeDuplicatesOfVia( via, toRemove ); + auto via2 = *via2_it; - /* To delete through Via on THT pads at same location - * Examine the list of connected pads: - * if one through pad is found, the via can be removed */ + if( via1->GetPosition() != via2->GetPosition() || via2->IsLocked() ) + continue; - const auto pads = m_brd->GetConnectivity()->GetConnectedPads( via ); - for( const auto pad : pads ) + if( via1->GetViaType() == via2->GetViaType() ) { - const LSET all_cu = LSET::AllCuMask(); - - if( ( pad->GetLayerSet() & all_cu ) == all_cu ) + if( m_itemsList ) { - if( m_itemsList ) - { - m_itemsList->emplace_back( new DRC_ITEM( m_units, DRCE_REDUNDANT_VIA, - via, via->GetPosition(), - nullptr, wxPoint() ) ); - } - - // redundant: delete the via - toRemove.insert( via ); - break; + m_itemsList->emplace_back( new DRC_ITEM( m_units, DRCE_REDUNDANT_VIA, via1, + via1->GetPosition(), via2, via2->GetPosition() ) ); } + + toRemove.insert( via2 ); + break; } } } + return removeItems( toRemove ); } -/** Utility: does the endpoint unconnected processed for one endpoint of one track - * Returns true if the track must be deleted, false if not necessarily */ -bool TRACKS_CLEANER::testTrackEndpointDangling( TRACK* aTrack, ENDPOINT_T aEndPoint ) +bool TRACKS_CLEANER::testTrackEndpointDangling( TRACK* aTrack ) { auto connectivity = m_brd->GetConnectivity(); - VECTOR2I endpoint ; + auto items = connectivity->GetConnectivityAlgo()->ItemEntry( aTrack ).GetItems(); - if( aTrack->Type() == PCB_TRACE_T ) - endpoint = aTrack->GetEndPoint( aEndPoint ); - else - endpoint = aTrack->GetStart( ); + // Not in the connectivity system. This is a bug! + if( items.empty() ) + { + wxASSERT( !items.empty() ); + return false; + } - //wxASSERT ( connectivity->GetConnectivityAlgo()->ItemEntry( aTrack ) != nullptr ); - wxASSERT ( connectivity->GetConnectivityAlgo()->ItemEntry( aTrack ).GetItems().size() != 0 ); - auto citem = connectivity->GetConnectivityAlgo()->ItemEntry( aTrack ).GetItems().front(); + auto citem = items.front(); if( !citem->Valid() ) return false; @@ -287,7 +280,7 @@ bool TRACKS_CLEANER::testTrackEndpointDangling( TRACK* aTrack, ENDPOINT_T aEndPo for( const auto& anchor : anchors ) { - if( anchor->Pos() == endpoint && anchor->IsDangling() ) + if( anchor->IsDangling() ) return true; } @@ -309,11 +302,10 @@ bool TRACKS_CLEANER::deleteDanglingTracks() buildTrackConnectionInfo(); item_erased = false; - TRACK* next_track; - - for( TRACK *track = m_brd->m_Track; track != NULL; track = next_track ) + for( auto track_it = m_brd->Tracks().begin(); track_it != m_brd->Tracks().end(); + track_it++ ) { - next_track = track->Next(); + auto track = *track_it; bool flag_erase = false; // Start without a good reason to erase it /* if a track endpoint is not connected to a pad, test if @@ -324,12 +316,8 @@ bool TRACKS_CLEANER::deleteDanglingTracks() * same layer */ // Check if there is nothing attached on the start - if( !( track->GetState( START_ON_PAD ) ) ) - flag_erase |= testTrackEndpointDangling( track, ENDPOINT_START ); - - // If not sure about removal, then check if there is nothing attached on the end - if( !flag_erase && !track->GetState( END_ON_PAD ) ) - flag_erase |= testTrackEndpointDangling( track, ENDPOINT_END ); + if( !( track->GetState( START_ON_PAD | END_ON_PAD ) ) ) + flag_erase |= testTrackEndpointDangling( track ); if( flag_erase ) { @@ -361,13 +349,13 @@ bool TRACKS_CLEANER::deleteDanglingTracks() // Delete null length track segments -bool TRACKS_CLEANER::deleteNullSegments() +bool TRACKS_CLEANER::deleteNullSegments( TRACKS& aTracks ) { std::set toRemove; - for( auto segment : m_brd->Tracks() ) + for( auto segment : aTracks ) { - if( segment->IsNull() ) // Length segment = 0; delete it + if( segment->IsNull() && segment->Type() == PCB_TRACE_T && !segment->IsLocked() ) { if( m_itemsList ) { @@ -383,87 +371,6 @@ bool TRACKS_CLEANER::deleteNullSegments() return removeItems( toRemove ); } -void TRACKS_CLEANER::removeDuplicatesOfTrack( const TRACK *aSeg, std::set& aToRemove ) -{ - if( aSeg->GetEditFlags() & STRUCT_DELETED ) - return; - - for( auto seg2 : m_brd->Tracks() ) - { - // New netcode, break out (can't be there any seg2) - if( aSeg->GetNetCode() != seg2->GetNetCode() ) - continue; - - if( aSeg == seg2 ) - continue; - - if( seg2->GetFlags() & STRUCT_DELETED ) - continue; - - // Must be of the same type, on the same layer and with the same endpoints (although - // they might be swapped) - if( aSeg->Type() == seg2->Type() && aSeg->GetLayer() == seg2->GetLayer() ) - { - if( ( aSeg->GetStart() == seg2->GetStart() && aSeg->GetEnd() == seg2->GetEnd() ) || - ( aSeg->GetStart() == seg2->GetEnd() && aSeg->GetEnd() == seg2->GetStart() ) ) - { - if( m_itemsList ) - { - m_itemsList->emplace_back( new DRC_ITEM( m_units, DRCE_DUPLICATE_TRACK, - seg2, seg2->GetPosition(), - nullptr, wxPoint() ) ); - } - - seg2->SetFlags( STRUCT_DELETED ); - aToRemove.insert( seg2 ); - } - } - } -} - - -bool TRACKS_CLEANER::MergeCollinearTracks( TRACK* aSegment ) -{ - bool merged_this = false; - - if( !aSegment->Next() ) - return merged_this; - - for( ENDPOINT_T endpoint : { ENDPOINT_START, ENDPOINT_END } ) - { - // search for a possible segment connected to the current endpoint of the current one - TRACK* seg2 = aSegment->GetTrack( aSegment->Next(), NULL, endpoint, true, false ); - - if( seg2 ) - { - // the two segments must have the same width and seg2 cannot be a via - if( aSegment->GetWidth() == seg2->GetWidth() && seg2->Type() == PCB_TRACE_T ) - { - // There can be only one segment connected - seg2->SetState( BUSY, true ); - TRACK* seg3 = aSegment->GetTrack( m_brd->m_Track, NULL, endpoint, true, false ); - seg2->SetState( BUSY, false ); - - if( seg3 ) - continue; - - // Try to merge them - TRACK* segDelete = mergeCollinearSegments( aSegment, seg2, endpoint ); - - // Merge succesful, seg2 has to go away - if( !m_dryRun && segDelete ) - { - m_brd->Remove( segDelete ); - m_commit.Removed( segDelete ); - merged_this = true; - } - } - } - } - - return merged_this; -} - // Delete null length segments, and intermediate points .. bool TRACKS_CLEANER::cleanupSegments() @@ -471,37 +378,68 @@ bool TRACKS_CLEANER::cleanupSegments() bool modified = false; // Easy things first - modified |= deleteNullSegments(); + modified |= deleteNullSegments( m_brd->Tracks() ); buildTrackConnectionInfo(); std::set toRemove; - // Delete redundant segments, i.e. segments having the same end points and layers - // (can happens when blocks are copied on themselve) - for( auto segment : m_brd->Tracks() ) - removeDuplicatesOfTrack( segment, toRemove ); + for( auto it = m_brd->Tracks().begin(); it != m_brd->Tracks().end(); it++ ) + { + auto track1 = *it; + + if( track1->Type() != PCB_TRACE_T || ( track1->GetFlags() & IS_DELETED ) + || track1->IsLocked() ) + continue; + + for( auto it2 = it + 1; it2 != m_brd->Tracks().end(); it2++ ) + { + auto track2 = *it2; + + if( track2->GetFlags() & IS_DELETED ) + continue; + + if( track1->IsPointOnEnds( track2->GetStart() ) + && track1->IsPointOnEnds( track2->GetEnd() ) + && ( track1->GetWidth() == track2->GetWidth() ) + && ( track1->GetLayer() == track2->GetLayer() ) ) + { + if( m_itemsList ) + { + m_itemsList->emplace_back( new DRC_ITEM( m_units, DRCE_DUPLICATE_TRACK, track2, + track2->GetPosition(), nullptr, wxPoint() ) ); + } + + track2->SetFlags( IS_DELETED ); + toRemove.insert( track2 ); + } + } + } modified |= removeItems( toRemove ); - if( modified ) - buildTrackConnectionInfo(); - // merge collinear segments: - TRACK* nextsegment; - - for( TRACK* segment = m_brd->m_Track; segment; segment = nextsegment ) + for( auto track_it = m_brd->Tracks().begin(); track_it != m_brd->Tracks().end(); track_it++ ) { - nextsegment = segment->Next(); + auto segment = *track_it; + auto connectivity = m_brd->GetConnectivity(); + auto clusters = connectivity->GetConnectivityAlgo()->GetClusters(); - if( segment->Type() == PCB_TRACE_T ) + auto& entry = m_brd->GetConnectivity()->GetConnectivityAlgo()->ItemEntry( segment ); + + for( auto citem : entry.GetItems() ) { - bool merged_this = MergeCollinearTracks( segment ); - - if( merged_this ) // The current segment was modified, retry to merge it again + for( auto connected : citem->ConnectedItems() ) { - nextsegment = segment->Next(); - modified = true; + if( connected->Valid() && connected->Parent()->Type() == PCB_TRACE_T + && !( connected->Parent()->GetFlags() & IS_DELETED ) ) + { + if( segment->ApproxCollinear( *static_cast( connected->Parent() ) ) ) + { + modified |= mergeCollinearSegments( + segment, static_cast( connected->Parent() ) ); + } + } } } } @@ -510,104 +448,13 @@ bool TRACKS_CLEANER::cleanupSegments() } -/* Utility: check for parallelism between two segments */ -static bool parallelismTest( int dx1, int dy1, int dx2, int dy2 ) +bool TRACKS_CLEANER::mergeCollinearSegments( TRACK* aSeg1, TRACK* aSeg2 ) { - /* The following condition list is ugly and repetitive, but I have - * not a better way to express clearly the trivial cases. Hope the - * compiler optimize it better than always doing the product - * below... */ - - // test for vertical alignment (easy to handle) - if( dx1 == 0 ) - return dx2 == 0; - - if( dx2 == 0 ) - return dx1 == 0; - - // test for horizontal alignment (easy to handle) - if( dy1 == 0 ) - return dy2 == 0; - - if( dy2 == 0 ) - return dy1 == 0; - - /* test for alignment in other cases: Do the usual cross product test - * (the same as testing the slope, but without a division) */ - return ((double)dy1 * dx2 == (double)dx1 * dy2); -} - - -/** Function used by cleanupSegments. - * Test if aTrackRef and aCandidate (which must have a common end) are collinear. - * and see if the common point is not on a pad (i.e. if this common point can be removed). - * the ending point of aTrackRef is the start point (aEndType == START) - * or the end point (aEndType != START) - * flags START_ON_PAD and END_ON_PAD must be set before calling this function - * if the common point can be deleted, this function - * change the common point coordinate of the aTrackRef segm - * (and therefore connect the 2 other ending points) - * and return aCandidate (which can be deleted). - * else return NULL - */ -static void updateConn( TRACK *track, const std::shared_ptr& connectivity ) -{ - for( auto pad : connectivity->GetConnectedPads( track ) ) - { - if( pad->HitTest( track->GetStart() ) ) - track->SetState( START_ON_PAD, true ); - - if( pad->HitTest( track->GetEnd() ) ) - track->SetState( END_ON_PAD, true ); - } -} - - -TRACK* TRACKS_CLEANER::mergeCollinearSegments( TRACK* aSeg1, TRACK* aSeg2, - ENDPOINT_T aEndType ) -{ - // First of all, they must be of the same width and must be both actual tracks - if( aSeg1->GetWidth() != aSeg2->GetWidth() || - aSeg1->Type() != PCB_TRACE_T || aSeg2->Type() != PCB_TRACE_T ) - { - return NULL; - } - - // Trivial case: exactly the same track - if( ( aSeg1->GetStart() == aSeg2->GetStart() && aSeg1->GetEnd() == aSeg2->GetEnd() ) || - ( aSeg1->GetStart() == aSeg2->GetEnd() && aSeg1->GetEnd() == aSeg2->GetStart() )) - { - if( m_itemsList ) - { - m_itemsList->emplace_back( new DRC_ITEM( m_units, DRCE_DUPLICATE_TRACK, - aSeg2, aSeg2->GetPosition(), - nullptr, wxPoint() ) ); - } - - return aSeg2; - } - - // Weed out non-parallel tracks - if( !parallelismTest( aSeg1->GetEnd().x - aSeg1->GetStart().x, - aSeg1->GetEnd().y - aSeg1->GetStart().y, - aSeg2->GetEnd().x - aSeg2->GetStart().x, - aSeg2->GetEnd().y - aSeg2->GetStart().y ) ) - { - return NULL; - } + if( aSeg1->IsLocked() || aSeg2->IsLocked() ) + return false; auto connectivity = m_brd->GetConnectivity(); - updateConn( aSeg1, connectivity ); - updateConn( aSeg2, connectivity ); - - if( ( aEndType == ENDPOINT_START && aSeg1->GetState( START_ON_PAD ) ) || - ( aEndType == ENDPOINT_END && aSeg1->GetState( END_ON_PAD ) ) ) - { - // We do not have a pad, which is a always terminal point for a track - return NULL; - } - if( m_itemsList ) { m_itemsList->emplace_back( new DRC_ITEM( m_units, DRCE_MERGE_TRACKS, @@ -619,41 +466,40 @@ TRACK* TRACKS_CLEANER::mergeCollinearSegments( TRACK* aSeg1, TRACK* aSeg2, { m_commit.Modify( aSeg1 ); - if( aEndType == ENDPOINT_START ) + int min_x = std::min( aSeg1->GetStart().x, + std::min( aSeg1->GetEnd().x, std::min( aSeg2->GetStart().x, aSeg2->GetEnd().x ) ) ); + int min_y = std::min( aSeg1->GetStart().y, + std::min( aSeg1->GetEnd().y, std::min( aSeg2->GetStart().y, aSeg2->GetEnd().y ) ) ); + int max_x = std::max( aSeg1->GetStart().x, + std::max( aSeg1->GetEnd().x, std::max( aSeg2->GetStart().x, aSeg2->GetEnd().x ) ) ); + int max_y = std::max( aSeg1->GetStart().y, + std::max( aSeg1->GetEnd().y, std::max( aSeg2->GetStart().y, aSeg2->GetEnd().y ) ) ); + + if( ( aSeg1->GetStart().x > aSeg1->GetEnd().x ) + == ( aSeg1->GetStart().y > aSeg1->GetEnd().y ) ) { - /* change the common point coordinate of pt_segm to use the other point - * of pt_segm (pt_segm will be removed later) */ - if( aSeg1->GetStart() == aSeg2->GetStart() ) - { - aSeg1->SetStart( aSeg2->GetEnd() ); - aSeg1->SetState( START_ON_PAD, aSeg2->GetState( END_ON_PAD ) ); - } - else - { - aSeg1->SetStart( aSeg2->GetStart() ); - aSeg1->SetState( START_ON_PAD, aSeg2->GetState( START_ON_PAD ) ); - } + aSeg1->SetStart( wxPoint( min_x, min_y ) ); + aSeg1->SetEnd( wxPoint( max_x, max_y ) ); } - else // aEndType == END + else { - /* change the common point coordinate of pt_segm to use the other point - * of pt_segm (pt_segm will be removed later) */ - if( aSeg1->GetEnd() == aSeg2->GetStart() ) - { - aSeg1->SetEnd( aSeg2->GetEnd() ); - aSeg1->SetState( END_ON_PAD, aSeg2->GetState( END_ON_PAD ) ); - } - else - { - aSeg1->SetEnd( aSeg2->GetStart() ); - aSeg1->SetState( END_ON_PAD, aSeg2->GetState( START_ON_PAD ) ); - } + aSeg1->SetStart( wxPoint( min_x, max_y ) ); + aSeg1->SetEnd( wxPoint( max_x, min_y ) ); } connectivity->Update( aSeg1 ); } - return aSeg2; + + // Merge succesful, seg2 has to go away + if( !m_dryRun && aSeg2 ) + { + aSeg2->SetFlags( IS_DELETED ); + m_brd->Remove( aSeg2 ); + m_commit.Removed( aSeg2 ); + } + + return !!aSeg2; } @@ -662,36 +508,11 @@ bool TRACKS_CLEANER::removeItems( std::set& aItems ) if( m_dryRun ) return false; - bool isModified = false; - for( auto item : aItems ) { - isModified = true; m_brd->Remove( item ); m_commit.Removed( item ); } - return isModified; -} - - -bool PCB_EDIT_FRAME::RemoveMisConnectedTracks() -{ - // Old model has to be refreshed, GAL normally does not keep updating it - Compile_Ratsnest( false ); - BOARD_COMMIT commit( this ); - - TRACKS_CLEANER cleaner( m_UserUnits, GetBoard(), commit ); - bool isModified = cleaner.CleanupBoard( true, nullptr, true, false, false, false ); - - if( isModified ) - { - // Clear undo and redo lists to avoid inconsistencies between lists - commit.Push( _( "Board cleanup" ) ); - Compile_Ratsnest( true ); - } - - GetGalCanvas()->Refresh( true ); - - return isModified; + return !aItems.empty(); } diff --git a/pcbnew/tracks_cleaner.h b/pcbnew/tracks_cleaner.h index f1a7f95f44..6baa3678e5 100644 --- a/pcbnew/tracks_cleaner.h +++ b/pcbnew/tracks_cleaner.h @@ -61,27 +61,13 @@ private: */ bool cleanupVias(); - /** - * Removes all the following THT vias on the same position of the - * specified one - */ - void removeDuplicatesOfVia( const VIA *aVia, std::set& aToRemove ); - - /** - * Removes all the following duplicates tracks of the specified one - */ - void removeDuplicatesOfTrack( const TRACK* aSeg, std::set& aToRemove ); - /** * Removes dangling tracks */ bool deleteDanglingTracks(); /// Delete null length track segments - bool deleteNullSegments(); - - /// Try to merge the segment to a following collinear one - bool MergeCollinearTracks( TRACK* aSegment ); + bool deleteNullSegments( TRACKS& aTracks ); /** * Merge collinear segments and remove duplicated and null len segments @@ -100,10 +86,9 @@ private: * merge aTrackRef and aCandidate, when possible, * i.e. when they are colinear, same width, and obviously same layer */ - TRACK* mergeCollinearSegments( TRACK* aSeg1, - TRACK* aSeg2, ENDPOINT_T aEndType ); + bool mergeCollinearSegments( TRACK* aSeg1, TRACK* aSeg2 ); - bool testTrackEndpointDangling( TRACK* aTrack, ENDPOINT_T aEndPoint ); + bool testTrackEndpointDangling( TRACK* aTrack ); EDA_UNITS_T m_units; BOARD* m_brd; diff --git a/pcbnew/undo_redo.cpp b/pcbnew/undo_redo.cpp index ac1be90a99..74f96bb5c3 100644 --- a/pcbnew/undo_redo.cpp +++ b/pcbnew/undo_redo.cpp @@ -119,41 +119,42 @@ using namespace std::placeholders; static bool TestForExistingItem( BOARD* aPcb, BOARD_ITEM* aItem ) { - static std::set itemsList; - - if( aItem == NULL ) // Build list + for( auto item : aPcb->Tracks() ) { - // Count items to store in itemsList: - BOARD_ITEM* item; - itemsList.clear(); - - // Store items in list: - // Append tracks: - for( item = aPcb->m_Track; item != NULL; item = item->Next() ) - itemsList.insert( item ); - - // Append modules: - std::copy( aPcb->Modules().begin(), aPcb->Modules().end(), - std::inserter( itemsList, itemsList.end() ) ); - - // Append drawings - for( auto ditem : aPcb->Drawings() ) - itemsList.insert( ditem ); - - // Append zones outlines - for( int ii = 0; ii < aPcb->GetAreaCount(); ii++ ) - itemsList.insert( aPcb->GetArea( ii ) ); - - NETINFO_LIST& netInfo = aPcb->GetNetInfo(); - - for( NETINFO_LIST::iterator i = netInfo.begin(); i != netInfo.end(); ++i ) - itemsList.insert( *i ); - - return false; + if( aItem == static_cast( item ) ) + return true; } - // search in list: - return itemsList.count( aItem ); + // Append modules: + for( auto item : aPcb->Modules() ) + { + if( aItem == static_cast( item ) ) + return true; + } + + // Append drawings + for( auto item : aPcb->Drawings() ) + { + if( aItem == static_cast( item ) ) + return true; + } + + // Append zones outlines + for( auto item : aPcb->Zones() ) + { + if( aItem == static_cast( item ) ) + return true; + } + + NETINFO_LIST& netInfo = aPcb->GetNetInfo(); + + for( NETINFO_LIST::iterator i = netInfo.begin(); i != netInfo.end(); ++i ) + { + if( aItem == static_cast( *i ) ) + return true; + } + + return false; } static void SwapItemData( BOARD_ITEM* aItem, BOARD_ITEM* aImage ) @@ -405,8 +406,6 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool // Undo in the reverse order of list creation: (this can allow stacked changes // like the same item can be changes and deleted in the same complex command - bool build_item_list = true; // if true the list of existing items must be rebuilt - // Restore changes in reverse order for( int ii = aList->GetCount() - 1; ii >= 0 ; ii-- ) { @@ -426,12 +425,6 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool && status != UR_GRIDORIGIN // origin markers never on board && status != UR_PAGESETTINGS ) // nor are page settings proxy items { - if( build_item_list ) - // Build list of existing items, for integrity test - TestForExistingItem( GetBoard(), NULL ); - - build_item_list = false; - if( !TestForExistingItem( GetBoard(), (BOARD_ITEM*) eda_item ) ) { // Checking if it ever happens @@ -442,6 +435,10 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool ii++; // the current item was removed, ii points now the next item // decrement it because it will be incremented later not_found = true; + + if( aList->GetCount() == 0 ) + break; + continue; } } @@ -496,7 +493,6 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aList->SetPickedItemStatus( UR_NEW, ii ); GetModel()->Add( (BOARD_ITEM*) eda_item ); view->Add( eda_item ); - build_item_list = true; break; case UR_MOVED: diff --git a/qa/testcases/test_002_board_class.py b/qa/testcases/test_002_board_class.py index 26062fc709..e9b8bd1027 100644 --- a/qa/testcases/test_002_board_class.py +++ b/qa/testcases/test_002_board_class.py @@ -29,15 +29,15 @@ class TestBoardClass(unittest.TestCase): def test_pcb_get_track_count(self): pcb = BOARD() - self.assertEqual(pcb.GetNumSegmTrack(),0) + self.assertEqual(pcb.Tracks().size(),0) track0 = TRACK(pcb) pcb.Add(track0) - self.assertEqual(pcb.GetNumSegmTrack(),1) + self.assertEqual(pcb.Tracks().size(),1) track1 = TRACK(pcb) pcb.Add(track1) - self.assertEqual(pcb.GetNumSegmTrack(),2) + self.assertEqual(pcb.Tracks().size(),2) def test_pcb_bounding_box(self): pcb = BOARD()