2011-09-23 13:57:12 +00:00
|
|
|
/**
|
|
|
|
* @file connect.cpp
|
|
|
|
* @brief Functions to handle existing tracks in ratsnest calculations.
|
|
|
|
*/
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2011-10-31 20:29:46 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
2012-06-08 09:56:42 +00:00
|
|
|
* Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
|
|
|
|
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
2015-02-22 21:25:29 +00:00
|
|
|
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
|
2011-10-31 20:29:46 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, you may find one here:
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
2012-01-23 04:33:36 +00:00
|
|
|
#include <fctsys.h>
|
|
|
|
#include <common.h>
|
|
|
|
#include <macros.h>
|
|
|
|
#include <wxBasePcbFrame.h>
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2012-01-23 04:33:36 +00:00
|
|
|
#include <pcbnew.h>
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2012-09-07 19:29:44 +00:00
|
|
|
// Helper classes to handle connection points
|
|
|
|
#include <connect.h>
|
2011-09-23 13:57:12 +00:00
|
|
|
|
2008-11-18 18:13:55 +00:00
|
|
|
extern void Merge_SubNets_Connected_By_CopperAreas( BOARD* aPcb );
|
|
|
|
extern void Merge_SubNets_Connected_By_CopperAreas( BOARD* aPcb, int aNetcode );
|
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
// Local functions
|
2007-08-23 04:28:46 +00:00
|
|
|
static void RebuildTrackChain( BOARD* pcb );
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
CONNECTIONS::CONNECTIONS( BOARD * aBrd )
|
|
|
|
{
|
|
|
|
m_brd = aBrd;
|
2015-02-22 21:25:29 +00:00
|
|
|
m_firstTrack = NULL;
|
|
|
|
m_lastTrack = NULL;
|
2011-12-04 17:57:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Fills m_sortedPads with all pads that be connected to tracks
|
|
|
|
* pads are sorted by X coordinate ( and Y coordinates for same X value )
|
|
|
|
* aNetcode = net code to filter pads or < 0 to put all pads in list
|
|
|
|
*/
|
|
|
|
void CONNECTIONS::BuildPadsList( int aNetcode )
|
|
|
|
{
|
|
|
|
// Creates sorted pad list if not exists
|
|
|
|
m_sortedPads.clear();
|
2011-12-17 21:21:03 +00:00
|
|
|
m_brd->GetSortedPadListByXthenYCoord( m_sortedPads, aNetcode < 0 ? -1 : aNetcode );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Explores the list of pads and adds to m_PadsConnected member
|
|
|
|
* of each pad pads connected to
|
|
|
|
* Here, connections are due to intersecting pads, not tracks
|
|
|
|
*/
|
|
|
|
void CONNECTIONS::SearchConnectionsPadsToIntersectingPads()
|
|
|
|
{
|
|
|
|
std::vector<CONNECTED_POINT*> candidates;
|
|
|
|
|
|
|
|
BuildPadsCandidatesList();
|
|
|
|
|
|
|
|
for( unsigned ii = 0; ii < m_sortedPads.size(); ii++ )
|
2011-12-04 17:57:03 +00:00
|
|
|
{
|
2014-06-25 17:01:50 +00:00
|
|
|
D_PAD* pad = m_sortedPads[ii];
|
|
|
|
|
2011-12-17 21:21:03 +00:00
|
|
|
pad->m_PadsConnected.clear();
|
|
|
|
candidates.clear();
|
2012-02-19 04:02:19 +00:00
|
|
|
|
* KIWAY Milestone A): Make major modules into DLL/DSOs.
! The initial testing of this commit should be done using a Debug build so that
all the wxASSERT()s are enabled. Also, be sure and keep enabled the
USE_KIWAY_DLLs option. The tree won't likely build without it. Turning it
off is senseless anyways. If you want stable code, go back to a prior version,
the one tagged with "stable".
* Relocate all functionality out of the wxApp derivative into more finely
targeted purposes:
a) DLL/DSO specific
b) PROJECT specific
c) EXE or process specific
d) configuration file specific data
e) configuration file manipulations functions.
All of this functionality was blended into an extremely large wxApp derivative
and that was incompatible with the desire to support multiple concurrently
loaded DLL/DSO's ("KIFACE")s and multiple concurrently open projects.
An amazing amount of organization come from simply sorting each bit of
functionality into the proper box.
* Switch to wxConfigBase from wxConfig everywhere except instantiation.
* Add classes KIWAY, KIFACE, KIFACE_I, SEARCH_STACK, PGM_BASE, PGM_KICAD,
PGM_SINGLE_TOP,
* Remove "Return" prefix on many function names.
* Remove obvious comments from CMakeLists.txt files, and from else() and endif()s.
* Fix building boost for use in a DSO on linux.
* Remove some of the assumptions in the CMakeLists.txt files that windows had
to be the host platform when building windows binaries.
* Reduce the number of wxStrings being constructed at program load time via
static construction.
* Pass wxConfigBase* to all SaveSettings() and LoadSettings() functions so that
these functions are useful even when the wxConfigBase comes from another
source, as is the case in the KICAD_MANAGER_FRAME.
* Move the setting of the KIPRJMOD environment variable into class PROJECT,
so that it can be moved into a project variable soon, and out of FP_LIB_TABLE.
* Add the KIWAY_PLAYER which is associated with a particular PROJECT, and all
its child wxFrames and wxDialogs now have a Kiway() member function which
returns a KIWAY& that that window tree branch is in support of. This is like
wxWindows DNA in that child windows get this member with proper value at time
of construction.
* Anticipate some of the needs for milestones B) and C) and make code
adjustments now in an effort to reduce work in those milestones.
* No testing has been done for python scripting, since milestone C) has that
being largely reworked and re-thought-out.
2014-03-20 00:42:08 +00:00
|
|
|
CollectItemsNearTo( candidates, pad->ShapePos(), pad->GetBoundingRadius() );
|
2012-02-19 04:02:19 +00:00
|
|
|
|
2011-12-17 21:21:03 +00:00
|
|
|
// add pads to pad.m_PadsConnected, if they are connected
|
|
|
|
for( unsigned jj = 0; jj < candidates.size(); jj++ )
|
2011-12-04 17:57:03 +00:00
|
|
|
{
|
2014-06-25 17:01:50 +00:00
|
|
|
CONNECTED_POINT* item = candidates[jj];
|
|
|
|
|
|
|
|
D_PAD* candidate_pad = item->GetPad();
|
|
|
|
|
2011-12-17 21:21:03 +00:00
|
|
|
if( pad == candidate_pad )
|
|
|
|
continue;
|
|
|
|
|
2014-06-25 17:01:50 +00:00
|
|
|
if( !( pad->GetLayerSet() & candidate_pad->GetLayerSet() ).any() )
|
2011-12-17 21:21:03 +00:00
|
|
|
continue;
|
|
|
|
if( pad->HitTest( item->GetPoint() ) )
|
|
|
|
{
|
|
|
|
pad->m_PadsConnected.push_back( candidate_pad );
|
|
|
|
}
|
2011-12-04 17:57:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-17 21:21:03 +00:00
|
|
|
/* Explores the list of pads
|
|
|
|
* Adds to m_PadsConnected member of each track the pad(s) connected to
|
|
|
|
* Adds to m_TracksConnected member of each pad the track(s) connected to
|
|
|
|
* D_PAD::m_TracksConnected is cleared before adding items
|
|
|
|
* TRACK::m_PadsConnected is not cleared
|
|
|
|
*/
|
2012-09-11 07:33:17 +00:00
|
|
|
void CONNECTIONS::SearchTracksConnectedToPads( bool add_to_padlist, bool add_to_tracklist)
|
2011-12-04 17:57:03 +00:00
|
|
|
{
|
|
|
|
std::vector<CONNECTED_POINT*> candidates;
|
|
|
|
|
|
|
|
for( unsigned ii = 0; ii < m_sortedPads.size(); ii++ )
|
|
|
|
{
|
|
|
|
D_PAD * pad = m_sortedPads[ii];
|
2011-12-17 21:21:03 +00:00
|
|
|
pad->m_TracksConnected.clear();
|
2011-12-04 17:57:03 +00:00
|
|
|
candidates.clear();
|
2011-12-17 21:21:03 +00:00
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
CollectItemsNearTo( candidates, pad->GetPosition(), pad->GetBoundingRadius() );
|
2011-12-17 21:21:03 +00:00
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
// add this pad to track.m_PadsConnected, if it is connected
|
|
|
|
for( unsigned jj = 0; jj < candidates.size(); jj++ )
|
|
|
|
{
|
2012-02-19 04:02:19 +00:00
|
|
|
CONNECTED_POINT* cp_item = candidates[jj];
|
|
|
|
|
2014-06-25 17:01:50 +00:00
|
|
|
if( !( pad->GetLayerSet() & cp_item->GetTrack()->GetLayerSet() ).any() )
|
2011-12-04 17:57:03 +00:00
|
|
|
continue;
|
2012-02-19 04:02:19 +00:00
|
|
|
|
2011-12-17 21:21:03 +00:00
|
|
|
if( pad->HitTest( cp_item->GetPoint() ) )
|
2011-12-04 17:57:03 +00:00
|
|
|
{
|
2012-09-11 07:33:17 +00:00
|
|
|
if( add_to_padlist )
|
|
|
|
cp_item->GetTrack()->m_PadsConnected.push_back( pad );
|
|
|
|
|
|
|
|
if( add_to_tracklist )
|
|
|
|
pad->m_TracksConnected.push_back( cp_item->GetTrack() );
|
2011-12-04 17:57:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CONNECTIONS::CollectItemsNearTo( std::vector<CONNECTED_POINT*>& aList,
|
|
|
|
const wxPoint& aPosition, int aDistMax )
|
|
|
|
{
|
|
|
|
/* Search items in m_Candidates that position is <= aDistMax from aPosition
|
|
|
|
* (Rectilinear distance)
|
|
|
|
* m_Candidates is sorted by X then Y values, so a fast binary search is used
|
|
|
|
* to locate the "best" entry point in list
|
|
|
|
* The best entry is a pad having its m_Pos.x == (or near) aPosition.x
|
|
|
|
* All candidates are near this candidate in list
|
|
|
|
* So from this entry point, a linear search is made to find all candidates
|
|
|
|
*/
|
|
|
|
int idxmax = m_candidates.size()-1;
|
|
|
|
|
|
|
|
int delta = m_candidates.size();
|
2011-12-28 15:14:46 +00:00
|
|
|
|
|
|
|
int idx = 0; // Starting index is the beginning of list
|
2011-12-04 17:57:03 +00:00
|
|
|
while( delta )
|
|
|
|
{
|
2011-12-28 15:14:46 +00:00
|
|
|
// Calculate half size of remaining interval to test.
|
|
|
|
// Ensure the computed value is not truncated (too small)
|
2011-12-04 17:57:03 +00:00
|
|
|
if( (delta & 1) && ( delta > 1 ) )
|
|
|
|
delta++;
|
|
|
|
delta /= 2;
|
|
|
|
|
|
|
|
CONNECTED_POINT& item = m_candidates[idx];
|
|
|
|
|
2011-12-17 21:21:03 +00:00
|
|
|
int dist = item.GetPoint().x - aPosition.x;
|
|
|
|
if( abs(dist) <= aDistMax )
|
|
|
|
{
|
2011-12-04 17:57:03 +00:00
|
|
|
break; // A good entry point is found. The list can be scanned from this point.
|
2011-12-17 21:21:03 +00:00
|
|
|
}
|
2011-12-04 17:57:03 +00:00
|
|
|
|
|
|
|
else if( item.GetPoint().x < aPosition.x ) // We should search after this item
|
|
|
|
{
|
|
|
|
idx += delta;
|
|
|
|
if( idx > idxmax )
|
|
|
|
idx = idxmax;
|
|
|
|
}
|
|
|
|
else // We should search before this item
|
|
|
|
{
|
|
|
|
idx -= delta;
|
|
|
|
if( idx < 0 )
|
|
|
|
idx = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now explore the candidate list from the "best" entry point found
|
|
|
|
* (candidate "near" aPosition.x)
|
|
|
|
* We explore the list until abs(candidate->m_Point.x - aPosition.x) > aDistMax
|
|
|
|
* because the list is sorted by X position (and for a given X pos, by Y pos)
|
|
|
|
* Currently a linear search is made because the number of candidates
|
|
|
|
* having the right X position is usually small
|
|
|
|
*/
|
|
|
|
// search next candidates in list
|
|
|
|
wxPoint diff;
|
|
|
|
for( int ii = idx; ii <= idxmax; ii++ )
|
|
|
|
{
|
|
|
|
CONNECTED_POINT* item = &m_candidates[ii];
|
|
|
|
diff = item->GetPoint() - aPosition;
|
|
|
|
if( abs(diff.x) > aDistMax )
|
|
|
|
break; // Exit: the distance is to long, we cannot find other candidates
|
|
|
|
if( abs(diff.y) > aDistMax )
|
|
|
|
continue; // the y distance is to long, but we can find other candidates
|
|
|
|
// We have here a good candidate: add it
|
|
|
|
aList.push_back( item );
|
|
|
|
}
|
|
|
|
// search previous candidates in list
|
|
|
|
for( int ii = idx-1; ii >=0; ii-- )
|
|
|
|
{
|
|
|
|
CONNECTED_POINT * item = &m_candidates[ii];
|
|
|
|
diff = item->GetPoint() - aPosition;
|
|
|
|
if( abs(diff.x) > aDistMax )
|
|
|
|
break;
|
|
|
|
if( abs(diff.y) > aDistMax )
|
|
|
|
continue;
|
|
|
|
// We have here a good candidate:add it
|
|
|
|
aList.push_back( item );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-17 21:21:03 +00:00
|
|
|
|
|
|
|
void CONNECTIONS::BuildPadsCandidatesList()
|
|
|
|
{
|
|
|
|
m_candidates.clear();
|
|
|
|
m_candidates.reserve( m_sortedPads.size() );
|
|
|
|
for( unsigned ii = 0; ii < m_sortedPads.size(); ii++ )
|
|
|
|
{
|
|
|
|
D_PAD * pad = m_sortedPads[ii];
|
|
|
|
CONNECTED_POINT candidate( pad, pad->GetPosition() );
|
|
|
|
m_candidates.push_back( candidate );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
/* sort function used to sort .m_Connected by X the Y values
|
|
|
|
* items are sorted by X coordinate value,
|
|
|
|
* and for same X value, by Y coordinate value.
|
|
|
|
*/
|
|
|
|
static bool sortConnectedPointByXthenYCoordinates( const CONNECTED_POINT & aRef,
|
|
|
|
const CONNECTED_POINT & aTst )
|
|
|
|
{
|
2011-12-04 17:57:03 +00:00
|
|
|
if( aRef.GetPoint().x == aTst.GetPoint().x )
|
|
|
|
return aRef.GetPoint().y < aTst.GetPoint().y;
|
|
|
|
return aRef.GetPoint().x < aTst.GetPoint().x;
|
2011-10-31 13:44:13 +00:00
|
|
|
}
|
|
|
|
|
2014-06-29 21:50:06 +00:00
|
|
|
void CONNECTIONS::BuildTracksCandidatesList( TRACK* aBegin, TRACK* aEnd)
|
2011-10-31 13:44:13 +00:00
|
|
|
{
|
2011-12-04 17:57:03 +00:00
|
|
|
m_candidates.clear();
|
2011-12-19 11:58:24 +00:00
|
|
|
m_firstTrack = m_lastTrack = aBegin;
|
2011-11-03 19:07:59 +00:00
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
unsigned ii = 0;
|
2014-06-29 21:50:06 +00:00
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
// Count candidates ( i.e. end points )
|
|
|
|
for( const TRACK* track = aBegin; track; track = track->Next() )
|
|
|
|
{
|
|
|
|
if( track->Type() == PCB_VIA_T )
|
|
|
|
ii++;
|
|
|
|
else
|
|
|
|
ii += 2;
|
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
m_lastTrack = track;
|
2014-06-29 21:50:06 +00:00
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
if( track == aEnd )
|
|
|
|
break;
|
|
|
|
}
|
2014-06-29 21:50:06 +00:00
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
// Build candidate list
|
2011-12-04 17:57:03 +00:00
|
|
|
m_candidates.reserve( ii );
|
2011-11-03 19:07:59 +00:00
|
|
|
for( TRACK* track = aBegin; track; track = track->Next() )
|
2011-10-31 13:44:13 +00:00
|
|
|
{
|
2014-06-29 21:50:06 +00:00
|
|
|
CONNECTED_POINT candidate( track, track->GetStart() );
|
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
m_candidates.push_back( candidate );
|
2011-10-31 13:44:13 +00:00
|
|
|
if( track->Type() != PCB_VIA_T )
|
|
|
|
{
|
2013-01-13 00:04:00 +00:00
|
|
|
CONNECTED_POINT candidate2( track, track->GetEnd());
|
2011-12-04 17:57:03 +00:00
|
|
|
m_candidates.push_back( candidate2 );
|
2011-10-31 13:44:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if( track == aEnd )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort list by increasing X coordinate,
|
|
|
|
// and for increasing Y coordinate when items have the same X coordinate
|
|
|
|
// So candidates to the same location are consecutive in list.
|
2011-12-04 17:57:03 +00:00
|
|
|
sort( m_candidates.begin(), m_candidates.end(), sortConnectedPointByXthenYCoordinates );
|
2011-10-31 13:44:13 +00:00
|
|
|
}
|
|
|
|
|
2014-06-29 21:50:06 +00:00
|
|
|
|
2013-01-08 17:58:06 +00:00
|
|
|
/* Populates .m_connected with tracks/vias connected to aTrack
|
|
|
|
* param aTrack = track or via to use as reference
|
|
|
|
* For calculation time reason, an exhaustive search cannot be made
|
|
|
|
* and a proximity search is made:
|
|
|
|
* Only tracks with one end near one end of aTrack are collected.
|
|
|
|
* near means dist <= aTrack width / 2
|
|
|
|
* because with this constraint we can make a fast search in track list
|
|
|
|
* m_candidates is expected to be populated by the track candidates ends list
|
|
|
|
*/
|
2014-06-29 21:50:06 +00:00
|
|
|
int CONNECTIONS::SearchConnectedTracks( const TRACK* aTrack )
|
2011-10-31 13:44:13 +00:00
|
|
|
{
|
|
|
|
int count = 0;
|
2011-12-04 17:57:03 +00:00
|
|
|
m_connected.clear();
|
2011-10-31 13:44:13 +00:00
|
|
|
|
2014-06-24 16:17:18 +00:00
|
|
|
LSET layerMask = aTrack->GetLayerSet();
|
2011-10-31 13:44:13 +00:00
|
|
|
|
|
|
|
// Search for connections to starting point:
|
2013-01-08 17:58:06 +00:00
|
|
|
#define USE_EXTENDED_SEARCH
|
2014-06-29 20:33:29 +00:00
|
|
|
|
2013-01-08 17:58:06 +00:00
|
|
|
#ifdef USE_EXTENDED_SEARCH
|
|
|
|
int dist_max = aTrack->GetWidth() / 2;
|
|
|
|
static std::vector<CONNECTED_POINT*> tracks_candidates;
|
|
|
|
#endif
|
2014-06-29 21:50:06 +00:00
|
|
|
|
2013-01-13 00:04:00 +00:00
|
|
|
wxPoint position = aTrack->GetStart();
|
2014-06-29 21:50:06 +00:00
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
for( int kk = 0; kk < 2; kk++ )
|
|
|
|
{
|
2013-01-08 17:58:06 +00:00
|
|
|
#ifndef USE_EXTENDED_SEARCH
|
2011-12-19 11:58:24 +00:00
|
|
|
int idx = searchEntryPointInCandidatesList( position );
|
2014-06-29 20:33:29 +00:00
|
|
|
|
|
|
|
if( idx >= 0 )
|
2011-10-31 13:44:13 +00:00
|
|
|
{
|
|
|
|
// search after:
|
2014-06-29 20:33:29 +00:00
|
|
|
for( unsigned ii = idx; ii < m_candidates.size(); ii ++ )
|
2011-10-31 13:44:13 +00:00
|
|
|
{
|
2011-12-04 17:57:03 +00:00
|
|
|
if( m_candidates[ii].GetTrack() == aTrack )
|
2011-10-31 13:44:13 +00:00
|
|
|
continue;
|
2014-06-29 21:50:06 +00:00
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
if( m_candidates[ii].GetPoint() != position )
|
2011-10-31 13:44:13 +00:00
|
|
|
break;
|
2014-06-29 21:50:06 +00:00
|
|
|
|
2014-06-29 20:33:29 +00:00
|
|
|
if( ( m_candidates[ii].GetTrack()->GetLayerSet() & layerMask ).any() )
|
2011-12-04 17:57:03 +00:00
|
|
|
m_connected.push_back( m_candidates[ii].GetTrack() );
|
2011-10-31 13:44:13 +00:00
|
|
|
}
|
2014-06-29 20:33:29 +00:00
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
// search before:
|
2014-06-29 20:33:29 +00:00
|
|
|
for( int ii = idx-1; ii >= 0; ii -- )
|
2011-10-31 13:44:13 +00:00
|
|
|
{
|
2011-12-04 17:57:03 +00:00
|
|
|
if( m_candidates[ii].GetTrack() == aTrack )
|
2011-10-31 13:44:13 +00:00
|
|
|
continue;
|
2014-06-29 21:50:06 +00:00
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
if( m_candidates[ii].GetPoint() != position )
|
2011-10-31 13:44:13 +00:00
|
|
|
break;
|
2014-06-29 21:50:06 +00:00
|
|
|
|
2014-06-29 20:33:29 +00:00
|
|
|
if( ( m_candidates[ii].GetTrack()->GetLayerSet() & layerMask ).any() )
|
2011-12-04 17:57:03 +00:00
|
|
|
m_connected.push_back( m_candidates[ii].GetTrack() );
|
2011-10-31 13:44:13 +00:00
|
|
|
}
|
|
|
|
}
|
2013-01-08 17:58:06 +00:00
|
|
|
#else
|
2014-06-29 21:50:06 +00:00
|
|
|
|
2013-01-08 17:58:06 +00:00
|
|
|
tracks_candidates.clear();
|
2014-06-29 21:50:06 +00:00
|
|
|
|
2013-01-08 17:58:06 +00:00
|
|
|
CollectItemsNearTo( tracks_candidates, position, dist_max );
|
2014-06-29 21:50:06 +00:00
|
|
|
|
|
|
|
for( unsigned ii = 0; ii < tracks_candidates.size(); ii++ )
|
2013-01-08 17:58:06 +00:00
|
|
|
{
|
2014-06-29 21:50:06 +00:00
|
|
|
TRACK* ctrack = tracks_candidates[ii]->GetTrack();
|
2013-01-08 17:58:06 +00:00
|
|
|
|
2014-06-25 17:01:50 +00:00
|
|
|
if( !( ctrack->GetLayerSet() & layerMask ).any() )
|
2013-01-08 17:58:06 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if( ctrack == aTrack )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// We have a good candidate: calculate the actual distance
|
2013-02-07 17:40:50 +00:00
|
|
|
// between ends, which should be <= dist max.
|
2013-01-08 17:58:06 +00:00
|
|
|
wxPoint delta = tracks_candidates[ii]->GetPoint() - position;
|
2014-06-29 21:50:06 +00:00
|
|
|
|
2013-05-01 17:32:36 +00:00
|
|
|
int dist = KiROUND( EuclideanNorm( delta ) );
|
2013-01-08 17:58:06 +00:00
|
|
|
|
|
|
|
if( dist > dist_max )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
m_connected.push_back( ctrack );
|
|
|
|
}
|
|
|
|
#endif
|
2011-10-31 13:44:13 +00:00
|
|
|
|
|
|
|
// Search for connections to ending point:
|
|
|
|
if( aTrack->Type() == PCB_VIA_T )
|
|
|
|
break;
|
|
|
|
|
2013-01-13 00:04:00 +00:00
|
|
|
position = aTrack->GetEnd();
|
2011-10-31 13:44:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2014-06-29 20:33:29 +00:00
|
|
|
|
|
|
|
int CONNECTIONS::searchEntryPointInCandidatesList( const wxPoint& aPoint )
|
2011-10-31 13:44:13 +00:00
|
|
|
{
|
|
|
|
// Search the aPoint coordinates in m_Candidates
|
|
|
|
// m_Candidates is sorted by X then Y values, and a fast binary search is used
|
2011-12-04 17:57:03 +00:00
|
|
|
int idxmax = m_candidates.size()-1;
|
2011-10-31 13:44:13 +00:00
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
int delta = m_candidates.size();
|
2011-12-28 15:14:46 +00:00
|
|
|
|
|
|
|
int idx = 0; // Starting index is the beginning of list
|
2014-06-29 20:33:29 +00:00
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
while( delta )
|
|
|
|
{
|
2011-12-28 15:14:46 +00:00
|
|
|
// Calculate half size of remaining interval to test.
|
|
|
|
// Ensure the computed value is not truncated (too small)
|
2014-06-29 20:33:29 +00:00
|
|
|
if( ( delta & 1 ) && ( delta > 1 ) )
|
2011-10-31 13:44:13 +00:00
|
|
|
delta++;
|
2014-06-29 20:33:29 +00:00
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
delta /= 2;
|
|
|
|
|
2014-06-29 20:33:29 +00:00
|
|
|
CONNECTED_POINT& candidate = m_candidates[idx];
|
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
if( candidate.GetPoint() == aPoint ) // candidate found
|
2011-10-31 13:44:13 +00:00
|
|
|
{
|
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not found: test the middle of the remaining sub list
|
2011-12-04 17:57:03 +00:00
|
|
|
if( candidate.GetPoint().x == aPoint.x ) // Must search considering Y coordinate
|
2011-10-31 13:44:13 +00:00
|
|
|
{
|
2011-12-04 17:57:03 +00:00
|
|
|
if(candidate.GetPoint().y < aPoint.y) // Must search after this item
|
2011-10-31 13:44:13 +00:00
|
|
|
{
|
|
|
|
idx += delta;
|
|
|
|
if( idx > idxmax )
|
|
|
|
idx = idxmax;
|
|
|
|
}
|
|
|
|
else // Must search before this item
|
|
|
|
{
|
|
|
|
idx -= delta;
|
|
|
|
if( idx < 0 )
|
|
|
|
idx = 0;
|
|
|
|
}
|
|
|
|
}
|
2011-12-04 17:57:03 +00:00
|
|
|
else if( candidate.GetPoint().x < aPoint.x ) // Must search after this item
|
2011-10-31 13:44:13 +00:00
|
|
|
{
|
|
|
|
idx += delta;
|
|
|
|
if( idx > idxmax )
|
|
|
|
idx = idxmax;
|
|
|
|
}
|
|
|
|
else // Must search before this item
|
|
|
|
{
|
|
|
|
idx -= delta;
|
|
|
|
if( idx < 0 )
|
|
|
|
idx = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
/* Used after a track change (delete a track ou add a track)
|
2011-12-17 21:21:03 +00:00
|
|
|
* Connections to pads are recalculated
|
2011-12-19 11:58:24 +00:00
|
|
|
* Note also aFirstTrack (and aLastTrack ) can be NULL
|
2011-11-03 19:07:59 +00:00
|
|
|
*/
|
2011-12-14 11:31:49 +00:00
|
|
|
void CONNECTIONS::Build_CurrNet_SubNets_Connections( TRACK* aFirstTrack, TRACK* aLastTrack, int aNetcode )
|
2011-11-03 19:07:59 +00:00
|
|
|
{
|
|
|
|
m_firstTrack = aFirstTrack; // The first track used to build m_Candidates
|
|
|
|
m_lastTrack = aLastTrack; // The last track used to build m_Candidates
|
|
|
|
|
|
|
|
// Pads subnets are expected already cleared, because this function
|
|
|
|
// does not know the full list of pads
|
2011-12-13 20:28:25 +00:00
|
|
|
BuildTracksCandidatesList( aFirstTrack, aLastTrack );
|
2011-12-17 21:21:03 +00:00
|
|
|
TRACK* curr_track;
|
2011-11-03 19:07:59 +00:00
|
|
|
for( curr_track = aFirstTrack; curr_track != NULL; curr_track = curr_track->Next() )
|
|
|
|
{
|
|
|
|
// Clear track subnet id (Pads subnets are cleared outside this function)
|
|
|
|
curr_track->SetSubNet( 0 );
|
|
|
|
curr_track->m_TracksConnected.clear();
|
2011-12-17 21:21:03 +00:00
|
|
|
curr_track->m_PadsConnected.clear();
|
2011-11-03 19:07:59 +00:00
|
|
|
|
|
|
|
// Update connections between tracks:
|
|
|
|
SearchConnectedTracks( curr_track );
|
2011-12-04 17:57:03 +00:00
|
|
|
curr_track->m_TracksConnected = m_connected;
|
2011-11-03 19:07:59 +00:00
|
|
|
|
|
|
|
if( curr_track == aLastTrack )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-12-14 11:31:49 +00:00
|
|
|
// Update connections between tracks and pads
|
|
|
|
BuildPadsList( aNetcode );
|
|
|
|
SearchTracksConnectedToPads();
|
2011-11-03 19:07:59 +00:00
|
|
|
|
2011-12-19 11:58:24 +00:00
|
|
|
// Update connections between intersecting pads (no tracks)
|
|
|
|
SearchConnectionsPadsToIntersectingPads();
|
|
|
|
|
2011-12-14 11:31:49 +00:00
|
|
|
// Creates sub nets (clusters) for the current net:
|
2011-11-03 19:07:59 +00:00
|
|
|
Propagate_SubNets();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-17 21:21:03 +00:00
|
|
|
/**
|
|
|
|
* Change a subnet value to a new value, in m_sortedPads pad list
|
|
|
|
* After that, 2 cluster (or subnets) are merged into only one.
|
|
|
|
* Note: the resulting subnet value is the smallest between aOldSubNet et aNewSubNet
|
|
|
|
*/
|
|
|
|
int CONNECTIONS::Merge_PadsSubNets( int aOldSubNet, int aNewSubNet )
|
|
|
|
{
|
|
|
|
int change_count = 0;
|
|
|
|
|
|
|
|
if( aOldSubNet == aNewSubNet )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if( (aOldSubNet > 0) && (aOldSubNet < aNewSubNet) )
|
2015-06-26 13:41:56 +00:00
|
|
|
std::swap( aOldSubNet, aNewSubNet );
|
2011-12-17 21:21:03 +00:00
|
|
|
|
|
|
|
// Examine connections between intersecting pads
|
|
|
|
for( unsigned ii = 0; ii < m_sortedPads.size(); ii++ )
|
|
|
|
{
|
|
|
|
D_PAD * curr_pad = m_sortedPads[ii];
|
|
|
|
if( curr_pad->GetSubNet() != aOldSubNet )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
change_count++;
|
|
|
|
curr_pad->SetSubNet( aNewSubNet );
|
|
|
|
}
|
|
|
|
|
|
|
|
return change_count;
|
|
|
|
}
|
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
/*
|
|
|
|
* Change a subnet value to a new value, for tracks and pads which are connected to.
|
|
|
|
* The result is merging 2 clusters (or subnets) into only one cluster.
|
2013-02-07 17:40:50 +00:00
|
|
|
* Note: the resulting sub net value is the smallest between aOldSubNet et aNewSubNet
|
2007-08-23 04:28:46 +00:00
|
|
|
*/
|
2011-11-03 19:07:59 +00:00
|
|
|
int CONNECTIONS::Merge_SubNets( int aOldSubNet, int aNewSubNet )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2011-11-03 19:07:59 +00:00
|
|
|
TRACK* curr_track;
|
|
|
|
int change_count = 0;
|
2007-08-23 04:28:46 +00:00
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
if( aOldSubNet == aNewSubNet )
|
2007-08-23 04:28:46 +00:00
|
|
|
return 0;
|
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
if( (aOldSubNet > 0) && (aOldSubNet < aNewSubNet) )
|
2015-06-26 13:41:56 +00:00
|
|
|
std::swap( aOldSubNet, aNewSubNet );
|
2007-08-23 04:28:46 +00:00
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
curr_track = (TRACK*)m_firstTrack;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
for( ; curr_track != NULL; curr_track = curr_track->Next() )
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2011-11-03 19:07:59 +00:00
|
|
|
if( curr_track->GetSubNet() != aOldSubNet )
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2011-11-03 19:07:59 +00:00
|
|
|
if( curr_track == m_lastTrack )
|
2007-08-23 04:28:46 +00:00
|
|
|
break;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2007-08-23 04:28:46 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
change_count++;
|
|
|
|
curr_track->SetSubNet( aNewSubNet );
|
2007-08-23 04:28:46 +00:00
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
for( unsigned ii = 0; ii < curr_track->m_PadsConnected.size(); ii++ )
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2011-12-04 17:57:03 +00:00
|
|
|
D_PAD * pad = curr_track->m_PadsConnected[ii];
|
|
|
|
if( pad->GetSubNet() == aOldSubNet )
|
2013-02-07 17:40:50 +00:00
|
|
|
{
|
2011-12-04 17:57:03 +00:00
|
|
|
pad->SetSubNet( curr_track->GetSubNet() );
|
2013-02-07 17:40:50 +00:00
|
|
|
}
|
2007-08-23 04:28:46 +00:00
|
|
|
}
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
if( curr_track == m_lastTrack )
|
2007-08-23 04:28:46 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
return change_count;
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
2007-08-23 04:28:46 +00:00
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
/* Test a list of track segments, to create or propagate a sub netcode to pads and
|
|
|
|
* segments connected together.
|
|
|
|
* The track list must be sorted by nets, and all segments
|
|
|
|
* from m_firstTrack to m_lastTrack have the same net
|
|
|
|
* When 2 items are connected (a track to a pad, or a track to an other track),
|
|
|
|
* they are grouped in a cluster.
|
2013-02-07 17:40:50 +00:00
|
|
|
* The .m_Subnet member is the cluster identifier (subnet id)
|
2007-11-27 17:42:15 +00:00
|
|
|
* For a given net, if all tracks are created, there is only one cluster.
|
2011-11-03 19:07:59 +00:00
|
|
|
* but if not all tracks are created, there are more than one cluster,
|
|
|
|
* and some ratsnests will be left active.
|
2013-02-07 17:40:50 +00:00
|
|
|
* A ratsnest is active when it "connect" 2 items having different subnet id
|
2007-08-23 04:28:46 +00:00
|
|
|
*/
|
2011-11-03 19:07:59 +00:00
|
|
|
void CONNECTIONS::Propagate_SubNets()
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2013-02-07 17:40:50 +00:00
|
|
|
int sub_netcode = 1;
|
2007-08-23 04:28:46 +00:00
|
|
|
|
2011-12-19 11:58:24 +00:00
|
|
|
TRACK* curr_track = (TRACK*)m_firstTrack;
|
|
|
|
if( curr_track )
|
|
|
|
curr_track->SetSubNet( sub_netcode );
|
|
|
|
|
2013-02-06 11:54:51 +00:00
|
|
|
// Examine connections between tracks and pads
|
2011-11-03 19:07:59 +00:00
|
|
|
for( ; curr_track != NULL; curr_track = curr_track->Next() )
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2012-02-19 04:02:19 +00:00
|
|
|
// First: handling connections to pads
|
2011-12-04 17:57:03 +00:00
|
|
|
for( unsigned ii = 0; ii < curr_track->m_PadsConnected.size(); ii++ )
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2011-12-04 17:57:03 +00:00
|
|
|
D_PAD * pad = curr_track->m_PadsConnected[ii];
|
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
if( curr_track->GetSubNet() ) // the track segment is already a cluster member
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2011-12-04 17:57:03 +00:00
|
|
|
if( pad->GetSubNet() > 0 )
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2012-02-19 04:02:19 +00:00
|
|
|
// The pad is already a cluster member, so we can merge the 2 clusters
|
2011-12-04 17:57:03 +00:00
|
|
|
Merge_SubNets( pad->GetSubNet(), curr_track->GetSubNet() );
|
2007-08-23 04:28:46 +00:00
|
|
|
}
|
2011-12-04 17:57:03 +00:00
|
|
|
else
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2011-12-04 17:57:03 +00:00
|
|
|
/* The pad is not yet attached to a cluster , so we can add this pad to
|
|
|
|
* the cluster */
|
|
|
|
pad->SetSubNet( curr_track->GetSubNet() );
|
|
|
|
}
|
|
|
|
}
|
2012-02-19 04:02:19 +00:00
|
|
|
else // the track segment is not attached to a cluster
|
2011-12-04 17:57:03 +00:00
|
|
|
{
|
|
|
|
if( pad->GetSubNet() > 0 )
|
|
|
|
{
|
2012-02-19 04:02:19 +00:00
|
|
|
// it is connected to a pad in a cluster, merge this track
|
2011-12-04 17:57:03 +00:00
|
|
|
curr_track->SetSubNet( pad->GetSubNet() );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* it is connected to a pad not in a cluster, so we must create a new
|
|
|
|
* cluster (only with the 2 items: the track and the pad) */
|
|
|
|
sub_netcode++;
|
|
|
|
curr_track->SetSubNet( sub_netcode );
|
|
|
|
pad->SetSubNet( curr_track->GetSubNet() );
|
2007-08-23 04:28:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
// Test connections between segments
|
2011-11-03 19:07:59 +00:00
|
|
|
for( unsigned ii = 0; ii < curr_track->m_TracksConnected.size(); ii++ )
|
2007-10-17 14:35:59 +00:00
|
|
|
{
|
2011-11-03 19:07:59 +00:00
|
|
|
BOARD_CONNECTED_ITEM* track = curr_track->m_TracksConnected[ii];
|
2014-06-29 20:33:29 +00:00
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
if( curr_track->GetSubNet() ) // The current track is already a cluster member
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2012-02-19 04:02:19 +00:00
|
|
|
// The other track is already a cluster member, so we can merge the 2 clusters
|
2011-11-03 19:07:59 +00:00
|
|
|
if( track->GetSubNet() )
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2011-11-03 19:07:59 +00:00
|
|
|
Merge_SubNets( track->GetSubNet(), curr_track->GetSubNet() );
|
2007-08-23 04:28:46 +00:00
|
|
|
}
|
2011-09-15 17:58:35 +00:00
|
|
|
else
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2014-06-29 20:33:29 +00:00
|
|
|
// The other track is not yet attached to a cluster , so we can add this
|
|
|
|
// other track to the cluster
|
2011-11-03 19:07:59 +00:00
|
|
|
track->SetSubNet( curr_track->GetSubNet() );
|
2007-08-23 04:28:46 +00:00
|
|
|
}
|
|
|
|
}
|
2011-11-03 19:07:59 +00:00
|
|
|
else // the current track segment is not yet attached to a cluster
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2011-11-03 19:07:59 +00:00
|
|
|
if( track->GetSubNet() )
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2011-11-03 19:07:59 +00:00
|
|
|
// The other track is already a cluster member, so we can add
|
|
|
|
// the current segment to the cluster
|
|
|
|
curr_track->SetSubNet( track->GetSubNet() );
|
2007-08-23 04:28:46 +00:00
|
|
|
}
|
2011-09-15 17:58:35 +00:00
|
|
|
else
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2014-06-29 20:33:29 +00:00
|
|
|
// it is connected to an other segment not in a cluster, so we must
|
|
|
|
// create a new cluster (only with the 2 track segments)
|
2008-11-18 18:13:55 +00:00
|
|
|
sub_netcode++;
|
2011-11-03 19:07:59 +00:00
|
|
|
curr_track->SetSubNet( sub_netcode );
|
|
|
|
track->SetSubNet( curr_track->GetSubNet() );
|
2007-08-23 04:28:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
if( curr_track == m_lastTrack )
|
2007-08-23 04:28:46 +00:00
|
|
|
break;
|
|
|
|
}
|
2013-02-07 17:40:50 +00:00
|
|
|
|
|
|
|
// Examine connections between intersecting pads, and propagate
|
|
|
|
// sub_netcodes to intersecting pads
|
|
|
|
for( unsigned ii = 0; ii < m_sortedPads.size(); ii++ )
|
|
|
|
{
|
2014-06-29 20:33:29 +00:00
|
|
|
D_PAD* curr_pad = m_sortedPads[ii];
|
|
|
|
|
2013-02-07 17:40:50 +00:00
|
|
|
for( unsigned jj = 0; jj < curr_pad->m_PadsConnected.size(); jj++ )
|
|
|
|
{
|
2014-06-29 20:33:29 +00:00
|
|
|
D_PAD* pad = curr_pad->m_PadsConnected[jj];
|
|
|
|
|
2013-02-07 17:40:50 +00:00
|
|
|
if( curr_pad->GetSubNet() ) // the current pad is already attached to a cluster
|
|
|
|
{
|
|
|
|
if( pad->GetSubNet() > 0 )
|
|
|
|
{
|
|
|
|
// The pad is already a cluster member, so we can merge the 2 clusters
|
|
|
|
// Store the initial subnets, which will be modified by Merge_PadsSubNets
|
|
|
|
int subnet1 = pad->GetSubNet();
|
|
|
|
int subnet2 = curr_pad->GetSubNet();
|
2014-06-29 20:33:29 +00:00
|
|
|
|
2013-02-07 17:40:50 +00:00
|
|
|
// merge subnets of pads only, even those not connected by tracks
|
|
|
|
Merge_PadsSubNets( subnet1, subnet2 );
|
2014-06-29 20:33:29 +00:00
|
|
|
|
2013-02-07 17:40:50 +00:00
|
|
|
// merge subnets of tracks (and pads, which are already merged)
|
|
|
|
Merge_SubNets( subnet1, subnet2 );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// The pad is not yet attached to a cluster,
|
|
|
|
// so we can add this pad to the cluster
|
|
|
|
pad->SetSubNet( curr_pad->GetSubNet() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else // the current pad is not attached to a cluster
|
|
|
|
{
|
|
|
|
if( pad->GetSubNet() > 0 )
|
|
|
|
{
|
|
|
|
// the connected pad is in a cluster,
|
|
|
|
// so we can add the current pad to the cluster
|
|
|
|
curr_pad->SetSubNet( pad->GetSubNet() );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// the connected pad is not in a cluster,
|
|
|
|
// so we must create a new cluster, with the 2 pads.
|
|
|
|
sub_netcode++;
|
|
|
|
curr_pad->SetSubNet( sub_netcode );
|
|
|
|
pad->SetSubNet( curr_pad->GetSubNet() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
2011-12-19 11:58:24 +00:00
|
|
|
/*
|
|
|
|
* Test all connections of the board,
|
|
|
|
* and update subnet variable of pads and tracks
|
|
|
|
* TestForActiveLinksInRatsnest must be called after this function
|
|
|
|
* to update active/inactive ratsnest items status
|
|
|
|
*/
|
2011-11-10 08:21:11 +00:00
|
|
|
void PCB_BASE_FRAME::TestConnections()
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2008-12-04 04:28:11 +00:00
|
|
|
// Clear the cluster identifier for all pads
|
2011-12-10 05:33:24 +00:00
|
|
|
for( unsigned i = 0; i< m_Pcb->GetPadCount(); ++i )
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2011-12-10 05:33:24 +00:00
|
|
|
D_PAD* pad = m_Pcb->GetPad(i);
|
2008-12-04 04:28:11 +00:00
|
|
|
|
|
|
|
pad->SetZoneSubNet( 0 );
|
|
|
|
pad->SetSubNet( 0 );
|
2007-08-23 04:28:46 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
m_Pcb->Test_Connections_To_Copper_Areas();
|
2008-11-18 18:13:55 +00:00
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
// Test existing connections net by net
|
2011-12-19 11:58:24 +00:00
|
|
|
// note some nets can have no tracks, and pads intersecting
|
|
|
|
// so Build_CurrNet_SubNets_Connections must be called for each net
|
2011-11-03 19:07:59 +00:00
|
|
|
CONNECTIONS connections( m_Pcb );
|
2014-06-29 20:33:29 +00:00
|
|
|
|
2011-12-19 11:58:24 +00:00
|
|
|
int last_net_tested = 0;
|
|
|
|
int current_net_code = 0;
|
2014-06-29 20:33:29 +00:00
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
for( TRACK* track = m_Pcb->m_Track; track; )
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2011-11-03 19:07:59 +00:00
|
|
|
// At this point, track is the first track of a given net
|
2014-02-25 10:40:34 +00:00
|
|
|
current_net_code = track->GetNetCode();
|
2014-06-29 20:33:29 +00:00
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
// Get last track of the current net
|
|
|
|
TRACK* lastTrack = track->GetEndNetCode( current_net_code );
|
2007-08-23 04:28:46 +00:00
|
|
|
|
2011-12-17 21:21:03 +00:00
|
|
|
if( current_net_code > 0 ) // do not spend time if net code = 0 ( dummy net )
|
2011-12-19 11:58:24 +00:00
|
|
|
{
|
|
|
|
// Test all previous nets having no tracks
|
|
|
|
for( int net = last_net_tested+1; net < current_net_code; net++ )
|
|
|
|
connections.Build_CurrNet_SubNets_Connections( NULL, NULL, net );
|
|
|
|
|
2011-12-14 11:31:49 +00:00
|
|
|
connections.Build_CurrNet_SubNets_Connections( track, lastTrack, current_net_code );
|
2011-12-19 11:58:24 +00:00
|
|
|
last_net_tested = current_net_code;
|
|
|
|
}
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
track = lastTrack->Next(); // this is now the first track of the next net
|
2007-08-23 04:28:46 +00:00
|
|
|
}
|
|
|
|
|
2011-12-19 11:58:24 +00:00
|
|
|
// Test last nets without tracks, if any
|
|
|
|
int netsCount = m_Pcb->GetNetCount();
|
|
|
|
for( int net = last_net_tested+1; net < netsCount; net++ )
|
|
|
|
connections.Build_CurrNet_SubNets_Connections( NULL, NULL, net );
|
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
Merge_SubNets_Connected_By_CopperAreas( m_Pcb );
|
2008-11-18 18:13:55 +00:00
|
|
|
|
2007-08-23 04:28:46 +00:00
|
|
|
return;
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
2007-08-23 04:28:46 +00:00
|
|
|
|
2011-09-15 17:58:35 +00:00
|
|
|
void PCB_BASE_FRAME::TestNetConnection( wxDC* aDC, int aNetCode )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2015-02-20 19:04:32 +00:00
|
|
|
// Skip dummy net -1, and "not connected" net 0 (grouping all not connected pads)
|
|
|
|
if( aNetCode <= 0 )
|
2007-08-23 04:28:46 +00:00
|
|
|
return;
|
|
|
|
|
2009-05-24 18:28:36 +00:00
|
|
|
if( (m_Pcb->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK) == 0 )
|
2011-09-15 17:58:35 +00:00
|
|
|
Compile_Ratsnest( aDC, true );
|
2007-08-23 04:28:46 +00:00
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
// Clear the cluster identifier (subnet) of pads for this net
|
2015-02-20 19:04:32 +00:00
|
|
|
// Pads are grouped by netcode (and in netname alphabetic order)
|
2011-12-10 05:33:24 +00:00
|
|
|
for( unsigned i = 0; i < m_Pcb->GetPadCount(); ++i )
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2011-12-10 05:33:24 +00:00
|
|
|
D_PAD* pad = m_Pcb->GetPad(i);
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2015-02-20 19:04:32 +00:00
|
|
|
if( m_Pcb->GetPad(i)->GetNetCode() == aNetCode )
|
|
|
|
pad->SetSubNet( 0 );
|
2007-08-23 04:28:46 +00:00
|
|
|
}
|
|
|
|
|
2011-09-15 17:58:35 +00:00
|
|
|
m_Pcb->Test_Connections_To_Copper_Areas( aNetCode );
|
2008-11-18 18:13:55 +00:00
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
// Search for the first and the last segment relative to the given net code
|
2007-08-23 04:28:46 +00:00
|
|
|
if( m_Pcb->m_Track )
|
|
|
|
{
|
2011-11-03 19:07:59 +00:00
|
|
|
CONNECTIONS connections( m_Pcb );
|
2014-06-29 20:33:29 +00:00
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
TRACK* lastTrack = NULL;
|
2015-02-20 19:04:32 +00:00
|
|
|
TRACK* firstTrack = m_Pcb->m_Track.GetFirst()->GetStartNetCode( aNetCode );
|
2007-08-23 04:28:46 +00:00
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
if( firstTrack )
|
|
|
|
lastTrack = firstTrack->GetEndNetCode( aNetCode );
|
2007-08-23 04:28:46 +00:00
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
if( firstTrack && lastTrack ) // i.e. if there are segments
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2015-02-20 19:04:32 +00:00
|
|
|
connections.Build_CurrNet_SubNets_Connections( firstTrack, lastTrack, aNetCode );
|
2007-08-23 04:28:46 +00:00
|
|
|
}
|
|
|
|
}
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2011-09-15 17:58:35 +00:00
|
|
|
Merge_SubNets_Connected_By_CopperAreas( m_Pcb, aNetCode );
|
2007-08-23 04:28:46 +00:00
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
// rebuild the active ratsnest for this net
|
2011-11-11 07:00:51 +00:00
|
|
|
DrawGeneralRatsnest( aDC, aNetCode );
|
|
|
|
TestForActiveLinksInRatsnest( aNetCode );
|
|
|
|
DrawGeneralRatsnest( aDC, aNetCode );
|
2007-08-23 04:28:46 +00:00
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
// Display results
|
2015-02-20 19:04:32 +00:00
|
|
|
wxString msg;
|
2011-11-11 07:00:51 +00:00
|
|
|
int net_notconnected_count = 0;
|
|
|
|
NETINFO_ITEM* net = m_Pcb->FindNet( aNetCode );
|
2013-01-09 18:52:44 +00:00
|
|
|
|
2012-01-19 18:12:30 +00:00
|
|
|
if( net ) // Should not occur, but ...
|
2011-11-11 07:00:51 +00:00
|
|
|
{
|
2012-01-19 18:12:30 +00:00
|
|
|
for( unsigned ii = net->m_RatsnestStartIdx; ii < net->m_RatsnestEndIdx; ii++ )
|
|
|
|
{
|
|
|
|
if( m_Pcb->m_FullRatsnest[ii].IsActive() )
|
|
|
|
net_notconnected_count++;
|
|
|
|
}
|
2013-01-09 18:52:44 +00:00
|
|
|
|
2015-02-20 19:04:32 +00:00
|
|
|
msg.Printf( wxT( "links %d nc %d net %d: not conn %d" ),
|
|
|
|
m_Pcb->GetRatsnestsCount(), m_Pcb->GetUnconnectedNetCount(), aNetCode,
|
2012-01-19 18:12:30 +00:00
|
|
|
net_notconnected_count );
|
2011-11-11 07:00:51 +00:00
|
|
|
}
|
2012-01-19 18:12:30 +00:00
|
|
|
else
|
2015-02-20 19:04:32 +00:00
|
|
|
msg.Printf( wxT( "net not found: netcode %d" ), aNetCode );
|
2007-08-23 04:28:46 +00:00
|
|
|
|
2011-02-11 20:48:13 +00:00
|
|
|
SetStatusText( msg );
|
2015-02-20 19:04:32 +00:00
|
|
|
|
2007-08-23 04:28:46 +00:00
|
|
|
return;
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
/* search connections between tracks and pads and propagate pad net codes to the track
|
|
|
|
* segments.
|
|
|
|
* Pads netcodes are assumed to be up to date.
|
2007-08-23 04:28:46 +00:00
|
|
|
*/
|
2011-09-07 19:41:04 +00:00
|
|
|
void PCB_BASE_FRAME::RecalculateAllTracksNetcode()
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2009-05-24 18:28:36 +00:00
|
|
|
// Build the net info list
|
2011-12-10 05:33:24 +00:00
|
|
|
GetBoard()->BuildListOfNets();
|
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
// Reset variables and flags used in computation
|
2014-06-30 04:40:16 +00:00
|
|
|
for( TRACK* t = m_Pcb->m_Track; t; t = t->Next() )
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2014-06-30 04:40:16 +00:00
|
|
|
t->m_TracksConnected.clear();
|
|
|
|
t->m_PadsConnected.clear();
|
|
|
|
t->start = NULL;
|
|
|
|
t->end = NULL;
|
|
|
|
t->SetState( BUSY | IN_EDIT | BEGIN_ONPAD | END_ONPAD, false );
|
|
|
|
t->SetZoneSubNet( 0 );
|
|
|
|
t->SetNetCode( NETINFO_LIST::UNCONNECTED );
|
2007-08-23 04:28:46 +00:00
|
|
|
}
|
|
|
|
|
2011-11-15 19:21:16 +00:00
|
|
|
// If no pad, reset pointers and netcode, and do nothing else
|
2011-12-10 05:33:24 +00:00
|
|
|
if( m_Pcb->GetPadCount() == 0 )
|
2011-11-15 19:21:16 +00:00
|
|
|
return;
|
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
CONNECTIONS connections( m_Pcb );
|
|
|
|
connections.BuildPadsList();
|
2011-12-19 11:58:24 +00:00
|
|
|
connections.BuildTracksCandidatesList(m_Pcb->m_Track);
|
2011-12-04 17:57:03 +00:00
|
|
|
|
|
|
|
// First pass: build connections between track segments and pads.
|
2011-12-13 20:28:25 +00:00
|
|
|
connections.SearchTracksConnectedToPads();
|
2011-11-15 19:21:16 +00:00
|
|
|
|
2014-06-30 04:40:16 +00:00
|
|
|
// For tracks connected to at least one pad,
|
|
|
|
// set the track net code to the pad netcode
|
|
|
|
for( TRACK* t = m_Pcb->m_Track; t; t = t->Next() )
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2014-06-30 04:40:16 +00:00
|
|
|
if( t->m_PadsConnected.size() )
|
|
|
|
t->SetNetCode( t->m_PadsConnected[0]->GetNetCode() );
|
2007-08-23 04:28:46 +00:00
|
|
|
}
|
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
// Pass 2: build connections between track ends
|
2014-06-30 04:40:16 +00:00
|
|
|
for( TRACK* t = m_Pcb->m_Track; t; t = t->Next() )
|
2011-09-22 19:16:55 +00:00
|
|
|
{
|
2014-06-30 04:40:16 +00:00
|
|
|
connections.SearchConnectedTracks( t );
|
|
|
|
connections.GetConnectedTracks( t );
|
2011-10-31 13:44:13 +00:00
|
|
|
}
|
|
|
|
|
2011-10-31 20:29:46 +00:00
|
|
|
// Propagate net codes from a segment to other connected segments
|
2011-12-04 17:57:03 +00:00
|
|
|
bool new_pass_request = true; // set to true if a track has its netcode changed from 0
|
2011-10-31 20:29:46 +00:00
|
|
|
// to a known netcode to re-evaluate netcodes
|
|
|
|
// of connected items
|
|
|
|
while( new_pass_request )
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2011-10-31 20:29:46 +00:00
|
|
|
new_pass_request = false;
|
2007-08-23 04:28:46 +00:00
|
|
|
|
2014-06-30 04:40:16 +00:00
|
|
|
for( TRACK* t = m_Pcb->m_Track; t; t = t->Next() )
|
2011-09-15 17:58:35 +00:00
|
|
|
{
|
2014-06-30 04:40:16 +00:00
|
|
|
int netcode = t->GetNetCode();
|
2014-06-29 20:33:29 +00:00
|
|
|
|
2011-10-31 20:29:46 +00:00
|
|
|
if( netcode == 0 )
|
2014-06-29 20:33:29 +00:00
|
|
|
{
|
|
|
|
// try to find a connected item having a netcode
|
2014-06-30 04:40:16 +00:00
|
|
|
for( unsigned kk = 0; kk < t->m_TracksConnected.size(); kk++ )
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2014-06-30 04:40:16 +00:00
|
|
|
int altnetcode = t->m_TracksConnected[kk]->GetNetCode();
|
2011-10-31 20:29:46 +00:00
|
|
|
if( altnetcode )
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2011-10-31 20:29:46 +00:00
|
|
|
new_pass_request = true;
|
|
|
|
netcode = altnetcode;
|
2014-06-30 04:40:16 +00:00
|
|
|
t->SetNetCode(netcode);
|
2011-10-31 20:29:46 +00:00
|
|
|
break;
|
2007-08-23 04:28:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-06-29 20:33:29 +00:00
|
|
|
|
2011-10-31 20:29:46 +00:00
|
|
|
if( netcode ) // this track has a netcode
|
2014-06-29 20:33:29 +00:00
|
|
|
{
|
|
|
|
// propagate this netcode to connected tracks having no netcode
|
2014-06-30 04:40:16 +00:00
|
|
|
for( unsigned kk = 0; kk < t->m_TracksConnected.size(); kk++ )
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2014-06-30 04:40:16 +00:00
|
|
|
int altnetcode = t->m_TracksConnected[kk]->GetNetCode();
|
2011-10-31 20:29:46 +00:00
|
|
|
if( altnetcode == 0 )
|
2007-08-23 04:28:46 +00:00
|
|
|
{
|
2014-06-30 04:40:16 +00:00
|
|
|
t->m_TracksConnected[kk]->SetNetCode(netcode);
|
2011-10-31 20:29:46 +00:00
|
|
|
new_pass_request = true;
|
2007-08-23 04:28:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
// Sort the track list by net codes:
|
2007-08-23 04:28:46 +00:00
|
|
|
RebuildTrackChain( m_Pcb );
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
2007-08-23 04:28:46 +00:00
|
|
|
|
2011-10-31 20:29:46 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Function SortTracksByNetCode used in RebuildTrackChain()
|
|
|
|
* to sort track segments by net code.
|
2007-08-23 04:28:46 +00:00
|
|
|
*/
|
2011-10-31 20:29:46 +00:00
|
|
|
static bool SortTracksByNetCode( const TRACK* const & ref, const TRACK* const & compare )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2012-06-11 12:04:34 +00:00
|
|
|
// For items having the same Net, keep the order in list
|
2014-02-25 10:40:34 +00:00
|
|
|
if( ref->GetNetCode() == compare->GetNetCode())
|
2012-06-11 12:04:34 +00:00
|
|
|
return ref->m_Param < compare->m_Param;
|
|
|
|
|
2014-02-25 10:40:34 +00:00
|
|
|
return ref->GetNetCode() < compare->GetNetCode();
|
2007-08-23 04:28:46 +00:00
|
|
|
}
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
/**
|
2011-12-04 17:57:03 +00:00
|
|
|
* Helper function RebuildTrackChain
|
2008-12-04 04:28:11 +00:00
|
|
|
* rebuilds the track segment linked list in order to have a chain
|
|
|
|
* sorted by increasing netcodes.
|
2012-06-11 12:04:34 +00:00
|
|
|
* We try to keep order of track segments in list, when possible
|
2007-11-27 17:42:15 +00:00
|
|
|
* @param pcb = board to rebuild
|
2007-08-23 04:28:46 +00:00
|
|
|
*/
|
2008-12-04 04:28:11 +00:00
|
|
|
static void RebuildTrackChain( BOARD* pcb )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2007-08-23 04:28:46 +00:00
|
|
|
if( pcb->m_Track == NULL )
|
|
|
|
return;
|
|
|
|
|
2011-10-31 20:29:46 +00:00
|
|
|
int item_count = pcb->m_Track.GetCount();
|
2007-08-23 04:28:46 +00:00
|
|
|
|
2011-10-31 20:29:46 +00:00
|
|
|
std::vector<TRACK*> trackList;
|
|
|
|
trackList.reserve( item_count );
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2012-06-11 12:04:34 +00:00
|
|
|
// Put track list in a temporary list to sort tracks by netcode
|
|
|
|
// We try to keep the initial order of track segments in list, when possible
|
|
|
|
// so we use m_Param (a member variable used for temporary storage)
|
|
|
|
// to temporary keep trace of the order of segments
|
|
|
|
// The sort function uses this variable to sort items that
|
|
|
|
// have the same net code.
|
|
|
|
// Without this, during sorting, the initial order is sometimes lost
|
|
|
|
// by the sort algorithm
|
|
|
|
for( int ii = 0; ii < item_count; ++ii )
|
|
|
|
{
|
|
|
|
pcb->m_Track->m_Param = ii;
|
2011-10-31 20:29:46 +00:00
|
|
|
trackList.push_back( pcb->m_Track.PopFront() );
|
2012-06-11 12:04:34 +00:00
|
|
|
}
|
2007-08-23 04:28:46 +00:00
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
// the list is empty now
|
|
|
|
wxASSERT( pcb->m_Track == NULL && pcb->m_Track.GetCount()==0 );
|
2007-08-23 04:28:46 +00:00
|
|
|
|
2011-10-31 20:29:46 +00:00
|
|
|
sort( trackList.begin(), trackList.end(), SortTracksByNetCode );
|
2008-11-24 06:53:43 +00:00
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
// add them back to the list
|
2011-10-31 20:29:46 +00:00
|
|
|
for( int i = 0; i < item_count; ++i )
|
|
|
|
pcb->m_Track.PushBack( trackList[i] );
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|