pcbnew: Move tracks to std::deque
This commit is contained in:
parent
d1877d7c1b
commit
888c01d11b
|
@ -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;
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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" ),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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() );
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
17
pcbnew/drc.h
17
pcbnew/drc.h
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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 )
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 ) )
|
||||
{
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue