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.

1155 lines
39 KiB

17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
  1. /***********************/
  2. /**** ratsnest.cpp ****/
  3. /* Ratsnets functions */
  4. /***********************/
  5. #include "fctsys.h"
  6. #include "gr_basic.h"
  7. #include "common.h"
  8. #include "class_drawpanel.h"
  9. #include "confirm.h"
  10. #include "pcbnew.h"
  11. #include "class_board_design_settings.h"
  12. #include "colors_selection.h"
  13. #include "protos.h"
  14. static std::vector <D_PAD*> s_localPadBuffer; // for local ratsnest
  15. // calculations when moving a
  16. // footprint: buffer of pads to
  17. // consider
  18. static bool DisplayRastnestInProgress; // Enable the display of the
  19. // ratsnest during the ratsnest
  20. // computations
  21. /* Note about the ratsnest computation:
  22. * Building the general ratsnest:
  23. * I used the "lee algorithm".
  24. * This is a 2 steps algorithm.
  25. * the m_SubRatsnest member of pads handle a "block number" or a "cluster
  26. * number" or a "subnet number"
  27. * initially, m_SubRatsnest = 0 (pad not connected).
  28. * Build_Board_Ratsnest( wxDC* DC ) Create this ratsnest
  29. * for each net:
  30. * First:
  31. * we create a link (and therefore a logical block) between 2 pad. This is
  32. * achieved by:
  33. * search for a pad without link.
  34. * search its nearest pad
  35. * link these 2 pads (i.e. create a ratsnest item)
  36. * the pads are grouped in a logical block ( a cluster).
  37. * until no pad without link found.
  38. * Each logical block has a number called block number or "subnet number",
  39. * stored in m_SubRatsnest member for each pad of the block.
  40. * The first block has its block number = 1, the second is 2 ...
  41. * the function to do that is gen_rats_pad_to_pad()
  42. *
  43. * Secondly:
  44. * The first pass created many logical blocks
  45. * A block contains 2 or more pads.
  46. * we create links between 2 block. This is achieved by:
  47. * Test all pads in the first block, and search (for each pad)
  48. * a neighbor in other blocks and compute the distance between pads,
  49. * We select the pad pair which have the smallest distance.
  50. * These 2 pads are linked (i.e. a new ratsnest item is created between the 2
  51. * pads)
  52. * and the 2 block are merged.
  53. * Therefore the logical block 1 contains the initial block 1 "eats" the pads
  54. * of the other block
  55. * The computation is made until only one block is found.
  56. * the function used is gen_rats_block_to_block()
  57. *
  58. *
  59. * How existing and new tracks are handled:
  60. * The complete ratsnest (using the pad analysis) is computed.
  61. * it is independent of the tracks and handle the "logical connections".
  62. * It depends only on the footprints geometry (and the netlist),
  63. * and must be computed only after a netlist read or a footprints geometry
  64. * change.
  65. * Each link (ratsnest) can only be INACTIVE (because pads are connected by a
  66. * track) or ACTIVE (no tracks)
  67. *
  68. * After the complete ratsnest is built, or when a track is added or deleted,
  69. * we run an algorithm derived from the complete ratsnest computation.
  70. * it is much faster because it analysis only the existing ratsnest and not all
  71. * the pads list
  72. * and determine only if an existing ratsnest must be activated
  73. * (no physical track exists) or not (a physical track exists)
  74. * if a track is added or deleted only the corresponding net is tested.
  75. *
  76. * the m_SubRatsnest member of pads is set to 0 (no blocks), and all links are
  77. * set to INACTIVE (ratsnest not show).
  78. * Before running this fast lee algorithm, we create blocks (and their
  79. * corresponding block number)
  80. * by grouping pads connected by tracks.
  81. * So, when tracks exists, the fast lee algorithm is started with some blocks
  82. * already created.
  83. * because the fast lee algorithm test only the ratsnest and does not search
  84. * for nearest pads (this search was previously made) the online ratsnest
  85. * can be done when a track is created without noticeable computing time
  86. * First:
  87. * for all links (in this step, all are inactive):
  88. * search for a link which have 1 (or 2) pad having the m_SubRatsnest member =
  89. * 0.
  90. * if found the link is set to ACTIVE (i.e. the ratsnest will be showed) and
  91. * the pad is merged with the block
  92. * or a new block is created ( see tst_rats_pad_to_pad() ).
  93. * Secondly:
  94. * blocks are tested:
  95. * for all links we search if the 2 pads linked are in 2 different block.
  96. * if yes, the link status is set to ACTIVE, and the 2 block are merged
  97. * until only one block is found
  98. * ( see tst_rats_block_to_block() )
  99. */
  100. /**
  101. * Function Compile_Ratsnest
  102. * Create the entire board ratsnest.
  103. * Must be called after a board change (changes for
  104. * pads, footprints or a read netlist ).
  105. * @param aDC = the current device context (can be NULL)
  106. * @param aDisplayStatus : if true, display the computation results
  107. */
  108. void PCB_BASE_FRAME::Compile_Ratsnest( wxDC* aDC, bool aDisplayStatus )
  109. {
  110. wxString msg;
  111. DisplayRastnestInProgress = TRUE;
  112. GetBoard()->m_Status_Pcb = 0; /* we want a full ratsnest computation,
  113. * from the scratch */
  114. ClearMsgPanel();
  115. // Rebuild the full pads and net info list
  116. RecalculateAllTracksNetcode();
  117. if( aDisplayStatus )
  118. {
  119. msg.Printf( wxT( " %d" ), m_Pcb->GetPadsCount() );
  120. AppendMsgPanel( wxT( "Pads" ), msg, RED );
  121. msg.Printf( wxT( " %d" ), m_Pcb->m_NetInfo->GetCount() );
  122. AppendMsgPanel( wxT( "Nets" ), msg, CYAN );
  123. }
  124. /* Compute the full ratsnest
  125. * which can be see like all the possible links or logical connections.
  126. * some of them are active (no track connected) and others are inactive
  127. * (when track connect pads)
  128. * This full ratsnest is not modified by track editing.
  129. * It changes only when a netlist is read, or footprints are modified
  130. */
  131. Build_Board_Ratsnest( aDC );
  132. /* Compute the pad connections due to the existing tracks (physical
  133. * connections) */
  134. test_connexions( aDC );
  135. /* Compute the active ratsnest, i.e. the unconnected links
  136. * it is faster than Build_Board_Ratsnest()
  137. * because many optimizations and computations are already made
  138. */
  139. Tst_Ratsnest( aDC, 0 );
  140. // Redraw the active ratsnest ( if enabled )
  141. if( GetBoard()->IsElementVisible(RATSNEST_VISIBLE) && aDC )
  142. DrawGeneralRatsnest( aDC, 0 );
  143. if( aDisplayStatus )
  144. m_Pcb->DisplayInfo( this );
  145. }
  146. /* Sort function used by QSORT
  147. * Sort pads by net code
  148. */
  149. static int sortByNetcode( const void* o1, const void* o2 )
  150. {
  151. D_PAD** pt_ref = (D_PAD**) o1;
  152. D_PAD** pt_compare = (D_PAD**) o2;
  153. return (*pt_ref)->GetNet() - (*pt_compare)->GetNet();
  154. }
  155. /* Sort function used by QSORT
  156. * Sort ratsnest by length
  157. */
  158. static int sort_by_length( const void* o1, const void* o2 )
  159. {
  160. RATSNEST_ITEM* ref = (RATSNEST_ITEM*) o1;
  161. RATSNEST_ITEM* compare = (RATSNEST_ITEM*) o2;
  162. return ref->m_Lenght - compare->m_Lenght;
  163. }
  164. /**
  165. * Function used by Build_Board_Ratsnest
  166. * This function creates a ratsnest between two blocks ( which fit the same
  167. * net )
  168. * A block is a group of pads already linked (by a previous ratsnest
  169. * computation, or tracks)
  170. * The search is made between the pads in block 1 (the reference block) and
  171. * other blocks
  172. * the block n ( n > 1 ) it connected to block 1 by their 2 nearest pads.
  173. * When the block is found, it is merged with the block 1
  174. * the D_PAD member m_SubRatsnest handles the block number
  175. * @param aRatsnestBuffer = a std::vector<RATSNEST_ITEM> buffer to fill with
  176. * new ratsnest items
  177. * @param aPadBuffer = a std::vector<D_PAD*> that is the list of pads to consider
  178. * @param aPadIdxStart = starting index (within the pad list) for search
  179. * @param aPadIdxMax = ending index (within the pad list) for search
  180. * @return blocks not connected count
  181. */
  182. static int gen_rats_block_to_block(
  183. std::vector<RATSNEST_ITEM>& aRatsnestBuffer,
  184. std::vector<D_PAD*>& aPadBuffer,
  185. unsigned aPadIdxStart,
  186. unsigned aPadIdxMax )
  187. {
  188. int dist_min, current_dist;
  189. int current_num_block = 1;
  190. int padBlock1Idx = -1; // Index in aPadBuffer for the "better" pad
  191. // found in block 1
  192. int padBlockToMergeIdx = -1; // Index in aPadBuffer for the "better" pad
  193. // found in block to merge
  194. dist_min = 0x7FFFFFFF;
  195. /* Search the nearest pad from block 1 */
  196. for( unsigned ii = aPadIdxStart; ii < aPadIdxMax; ii++ )
  197. {
  198. D_PAD* ref_pad = aPadBuffer[ii];
  199. /* search a pad which is in the block 1 */
  200. if( ref_pad->GetSubRatsnest() != 1 )
  201. continue;
  202. /* pad is found, search its nearest neighbor in other blocks */
  203. for( unsigned jj = aPadIdxStart; jj < aPadIdxMax; jj++ )
  204. {
  205. D_PAD* curr_pad = aPadBuffer[jj];
  206. if( curr_pad->GetSubRatsnest() == 1 ) // not in an other block
  207. continue;
  208. /* Compare distance between pads ("Manhattan" distance) */
  209. current_dist = abs( curr_pad->m_Pos.x - ref_pad->m_Pos.x ) +
  210. abs( curr_pad->m_Pos.y - ref_pad->m_Pos.y );
  211. if( dist_min > current_dist ) // we have found a better pad pair
  212. {
  213. // The tested block can be a good candidate for merging
  214. // we memorize the "best" current values for merging
  215. current_num_block = curr_pad->GetSubRatsnest();
  216. dist_min = current_dist;
  217. padBlockToMergeIdx = jj;
  218. padBlock1Idx = ii;
  219. }
  220. }
  221. }
  222. /* The reference block is labeled block 1.
  223. * if current_num_block != 1 we have found an other block, and we must
  224. * merge it with the reference block
  225. * The link is made by the 2 nearest pads
  226. */
  227. if( current_num_block > 1 )
  228. {
  229. /* The block n (n=current_num_block) is merged with the bloc 1 :
  230. * to do that, we set the m_SubRatsnest member to 1 for all pads in
  231. * block n
  232. */
  233. for( unsigned ii = aPadIdxStart; ii < aPadIdxMax; ii++ )
  234. {
  235. D_PAD* pad = aPadBuffer[ii];
  236. if( pad->GetSubRatsnest() == current_num_block )
  237. pad->SetSubRatsnest( 1 );
  238. }
  239. if( padBlock1Idx < 0 )
  240. DisplayError( NULL,
  241. wxT( "gen_rats_block_to_block() internal error" ) );
  242. else
  243. {
  244. /* Create the new ratsnest */
  245. RATSNEST_ITEM net;
  246. net.SetNet( aPadBuffer[padBlock1Idx]->GetNet() );
  247. net.m_Status = CH_ACTIF | CH_VISIBLE;
  248. net.m_Lenght = dist_min;
  249. net.m_PadStart = aPadBuffer[padBlock1Idx];
  250. net.m_PadEnd = aPadBuffer[padBlockToMergeIdx];
  251. aRatsnestBuffer.push_back( net );
  252. }
  253. }
  254. return current_num_block;
  255. }
  256. /**
  257. * Function used by Build_Board_Ratsnest
  258. * this is the first pass of the lee algorithm
  259. * This function creates the link (ratsnest) between 2 pads ( fitting the same
  260. * net )
  261. * the function search for a first not connected pad and search its nearest
  262. * neighbor
  263. * Its creates a block if the 2 pads are not connected, or merge the
  264. * unconnected pad to the existing block.
  265. * These blocks include 2 pads and the 2 pads are linked by a ratsnest.
  266. *
  267. * @param aRatsnestBuffer = a std::vector<RATSNEST_ITEM> buffer to fill with
  268. * new ratsnest items
  269. * @param aPadBuffer = a std::vector<D_PAD*> that is the list of pads to
  270. * consider
  271. * @param aPadIdxStart = starting index (within the pad list) for search
  272. * @param aPadIdxMax = ending index (within the pad list) for search
  273. * @param current_num_block = Last existing block number of pads
  274. * These block are created by the existing tracks analysis
  275. *
  276. * @return the last block number used
  277. */
  278. static int gen_rats_pad_to_pad( vector<RATSNEST_ITEM>& aRatsnestBuffer,
  279. std::vector<D_PAD*>& aPadBuffer,
  280. unsigned aPadIdxStart,
  281. unsigned aPadIdxMax,
  282. int current_num_block )
  283. {
  284. int dist_min, current_dist;
  285. D_PAD* ref_pad, * pad;
  286. for( unsigned ii = aPadIdxStart; ii < aPadIdxMax; ii++ )
  287. {
  288. ref_pad = aPadBuffer[ii];
  289. if( ref_pad->GetSubRatsnest() )
  290. continue; // Pad already connected
  291. dist_min = 0x7FFFFFFF;
  292. int padBlockToMergeIdx = -1; // Index in aPadBuffer for the "better"
  293. // pad found in block to merge
  294. for( unsigned jj = aPadIdxStart; jj < aPadIdxMax; jj++ )
  295. {
  296. if( ii == jj )
  297. continue;
  298. pad = aPadBuffer[jj];
  299. /* Compare distance between pads ("Manhattan" distance) */
  300. current_dist = abs( pad->m_Pos.x - ref_pad->m_Pos.x ) +
  301. abs( pad->m_Pos.y - ref_pad->m_Pos.y );
  302. if( dist_min > current_dist )
  303. {
  304. dist_min = current_dist;
  305. padBlockToMergeIdx = jj;
  306. }
  307. }
  308. if( padBlockToMergeIdx >= 0 )
  309. {
  310. pad = aPadBuffer[padBlockToMergeIdx];
  311. /* Update the block number
  312. * if the 2 pads are not already created : a new block is created
  313. */
  314. if( (pad->GetSubRatsnest() == 0)
  315. && (ref_pad->GetSubRatsnest() == 0) )
  316. {
  317. current_num_block++; // Creates a new block number (or
  318. // subratsnest)
  319. pad->SetSubRatsnest( current_num_block );
  320. ref_pad->SetSubRatsnest( current_num_block );
  321. }
  322. /* If a pad is already connected connected : merge the other pad in
  323. * the block */
  324. else
  325. {
  326. ref_pad->SetSubRatsnest( pad->GetSubRatsnest() );
  327. }
  328. /* Create the new ratsnest item */
  329. RATSNEST_ITEM rast;
  330. rast.SetNet( ref_pad->GetNet() );
  331. rast.m_Status = CH_ACTIF | CH_VISIBLE;
  332. rast.m_Lenght = dist_min;
  333. rast.m_PadStart = ref_pad;
  334. rast.m_PadEnd = pad;
  335. aRatsnestBuffer.push_back( rast );
  336. }
  337. }
  338. return current_num_block;
  339. }
  340. /**
  341. * Function to compute the full ratsnest (using the LEE algorithm )
  342. * In the functions tracks are not considered
  343. * This is only the "basic" ratsnest depending only on pads.
  344. *
  345. * - Create the sorted pad list (if necessary)
  346. * The active pads (i.e included in a net ) are called nodes
  347. * This pad list is sorted by net codes
  348. *
  349. * - Compute the ratsnest (LEE algorithm ):
  350. * a - Create the ratsnest between a not connected pad and its nearest
  351. * neighbor. Blocks of pads are created
  352. * b - Create the ratsnest between blocks:
  353. * Test the pads of the 1st block and create a link (ratsnest)
  354. * with the nearest pad found in an other block.
  355. * The other block is merged with the first block.
  356. * until only one block is left.
  357. *
  358. * A ratsnest can be seen as a logical connection.
  359. *
  360. * Update :
  361. * nb_nodes = Active pads count for the board
  362. * nb_links = link count for the board (logical connection count)
  363. * (there are n-1 links for an equipotent which have n active pads) .
  364. *
  365. */
  366. void PCB_BASE_FRAME::Build_Board_Ratsnest( wxDC* DC )
  367. {
  368. D_PAD* pad;
  369. int noconn;
  370. m_Pcb->m_NbNoconnect = 0;
  371. m_Pcb->m_FullRatsnest.clear();
  372. if( m_Pcb->GetPadsCount() == 0 )
  373. return;
  374. /* Created pad list and the net_codes if needed */
  375. if( (m_Pcb->m_Status_Pcb & NET_CODES_OK) == 0 )
  376. m_Pcb->m_NetInfo->BuildListOfNets();
  377. for( unsigned ii = 0; ii<m_Pcb->GetPadsCount(); ++ii )
  378. {
  379. pad = m_Pcb->m_NetInfo->GetPad( ii );
  380. pad->SetSubRatsnest( 0 );
  381. }
  382. if( m_Pcb->GetNodesCount() == 0 )
  383. return; /* No useful connections. */
  384. /* Ratsnest computation */
  385. DisplayRastnestInProgress = TRUE;
  386. unsigned current_net_code = 1; // First net code is analyzed.
  387. // (net_code = 0 -> no connect)
  388. noconn = 0;
  389. for( ; current_net_code < m_Pcb->m_NetInfo->GetCount(); current_net_code++ )
  390. {
  391. NETINFO_ITEM* net = m_Pcb->FindNet( current_net_code );
  392. if( net == NULL ) //Should not occur
  393. {
  394. DisplayError( this,
  395. wxT( "Build_Board_Ratsnest() error: net not found" ) );
  396. return;
  397. }
  398. net->m_RatsnestStartIdx = m_Pcb->GetRatsnestsCount();
  399. // Search for the last subratsnest already in use
  400. int num_block = 0;
  401. for( unsigned ii = 0; ii < net->m_ListPad.size(); ii++ )
  402. {
  403. pad = net->m_ListPad[ii];
  404. if( num_block < pad->GetSubRatsnest() )
  405. num_block = pad->GetSubRatsnest();
  406. }
  407. /* Compute the ratsnest relative to the current net */
  408. /* a - first pass : create the blocks from not already in block pads */
  409. int icnt = gen_rats_pad_to_pad( m_Pcb->m_FullRatsnest,
  410. net->m_ListPad,
  411. 0,
  412. net->m_ListPad.size(),
  413. num_block );
  414. /* b - blocks connection (Iteration) */
  415. while( icnt > 1 )
  416. {
  417. icnt = gen_rats_block_to_block( m_Pcb->m_FullRatsnest,
  418. net->m_ListPad,
  419. 0,
  420. net->m_ListPad.size() );
  421. net = m_Pcb->FindNet( current_net_code );
  422. }
  423. net->m_RatsnestEndIdx = m_Pcb->GetRatsnestsCount();
  424. /* sort by length */
  425. net = m_Pcb->FindNet( current_net_code );
  426. if( ( net->m_RatsnestEndIdx - net->m_RatsnestStartIdx ) > 1 )
  427. {
  428. RATSNEST_ITEM* rats = &m_Pcb->m_FullRatsnest[0];
  429. qsort( rats + net->m_RatsnestStartIdx,
  430. net->m_RatsnestEndIdx - net->m_RatsnestStartIdx,
  431. sizeof(RATSNEST_ITEM), sort_by_length );
  432. }
  433. }
  434. m_Pcb->m_NbNoconnect = noconn;
  435. m_Pcb->m_Status_Pcb |= LISTE_RATSNEST_ITEM_OK;
  436. // erase the ratsnest displayed on screen if needed
  437. for( unsigned ii = 0; ii < m_Pcb->GetRatsnestsCount(); ii++ )
  438. {
  439. if( !GetBoard()->IsElementVisible(RATSNEST_VISIBLE) ) // Clear VISIBLE flag
  440. m_Pcb->m_FullRatsnest[ii].m_Status &= ~CH_VISIBLE;
  441. if( DC )
  442. m_Pcb->m_FullRatsnest[ii].Draw( DrawPanel, DC, GR_XOR,
  443. wxPoint( 0, 0 ) );
  444. }
  445. }
  446. /**
  447. * function Displays the general ratsnest
  448. * Only ratsnest with the status bit CH_VISIBLE is set are displayed
  449. * @param aDC = the current device context (can be NULL)
  450. * @param aNetcode if > 0, Display only the ratsnest relative to the
  451. * corresponding net_code
  452. */
  453. void PCB_BASE_FRAME::DrawGeneralRatsnest( wxDC* aDC, int aNetcode )
  454. {
  455. if( ( m_Pcb->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK ) == 0 )
  456. return;
  457. if( ( m_Pcb->m_Status_Pcb & DO_NOT_SHOW_GENERAL_RASTNEST ) )
  458. return;
  459. if( aDC == NULL )
  460. return;
  461. int state = CH_VISIBLE | CH_ACTIF;
  462. for( unsigned ii = 0; ii < m_Pcb->GetRatsnestsCount(); ii++ )
  463. {
  464. RATSNEST_ITEM& item = m_Pcb->m_FullRatsnest[ii];
  465. if( ( item.m_Status & state ) != state )
  466. continue;
  467. if( ( aNetcode <= 0 ) || ( aNetcode == item.GetNet() ) )
  468. {
  469. item.Draw( DrawPanel, aDC, GR_XOR, wxPoint( 0, 0 ) );
  470. }
  471. }
  472. }
  473. /**
  474. * Function used by Tst_Ratsnest
  475. * Function like gen_rats_block_to_block(..)
  476. * Function testing the ratsnest between 2 blocks ( same net )
  477. * The search is made between pads in block 1 and the others blocks
  478. * The block n ( n > 1 ) is merged with block 1 by the smallest ratsnest
  479. * Difference between gen_rats_block_to_block(..):
  480. * The analysis is not made pads to pads but uses the general ratsnest list.
  481. * The function activate the smallest ratsnest between block 1 and the block n
  482. * (activate a logical connexion)
  483. * @param aRatsnestBuffer = the buffer to store NETINFO_ITEM* items
  484. * @param net = the current NETINFO_ITEM for the current net
  485. * output:
  486. * .state member of the ratsnest
  487. * @return blocks not connected count
  488. */
  489. static int tst_rats_block_to_block( NETINFO_ITEM* net,
  490. vector<RATSNEST_ITEM>& aRatsnestBuffer )
  491. {
  492. int current_num_block, min_block;
  493. RATSNEST_ITEM* rats, * min_rats;
  494. /* Search a link from a block to an other block */
  495. min_rats = NULL;
  496. for( unsigned ii = net->m_RatsnestStartIdx;
  497. ii < net->m_RatsnestEndIdx;
  498. ii++ )
  499. {
  500. rats = &aRatsnestBuffer[ii];
  501. if( rats->m_PadStart->GetSubRatsnest() ==
  502. rats->m_PadEnd->GetSubRatsnest() ) // Same block
  503. continue;
  504. if( min_rats == NULL )
  505. min_rats = rats;
  506. else if( min_rats->m_Lenght > rats->m_Lenght )
  507. min_rats = rats;
  508. }
  509. if( min_rats == NULL )
  510. return 1;
  511. /* At this point we have found a link between 2 different blocks (clusters)
  512. * we must set its status to ACTIVE and merge the 2 blocks
  513. */
  514. min_rats->m_Status |= CH_ACTIF;
  515. current_num_block = min_rats->m_PadStart->GetSubRatsnest();
  516. min_block = min_rats->m_PadEnd->GetSubRatsnest();
  517. if( min_block > current_num_block )
  518. EXCHG( min_block, current_num_block );
  519. /* Merging the 2 blocks in one cluster */
  520. for( unsigned ii = 0; ii < net->m_ListPad.size(); ii++ )
  521. {
  522. if( net->m_ListPad[ii]->GetSubRatsnest() == current_num_block )
  523. {
  524. net->m_ListPad[ii]->SetSubRatsnest( min_block );
  525. }
  526. }
  527. return current_num_block;
  528. }
  529. /**
  530. * Function used by Tst_Ratsnest_general
  531. * The general ratsnest list must exists
  532. * Activates the ratsnest between 2 pads ( supposes du meme net )
  533. * The function links 1 pad not already connected an other pad and activate
  534. * some blocks linked by a ratsnest
  535. * Its test only the existing ratsnest and activate some ratsnest (status bit
  536. * CH_ACTIF set)
  537. *
  538. * @param start_rat_list = starting address for the ratsnest list
  539. * @param end_rat_list = ending address for the ratsnest list
  540. * @param current_num_block = last block number (computed from the track
  541. * analysis)
  542. *
  543. * output:
  544. * ratsnest list (status member set)
  545. * and pad list (m_SubRatsnest set)
  546. *
  547. * @return new block number
  548. */
  549. static int tst_rats_pad_to_pad( int current_num_block,
  550. RATSNEST_ITEM* start_rat_list,
  551. RATSNEST_ITEM* end_rat_list )
  552. {
  553. D_PAD* pad_start, * pad_end;
  554. RATSNEST_ITEM* chevelu;
  555. for( chevelu = start_rat_list; chevelu < end_rat_list; chevelu++ )
  556. {
  557. pad_start = chevelu->m_PadStart;
  558. pad_end = chevelu->m_PadEnd;
  559. /* Update the block if the 2 pads are not connected : a new block is
  560. * created
  561. */
  562. if( (pad_start->GetSubRatsnest() == 0)
  563. && (pad_end->GetSubRatsnest() == 0) )
  564. {
  565. current_num_block++;
  566. pad_start->SetSubRatsnest( current_num_block );
  567. pad_end->SetSubRatsnest( current_num_block );
  568. chevelu->m_Status |= CH_ACTIF;
  569. }
  570. /* If a pad is already connected : the other is merged in the current
  571. * block */
  572. else if( pad_start->GetSubRatsnest() == 0 )
  573. {
  574. pad_start->SetSubRatsnest( pad_end->GetSubRatsnest() );
  575. chevelu->m_Status |= CH_ACTIF;
  576. }
  577. else if( pad_end->GetSubRatsnest() == 0 )
  578. {
  579. pad_end->SetSubRatsnest( pad_start->GetSubRatsnest() );
  580. chevelu->m_Status |= CH_ACTIF;
  581. }
  582. }
  583. return current_num_block;
  584. }
  585. /* Compute the active ratsnest
  586. * The general ratsnest list must exists
  587. * Compute the ACTIVE ratsnest in the general ratsnest list
  588. * if ref_netcode == 0, test all nets, else test only ref_netcode
  589. */
  590. void PCB_BASE_FRAME::Tst_Ratsnest( wxDC* DC, int ref_netcode )
  591. {
  592. RATSNEST_ITEM* rats;
  593. D_PAD* pad;
  594. NETINFO_ITEM* net;
  595. if( m_Pcb->GetPadsCount() == 0 )
  596. return;
  597. if( (m_Pcb->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK) == 0 )
  598. Build_Board_Ratsnest( DC );
  599. for( int net_code = 1;
  600. net_code < (int) m_Pcb->m_NetInfo->GetCount();
  601. net_code++ )
  602. {
  603. net = m_Pcb->FindNet( net_code );
  604. if( net == NULL ) //Should not occur
  605. {
  606. DisplayError( this, wxT( "Tst_Ratsnest() error: net not found" ) );
  607. return;
  608. }
  609. if( ref_netcode && (net_code != ref_netcode) )
  610. continue;
  611. int num_block = 0;
  612. for( unsigned ip = 0; ip < net->m_ListPad.size(); ip++ )
  613. {
  614. pad = net->m_ListPad[ip];
  615. int subnet = pad->GetSubNet();
  616. pad->SetSubRatsnest( subnet );
  617. num_block = MAX( num_block, subnet );
  618. }
  619. for( unsigned ii = net->m_RatsnestStartIdx;
  620. ii < net->m_RatsnestEndIdx;
  621. ii++ )
  622. {
  623. m_Pcb->m_FullRatsnest[ii].m_Status &= ~CH_ACTIF;
  624. }
  625. /* a - test connection between pads */
  626. rats = &m_Pcb->m_FullRatsnest[0];
  627. int icnt = tst_rats_pad_to_pad( num_block,
  628. rats + net->m_RatsnestStartIdx,
  629. rats + net->m_RatsnestEndIdx );
  630. /* b - test connection between blocks (Iteration) */
  631. while( icnt > 1 )
  632. {
  633. icnt = tst_rats_block_to_block( net, m_Pcb->m_FullRatsnest );
  634. }
  635. }
  636. m_Pcb->m_NbNoconnect = 0;
  637. for( unsigned ii = 0; ii < m_Pcb->GetRatsnestsCount(); ii++ )
  638. {
  639. if( m_Pcb->m_FullRatsnest[ii].m_Status & CH_ACTIF )
  640. m_Pcb->m_NbNoconnect++;
  641. }
  642. }
  643. /**
  644. * Function Test_1_Net_Ratsnest
  645. * Compute the ratsnest relative to the net "net_code"
  646. * @param aDC - Device context to draw on.
  647. * @param aNetcode = netcode used to compute the ratsnest.
  648. */
  649. int PCB_BASE_FRAME::Test_1_Net_Ratsnest( wxDC* aDC, int aNetcode )
  650. {
  651. DisplayRastnestInProgress = FALSE;
  652. DrawGeneralRatsnest( aDC, aNetcode );
  653. Tst_Ratsnest( aDC, aNetcode );
  654. DrawGeneralRatsnest( aDC, aNetcode );
  655. return m_Pcb->GetRatsnestsCount();
  656. }
  657. /*
  658. * Function build_ratsnest_module
  659. * Build a ratsnest relative to one footprint. This is a simplified computation
  660. * used only in move footprint. It is not optimal, but it is fast and sufficient
  661. * to help a footprint placement
  662. * It shows the connections from a pad to the nearest connected pad
  663. *
  664. * The ratsnest has 2 sections:
  665. * - An "internal" ratsnest relative to pads of this footprint which are
  666. * in the same net.
  667. * this ratsnest section is computed once.
  668. * - An "external" ratsnest connecting a pad of this footprint to an other
  669. * pad (in an other footprint)
  670. * The ratsnest section must be computed for each new position
  671. */
  672. void PCB_BASE_FRAME::build_ratsnest_module( MODULE* aModule )
  673. {
  674. static unsigned pads_module_count; // node count (node = pad with a net
  675. // code) for the footprint being moved
  676. static unsigned internalRatsCount; // number of internal links (links
  677. // between pads of the module)
  678. D_PAD** baseListePad;
  679. D_PAD* pad_ref;
  680. D_PAD* pad_externe;
  681. int current_net_code;
  682. int distance;
  683. wxPoint pad_pos; // True pad position according to the
  684. // current footprint position
  685. if( (GetBoard()->m_Status_Pcb & LISTE_PAD_OK) == 0 )
  686. {
  687. GetBoard()->m_Status_Pcb = 0;
  688. GetBoard()->m_NetInfo->BuildListOfNets();
  689. }
  690. /* Compute the "local" ratsnest if needed (when this footprint starts move)
  691. * and the list of external pads to consider, i.e pads in others
  692. * footprints which are "connected" to
  693. * a pad in the current footprint
  694. */
  695. if( (m_Pcb->m_Status_Pcb & RATSNEST_ITEM_LOCAL_OK) != 0 )
  696. goto CalculateExternalRatsnest;
  697. /* Compute the "internal" ratsnest, i.e the links between the current
  698. *footprint pads */
  699. s_localPadBuffer.clear();
  700. m_Pcb->m_LocalRatsnest.clear();
  701. for( pad_ref = aModule->m_Pads; pad_ref != NULL; pad_ref = pad_ref->Next() )
  702. {
  703. if( pad_ref->GetNet() == 0 )
  704. continue;
  705. s_localPadBuffer.push_back( pad_ref );
  706. pad_ref->SetSubRatsnest( 0 );
  707. pad_ref->SetSubNet( 0 );
  708. }
  709. pads_module_count = s_localPadBuffer.size();
  710. if( pads_module_count == 0 )
  711. return; /* no connection! */
  712. qsort( &s_localPadBuffer[0],
  713. pads_module_count,
  714. sizeof(D_PAD*),
  715. sortByNetcode );
  716. /* Build the list of pads linked to the current footprint pads */
  717. DisplayRastnestInProgress = FALSE;
  718. current_net_code = 0;
  719. for( unsigned ii = 0; ii < pads_module_count; ii++ )
  720. {
  721. pad_ref = s_localPadBuffer[ii];
  722. if( pad_ref->GetNet() == current_net_code )
  723. continue;
  724. // A new net was found, load all pads of others modules members of this
  725. // net:
  726. NETINFO_ITEM* net = m_Pcb->FindNet( pad_ref->GetNet() );
  727. if( net == NULL ) //Should not occur
  728. {
  729. DisplayError( this,
  730. wxT( "build_ratsnest_module() error: net not found" ) );
  731. return;
  732. }
  733. for( unsigned jj = 0; jj < net->m_ListPad.size(); jj++ )
  734. {
  735. pad_externe = net->m_ListPad[jj];
  736. if( pad_externe->GetParent() == aModule )
  737. continue;
  738. pad_externe->SetSubRatsnest( 0 );
  739. pad_externe->SetSubNet( 0 );
  740. s_localPadBuffer.push_back( pad_externe );
  741. }
  742. }
  743. /* Sort the pad list by net_code */
  744. baseListePad = &s_localPadBuffer[0];
  745. qsort( baseListePad + pads_module_count,
  746. s_localPadBuffer.size() - pads_module_count,
  747. sizeof(D_PAD*), sortByNetcode );
  748. /* Compute the internal rats nest:
  749. * this is the same as general ratsnest, but considers only the current
  750. * footprint pads it is therefore not time consuming, and it is made only
  751. * once
  752. */
  753. current_net_code = s_localPadBuffer[0]->GetNet();
  754. for( unsigned ii = 0; ii < pads_module_count; ii++ )
  755. {
  756. /* Search the end of pad list relative to the current net */
  757. unsigned jj = ii + 1;
  758. for( ; jj <= pads_module_count; jj++ )
  759. {
  760. if( jj >= pads_module_count )
  761. break;
  762. if( s_localPadBuffer[jj]->GetNet() != current_net_code )
  763. break;
  764. }
  765. /* End of list found: */
  766. /* a - first step of lee algorithm : build the pad to pad link list */
  767. int icnt = gen_rats_pad_to_pad( m_Pcb->m_LocalRatsnest,
  768. s_localPadBuffer,
  769. ii, jj, 0 );
  770. /* b - second step of lee algorithm : build the block to block link
  771. *list (Iteration) */
  772. while( icnt > 1 )
  773. {
  774. icnt = gen_rats_block_to_block( m_Pcb->m_LocalRatsnest,
  775. s_localPadBuffer,
  776. ii, jj );
  777. }
  778. ii = jj;
  779. if( ii < s_localPadBuffer.size() )
  780. current_net_code = s_localPadBuffer[ii]->GetNet();
  781. }
  782. internalRatsCount = m_Pcb->m_LocalRatsnest.size();
  783. /* set the ratsnest status, flag LOCAL_RATSNEST_ITEM */
  784. for( unsigned ii = 0; ii < m_Pcb->m_LocalRatsnest.size(); ii++ )
  785. {
  786. m_Pcb->m_LocalRatsnest[ii].m_Status = LOCAL_RATSNEST_ITEM;
  787. }
  788. m_Pcb->m_Status_Pcb |= RATSNEST_ITEM_LOCAL_OK;
  789. /* This section computes the "external" ratsnest: must be done when the
  790. * footprint position changes
  791. */
  792. CalculateExternalRatsnest:
  793. /* This section search:
  794. * for each current module pad the nearest neighbor external pad (of
  795. * course for the same net code).
  796. * For each current footprint cluster of pad (pads having the same net
  797. * code),
  798. * we search the smaller rats nest.
  799. * so, for each net, only one rats nest item is created
  800. */
  801. RATSNEST_ITEM local_rats;
  802. local_rats.m_Lenght = 0x7FFFFFFF;
  803. local_rats.m_Status = 0;
  804. bool addRats = false;
  805. if( internalRatsCount < m_Pcb->m_LocalRatsnest.size() )
  806. m_Pcb->m_LocalRatsnest.erase(
  807. m_Pcb->m_LocalRatsnest.begin() + internalRatsCount,
  808. m_Pcb->m_LocalRatsnest.end() );
  809. current_net_code = s_localPadBuffer[0]->GetNet();
  810. for( unsigned ii = 0; ii < pads_module_count; ii++ )
  811. {
  812. pad_ref = s_localPadBuffer[ii];
  813. if( pad_ref->GetNet() != current_net_code )
  814. {
  815. /* if needed, creates a new ratsnest for the old net */
  816. if( addRats )
  817. {
  818. m_Pcb->m_LocalRatsnest.push_back( local_rats );
  819. }
  820. addRats = false;
  821. current_net_code = pad_ref->GetNet();
  822. local_rats.m_Lenght = 0x7FFFFFFF;
  823. }
  824. pad_pos = pad_ref->m_Pos - g_Offset_Module;
  825. // Search the nearest external pad of this current pad
  826. for( unsigned jj = pads_module_count;
  827. jj < s_localPadBuffer.size();
  828. jj++ )
  829. {
  830. pad_externe = s_localPadBuffer[jj];
  831. /* we search pads having the same net code */
  832. if( pad_externe->GetNet() < pad_ref->GetNet() )
  833. continue;
  834. if( pad_externe->GetNet() > pad_ref->GetNet() ) // remember pads
  835. // are sorted by
  836. // net code
  837. break;
  838. distance = abs( pad_externe->m_Pos.x - pad_pos.x ) +
  839. abs( pad_externe->m_Pos.y - pad_pos.y );
  840. if( distance < local_rats.m_Lenght )
  841. {
  842. local_rats.m_PadStart = pad_ref;
  843. local_rats.m_PadEnd = pad_externe;
  844. local_rats.SetNet( pad_ref->GetNet() );
  845. local_rats.m_Lenght = distance;
  846. local_rats.m_Status = 0;
  847. addRats = true;
  848. }
  849. }
  850. }
  851. if( addRats ) // Ensure the last created rats nest item is stored in buffer
  852. m_Pcb->m_LocalRatsnest.push_back( local_rats );
  853. }
  854. /*
  855. * Display the ratsnest of a moving footprint, computed by
  856. * build_ratsnest_module()
  857. */
  858. void PCB_BASE_FRAME::trace_ratsnest_module( wxDC* DC )
  859. {
  860. if( DC == NULL )
  861. return;
  862. if( ( m_Pcb->m_Status_Pcb & RATSNEST_ITEM_LOCAL_OK ) == 0 )
  863. return;
  864. int tmpcolor = g_ColorsSettings.GetItemColor(RATSNEST_VISIBLE);
  865. for( unsigned ii = 0; ii < m_Pcb->m_LocalRatsnest.size(); ii++ )
  866. {
  867. RATSNEST_ITEM* rats = &m_Pcb->m_LocalRatsnest[ii];
  868. if( rats->m_Status & LOCAL_RATSNEST_ITEM )
  869. {
  870. g_ColorsSettings.SetItemColor(RATSNEST_VISIBLE, YELLOW);
  871. rats->Draw( DrawPanel, DC, GR_XOR, g_Offset_Module );
  872. }
  873. else
  874. {
  875. g_ColorsSettings.SetItemColor(RATSNEST_VISIBLE, tmpcolor);
  876. wxPoint tmp = rats->m_PadStart->m_Pos;
  877. rats->m_PadStart->m_Pos -= g_Offset_Module;
  878. rats->Draw( DrawPanel, DC, GR_XOR, wxPoint( 0, 0 ) );
  879. rats->m_PadStart->m_Pos = tmp;
  880. }
  881. }
  882. g_ColorsSettings.SetItemColor(RATSNEST_VISIBLE, tmpcolor);
  883. }
  884. /*
  885. * Construction of the list mode display for quick calculation
  886. * in real time the net of a pad in the paths of a track starting
  887. * on the pad.
  888. *
  889. * Parameters:
  890. * Pad_ref (if null: 0 has put the number of ratsnest)
  891. * Ox, oy = coord of extremity of the track record
  892. * Init (flag)
  893. * = 0: update of the ratsnest.
  894. * <> 0: Creating a list
  895. */
  896. /* Buffer to store pads coordinates when creating a track.
  897. * these pads are members of the net
  898. * and when the mouse is moved, the g_MaxLinksShowed links to neighbors are
  899. * drawn
  900. */
  901. static std::vector <wxPoint> s_RatsnestMouseToPads;
  902. static wxPoint s_CursorPos; // Coordinate of the moving point (mouse cursor and
  903. // end of current track segment)
  904. /* Used by build_ratsnest_pad(): sort function by link length (manhattan
  905. * distance)
  906. */
  907. static bool sort_by_localnetlength( const wxPoint& ref, const wxPoint& compare )
  908. {
  909. wxPoint deltaref = ref - s_CursorPos;
  910. wxPoint deltacmp = compare - s_CursorPos;
  911. // = distance between ref coordinate and pad ref
  912. int lengthref = abs( deltaref.x ) + abs( deltaref.y );
  913. // distance between ref coordinate and the other pad
  914. int lengthcmp = abs( deltacmp.x ) + abs( deltacmp.y );
  915. return lengthref < lengthcmp;
  916. }
  917. void PCB_BASE_FRAME::build_ratsnest_pad( BOARD_ITEM* ref, const wxPoint& refpos, bool init )
  918. {
  919. int current_net_code = 0, conn_number = 0;
  920. D_PAD* pad_ref = NULL;
  921. if( ( ( m_Pcb->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK ) == 0 )
  922. || ( ( m_Pcb->m_Status_Pcb & LISTE_PAD_OK ) == 0 )
  923. || ( ( m_Pcb->m_Status_Pcb & NET_CODES_OK ) == 0 ) )
  924. {
  925. s_RatsnestMouseToPads.clear();
  926. return;
  927. }
  928. s_CursorPos = refpos;
  929. if( init )
  930. {
  931. s_RatsnestMouseToPads.clear();
  932. if( ref == NULL )
  933. return;
  934. switch( ref->Type() )
  935. {
  936. case TYPE_PAD:
  937. pad_ref = (D_PAD*) ref;
  938. current_net_code = pad_ref->GetNet();
  939. conn_number = pad_ref->GetSubNet();
  940. break;
  941. case TYPE_TRACK:
  942. case TYPE_VIA:
  943. {
  944. TRACK* track_ref = (TRACK*) ref;
  945. current_net_code = track_ref->GetNet();
  946. conn_number = track_ref->GetSubNet();
  947. break;
  948. }
  949. default:
  950. ;
  951. }
  952. if( current_net_code <= 0 )
  953. return;
  954. NETINFO_ITEM* net = m_Pcb->FindNet( current_net_code );
  955. if( net == NULL ) // Should not occur
  956. {
  957. DisplayError( this,
  958. wxT( "build_ratsnest_pad() error: net not found" ) );
  959. return;
  960. }
  961. // Create a list of pads candidates ( pads not already connected to the
  962. // current track:
  963. for( unsigned ii = 0; ii < net->m_ListPad.size(); ii++ )
  964. {
  965. D_PAD* pad = net->m_ListPad[ii];
  966. if( pad == pad_ref )
  967. continue;
  968. if( !pad->GetSubNet() || (pad->GetSubNet() != conn_number) )
  969. s_RatsnestMouseToPads.push_back( pad->m_Pos );
  970. }
  971. } /* end if Init */
  972. if( s_RatsnestMouseToPads.size() > 1 )
  973. sort( s_RatsnestMouseToPads.begin(),
  974. s_RatsnestMouseToPads.end(), sort_by_localnetlength );
  975. }
  976. /*
  977. * Displays a "ratsnest" during track creation
  978. */
  979. void PCB_BASE_FRAME::trace_ratsnest_pad( wxDC* DC )
  980. {
  981. if( DC == NULL )
  982. return;
  983. if( s_RatsnestMouseToPads.size() == 0 )
  984. return;
  985. GRSetDrawMode( DC, GR_XOR );
  986. for( int ii = 0; ii < (int) s_RatsnestMouseToPads.size(); ii++ )
  987. {
  988. if( ii >= g_MaxLinksShowed )
  989. break;
  990. GRLine( &DrawPanel->m_ClipBox, DC, s_CursorPos,
  991. s_RatsnestMouseToPads[ii], 0, YELLOW );
  992. }
  993. }