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.

889 lines
29 KiB

14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
17 years ago
17 years ago
13 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
17 years ago
17 years ago
14 years ago
14 years ago
14 years ago
  1. /**
  2. * @file ratsnest.cpp
  3. * @brief Ratsnets functions.
  4. */
  5. #include <fctsys.h>
  6. #include <gr_basic.h>
  7. #include <common.h>
  8. #include <class_drawpanel.h>
  9. #include <colors_selection.h>
  10. #include <wxBasePcbFrame.h>
  11. #include <macros.h>
  12. #include <class_board.h>
  13. #include <class_module.h>
  14. #include <class_track.h>
  15. #include <pcbnew.h>
  16. #include <minimun_spanning_tree.h>
  17. /**
  18. * @brief class MIN_SPAN_TREE_PADS (derived from MIN_SPAN_TREE) specialize
  19. * the basic class to calculate a minimum spanning tree from a list of pads,
  20. * and to add this tree as ratsnest to the main ratsnest list.
  21. */
  22. class MIN_SPAN_TREE_PADS: public MIN_SPAN_TREE
  23. {
  24. friend class MIN_SPAN_TREE;
  25. public:
  26. std::vector <D_PAD*>* m_PadsList; // list of pads:
  27. /* these pads are the parents of nodes of the tree.
  28. * Each node position is the corresponding pad position.
  29. * This pad list is used to evaluate the weight of an edge in tree.
  30. * -> edge = link between 2 nodes = links between 2 pads.
  31. * -> weight of a link = rectilinear distance between the 2 pads
  32. */
  33. public:
  34. MIN_SPAN_TREE_PADS(): MIN_SPAN_TREE()
  35. {
  36. m_PadsList = NULL;
  37. }
  38. void MSP_Init( std::vector <D_PAD*>* aPadsList )
  39. {
  40. m_PadsList = aPadsList;
  41. MIN_SPAN_TREE::MSP_Init( (int) m_PadsList->size() );
  42. }
  43. /**
  44. * Function AddTreeToRatsnest
  45. * Adds the current minimum spanning tree as ratsnest items
  46. * to the main ratsnest list
  47. * @param aRatsnestList = the main ratsnest list
  48. */
  49. void AddTreeToRatsnest( std::vector<RATSNEST_ITEM> &aRatsnestList );
  50. /**
  51. * Function GetWeight
  52. * calculates the weight between 2 items
  53. * NOTE: The weight between a node and itself should be 0
  54. * @param aItem1 = first item
  55. * @param aItem2 = other item
  56. * @return the weight between items ( the rectilinear distance )
  57. */
  58. int GetWeight( int aItem1, int aItem2 );
  59. };
  60. void MIN_SPAN_TREE_PADS::AddTreeToRatsnest( std::vector<RATSNEST_ITEM> &aRatsnestList )
  61. {
  62. std::vector<D_PAD*> & padsBuffer = *m_PadsList;
  63. int netcode = padsBuffer[0]->GetNet();
  64. // Note: to get edges in minimum spanning tree,
  65. // the index value 0 is not used: it is just
  66. // the entry point of the minimum spanning tree.
  67. // The first edge (i.e. rastnest) starts at index 1
  68. for( int ii = 1; ii < m_Size; ii++ )
  69. {
  70. // Create the new ratsnest
  71. RATSNEST_ITEM net;
  72. net.SetNet( netcode );
  73. net.m_Status = CH_ACTIF | CH_VISIBLE;
  74. net.m_Lenght = GetDist(ii);
  75. net.m_PadStart = padsBuffer[ii];
  76. net.m_PadEnd = padsBuffer[ GetWhoTo(ii) ];
  77. aRatsnestList.push_back( net );
  78. }
  79. }
  80. /* Function GetWeight
  81. * calculates the weight between 2 items
  82. * Here it calculate the rectilinear distance between 2 pads (2 items)
  83. * NOTE: The weight between a node and itself should be <=0
  84. * aItem1 and aItem2 are the 2 items
  85. * return the rectilinear distance
  86. */
  87. int MIN_SPAN_TREE_PADS::GetWeight( int aItem1, int aItem2 )
  88. {
  89. // NOTE: The distance (weight) between a node and itself should be 0
  90. // so we add 1 to other distances to be sure we never have 0
  91. // in cases other than a node and itself
  92. D_PAD* pad1 = (*m_PadsList)[aItem1];
  93. D_PAD* pad2 = (*m_PadsList)[aItem2];
  94. if( pad1 == pad2 )
  95. return 0;
  96. int weight = abs( pad2->GetPosition().x - pad1->GetPosition().x ) +
  97. abs( pad2->GetPosition().y - pad1->GetPosition().y );
  98. return weight + 1;
  99. }
  100. /* Note about the ratsnest computation:
  101. * Building the general ratsnest:
  102. * For each net, the ratsnest is the set of lines connecting pads,
  103. * using the shorter distance
  104. * Therefore this problem is well known in graph therory, and sloved
  105. * using the "minimum spanning tree".
  106. * We use here an algorithm to build the minimum spanning tree known as Prim's algorithm
  107. */
  108. /**
  109. * Function Compile_Ratsnest
  110. * Create the entire board ratsnest.
  111. * Must be called after a board change (changes for
  112. * pads, footprints or a read netlist ).
  113. * @param aDC = the current device context (can be NULL)
  114. * @param aDisplayStatus : if true, display the computation results
  115. */
  116. void PCB_BASE_FRAME::Compile_Ratsnest( wxDC* aDC, bool aDisplayStatus )
  117. {
  118. wxString msg;
  119. GetBoard()->m_Status_Pcb = 0; // we want a full ratsnest computation, from the scratch
  120. ClearMsgPanel();
  121. // Rebuild the full pads and net info list
  122. RecalculateAllTracksNetcode();
  123. if( aDisplayStatus )
  124. {
  125. msg.Printf( wxT( " %d" ), m_Pcb->GetPadCount() );
  126. AppendMsgPanel( wxT( "Pads" ), msg, RED );
  127. msg.Printf( wxT( " %d" ), m_Pcb->GetNetCount() );
  128. AppendMsgPanel( wxT( "Nets" ), msg, CYAN );
  129. }
  130. /* Compute the full ratsnest
  131. * which can be see like all the possible links or logical connections.
  132. * some of them are active (no track connected) and others are inactive
  133. * (when tracks connect pads)
  134. * This full ratsnest is not modified by track editing.
  135. * It changes only when a netlist is read, or footprints are modified
  136. */
  137. Build_Board_Ratsnest();
  138. // Compute the pad connections due to the existing tracks (physical connections)
  139. TestConnections();
  140. /* Compute the active ratsnest, i.e. the unconnected links
  141. */
  142. TestForActiveLinksInRatsnest( 0 );
  143. // Redraw the active ratsnest ( if enabled )
  144. if( GetBoard()->IsElementVisible(RATSNEST_VISIBLE) && aDC )
  145. DrawGeneralRatsnest( aDC, 0 );
  146. if( aDisplayStatus )
  147. SetMsgPanel( m_Pcb );
  148. }
  149. /* Sort function used by QSORT
  150. * Sort pads by net code
  151. */
  152. static bool sortByNetcode( const D_PAD* const & ref, const D_PAD* const & item )
  153. {
  154. return ref->GetNet() < item->GetNet();
  155. }
  156. /**
  157. * Function to compute the full ratsnest
  158. * This is the "basic" ratsnest depending only on pads.
  159. *
  160. * Create the sorted pad list (if necessary)
  161. * The active pads (i.e included in a net ) are called nodes
  162. * This pad list is sorted by net codes
  163. * A ratsnest can be seen as a logical connection.
  164. *
  165. * Update :
  166. * nb_nodes = Active pads count for the board
  167. * nb_links = link count for the board (logical connection count)
  168. * (there are n-1 links in a net which counting n active pads) .
  169. */
  170. void PCB_BASE_FRAME::Build_Board_Ratsnest()
  171. {
  172. D_PAD* pad;
  173. int noconn;
  174. m_Pcb->SetUnconnectedNetCount( 0 );
  175. m_Pcb->m_FullRatsnest.clear();
  176. if( m_Pcb->GetPadCount() == 0 )
  177. return;
  178. // Created pad list and the net_codes if needed
  179. if( (m_Pcb->m_Status_Pcb & NET_CODES_OK) == 0 )
  180. m_Pcb->BuildListOfNets();
  181. for( unsigned ii = 0; ii<m_Pcb->GetPadCount(); ++ii )
  182. {
  183. pad = m_Pcb->GetPad( ii );
  184. pad->SetSubRatsnest( 0 );
  185. }
  186. if( m_Pcb->GetNodesCount() == 0 )
  187. return; // No useful connections.
  188. // Ratsnest computation
  189. unsigned current_net_code = 1; // First net code is analyzed.
  190. // (net_code = 0 -> no connect)
  191. noconn = 0;
  192. MIN_SPAN_TREE_PADS min_spanning_tree;
  193. for( ; current_net_code < m_Pcb->GetNetCount(); current_net_code++ )
  194. {
  195. NETINFO_ITEM* net = m_Pcb->FindNet( current_net_code );
  196. if( net == NULL ) //Should not occur
  197. {
  198. wxMessageBox( wxT( "Build_Board_Ratsnest() error: net not found" ) );
  199. return;
  200. }
  201. net->m_RatsnestStartIdx = m_Pcb->GetRatsnestsCount();
  202. min_spanning_tree.MSP_Init( &net->m_PadInNetList );
  203. min_spanning_tree.BuildTree();
  204. min_spanning_tree.AddTreeToRatsnest( m_Pcb->m_FullRatsnest );
  205. net->m_RatsnestEndIdx = m_Pcb->GetRatsnestsCount();
  206. }
  207. m_Pcb->SetUnconnectedNetCount( noconn );
  208. m_Pcb->m_Status_Pcb |= LISTE_RATSNEST_ITEM_OK;
  209. // Update the ratsnest display option (visible/invisible) flag
  210. for( unsigned ii = 0; ii < m_Pcb->GetRatsnestsCount(); ii++ )
  211. {
  212. if( !GetBoard()->IsElementVisible(RATSNEST_VISIBLE) ) // Clear VISIBLE flag
  213. m_Pcb->m_FullRatsnest[ii].m_Status &= ~CH_VISIBLE;
  214. }
  215. }
  216. /**
  217. * function DrawGeneralRatsnest
  218. * Only ratsnest items with the status bit CH_VISIBLE set are displayed
  219. * @param aDC = the current device context (can be NULL)
  220. * @param aNetcode: if > 0, Display only the ratsnest relative to the
  221. * corresponding net_code
  222. */
  223. void PCB_BASE_FRAME::DrawGeneralRatsnest( wxDC* aDC, int aNetcode )
  224. {
  225. if( ( m_Pcb->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK ) == 0 )
  226. return;
  227. if( ( m_Pcb->m_Status_Pcb & DO_NOT_SHOW_GENERAL_RASTNEST ) )
  228. return;
  229. if( aDC == NULL )
  230. return;
  231. const int state = CH_VISIBLE | CH_ACTIF;
  232. for( unsigned ii = 0; ii < m_Pcb->GetRatsnestsCount(); ii++ )
  233. {
  234. RATSNEST_ITEM& item = m_Pcb->m_FullRatsnest[ii];
  235. if( ( item.m_Status & state ) != state )
  236. continue;
  237. if( ( aNetcode <= 0 ) || ( aNetcode == item.GetNet() ) )
  238. {
  239. item.Draw( m_canvas, aDC, GR_XOR, wxPoint( 0, 0 ) );
  240. }
  241. }
  242. }
  243. /**
  244. * Function used by TestForActiveLinksInRatsnest
  245. * Function testing the ratsnest between 2 blocks ( of the same net )
  246. * The search is made between pads in block 1 and the others blocks
  247. * The block n ( n > 1 ) is merged with block 1 and linked by the smallest ratsnest
  248. * between block 1 and the block n (activate the logical connection)
  249. * @param aRatsnestBuffer = the buffer to store NETINFO_ITEM* items
  250. * @param aNetinfo = the current NETINFO_ITEM for the current net
  251. * output: .state member, bit CH_ACTIF of the ratsnest item
  252. * @return last subratsnest id in use
  253. */
  254. static int tst_links_between_blocks( NETINFO_ITEM* aNetinfo,
  255. std::vector<RATSNEST_ITEM>& aRatsnestBuffer )
  256. {
  257. int subratsnest_id, min_id;
  258. RATSNEST_ITEM* link, * best_link;
  259. // Search a link from a block to an other block
  260. best_link = NULL;
  261. for( unsigned ii = aNetinfo->m_RatsnestStartIdx; ii < aNetinfo->m_RatsnestEndIdx; ii++ )
  262. {
  263. link = &aRatsnestBuffer[ii];
  264. // If this link joints 2 pads inside the same block, do nothing
  265. // (these pads are already connected)
  266. if( link->m_PadStart->GetSubRatsnest() == link->m_PadEnd->GetSubRatsnest() )
  267. continue;
  268. // This link joints 2 pads of different blocks: this is a candidate,
  269. // but we want to select the shorter link, so use it only if it is shorter
  270. // than the previous candidate:
  271. if( best_link == NULL ) // no candidate
  272. best_link = link;
  273. else if( best_link->m_Lenght > link->m_Lenght ) // It is a better candidate.
  274. best_link = link;
  275. }
  276. if( best_link == NULL )
  277. return 1;
  278. /* At this point we have found a link between 2 different blocks (subratsnest)
  279. * we must set its status to ACTIVE and merge the 2 blocks
  280. */
  281. best_link->m_Status |= CH_ACTIF;
  282. subratsnest_id = best_link->m_PadStart->GetSubRatsnest();
  283. min_id = best_link->m_PadEnd->GetSubRatsnest();
  284. if( min_id > subratsnest_id )
  285. EXCHG( min_id, subratsnest_id );
  286. // Merge the 2 blocks in one sub ratsnest:
  287. for( unsigned ii = 0; ii < aNetinfo->m_PadInNetList.size(); ii++ )
  288. {
  289. if( aNetinfo->m_PadInNetList[ii]->GetSubRatsnest() == subratsnest_id )
  290. {
  291. aNetinfo->m_PadInNetList[ii]->SetSubRatsnest( min_id );
  292. }
  293. }
  294. return subratsnest_id;
  295. }
  296. /**
  297. * Function used by TestForActiveLinksInRatsnest_general
  298. * The general ratsnest list must exists because this function explores this ratsnest
  299. * Activates (i.e. set the CH_ACTIF flag) the ratsnest links between 2 pads when
  300. * at least one pad not already connected (SubRatsnest = 0)
  301. * and actives the corresponding link
  302. *
  303. * @param aFirstItem = starting address for the ratsnest list
  304. * @param aLastItem = ending address for the ratsnest list
  305. * @param aCurrSubRatsnestId = last sub ratsnest id in use (computed from the track
  306. * analysis)
  307. *
  308. * output:
  309. * ratsnest list (status member bit CH_ACTIF set)
  310. * and pads linked (m_SubRatsnest value set)
  311. *
  312. * @return new block number
  313. */
  314. static void tst_links_between_pads( int & aCurrSubRatsnestId,
  315. RATSNEST_ITEM* aFirstItem,
  316. RATSNEST_ITEM* aLastItem )
  317. {
  318. for( RATSNEST_ITEM* item = aFirstItem; item < aLastItem; item++ )
  319. {
  320. D_PAD* pad_start = item->m_PadStart;
  321. D_PAD* pad_end = item->m_PadEnd;
  322. /* Update the current SubRatsnest if the 2 pads are not connected :
  323. * a new cluster is created and the link activated
  324. */
  325. if( (pad_start->GetSubRatsnest() == 0) && (pad_end->GetSubRatsnest() == 0) )
  326. {
  327. aCurrSubRatsnestId++;
  328. pad_start->SetSubRatsnest( aCurrSubRatsnestId );
  329. pad_end->SetSubRatsnest( aCurrSubRatsnestId );
  330. item->m_Status |= CH_ACTIF;
  331. }
  332. /* If a pad is already connected to a subratsnest: activate the link
  333. * the pad other is merged in the existing subratsnest
  334. */
  335. else if( pad_start->GetSubRatsnest() == 0 )
  336. {
  337. pad_start->SetSubRatsnest( pad_end->GetSubRatsnest() );
  338. item->m_Status |= CH_ACTIF;
  339. }
  340. else if( pad_end->GetSubRatsnest() == 0 )
  341. {
  342. pad_end->SetSubRatsnest( pad_start->GetSubRatsnest() );
  343. item->m_Status |= CH_ACTIF;
  344. }
  345. }
  346. }
  347. /* function TestForActiveLinksInRatsnest
  348. * determine the active links inside the full ratsnest
  349. *
  350. * I used an algorithm inspired by the "Lee algorithm".
  351. * The idea is all pads must be connected by a physical track or a logical track
  352. * a physical track is the existing track on copper layers.
  353. * a logical track is the link that must be activated (visible) if
  354. * no track found between 2 pads.
  355. * The algorithm explore the existing full ratnest
  356. * This is a 2 steps algorithm (executed for each net).
  357. * - First:
  358. * Initialise for each pad the subratsnest id to its subnet value
  359. * explore the full ratnest (relative to the net) and active a link each time at least one pad of
  360. * the given link is not connected to an other pad by a track ( subratsnest = 0)
  361. * If the 2 pads linked have both the subratsnest id = 0, a new subratsnest value is created
  362. * - Second:
  363. * explore the full ratnest (relative to the net) and find a link that links
  364. * 2 pads having different subratsnest values
  365. * Active the link and merge the 2 subratsnest value.
  366. *
  367. * This is usually fast because the ratsnest is not built here: it is just explored
  368. * to see what link must be activated
  369. */
  370. void PCB_BASE_FRAME::TestForActiveLinksInRatsnest( int aNetCode )
  371. {
  372. RATSNEST_ITEM* rats;
  373. D_PAD* pad;
  374. NETINFO_ITEM* net;
  375. if( m_Pcb->GetPadCount() == 0 )
  376. return;
  377. if( (m_Pcb->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK) == 0 )
  378. Build_Board_Ratsnest();
  379. for( int net_code = 1; net_code < (int) m_Pcb->GetNetCount(); net_code++ )
  380. {
  381. net = m_Pcb->FindNet( net_code );
  382. wxCHECK_RET( net != NULL,
  383. wxString::Format( wxT( "Net code %d not found!" ), net_code ) );
  384. if( aNetCode && (net_code != aNetCode) )
  385. continue;
  386. // Create subratsnests id from subnets created by existing tracks:
  387. int subratsnest = 0;
  388. for( unsigned ip = 0; ip < net->m_PadInNetList.size(); ip++ )
  389. {
  390. pad = net->m_PadInNetList[ip];
  391. int subnet = pad->GetSubNet();
  392. pad->SetSubRatsnest( subnet );
  393. subratsnest = std::max( subratsnest, subnet );
  394. }
  395. for( unsigned ii = net->m_RatsnestStartIdx; ii < net->m_RatsnestEndIdx; ii++ )
  396. {
  397. m_Pcb->m_FullRatsnest[ii].m_Status &= ~CH_ACTIF;
  398. }
  399. // First pass - activate links for not connected pads
  400. rats = &m_Pcb->m_FullRatsnest[0];
  401. tst_links_between_pads( subratsnest,
  402. rats + net->m_RatsnestStartIdx,
  403. rats + net->m_RatsnestEndIdx );
  404. // Second pass activate links between blocks (Iteration)
  405. while( subratsnest > 1 )
  406. {
  407. subratsnest = tst_links_between_blocks( net, m_Pcb->m_FullRatsnest );
  408. }
  409. }
  410. m_Pcb->SetUnconnectedNetCount( 0 );
  411. unsigned cnt = 0;
  412. for( unsigned ii = 0; ii < m_Pcb->GetRatsnestsCount(); ii++ )
  413. {
  414. if( m_Pcb->m_FullRatsnest[ii].IsActive() )
  415. cnt++;
  416. }
  417. m_Pcb->SetUnconnectedNetCount( cnt );
  418. }
  419. void PCB_BASE_FRAME::build_ratsnest_module( MODULE* aModule )
  420. {
  421. // for local ratsnest calculation when moving a footprint:
  422. // list of pads to use for this local ratsnets:
  423. // this is the list of connected pads of the current module,
  424. // and all pads connected to these pads:
  425. static std::vector <D_PAD*> localPadList;
  426. static unsigned pads_module_count; // node count (node = pad with a net
  427. // code) for the footprint being moved
  428. static unsigned internalRatsCount; // number of internal links (links
  429. // between pads of the module)
  430. D_PAD* pad_ref;
  431. D_PAD* pad_externe;
  432. int current_net_code;
  433. int distance;
  434. wxPoint pad_pos; // True pad position according to the
  435. // current footprint position
  436. if( (GetBoard()->m_Status_Pcb & LISTE_PAD_OK) == 0 )
  437. {
  438. GetBoard()->m_Status_Pcb = 0;
  439. GetBoard()->BuildListOfNets();
  440. }
  441. /* Compute the "local" ratsnest if needed (when this footprint starts move)
  442. * and the list of external pads to consider, i.e pads in others
  443. * footprints which are "connected" to
  444. * a pad in the current footprint
  445. */
  446. if( (m_Pcb->m_Status_Pcb & RATSNEST_ITEM_LOCAL_OK) == 0 )
  447. {
  448. /* Compute the "internal" ratsnest, i.e the links between the current
  449. * footprint pads
  450. */
  451. localPadList.clear();
  452. m_Pcb->m_LocalRatsnest.clear();
  453. // collect active pads of the module:
  454. for( pad_ref = aModule->Pads(); pad_ref != NULL; pad_ref = pad_ref->Next() )
  455. {
  456. if( pad_ref->GetNet() == 0 )
  457. continue;
  458. localPadList.push_back( pad_ref );
  459. pad_ref->SetSubRatsnest( 0 );
  460. pad_ref->SetSubNet( 0 );
  461. }
  462. pads_module_count = localPadList.size();
  463. if( pads_module_count == 0 )
  464. return; // no connection!
  465. sort( localPadList.begin(), localPadList.end(), sortByNetcode );
  466. // Build the list of pads linked to the current footprint pads
  467. current_net_code = 0;
  468. for( unsigned ii = 0; ii < pads_module_count; ii++ )
  469. {
  470. pad_ref = localPadList[ii];
  471. if( pad_ref->GetNet() == current_net_code )
  472. continue;
  473. // A new net was found, load all pads of others modules members of this net:
  474. NETINFO_ITEM* net = m_Pcb->FindNet( pad_ref->GetNet() );
  475. if( net == NULL ) //Should not occur
  476. {
  477. wxMessageBox( wxT( "build_ratsnest_module() error: net not found" ) );
  478. return;
  479. }
  480. for( unsigned jj = 0; jj < net->m_PadInNetList.size(); jj++ )
  481. {
  482. pad_externe = net->m_PadInNetList[jj];
  483. if( pad_externe->GetParent() == aModule )
  484. continue;
  485. pad_externe->SetSubRatsnest( 0 );
  486. pad_externe->SetSubNet( 0 );
  487. localPadList.push_back( pad_externe );
  488. }
  489. }
  490. // Sort the pad list by net_code
  491. sort( localPadList.begin() + pads_module_count, localPadList.end(),
  492. sortByNetcode );
  493. /* Compute the internal rats nest:
  494. * this is the same as general ratsnest, but considers only the current
  495. * footprint pads it is therefore not time consuming, and it is made only
  496. * once
  497. */
  498. current_net_code = localPadList[0]->GetNet();
  499. MIN_SPAN_TREE_PADS min_spanning_tree;
  500. std::vector<D_PAD*> padsBuffer; // contains pads of only one net
  501. for( unsigned ii = 0; ii < pads_module_count; ii++ )
  502. {
  503. // Search the end of pad list relative to the current net
  504. unsigned jj = ii + 1;
  505. for( ; jj <= pads_module_count; jj++ )
  506. {
  507. if( jj >= pads_module_count )
  508. break;
  509. if( localPadList[jj]->GetNet() != current_net_code )
  510. break;
  511. }
  512. for(unsigned kk = ii; kk < jj; kk++ )
  513. padsBuffer.push_back( localPadList[kk] );
  514. min_spanning_tree.MSP_Init( &padsBuffer );
  515. min_spanning_tree.BuildTree();
  516. min_spanning_tree.AddTreeToRatsnest( m_Pcb->m_LocalRatsnest );
  517. padsBuffer.clear();
  518. ii = jj;
  519. if( ii < localPadList.size() )
  520. current_net_code = localPadList[ii]->GetNet();
  521. }
  522. internalRatsCount = m_Pcb->m_LocalRatsnest.size();
  523. // set the flag LOCAL_RATSNEST_ITEM of the ratsnest status:
  524. for( unsigned ii = 0; ii < m_Pcb->m_LocalRatsnest.size(); ii++ )
  525. m_Pcb->m_LocalRatsnest[ii].m_Status = LOCAL_RATSNEST_ITEM;
  526. m_Pcb->m_Status_Pcb |= RATSNEST_ITEM_LOCAL_OK;
  527. } // End of internal ratsnest build
  528. /* This section computes the "external" ratsnest: it is done when the
  529. * footprint position changes
  530. *
  531. * This section search:
  532. * for each current module pad the nearest neighbor external pad (of
  533. * course for the same net code).
  534. * For each current footprint cluster of pad (pads having the same net
  535. * code),
  536. * we search the smaller rats nest.
  537. * so, for each net, only one rats nest item is created
  538. */
  539. RATSNEST_ITEM local_rats;
  540. local_rats.m_Lenght = INT_MAX;
  541. local_rats.m_Status = 0;
  542. bool addRats = false;
  543. // Erase external ratsnest items:
  544. if( internalRatsCount < m_Pcb->m_LocalRatsnest.size() )
  545. m_Pcb->m_LocalRatsnest.erase( m_Pcb->m_LocalRatsnest.begin() + internalRatsCount,
  546. m_Pcb->m_LocalRatsnest.end() );
  547. current_net_code = localPadList[0]->GetNet();
  548. for( unsigned ii = 0; ii < pads_module_count; ii++ )
  549. {
  550. pad_ref = localPadList[ii];
  551. if( pad_ref->GetNet() != current_net_code )
  552. {
  553. // if needed, creates a new ratsnest for the old net
  554. if( addRats )
  555. {
  556. m_Pcb->m_LocalRatsnest.push_back( local_rats );
  557. }
  558. addRats = false;
  559. current_net_code = pad_ref->GetNet();
  560. local_rats.m_Lenght = INT_MAX;
  561. }
  562. pad_pos = pad_ref->GetPosition() - g_Offset_Module;
  563. // Search the nearest external pad of this current pad
  564. for( unsigned jj = pads_module_count; jj < localPadList.size(); jj++ )
  565. {
  566. pad_externe = localPadList[jj];
  567. // we search pads having the same net code
  568. if( pad_externe->GetNet() < pad_ref->GetNet() )
  569. continue;
  570. if( pad_externe->GetNet() > pad_ref->GetNet() ) // pads are sorted by net code
  571. break;
  572. distance = abs( pad_externe->GetPosition().x - pad_pos.x ) +
  573. abs( pad_externe->GetPosition().y - pad_pos.y );
  574. if( distance < local_rats.m_Lenght )
  575. {
  576. local_rats.m_PadStart = pad_ref;
  577. local_rats.m_PadEnd = pad_externe;
  578. local_rats.SetNet( pad_ref->GetNet() );
  579. local_rats.m_Lenght = distance;
  580. local_rats.m_Status = 0;
  581. addRats = true;
  582. }
  583. }
  584. }
  585. if( addRats ) // Ensure the last created rats nest item is stored in buffer
  586. m_Pcb->m_LocalRatsnest.push_back( local_rats );
  587. }
  588. void PCB_BASE_FRAME::TraceModuleRatsNest( wxDC* DC )
  589. {
  590. if( DC == NULL )
  591. return;
  592. if( ( m_Pcb->m_Status_Pcb & RATSNEST_ITEM_LOCAL_OK ) == 0 )
  593. return;
  594. EDA_COLOR_T tmpcolor = g_ColorsSettings.GetItemColor(RATSNEST_VISIBLE);
  595. for( unsigned ii = 0; ii < m_Pcb->m_LocalRatsnest.size(); ii++ )
  596. {
  597. RATSNEST_ITEM* rats = &m_Pcb->m_LocalRatsnest[ii];
  598. if( rats->m_Status & LOCAL_RATSNEST_ITEM )
  599. {
  600. g_ColorsSettings.SetItemColor(RATSNEST_VISIBLE, YELLOW);
  601. rats->Draw( m_canvas, DC, GR_XOR, g_Offset_Module );
  602. }
  603. else
  604. {
  605. g_ColorsSettings.SetItemColor(RATSNEST_VISIBLE, tmpcolor);
  606. wxPoint tmp = rats->m_PadStart->GetPosition();
  607. rats->m_PadStart->SetPosition( tmp - g_Offset_Module );
  608. rats->Draw( m_canvas, DC, GR_XOR, wxPoint( 0, 0 ) );
  609. rats->m_PadStart->SetPosition( tmp );
  610. }
  611. }
  612. g_ColorsSettings.SetItemColor( RATSNEST_VISIBLE, tmpcolor );
  613. }
  614. /*
  615. * PCB_BASE_FRAME::BuildAirWiresTargetsList and
  616. * PCB_BASE_FRAME::TraceAirWiresToTargets
  617. * are 2 function to show the near connecting points when
  618. * a new track is created, by displaying g_MaxLinksShowed airwires
  619. * between the on grid mouse cursor and these connecting points
  620. * during the creation of a track
  621. */
  622. /* Buffer to store pads coordinates when creating a track.
  623. * these pads are members of the net
  624. * and when the mouse is moved, the g_MaxLinksShowed links to neighbors are
  625. * drawn
  626. */
  627. static std::vector <wxPoint> s_TargetsLocations;
  628. static wxPoint s_CursorPos; // Coordinate of the moving point (mouse cursor and
  629. // end of current track segment)
  630. /* Used by BuildAirWiresTargetsList(): sort function by link length
  631. * (rectilinear distance between s_CursorPos and item pos)
  632. */
  633. static bool sort_by_distance( const wxPoint& ref, const wxPoint& compare )
  634. {
  635. wxPoint deltaref = ref - s_CursorPos; // relative coordinate of ref
  636. wxPoint deltacmp = compare - s_CursorPos; // relative coordinate of compare
  637. // rectilinear distance between ref and s_CursorPos:
  638. int lengthref = abs( deltaref.x ) + abs( deltaref.y );
  639. // rectilinear distance between compare and s_CursorPos:
  640. int lengthcmp = abs( deltacmp.x ) + abs( deltacmp.y );
  641. return lengthref < lengthcmp;
  642. }
  643. static bool sort_by_point( const wxPoint& ref, const wxPoint& compare )
  644. {
  645. if( ref.x == compare.x )
  646. return ref.y < compare.y;
  647. return ref.x < compare.x;
  648. }
  649. /* Function BuildAirWiresTargetsList
  650. * Build a list of candidates that can be a coonection point
  651. * when a track is started.
  652. * This functions prepares data to show airwires to nearest connecting points (pads)
  653. * from the current new track to candidates during track creation
  654. */
  655. void PCB_BASE_FRAME::BuildAirWiresTargetsList( BOARD_CONNECTED_ITEM* aItemRef,
  656. const wxPoint& aPosition, bool aInit )
  657. {
  658. if( ( ( m_Pcb->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK ) == 0 )
  659. || ( ( m_Pcb->m_Status_Pcb & LISTE_PAD_OK ) == 0 )
  660. || ( ( m_Pcb->m_Status_Pcb & NET_CODES_OK ) == 0 ) )
  661. {
  662. s_TargetsLocations.clear();
  663. return;
  664. }
  665. s_CursorPos = aPosition; // needed for sort_by_distance
  666. if( aInit )
  667. {
  668. s_TargetsLocations.clear();
  669. if( aItemRef == NULL )
  670. return;
  671. int net_code = aItemRef->GetNet();
  672. int subnet = aItemRef->GetSubNet();
  673. if( net_code <= 0 )
  674. return;
  675. NETINFO_ITEM* net = m_Pcb->FindNet( net_code );
  676. if( net == NULL ) // Should not occur
  677. {
  678. wxMessageBox( wxT( "BuildAirWiresTargetsList() error: net not found" ) );
  679. return;
  680. }
  681. // Create a list of pads candidates ( pads not already connected to the
  682. // current track ):
  683. for( unsigned ii = 0; ii < net->m_PadInNetList.size(); ii++ )
  684. {
  685. D_PAD* pad = net->m_PadInNetList[ii];
  686. if( pad == aItemRef )
  687. continue;
  688. if( !pad->GetSubNet() || (pad->GetSubNet() != subnet) )
  689. s_TargetsLocations.push_back( pad->GetPosition() );
  690. }
  691. // Create a list of tracks ends candidates, not already connected to the
  692. // current track:
  693. for( TRACK* track = m_Pcb->m_Track; track; track = track->Next() )
  694. {
  695. if( track->GetNet() < net_code )
  696. continue;
  697. if( track->GetNet() > net_code )
  698. break;;
  699. if( !track->GetSubNet() || (track->GetSubNet() != subnet) )
  700. {
  701. if( aPosition != track->GetStart() )
  702. s_TargetsLocations.push_back( track->GetStart() );
  703. if( aPosition != track->GetEnd() && track->GetStart() != track->GetEnd() )
  704. s_TargetsLocations.push_back( track->GetEnd() );
  705. }
  706. }
  707. // Remove duplicate targets, using the C++ unique algorithm
  708. sort( s_TargetsLocations.begin(), s_TargetsLocations.end(), sort_by_point );
  709. std::vector< wxPoint >::iterator it = unique( s_TargetsLocations.begin(), s_TargetsLocations.end() );
  710. // Using the C++ unique algorithm only moves the duplicate entries to the end of
  711. // of the array. This removes the duplicate entries from the array.
  712. s_TargetsLocations.resize( it - s_TargetsLocations.begin() );
  713. } // end if Init
  714. // in all cases, sort by distances:
  715. sort( s_TargetsLocations.begin(), s_TargetsLocations.end(), sort_by_distance );
  716. }
  717. void PCB_BASE_FRAME::TraceAirWiresToTargets( wxDC* aDC )
  718. {
  719. if( aDC == NULL )
  720. return;
  721. if( s_TargetsLocations.size() == 0 )
  722. return;
  723. GRSetDrawMode( aDC, GR_XOR );
  724. for( int ii = 0; ii < (int) s_TargetsLocations.size(); ii++ )
  725. {
  726. if( ii >= g_MaxLinksShowed )
  727. break;
  728. GRLine( m_canvas->GetClipBox(), aDC, s_CursorPos, s_TargetsLocations[ii], 0, YELLOW );
  729. }
  730. }