You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1107 lines
38 KiB

14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
  1. /**
  2. * @file connect.cpp
  3. * @brief Functions to handle existing tracks in ratsnest calculations.
  4. */
  5. /*
  6. * This program source code file is part of KiCad, a free EDA CAD application.
  7. *
  8. * Copyright (C) 2011 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.com
  9. * Copyright (C) 2004-2011 KiCad Developers, see change_log.txt for contributors.
  10. *
  11. * This program is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU General Public License
  13. * as published by the Free Software Foundation; either version 2
  14. * of the License, or (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, you may find one here:
  23. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  24. * or you may search the http://www.gnu.org website for the version 2 license,
  25. * or you may write to the Free Software Foundation, Inc.,
  26. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  27. */
  28. #include <fctsys.h>
  29. #include <common.h>
  30. #include <pcbcommon.h>
  31. #include <macros.h>
  32. #include <wxBasePcbFrame.h>
  33. #include <class_track.h>
  34. #include <class_board.h>
  35. #include <pcbnew.h>
  36. extern void Merge_SubNets_Connected_By_CopperAreas( BOARD* aPcb );
  37. extern void Merge_SubNets_Connected_By_CopperAreas( BOARD* aPcb, int aNetcode );
  38. // Local functions
  39. static void RebuildTrackChain( BOARD* pcb );
  40. // A helper class to handle connection points (i.e. candidates) for tracks
  41. class CONNECTED_POINT
  42. {
  43. private:
  44. BOARD_CONNECTED_ITEM * m_item; // a link to the parent item (track, via or pad)
  45. wxPoint m_point; // the connection point
  46. public:
  47. CONNECTED_POINT( TRACK * aTrack, const wxPoint & aPoint)
  48. {
  49. m_item = aTrack;
  50. m_point = aPoint;
  51. }
  52. CONNECTED_POINT( D_PAD * aPad, const wxPoint & aPoint)
  53. {
  54. m_item = aPad;
  55. m_point = aPoint;
  56. }
  57. TRACK * GetTrack() const
  58. {
  59. return m_item->Type() != PCB_PAD_T ? (TRACK*) m_item : NULL ;
  60. }
  61. D_PAD * GetPad() const
  62. {
  63. return m_item->Type() == PCB_PAD_T ? (D_PAD*) m_item : NULL;
  64. }
  65. const wxPoint & GetPoint() const { return m_point; }
  66. };
  67. // A helper class to handle connections calculations:
  68. class CONNECTIONS
  69. {
  70. private:
  71. std::vector <TRACK*> m_connected; // List of connected tracks/vias
  72. // to a given track or via
  73. std::vector <CONNECTED_POINT> m_candidates; // List of points to test
  74. // (end points of tracks or vias location )
  75. BOARD * m_brd; // the master board.
  76. const TRACK * m_firstTrack; // The first track used to build m_Candidates
  77. const TRACK * m_lastTrack; // The last track used to build m_Candidates
  78. std::vector<D_PAD*> m_sortedPads; // list of sorted pads by X (then Y) coordinate
  79. public:
  80. CONNECTIONS( BOARD * aBrd );
  81. ~CONNECTIONS() {};
  82. /** Function BuildPadsList
  83. * Fills m_sortedPads with all pads that be connected to tracks
  84. * pads are sorted by > then Y coordinates to allow fast binary search in list
  85. * @param aNetcode = net code to use to filter pads
  86. * if aNetcode < 0, all pads will be put in list (default)
  87. */
  88. void BuildPadsList( int aNetcode = -1 );
  89. /**
  90. * @return the pads list used in connections calculations
  91. */
  92. std::vector<D_PAD*>& GetPadsList() { return m_sortedPads; }
  93. /**
  94. * Function Build_CurrNet_SubNets_Connections
  95. * should be called after a track change (delete or add a track):
  96. * Connections to pads and to tracks are recalculated
  97. * If a track is deleted, the other pointers to pads do not change.
  98. * When a new track is added in track list, its pointers to pads are already initialized
  99. * Builds the subnets inside a net (tracks from aFirstTrack to aFirstTrack).
  100. * subnets are clusters of pads and tracks that are connected together.
  101. * When all tracks are created relative to the net, there is only a cluster
  102. * when not tracks there are a cluster per pad
  103. * @param aFirstTrack = first track of the given net
  104. * @param aLastTrack = last track of the given net
  105. * @param aNetcode = the netcode of the given net
  106. */
  107. void Build_CurrNet_SubNets_Connections( TRACK* aFirstTrack, TRACK* aLastTrack, int aNetcode );
  108. /**
  109. * Function BuildTracksCandidatesList
  110. * Fills m_Candidates with all connecting points (track ends or via location)
  111. * with tracks from aBegin to aEnd.
  112. * if aEnd == NULL, uses all tracks from aBegin
  113. */
  114. void BuildTracksCandidatesList( TRACK * aBegin, TRACK * aEnd = NULL);
  115. /**
  116. * Function BuildPadsCandidatesList
  117. * Fills m_Candidates with all pads connecting points (pads position)
  118. * m_sortedPads must be built
  119. */
  120. void BuildPadsCandidatesList();
  121. /**
  122. * function SearchConnectedTracks
  123. * Fills m_Connected with tracks/vias connected to aTrack
  124. * @param aTrack = track or via to use as reference
  125. */
  126. int SearchConnectedTracks( const TRACK * aTrack );
  127. /**
  128. * Function GetConnectedTracks
  129. * Copy m_Connected that contains the list of tracks connected
  130. * calculated by SearchConnectedTracks
  131. * in aTrack->m_TracksConnected
  132. * @param aTrack = track or via to fill with connected tracks
  133. */
  134. void GetConnectedTracks(TRACK * aTrack)
  135. {
  136. aTrack->m_TracksConnected = m_connected;
  137. }
  138. /**
  139. * function SearchConnectionsPadsToIntersectingPads
  140. * Explores the list of pads and adds to m_PadsConnected member
  141. * of each pad pads connected to
  142. * Here, connections are due to intersecting pads, not tracks
  143. * m_sortedPads must be initialized
  144. */
  145. void SearchConnectionsPadsToIntersectingPads();
  146. /**
  147. * function SearchTracksConnectedToPads
  148. * Explores the list of pads.
  149. * Adds to m_PadsConnected member of each track the pad(s) connected to
  150. * Adds to m_TracksConnected member of each pad the track(s) connected to
  151. * D_PAD::m_TracksConnected is cleared before adding items
  152. * TRACK::m_PadsConnected is not cleared
  153. */
  154. void SearchTracksConnectedToPads();
  155. /**
  156. * function CollectItemsNearTo
  157. * Used by SearchTracksConnectedToPads
  158. * Fills aList with pads near to aPosition
  159. * near means aPosition to pad position <= aDistMax
  160. * @param aList = list to fill
  161. * @param aPosition = aPosition to use as reference
  162. * @param aDistMax = dist max from aPosition to a candidate to select it
  163. */
  164. void CollectItemsNearTo( std::vector<CONNECTED_POINT*>& aList,
  165. const wxPoint& aPosition, int aDistMax );
  166. /**
  167. * Function Propagate_SubNets
  168. * Test a list of tracks, to create or propagate a sub netcode to pads and
  169. * segments connected together.
  170. * The track list must be sorted by nets, and all segments
  171. * from m_firstTrack to m_lastTrack have the same net.
  172. * When 2 items are connected (a track to a pad, or a track to an other track),
  173. * they are grouped in a cluster.
  174. * For pads, this is the .m_physical_connexion member which is a cluster identifier
  175. * For tracks, this is the .m_Subnet member which is a cluster identifier
  176. * For a given net, if all tracks are created, there is only one cluster.
  177. * but if not all tracks are created, there are more than one cluster,
  178. * and some ratsnests will be left active.
  179. */
  180. void Propagate_SubNets();
  181. private:
  182. /**
  183. * function searchEntryPointInCandidatesList
  184. * Search an item in m_Connected connected to aPoint
  185. * note m_Connected containts usually more than one candidate
  186. * and searchEntryPointInCandidatesList returns an index to one of these candidates
  187. * Others are neightbor of the indexed item.
  188. * @param aPoint is the reference coordinates
  189. * @return the index of item found or -1 if no candidate
  190. */
  191. int searchEntryPointInCandidatesList( const wxPoint & aPoint);
  192. /**
  193. * Function Merge_SubNets
  194. * Change a subnet old value to a new value, for tracks and pads which are connected to
  195. * tracks from m_firstTrack to m_lastTrack and their connected pads.
  196. * and modify the subnet parameter (change the old value to the new value).
  197. * After that, 2 cluster (or subnets) are merged into only one.
  198. * Note: the resulting sub net value is the smallest between aOldSubNet and aNewSubNet
  199. * @return modification count
  200. * @param aOldSubNet = subnet value to modify
  201. * @param aNewSubNet = new subnet value for each item which have old_val as subnet value
  202. */
  203. int Merge_SubNets( int aOldSubNet, int aNewSubNet );
  204. /**
  205. * Function Merge_PadsSubNets
  206. * Change a subnet value to a new value, in m_sortedPads pad list
  207. * After that, 2 cluster (or subnets) are merged into only one.
  208. * Note: the resulting subnet value is the smallest between aOldSubNet et aNewSubNet
  209. * @return modification count
  210. * @param aOldSubNet = subnet value to modify
  211. * @param aNewSubNet = new subnet value for each item which have old_val as subnet value
  212. */
  213. int Merge_PadsSubNets( int aOldSubNet, int aNewSubNet );
  214. };
  215. CONNECTIONS::CONNECTIONS( BOARD * aBrd )
  216. {
  217. m_brd = aBrd;
  218. }
  219. /* Fills m_sortedPads with all pads that be connected to tracks
  220. * pads are sorted by X coordinate ( and Y coordinates for same X value )
  221. * aNetcode = net code to filter pads or < 0 to put all pads in list
  222. */
  223. void CONNECTIONS::BuildPadsList( int aNetcode )
  224. {
  225. // Creates sorted pad list if not exists
  226. m_sortedPads.clear();
  227. m_brd->GetSortedPadListByXthenYCoord( m_sortedPads, aNetcode < 0 ? -1 : aNetcode );
  228. }
  229. /* Explores the list of pads and adds to m_PadsConnected member
  230. * of each pad pads connected to
  231. * Here, connections are due to intersecting pads, not tracks
  232. */
  233. void CONNECTIONS::SearchConnectionsPadsToIntersectingPads()
  234. {
  235. std::vector<CONNECTED_POINT*> candidates;
  236. BuildPadsCandidatesList();
  237. for( unsigned ii = 0; ii < m_sortedPads.size(); ii++ )
  238. {
  239. D_PAD * pad = m_sortedPads[ii];
  240. pad->m_PadsConnected.clear();
  241. candidates.clear();
  242. CollectItemsNearTo( candidates, pad->ReturnShapePos(), pad->GetBoundingRadius() );
  243. // add pads to pad.m_PadsConnected, if they are connected
  244. for( unsigned jj = 0; jj < candidates.size(); jj++ )
  245. {
  246. CONNECTED_POINT * item = candidates[jj];
  247. D_PAD * candidate_pad = item->GetPad();
  248. if( pad == candidate_pad )
  249. continue;
  250. if( (pad->GetLayerMask() & candidate_pad->GetLayerMask()) == 0 )
  251. continue;
  252. if( pad->HitTest( item->GetPoint() ) )
  253. {
  254. pad->m_PadsConnected.push_back( candidate_pad );
  255. }
  256. }
  257. }
  258. }
  259. /* Explores the list of pads
  260. * Adds to m_PadsConnected member of each track the pad(s) connected to
  261. * Adds to m_TracksConnected member of each pad the track(s) connected to
  262. * D_PAD::m_TracksConnected is cleared before adding items
  263. * TRACK::m_PadsConnected is not cleared
  264. */
  265. void CONNECTIONS::SearchTracksConnectedToPads()
  266. {
  267. std::vector<CONNECTED_POINT*> candidates;
  268. for( unsigned ii = 0; ii < m_sortedPads.size(); ii++ )
  269. {
  270. D_PAD * pad = m_sortedPads[ii];
  271. pad->m_TracksConnected.clear();
  272. candidates.clear();
  273. CollectItemsNearTo( candidates, pad->GetPosition(), pad->GetBoundingRadius() );
  274. // add this pad to track.m_PadsConnected, if it is connected
  275. for( unsigned jj = 0; jj < candidates.size(); jj++ )
  276. {
  277. CONNECTED_POINT* cp_item = candidates[jj];
  278. if( (pad->GetLayerMask() & cp_item->GetTrack()->ReturnMaskLayer()) == 0 )
  279. continue;
  280. if( pad->HitTest( cp_item->GetPoint() ) )
  281. {
  282. cp_item->GetTrack()->m_PadsConnected.push_back( pad );
  283. pad->m_TracksConnected.push_back( cp_item->GetTrack() );
  284. }
  285. }
  286. }
  287. }
  288. void CONNECTIONS::CollectItemsNearTo( std::vector<CONNECTED_POINT*>& aList,
  289. const wxPoint& aPosition, int aDistMax )
  290. {
  291. /* Search items in m_Candidates that position is <= aDistMax from aPosition
  292. * (Rectilinear distance)
  293. * m_Candidates is sorted by X then Y values, so a fast binary search is used
  294. * to locate the "best" entry point in list
  295. * The best entry is a pad having its m_Pos.x == (or near) aPosition.x
  296. * All candidates are near this candidate in list
  297. * So from this entry point, a linear search is made to find all candidates
  298. */
  299. int idxmax = m_candidates.size()-1;
  300. int delta = m_candidates.size();
  301. int idx = 0; // Starting index is the beginning of list
  302. while( delta )
  303. {
  304. // Calculate half size of remaining interval to test.
  305. // Ensure the computed value is not truncated (too small)
  306. if( (delta & 1) && ( delta > 1 ) )
  307. delta++;
  308. delta /= 2;
  309. CONNECTED_POINT& item = m_candidates[idx];
  310. int dist = item.GetPoint().x - aPosition.x;
  311. if( abs(dist) <= aDistMax )
  312. {
  313. break; // A good entry point is found. The list can be scanned from this point.
  314. }
  315. else if( item.GetPoint().x < aPosition.x ) // We should search after this item
  316. {
  317. idx += delta;
  318. if( idx > idxmax )
  319. idx = idxmax;
  320. }
  321. else // We should search before this item
  322. {
  323. idx -= delta;
  324. if( idx < 0 )
  325. idx = 0;
  326. }
  327. }
  328. /* Now explore the candidate list from the "best" entry point found
  329. * (candidate "near" aPosition.x)
  330. * We explore the list until abs(candidate->m_Point.x - aPosition.x) > aDistMax
  331. * because the list is sorted by X position (and for a given X pos, by Y pos)
  332. * Currently a linear search is made because the number of candidates
  333. * having the right X position is usually small
  334. */
  335. // search next candidates in list
  336. wxPoint diff;
  337. for( int ii = idx; ii <= idxmax; ii++ )
  338. {
  339. CONNECTED_POINT* item = &m_candidates[ii];
  340. diff = item->GetPoint() - aPosition;
  341. if( abs(diff.x) > aDistMax )
  342. break; // Exit: the distance is to long, we cannot find other candidates
  343. if( abs(diff.y) > aDistMax )
  344. continue; // the y distance is to long, but we can find other candidates
  345. // We have here a good candidate: add it
  346. aList.push_back( item );
  347. }
  348. // search previous candidates in list
  349. for( int ii = idx-1; ii >=0; ii-- )
  350. {
  351. CONNECTED_POINT * item = &m_candidates[ii];
  352. diff = item->GetPoint() - aPosition;
  353. if( abs(diff.x) > aDistMax )
  354. break;
  355. if( abs(diff.y) > aDistMax )
  356. continue;
  357. // We have here a good candidate:add it
  358. aList.push_back( item );
  359. }
  360. }
  361. void CONNECTIONS::BuildPadsCandidatesList()
  362. {
  363. m_candidates.clear();
  364. m_candidates.reserve( m_sortedPads.size() );
  365. for( unsigned ii = 0; ii < m_sortedPads.size(); ii++ )
  366. {
  367. D_PAD * pad = m_sortedPads[ii];
  368. CONNECTED_POINT candidate( pad, pad->GetPosition() );
  369. m_candidates.push_back( candidate );
  370. }
  371. }
  372. /* sort function used to sort .m_Connected by X the Y values
  373. * items are sorted by X coordinate value,
  374. * and for same X value, by Y coordinate value.
  375. */
  376. static bool sortConnectedPointByXthenYCoordinates( const CONNECTED_POINT & aRef,
  377. const CONNECTED_POINT & aTst )
  378. {
  379. if( aRef.GetPoint().x == aTst.GetPoint().x )
  380. return aRef.GetPoint().y < aTst.GetPoint().y;
  381. return aRef.GetPoint().x < aTst.GetPoint().x;
  382. }
  383. void CONNECTIONS::BuildTracksCandidatesList( TRACK * aBegin, TRACK * aEnd)
  384. {
  385. m_candidates.clear();
  386. // if( aBegin == NULL )
  387. // aBegin = m_brd->m_Track;
  388. m_firstTrack = m_lastTrack = aBegin;
  389. unsigned ii = 0;
  390. // Count candidates ( i.e. end points )
  391. for( const TRACK* track = aBegin; track; track = track->Next() )
  392. {
  393. if( track->Type() == PCB_VIA_T )
  394. ii++;
  395. else
  396. ii += 2;
  397. m_lastTrack = track;
  398. if( track == aEnd )
  399. break;
  400. }
  401. // Build candidate list
  402. m_candidates.reserve( ii );
  403. for( TRACK* track = aBegin; track; track = track->Next() )
  404. {
  405. CONNECTED_POINT candidate( track, track->m_Start);
  406. m_candidates.push_back( candidate );
  407. if( track->Type() != PCB_VIA_T )
  408. {
  409. CONNECTED_POINT candidate2( track, track->m_End);
  410. m_candidates.push_back( candidate2 );
  411. }
  412. if( track == aEnd )
  413. break;
  414. }
  415. // Sort list by increasing X coordinate,
  416. // and for increasing Y coordinate when items have the same X coordinate
  417. // So candidates to the same location are consecutive in list.
  418. sort( m_candidates.begin(), m_candidates.end(), sortConnectedPointByXthenYCoordinates );
  419. }
  420. int CONNECTIONS::SearchConnectedTracks( const TRACK * aTrack )
  421. {
  422. int count = 0;
  423. m_connected.clear();
  424. int layerMask = aTrack->ReturnMaskLayer();
  425. // Search for connections to starting point:
  426. wxPoint position = aTrack->m_Start;
  427. for( int kk = 0; kk < 2; kk++ )
  428. {
  429. int idx = searchEntryPointInCandidatesList( position );
  430. if ( idx >= 0 )
  431. {
  432. // search after:
  433. for ( unsigned ii = idx; ii < m_candidates.size(); ii ++ )
  434. {
  435. if( m_candidates[ii].GetTrack() == aTrack )
  436. continue;
  437. if( m_candidates[ii].GetPoint() != position )
  438. break;
  439. if( (m_candidates[ii].GetTrack()->ReturnMaskLayer() & layerMask ) != 0 )
  440. m_connected.push_back( m_candidates[ii].GetTrack() );
  441. }
  442. // search before:
  443. for ( int ii = idx-1; ii >= 0; ii -- )
  444. {
  445. if( m_candidates[ii].GetTrack() == aTrack )
  446. continue;
  447. if( m_candidates[ii].GetPoint() != position )
  448. break;
  449. if( (m_candidates[ii].GetTrack()->ReturnMaskLayer() & layerMask ) != 0 )
  450. m_connected.push_back( m_candidates[ii].GetTrack() );
  451. }
  452. }
  453. // Search for connections to ending point:
  454. if( aTrack->Type() == PCB_VIA_T )
  455. break;
  456. position = aTrack->m_End;
  457. }
  458. return count;
  459. }
  460. int CONNECTIONS::searchEntryPointInCandidatesList( const wxPoint & aPoint)
  461. {
  462. // Search the aPoint coordinates in m_Candidates
  463. // m_Candidates is sorted by X then Y values, and a fast binary search is used
  464. int idxmax = m_candidates.size()-1;
  465. int delta = m_candidates.size();
  466. int idx = 0; // Starting index is the beginning of list
  467. while( delta )
  468. {
  469. // Calculate half size of remaining interval to test.
  470. // Ensure the computed value is not truncated (too small)
  471. if( (delta & 1) && ( delta > 1 ) )
  472. delta++;
  473. delta /= 2;
  474. CONNECTED_POINT & candidate = m_candidates[idx];
  475. if( candidate.GetPoint() == aPoint ) // candidate found
  476. {
  477. return idx;
  478. }
  479. // Not found: test the middle of the remaining sub list
  480. if( candidate.GetPoint().x == aPoint.x ) // Must search considering Y coordinate
  481. {
  482. if(candidate.GetPoint().y < aPoint.y) // Must search after this item
  483. {
  484. idx += delta;
  485. if( idx > idxmax )
  486. idx = idxmax;
  487. }
  488. else // Must search before this item
  489. {
  490. idx -= delta;
  491. if( idx < 0 )
  492. idx = 0;
  493. }
  494. }
  495. else if( candidate.GetPoint().x < aPoint.x ) // Must search after this item
  496. {
  497. idx += delta;
  498. if( idx > idxmax )
  499. idx = idxmax;
  500. }
  501. else // Must search before this item
  502. {
  503. idx -= delta;
  504. if( idx < 0 )
  505. idx = 0;
  506. }
  507. }
  508. return -1;
  509. }
  510. /* Used after a track change (delete a track ou add a track)
  511. * Connections to pads are recalculated
  512. * Note also aFirstTrack (and aLastTrack ) can be NULL
  513. */
  514. void CONNECTIONS::Build_CurrNet_SubNets_Connections( TRACK* aFirstTrack, TRACK* aLastTrack, int aNetcode )
  515. {
  516. m_firstTrack = aFirstTrack; // The first track used to build m_Candidates
  517. m_lastTrack = aLastTrack; // The last track used to build m_Candidates
  518. // Pads subnets are expected already cleared, because this function
  519. // does not know the full list of pads
  520. BuildTracksCandidatesList( aFirstTrack, aLastTrack );
  521. TRACK* curr_track;
  522. for( curr_track = aFirstTrack; curr_track != NULL; curr_track = curr_track->Next() )
  523. {
  524. // Clear track subnet id (Pads subnets are cleared outside this function)
  525. curr_track->SetSubNet( 0 );
  526. curr_track->m_TracksConnected.clear();
  527. curr_track->m_PadsConnected.clear();
  528. // Update connections between tracks:
  529. SearchConnectedTracks( curr_track );
  530. curr_track->m_TracksConnected = m_connected;
  531. if( curr_track == aLastTrack )
  532. break;
  533. }
  534. // Update connections between tracks and pads
  535. BuildPadsList( aNetcode );
  536. SearchTracksConnectedToPads();
  537. // Update connections between intersecting pads (no tracks)
  538. SearchConnectionsPadsToIntersectingPads();
  539. // Creates sub nets (clusters) for the current net:
  540. Propagate_SubNets();
  541. }
  542. /**
  543. * Change a subnet value to a new value, in m_sortedPads pad list
  544. * After that, 2 cluster (or subnets) are merged into only one.
  545. * Note: the resulting subnet value is the smallest between aOldSubNet et aNewSubNet
  546. */
  547. int CONNECTIONS::Merge_PadsSubNets( int aOldSubNet, int aNewSubNet )
  548. {
  549. int change_count = 0;
  550. if( aOldSubNet == aNewSubNet )
  551. return 0;
  552. if( (aOldSubNet > 0) && (aOldSubNet < aNewSubNet) )
  553. EXCHG( aOldSubNet, aNewSubNet );
  554. // Examine connections between intersecting pads
  555. for( unsigned ii = 0; ii < m_sortedPads.size(); ii++ )
  556. {
  557. D_PAD * curr_pad = m_sortedPads[ii];
  558. if( curr_pad->GetSubNet() != aOldSubNet )
  559. continue;
  560. change_count++;
  561. curr_pad->SetSubNet( aNewSubNet );
  562. }
  563. return change_count;
  564. }
  565. /*
  566. * Change a subnet value to a new value, for tracks and pads which are connected to.
  567. * The result is merging 2 clusters (or subnets) into only one cluster.
  568. * Note: the resultig sub net value is the smallest between aOldSubNet et aNewSubNet
  569. */
  570. int CONNECTIONS::Merge_SubNets( int aOldSubNet, int aNewSubNet )
  571. {
  572. TRACK* curr_track;
  573. int change_count = 0;
  574. if( aOldSubNet == aNewSubNet )
  575. return 0;
  576. if( (aOldSubNet > 0) && (aOldSubNet < aNewSubNet) )
  577. EXCHG( aOldSubNet, aNewSubNet );
  578. curr_track = (TRACK*)m_firstTrack;
  579. for( ; curr_track != NULL; curr_track = curr_track->Next() )
  580. {
  581. if( curr_track->GetSubNet() != aOldSubNet )
  582. {
  583. if( curr_track == m_lastTrack )
  584. break;
  585. continue;
  586. }
  587. change_count++;
  588. curr_track->SetSubNet( aNewSubNet );
  589. for( unsigned ii = 0; ii < curr_track->m_PadsConnected.size(); ii++ )
  590. {
  591. D_PAD * pad = curr_track->m_PadsConnected[ii];
  592. if( pad->GetSubNet() == aOldSubNet )
  593. pad->SetSubNet( curr_track->GetSubNet() );
  594. }
  595. if( curr_track == m_lastTrack )
  596. break;
  597. }
  598. return change_count;
  599. }
  600. /* Test a list of track segments, to create or propagate a sub netcode to pads and
  601. * segments connected together.
  602. * The track list must be sorted by nets, and all segments
  603. * from m_firstTrack to m_lastTrack have the same net
  604. * When 2 items are connected (a track to a pad, or a track to an other track),
  605. * they are grouped in a cluster.
  606. * For pads, this is the .m_physical_connexion member which is a cluster identifier
  607. * For tracks, this is the .m_Subnet member which is a cluster identifier
  608. * For a given net, if all tracks are created, there is only one cluster.
  609. * but if not all tracks are created, there are more than one cluster,
  610. * and some ratsnests will be left active.
  611. */
  612. void CONNECTIONS::Propagate_SubNets()
  613. {
  614. int sub_netcode = 0;
  615. // Examine connections between intersecting pads
  616. for( unsigned ii = 0; ii < m_sortedPads.size(); ii++ )
  617. {
  618. D_PAD * curr_pad = m_sortedPads[ii];
  619. for( unsigned jj = 0; jj < curr_pad->m_PadsConnected.size(); jj++ )
  620. {
  621. D_PAD * pad = curr_pad->m_PadsConnected[jj];
  622. if( curr_pad->GetSubNet() )
  623. {
  624. if( pad->GetSubNet() > 0 )
  625. {
  626. // The pad is already a cluster member, so we can merge the 2 clusters
  627. Merge_PadsSubNets( pad->GetSubNet(), curr_pad->GetSubNet() );
  628. }
  629. else
  630. {
  631. // The pad is not yet attached to a cluster,
  632. // so we can add this pad to the cluster
  633. pad->SetSubNet( curr_pad->GetSubNet() );
  634. }
  635. }
  636. else // the track segment is not attached to a cluster
  637. {
  638. if( pad->GetSubNet() > 0 )
  639. {
  640. // it is connected to a pad in a cluster, merge this pad
  641. curr_pad->SetSubNet( pad->GetSubNet() );
  642. }
  643. else
  644. {
  645. // it is connected to a pad not in a cluster,
  646. // so we must create a new cluster (only with the 2 pads.
  647. sub_netcode++;
  648. curr_pad->SetSubNet( sub_netcode );
  649. pad->SetSubNet( curr_pad->GetSubNet() );
  650. }
  651. }
  652. }
  653. }
  654. sub_netcode++;
  655. TRACK* curr_track = (TRACK*)m_firstTrack;
  656. if( curr_track )
  657. curr_track->SetSubNet( sub_netcode );
  658. // Examine connections between trcaks and pads
  659. for( ; curr_track != NULL; curr_track = curr_track->Next() )
  660. {
  661. // First: handling connections to pads
  662. for( unsigned ii = 0; ii < curr_track->m_PadsConnected.size(); ii++ )
  663. {
  664. D_PAD * pad = curr_track->m_PadsConnected[ii];
  665. if( curr_track->GetSubNet() ) // the track segment is already a cluster member
  666. {
  667. if( pad->GetSubNet() > 0 )
  668. {
  669. // The pad is already a cluster member, so we can merge the 2 clusters
  670. Merge_SubNets( pad->GetSubNet(), curr_track->GetSubNet() );
  671. }
  672. else
  673. {
  674. /* The pad is not yet attached to a cluster , so we can add this pad to
  675. * the cluster */
  676. pad->SetSubNet( curr_track->GetSubNet() );
  677. }
  678. }
  679. else // the track segment is not attached to a cluster
  680. {
  681. if( pad->GetSubNet() > 0 )
  682. {
  683. // it is connected to a pad in a cluster, merge this track
  684. curr_track->SetSubNet( pad->GetSubNet() );
  685. }
  686. else
  687. {
  688. /* it is connected to a pad not in a cluster, so we must create a new
  689. * cluster (only with the 2 items: the track and the pad) */
  690. sub_netcode++;
  691. curr_track->SetSubNet( sub_netcode );
  692. pad->SetSubNet( curr_track->GetSubNet() );
  693. }
  694. }
  695. }
  696. // Test connections between segments
  697. for( unsigned ii = 0; ii < curr_track->m_TracksConnected.size(); ii++ )
  698. {
  699. BOARD_CONNECTED_ITEM* track = curr_track->m_TracksConnected[ii];
  700. if( curr_track->GetSubNet() ) // The current track is already a cluster member
  701. {
  702. // The other track is already a cluster member, so we can merge the 2 clusters
  703. if( track->GetSubNet() )
  704. {
  705. Merge_SubNets( track->GetSubNet(), curr_track->GetSubNet() );
  706. }
  707. else
  708. {
  709. /* The other track is not yet attached to a cluster , so we can add this
  710. * other track to the cluster */
  711. track->SetSubNet( curr_track->GetSubNet() );
  712. }
  713. }
  714. else // the current track segment is not yet attached to a cluster
  715. {
  716. if( track->GetSubNet() )
  717. {
  718. // The other track is already a cluster member, so we can add
  719. // the current segment to the cluster
  720. curr_track->SetSubNet( track->GetSubNet() );
  721. }
  722. else
  723. {
  724. /* it is connected to an other segment not in a cluster, so we must
  725. * create a new cluster (only with the 2 track segments) */
  726. sub_netcode++;
  727. curr_track->SetSubNet( sub_netcode );
  728. track->SetSubNet( curr_track->GetSubNet() );
  729. }
  730. }
  731. }
  732. if( curr_track == m_lastTrack )
  733. break;
  734. }
  735. }
  736. /*
  737. * Test all connections of the board,
  738. * and update subnet variable of pads and tracks
  739. * TestForActiveLinksInRatsnest must be called after this function
  740. * to update active/inactive ratsnest items status
  741. */
  742. void PCB_BASE_FRAME::TestConnections()
  743. {
  744. // Clear the cluster identifier for all pads
  745. for( unsigned i = 0; i< m_Pcb->GetPadCount(); ++i )
  746. {
  747. D_PAD* pad = m_Pcb->GetPad(i);
  748. pad->SetZoneSubNet( 0 );
  749. pad->SetSubNet( 0 );
  750. }
  751. m_Pcb->Test_Connections_To_Copper_Areas();
  752. // Test existing connections net by net
  753. // note some nets can have no tracks, and pads intersecting
  754. // so Build_CurrNet_SubNets_Connections must be called for each net
  755. CONNECTIONS connections( m_Pcb );
  756. int last_net_tested = 0;
  757. int current_net_code = 0;
  758. for( TRACK* track = m_Pcb->m_Track; track; )
  759. {
  760. // At this point, track is the first track of a given net
  761. current_net_code = track->GetNet();
  762. // Get last track of the current net
  763. TRACK* lastTrack = track->GetEndNetCode( current_net_code );
  764. if( current_net_code > 0 ) // do not spend time if net code = 0 ( dummy net )
  765. {
  766. // Test all previous nets having no tracks
  767. for( int net = last_net_tested+1; net < current_net_code; net++ )
  768. connections.Build_CurrNet_SubNets_Connections( NULL, NULL, net );
  769. connections.Build_CurrNet_SubNets_Connections( track, lastTrack, current_net_code );
  770. last_net_tested = current_net_code;
  771. }
  772. track = lastTrack->Next(); // this is now the first track of the next net
  773. }
  774. // Test last nets without tracks, if any
  775. int netsCount = m_Pcb->GetNetCount();
  776. for( int net = last_net_tested+1; net < netsCount; net++ )
  777. connections.Build_CurrNet_SubNets_Connections( NULL, NULL, net );
  778. Merge_SubNets_Connected_By_CopperAreas( m_Pcb );
  779. return;
  780. }
  781. void PCB_BASE_FRAME::TestNetConnection( wxDC* aDC, int aNetCode )
  782. {
  783. wxString msg;
  784. if( aNetCode <= 0 ) // -1 = not existing net, 0 = dummy net
  785. return;
  786. if( (m_Pcb->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK) == 0 )
  787. Compile_Ratsnest( aDC, true );
  788. // Clear the cluster identifier (subnet) of pads for this net
  789. for( unsigned i = 0; i < m_Pcb->GetPadCount(); ++i )
  790. {
  791. D_PAD* pad = m_Pcb->GetPad(i);
  792. int pad_net_code = pad->GetNet();
  793. if( pad_net_code < aNetCode )
  794. continue;
  795. if( pad_net_code > aNetCode )
  796. break;
  797. pad->SetSubNet( 0 );
  798. }
  799. m_Pcb->Test_Connections_To_Copper_Areas( aNetCode );
  800. // Search for the first and the last segment relative to the given net code
  801. if( m_Pcb->m_Track )
  802. {
  803. CONNECTIONS connections( m_Pcb );
  804. TRACK* firstTrack;
  805. TRACK* lastTrack = NULL;
  806. firstTrack = m_Pcb->m_Track.GetFirst()->GetStartNetCode( aNetCode );
  807. if( firstTrack )
  808. lastTrack = firstTrack->GetEndNetCode( aNetCode );
  809. if( firstTrack && lastTrack ) // i.e. if there are segments
  810. {
  811. connections.Build_CurrNet_SubNets_Connections( firstTrack, lastTrack, firstTrack->GetNet() );
  812. }
  813. }
  814. Merge_SubNets_Connected_By_CopperAreas( m_Pcb, aNetCode );
  815. // rebuild the active ratsnest for this net
  816. DrawGeneralRatsnest( aDC, aNetCode );
  817. TestForActiveLinksInRatsnest( aNetCode );
  818. DrawGeneralRatsnest( aDC, aNetCode );
  819. // Display results
  820. int net_notconnected_count = 0;
  821. NETINFO_ITEM* net = m_Pcb->FindNet( aNetCode );
  822. if( net ) // Should not occur, but ...
  823. {
  824. for( unsigned ii = net->m_RatsnestStartIdx; ii < net->m_RatsnestEndIdx; ii++ )
  825. {
  826. if( m_Pcb->m_FullRatsnest[ii].IsActive() )
  827. net_notconnected_count++;
  828. }
  829. msg.Printf( wxT( "links %d nc %d net:nc %d" ),
  830. m_Pcb->GetRatsnestsCount(), m_Pcb->GetNoconnectCount(),
  831. net_notconnected_count );
  832. }
  833. else
  834. msg.Printf( wxT( "net not found: netcode %d" ),aNetCode );
  835. SetStatusText( msg );
  836. return;
  837. }
  838. /* search connections between tracks and pads and propagate pad net codes to the track
  839. * segments.
  840. * Pads netcodes are assumed to be up to date.
  841. */
  842. void PCB_BASE_FRAME::RecalculateAllTracksNetcode()
  843. {
  844. TRACK* curr_track;
  845. // Build the net info list
  846. GetBoard()->BuildListOfNets();
  847. // Reset variables and flags used in computation
  848. curr_track = m_Pcb->m_Track;
  849. for( ; curr_track != NULL; curr_track = curr_track->Next() )
  850. {
  851. curr_track->m_TracksConnected.clear();
  852. curr_track->m_PadsConnected.clear();
  853. curr_track->start = NULL;
  854. curr_track->end = NULL;
  855. curr_track->SetState( BUSY | IN_EDIT | BEGIN_ONPAD | END_ONPAD, OFF );
  856. curr_track->SetZoneSubNet( 0 );
  857. curr_track->SetNet( 0 ); // net code = 0 means not connected
  858. }
  859. // If no pad, reset pointers and netcode, and do nothing else
  860. if( m_Pcb->GetPadCount() == 0 )
  861. return;
  862. CONNECTIONS connections( m_Pcb );
  863. connections.BuildPadsList();
  864. connections.BuildTracksCandidatesList(m_Pcb->m_Track);
  865. // First pass: build connections between track segments and pads.
  866. connections.SearchTracksConnectedToPads();
  867. /* For tracks connected to at least one pad,
  868. * set the track net code to the pad netcode
  869. */
  870. curr_track = m_Pcb->m_Track;
  871. for( ; curr_track != NULL; curr_track = curr_track->Next() )
  872. {
  873. if( curr_track->m_PadsConnected.size() )
  874. curr_track->SetNet( curr_track->m_PadsConnected[0]->GetNet() );
  875. }
  876. // Pass 2: build connections between track ends
  877. for( curr_track = m_Pcb->m_Track; curr_track != NULL; curr_track = curr_track->Next() )
  878. {
  879. connections.SearchConnectedTracks( curr_track );
  880. connections.GetConnectedTracks( curr_track );
  881. }
  882. // Propagate net codes from a segment to other connected segments
  883. bool new_pass_request = true; // set to true if a track has its netcode changed from 0
  884. // to a known netcode to re-evaluate netcodes
  885. // of connected items
  886. while( new_pass_request )
  887. {
  888. new_pass_request = false;
  889. for( curr_track = m_Pcb->m_Track; curr_track; curr_track = curr_track->Next() )
  890. {
  891. int netcode = curr_track->GetNet();
  892. if( netcode == 0 )
  893. { // try to find a connected item having a netcode
  894. for( unsigned kk = 0; kk < curr_track->m_TracksConnected.size(); kk++ )
  895. {
  896. int altnetcode = curr_track->m_TracksConnected[kk]->GetNet();
  897. if( altnetcode )
  898. {
  899. new_pass_request = true;
  900. netcode = altnetcode;
  901. curr_track->SetNet(netcode);
  902. break;
  903. }
  904. }
  905. }
  906. if( netcode ) // this track has a netcode
  907. { // propagate this netcode to connected tracks having no netcode
  908. for( unsigned kk = 0; kk < curr_track->m_TracksConnected.size(); kk++ )
  909. {
  910. int altnetcode = curr_track->m_TracksConnected[kk]->GetNet();
  911. if( altnetcode == 0 )
  912. {
  913. curr_track->m_TracksConnected[kk]->SetNet(netcode);
  914. new_pass_request = true;
  915. }
  916. }
  917. }
  918. }
  919. }
  920. // Sort the track list by net codes:
  921. RebuildTrackChain( m_Pcb );
  922. }
  923. /*
  924. * Function SortTracksByNetCode used in RebuildTrackChain()
  925. * to sort track segments by net code.
  926. */
  927. static bool SortTracksByNetCode( const TRACK* const & ref, const TRACK* const & compare )
  928. {
  929. return ref->GetNet() < compare->GetNet();
  930. }
  931. /**
  932. * Helper function RebuildTrackChain
  933. * rebuilds the track segment linked list in order to have a chain
  934. * sorted by increasing netcodes.
  935. * @param pcb = board to rebuild
  936. */
  937. static void RebuildTrackChain( BOARD* pcb )
  938. {
  939. if( pcb->m_Track == NULL )
  940. return;
  941. int item_count = pcb->m_Track.GetCount();
  942. std::vector<TRACK*> trackList;
  943. trackList.reserve( item_count );
  944. for( int i = 0; i < item_count; ++i )
  945. trackList.push_back( pcb->m_Track.PopFront() );
  946. // the list is empty now
  947. wxASSERT( pcb->m_Track == NULL && pcb->m_Track.GetCount()==0 );
  948. sort( trackList.begin(), trackList.end(), SortTracksByNetCode );
  949. // add them back to the list
  950. for( int i = 0; i < item_count; ++i )
  951. pcb->m_Track.PushBack( trackList[i] );
  952. }