pcbnew: Move tracks to std::deque

This commit is contained in:
Seth Hillbrand 2019-05-30 19:30:28 -07:00
parent d1877d7c1b
commit 888c01d11b
45 changed files with 381 additions and 1974 deletions

View File

@ -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;

View File

@ -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 )
{

View File

@ -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 )
{

View File

@ -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)

View File

@ -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;

View File

@ -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.
* <p>
* 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<double>::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 <stdio.h>
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<TRACK*>( aBoardItem ) );
else
{
TRACK* insertAid;
insertAid = ( (TRACK*) aBoardItem )->GetBestInsertPoint( this );
m_Track.Insert( (TRACK*) aBoardItem, insertAid );
}
m_tracks.push_front( static_cast<TRACK*>( 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<TRACK*>( m_tracks, inspector, testData, p );
++p;
break;
case PCB_TRACE_T:
result = IterateForward( m_Track, inspector, testData, p );
result = IterateForward<TRACK*>( 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<TRACK*> BOARD::GetTracksByPosition( const wxPoint& aPosition, PCB_LAYER_ID aLayer ) const
{
std::list<TRACK*> 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<int, double, double> 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<const BOARD_CONNECTED_ITEM*>( &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<TRACK*>( 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<D_PAD*>( 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<D_PAD*>( 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<TRACK>* list = (DLIST<TRACK>*)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<TRACK>* list = (DLIST<TRACK>*)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 )
{

View File

@ -30,6 +30,7 @@
#ifndef CLASS_BOARD_H_
#define CLASS_BOARD_H_
#include <tuple>
#include <dlist.h>
#include <core/iterators.h>
@ -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<TRACK> m_Track; // linked list of TRACKs and VIAs
DLIST_ITERATOR_WRAPPER<TRACK> Tracks() { return DLIST_ITERATOR_WRAPPER<TRACK>(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<BOARD_CONNECTED_ITEM*> 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.
* <p>
* 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.
* </p>
* @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 (<PCB_LAYER_ID>::UNDEFINED_LAYER) for a don't care.
* @return std::list<TRACK*> A list of TRACK* items that can be zero if no track is found.
*/
std::list<TRACK*> 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<D_PAD*>& 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 <number, length, package length>
*/
TRACK* GetVisibleTrack( TRACK* aStartingTrace, const wxPoint& aPosition, LSET aLayerSet ) const;
/**
* Function MarkTrace
* marks a chain of trace segments, connected to \a aTrace.
* <p>
* 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.
* </p>
*
* @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<int, double, double> 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.
* <p>
* This may be a PAD or another trace segment.
* </p>
*
* @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.
* <p>
* The new segment starts from \a aPosition and ends at the end point of \a
* aSegment. The original segment now ends at \a aPosition.
* </p>
*
* @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).

View File

@ -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" ),

View File

@ -37,6 +37,8 @@
#include <pcb_display_options.h>
#include <pcbnew.h>
#include <geometry/seg.h>
#include <trigo.h>
@ -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.
* <p>
* The segments of track that are flagged as deleted or busy are ignored. Layer
* visibility is also ignored.
* </p>
* @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<TRACK*>( Pnext ); }
TRACK* Back() const { return static_cast<TRACK*>( 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<TRACK> 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<VIA*>( 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<TRACK*>( aTrk );
else
return NULL;
}
#endif // CLASS_TRACK_H

View File

@ -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<const VIA*>( track );
if( via )

View File

@ -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 )

View File

@ -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 );
}

View File

@ -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() );

View File

@ -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 )
{

View File

@ -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;

View File

@ -29,10 +29,12 @@
#ifndef DRC_H
#define DRC_H
#include <vector>
#include <memory>
#include <class_board.h>
#include <class_track.h>
#include <geometry/seg.h>
#include <geometry/shape_poly_set.h>
#include <memory>
#include <vector>
#include <drc/drc_marker_factory.h>
@ -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

View File

@ -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;

View File

@ -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 );

View File

@ -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 )
{

View File

@ -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<VIA*>( 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<VIA*>( 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 <int> trackinfo;
std::set<int> 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 );
}

View File

@ -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 )
{

View File

@ -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<VIA*>( track );
int hole_sz = via->GetDrillValue();
if( hole_sz == 0 ) // Should not occur.

View File

@ -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

View File

@ -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_

View File

@ -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 )
{

View File

@ -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

View File

@ -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 );

View File

@ -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 );

View File

@ -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::vector<MSG_PA
int viasCount = 0;
int trackSegmentsCount = 0;
for( const BOARD_ITEM* item = board->m_Track; item; item = item->Next() )
for( auto item : board->Tracks() )
{
if( item->Type() == PCB_VIA_T )
viasCount++;

View File

@ -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 );

View File

@ -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;

View File

@ -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 )
{

View File

@ -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<const VIA*>( 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<const VIA*>( 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<const VIA*>( track );

View File

@ -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<const VIA*>( pts );

View File

@ -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 )
}
}

View File

@ -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();

View File

@ -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)

View File

@ -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 ) )
{

View File

@ -838,7 +838,7 @@ int PCBNEW_CONTROL::placeBoardItems( BOARD* aBoard )
bool isNew = board() != aBoard;
std::vector<BOARD_ITEM*> 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 );

View File

@ -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<BOARD_CONNECTED_ITEM*>( &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

View File

@ -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 );

View File

@ -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<BOARD_ITEM *>& 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<BOARD_ITEM*> toRemove;
std::vector<VIA*> 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<VIA*>( 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<BOARD_ITEM *> 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<BOARD_ITEM*>& 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<BOARD_ITEM*> 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<TRACK*>( connected->Parent() ) ) )
{
modified |= mergeCollinearSegments(
segment, static_cast<TRACK*>( 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_DATA>& 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<BOARD_ITEM*>& 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();
}

View File

@ -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<BOARD_ITEM *>& aToRemove );
/**
* Removes all the following duplicates tracks of the specified one
*/
void removeDuplicatesOfTrack( const TRACK* aSeg, std::set<BOARD_ITEM*>& 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;

View File

@ -119,41 +119,42 @@ using namespace std::placeholders;
static bool TestForExistingItem( BOARD* aPcb, BOARD_ITEM* aItem )
{
static std::set<BOARD_ITEM*> 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<BOARD_ITEM*>( item ) )
return true;
}
// search in list:
return itemsList.count( aItem );
// Append modules:
for( auto item : aPcb->Modules() )
{
if( aItem == static_cast<BOARD_ITEM*>( item ) )
return true;
}
// Append drawings
for( auto item : aPcb->Drawings() )
{
if( aItem == static_cast<BOARD_ITEM*>( item ) )
return true;
}
// Append zones outlines
for( auto item : aPcb->Zones() )
{
if( aItem == static_cast<BOARD_ITEM*>( item ) )
return true;
}
NETINFO_LIST& netInfo = aPcb->GetNetInfo();
for( NETINFO_LIST::iterator i = netInfo.begin(); i != netInfo.end(); ++i )
{
if( aItem == static_cast<BOARD_ITEM*>( *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:

View File

@ -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()