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.

641 lines
17 KiB

19 years ago
19 years ago
19 years ago
18 years ago
18 years ago
19 years ago
18 years ago
19 years ago
18 years ago
19 years ago
18 years ago
19 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
  1. /*******************/
  2. /* Locate element. */
  3. /*******************/
  4. #include "fctsys.h"
  5. #include "common.h"
  6. #include "pcbnew.h"
  7. #include "class_board_design_settings.h"
  8. #include "protos.h"
  9. /**
  10. * Function RefPos
  11. * returns the reference position, coming from either the mouse position or the
  12. * the cursor position, based on whether the typeloc has the CURSEUR_OFF_GRILLE
  13. * flag ORed in or not.
  14. * @param typeloc int with possible CURSEUR_OFF_GRILLE bit on.
  15. * @return wxPoint - The reference point, either the mouse position or
  16. * the cursor position.
  17. */
  18. wxPoint inline RefPos( int typeloc )
  19. {
  20. return ActiveScreen->RefPos( (typeloc & CURSEUR_OFF_GRILLE) != 0 );
  21. }
  22. /* Locates a via point pX, pY
  23. * If layer < 0 will be located via whatever layer
  24. * If layer = 0 .. 15 Via will be located according to its type:
  25. * - Traverse: all layers
  26. * - = Blind between layers useful
  27. * - Blind idem
  28. * Entry: coord point of reference, layer
  29. * Output: NULL if not via
  30. * (* TRACK) address via
  31. */
  32. TRACK* Locate_Via( BOARD* Pcb, const wxPoint& pos, int layer )
  33. {
  34. TRACK* track;
  35. for( track = Pcb->m_Track; track; track = track->Next() )
  36. {
  37. if( track->Type() != TYPE_VIA )
  38. continue;
  39. if( track->m_Start != pos )
  40. continue;
  41. if( track->GetState( BUSY | DELETED ) )
  42. continue;
  43. if( layer < 0 )
  44. break;
  45. if( track->IsOnLayer( layer ) )
  46. break;
  47. }
  48. return track;
  49. }
  50. TRACK* Locate_Via_Area( TRACK* aStart, const wxPoint& pos, int layer )
  51. {
  52. TRACK* track;
  53. for( track = aStart; track; track = track->Next() )
  54. {
  55. if( track->Type() != TYPE_VIA )
  56. continue;
  57. if( !track->HitTest(pos) )
  58. continue;
  59. if( track->GetState( BUSY | DELETED ) )
  60. continue;
  61. if( layer < 0 )
  62. break;
  63. if( track->IsOnLayer( layer ) )
  64. break;
  65. }
  66. return track;
  67. }
  68. /* Locate the pad CONNECTED to a track
  69. * input: ptr_piste: pointer to the segment of track
  70. * Extr = flag = START -> beginning of the test segment
  71. * END -> end of the segment to be tested
  72. * Returns:
  73. * A pointer to the description of the pad if found.
  74. * NULL pointer if pad NOT FOUND
  75. */
  76. D_PAD* Locate_Pad_Connecte( BOARD* Pcb, TRACK* ptr_piste, int extr )
  77. {
  78. D_PAD* ptr_pad = NULL;
  79. wxPoint ref_pos;
  80. int masque_layer = g_TabOneLayerMask[ptr_piste->GetLayer()];
  81. if( extr == START )
  82. {
  83. ref_pos = ptr_piste->m_Start;
  84. }
  85. else
  86. {
  87. ref_pos = ptr_piste->m_End;
  88. }
  89. for( MODULE* module = Pcb->m_Modules; module; module = module->Next() )
  90. {
  91. ptr_pad = Locate_Pads( module, ref_pos, masque_layer );
  92. if( ptr_pad != NULL )
  93. break;
  94. }
  95. return ptr_pad;
  96. }
  97. /*
  98. * Locate pad pointed to by the coordinates ref_pos.x,, ref_pos.y or
  99. * the mouse, search done on all tracks.
  100. * Input:
  101. * - mouse coord or ref_pos
  102. * Returns:
  103. * Pointer to the pad if found.
  104. * NULL pointer if pad NOT FOUND
  105. * Num_empr = number of fingerprint pad
  106. *
  107. * Priority is the active layer
  108. */
  109. D_PAD* Locate_Any_Pad( BOARD* Pcb, int typeloc, bool OnlyCurrentLayer )
  110. {
  111. wxPoint ref_pos = RefPos( typeloc );
  112. return Locate_Any_Pad( Pcb, ref_pos, OnlyCurrentLayer );
  113. }
  114. D_PAD* Locate_Any_Pad( BOARD* Pcb, const wxPoint& ref_pos,
  115. bool OnlyCurrentLayer )
  116. {
  117. int layer_mask =
  118. g_TabOneLayerMask[ ( (PCB_SCREEN*) ActiveScreen )->m_Active_Layer];
  119. for( MODULE* module=Pcb->m_Modules; module; module = module->Next() )
  120. {
  121. D_PAD* pt_pad;
  122. /* First: Search a pad on the active layer: */
  123. if( ( pt_pad = Locate_Pads( module, ref_pos, layer_mask ) ) != NULL )
  124. return pt_pad;
  125. /* If not found, search on other layers: */
  126. if( !OnlyCurrentLayer )
  127. {
  128. if( ( pt_pad = Locate_Pads( module, ref_pos, ALL_LAYERS ) ) != NULL )
  129. return pt_pad;
  130. }
  131. }
  132. return NULL;
  133. }
  134. /* Locate pad pointed to by the coordinate ref_pos.x,, ref_pos.y or
  135. * the mouse on the current footprint.
  136. * Input:
  137. * - General parameters of the footprint update by characters()
  138. * - = Masque_layer layer(s) (bit_masque) which must be the pad
  139. * Returns:
  140. * A pointer to the pad if found
  141. * NULL pointer if pad NOT FOUND
  142. */
  143. D_PAD* Locate_Pads( MODULE* module, int masque_layer, int typeloc )
  144. {
  145. wxPoint ref_pos = RefPos( typeloc );
  146. return Locate_Pads( module, ref_pos, masque_layer );
  147. }
  148. D_PAD* Locate_Pads( MODULE* module, const wxPoint& ref_pos, int masque_layer )
  149. {
  150. for( D_PAD* pt_pad = module->m_Pads; pt_pad; pt_pad = pt_pad->Next() )
  151. {
  152. /* ... and on the correct layer. */
  153. if( ( pt_pad->m_Masque_Layer & masque_layer ) == 0 )
  154. continue;
  155. if( pt_pad->HitTest( ref_pos ) )
  156. return pt_pad;
  157. }
  158. return NULL;
  159. }
  160. /**
  161. * Function Locate_Prefered_Module
  162. * locates a footprint by its bounding rectangle. If several footprints
  163. * are possible, then the priority is: the closest on the active layer, then
  164. * closest.
  165. * The current mouse or cursor coordinates are grabbed from the active window
  166. * to perform hit-testing.
  167. * distance is calculated via manhattan distance from the center of the
  168. * bounding rectangle to the cursor position.
  169. *
  170. * @param Pcb The BOARD to search within.
  171. * @param typeloc Flag bits, tuning the search, see pcbnew.h
  172. * @return MODULE* - the best module or NULL if none.
  173. */
  174. MODULE* Locate_Prefered_Module( BOARD* Pcb, int typeloc )
  175. {
  176. MODULE* pt_module;
  177. int lx, ly;
  178. MODULE* module = NULL;
  179. MODULE* Altmodule = NULL;
  180. int min_dim = 0x7FFFFFFF;
  181. int alt_min_dim = 0x7FFFFFFF;
  182. int layer;
  183. wxPoint ref_pos;
  184. ref_pos = RefPos( typeloc );
  185. pt_module = Pcb->m_Modules;
  186. for( ; pt_module; pt_module = (MODULE*) pt_module->Next() )
  187. {
  188. // is the ref point within the module's bounds?
  189. if( !pt_module->HitTest( ref_pos ) )
  190. continue;
  191. // if caller wants to ignore locked modules, and this one is locked,
  192. // skip it.
  193. if( (typeloc & IGNORE_LOCKED) && pt_module->IsLocked() )
  194. continue;
  195. /* Calculate priority: the priority is given to the layer of the
  196. * module and the copper layer if the module layer is indelible,
  197. * adhesive copper, a layer if cmp module layer is indelible,
  198. * adhesive component.
  199. */
  200. layer = pt_module->GetLayer();
  201. if( layer==ADHESIVE_N_BACK || layer==SILKSCREEN_N_BACK )
  202. layer = LAYER_N_BACK;
  203. else if( layer==ADHESIVE_N_FRONT || layer==SILKSCREEN_N_FRONT )
  204. layer = LAYER_N_FRONT;
  205. /* Test of minimum size to choosing the best candidate. */
  206. int offx = pt_module->m_BoundaryBox.m_Size.x / 2 +
  207. pt_module->m_BoundaryBox.m_Pos.x +
  208. pt_module->m_Pos.x;
  209. int offy = pt_module->m_BoundaryBox.m_Size.y / 2
  210. + pt_module->m_BoundaryBox.m_Pos.y
  211. + pt_module->m_Pos.y;
  212. //off x & offy point to the middle of the box.
  213. int dist = abs( ref_pos.x - offx ) + abs( ref_pos.y - offy );
  214. lx = pt_module->m_BoundaryBox.GetWidth();
  215. ly = pt_module->m_BoundaryBox.GetHeight();
  216. //int dist = MIN(lx, ly); // to pick the smallest module (kinda
  217. // screwy with same-sized modules -- this is bad!)
  218. if( ( (PCB_SCREEN*) ActiveScreen )->m_Active_Layer == layer )
  219. {
  220. if( dist <= min_dim )
  221. {
  222. /* better footprint shown on the active layer */
  223. module = pt_module;
  224. min_dim = dist;
  225. }
  226. }
  227. else if( !( typeloc & MATCH_LAYER )
  228. && ( !( typeloc & VISIBLE_ONLY )
  229. || Pcb->IsModuleLayerVisible( layer ) ) )
  230. {
  231. if( dist <= alt_min_dim )
  232. {
  233. /* better footprint shown on other layers */
  234. Altmodule = pt_module;
  235. alt_min_dim = dist;
  236. }
  237. }
  238. }
  239. if( module )
  240. {
  241. return module;
  242. }
  243. if( Altmodule )
  244. {
  245. return Altmodule;
  246. }
  247. return NULL;
  248. }
  249. /*
  250. * return true if the dist between p1 and p2 < max_dist
  251. * Currently in test (currently rasnest algos work only if p1 == p2)
  252. */
  253. inline bool IsPointsAreNear(wxPoint & p1, wxPoint & p2, int max_dist)
  254. {
  255. #if 0 // Do not change it: does not work
  256. {
  257. int dist;
  258. dist = abs(p1.x - p2.x) + abs (p1.y - p2.y);
  259. dist *= 7;
  260. dist /= 10;
  261. if ( dist < max_dist ) return true;
  262. }
  263. #else
  264. if ( p1 == p2 ) return true;
  265. #endif
  266. return false;
  267. }
  268. /** Search for the track (or via) segment which is connected to the track
  269. * segment PtRefSegm
  270. * if extr == START, the starting track segment PtRefSegm is used to locate
  271. * a connected segment
  272. * if extr == END, the ending track segment PtRefSegm is used
  273. * The test connection consider only end track segments
  274. *
  275. * Search is made from pt_base to pt_lim (in the track linked list)
  276. * if pt_lim == NULL, the search is made from pt_base to the end of list
  277. *
  278. * In order to have a fast computation time:
  279. * a first search is made considering only the +/- 50 next door neighbor
  280. * of PtRefSegm.
  281. * if no track is found : the entire list is tested
  282. *
  283. * @param PtRefSegm = reference segment
  284. * @param pt_base = lower limit for search
  285. * @param pt_lim = upper limit for search (can be NULL)
  286. * @param extr = START or END = end of ref track segment to use in tests
  287. */
  288. TRACK* Locate_Piste_Connectee( TRACK* PtRefSegm, TRACK* pt_base,
  289. TRACK* pt_lim, int extr )
  290. {
  291. const int NEIGHTBOUR_COUNT_MAX = 50;
  292. TRACK* PtSegmB, * PtSegmN;
  293. int Reflayer;
  294. wxPoint pos_ref;
  295. int ii;
  296. int max_dist;
  297. if( extr == START )
  298. pos_ref = PtRefSegm->m_Start;
  299. else
  300. pos_ref = PtRefSegm->m_End;
  301. Reflayer = PtRefSegm->ReturnMaskLayer();
  302. PtSegmB = PtSegmN = PtRefSegm;
  303. for( ii = 0; ii < NEIGHTBOUR_COUNT_MAX; ii++ )
  304. {
  305. if( (PtSegmN == NULL) && (PtSegmB == NULL) )
  306. break;
  307. if( PtSegmN )
  308. {
  309. if( PtSegmN->GetState( BUSY | DELETED ) )
  310. goto suite;
  311. if( PtSegmN == PtRefSegm )
  312. goto suite;
  313. /* max_dist is the max distance between 2 track ends which
  314. * ensure a copper continuity */
  315. max_dist = (PtSegmN->m_Width + PtRefSegm->m_Width)/2;
  316. if( IsPointsAreNear(pos_ref, PtSegmN->m_Start, max_dist) )
  317. {
  318. if( Reflayer & PtSegmN->ReturnMaskLayer() )
  319. return PtSegmN;
  320. }
  321. if( IsPointsAreNear(pos_ref, PtSegmN->m_End, max_dist) )
  322. {
  323. if( Reflayer & PtSegmN->ReturnMaskLayer() )
  324. return PtSegmN;
  325. }
  326. suite:
  327. if( PtSegmN == pt_lim )
  328. PtSegmN = NULL;
  329. else
  330. PtSegmN = PtSegmN->Next();
  331. }
  332. if( PtSegmB )
  333. {
  334. if( PtSegmB->GetState( BUSY | DELETED ) )
  335. goto suite1;
  336. if( PtSegmB == PtRefSegm )
  337. goto suite1;
  338. max_dist = (PtSegmB->m_Width + PtRefSegm->m_Width)/2;
  339. if( IsPointsAreNear(pos_ref, PtSegmB->m_Start, max_dist) )
  340. {
  341. if( Reflayer & PtSegmB->ReturnMaskLayer() )
  342. return PtSegmB;
  343. }
  344. if( IsPointsAreNear(pos_ref, PtSegmB->m_End, max_dist) )
  345. {
  346. if( Reflayer & PtSegmB->ReturnMaskLayer() )
  347. return PtSegmB;
  348. }
  349. suite1:
  350. if( PtSegmB == pt_base )
  351. PtSegmB = NULL;
  352. else if( PtSegmB->Type() != TYPE_PCB )
  353. PtSegmB = PtSegmB->Back();
  354. else
  355. PtSegmB = NULL;
  356. }
  357. }
  358. /* General search. */
  359. for( PtSegmN = pt_base; PtSegmN != NULL; PtSegmN = PtSegmN->Next() )
  360. {
  361. if( PtSegmN->GetState( DELETED | BUSY ) )
  362. {
  363. if( PtSegmN == pt_lim )
  364. break;
  365. continue;
  366. }
  367. if( PtSegmN == PtRefSegm )
  368. {
  369. if( PtSegmN == pt_lim )
  370. break;
  371. continue;
  372. }
  373. max_dist = ( PtSegmN->m_Width + PtRefSegm->m_Width ) / 2;
  374. if( IsPointsAreNear( pos_ref, PtSegmN->m_Start, max_dist ) )
  375. {
  376. if( Reflayer & PtSegmN->ReturnMaskLayer() )
  377. return PtSegmN;
  378. }
  379. if( IsPointsAreNear( pos_ref, PtSegmN->m_End, max_dist ) )
  380. {
  381. if( Reflayer & PtSegmN->ReturnMaskLayer() )
  382. return PtSegmN;
  383. }
  384. if( PtSegmN == pt_lim )
  385. break;
  386. }
  387. return NULL;
  388. }
  389. /*
  390. * 1 - Locate segment of track leading from the mouse.
  391. * 2 - Locate segment of track point by point
  392. * ref_pos.x, ref_pos.y.r
  393. *
  394. * The search begins to address start_adresse
  395. */
  396. TRACK* Locate_Pistes(BOARD* aPcb, TRACK* start_adresse, int MasqueLayer, int typeloc )
  397. {
  398. wxPoint ref_pos = RefPos( typeloc );
  399. return Locate_Pistes( aPcb, start_adresse, ref_pos, MasqueLayer );
  400. }
  401. TRACK* Locate_Pistes(BOARD* aPcb, TRACK* start_adresse, const wxPoint& ref_pos,
  402. int MasqueLayer )
  403. {
  404. for( TRACK* track = start_adresse; track; track = track->Next() )
  405. {
  406. int layer = track->GetLayer();
  407. if( track->GetState( BUSY | DELETED ) )
  408. {
  409. // D( printf( "track %p is BUSY | DELETED. BUSY=%d DELETED=%d\n",
  410. // track, track->GetState( BUSY ),
  411. // track->GetState( DELETED ) );)
  412. continue;
  413. }
  414. if( aPcb->GetBoardDesignSettings()->IsLayerVisible( layer ) == false )
  415. continue;
  416. if( track->Type() == TYPE_VIA ) /* VIA encountered. */
  417. {
  418. if( track->HitTest( ref_pos ) )
  419. return track;
  420. }
  421. else
  422. {
  423. if( (g_TabOneLayerMask[layer] & MasqueLayer) == 0 )
  424. continue; /* Segments on different layers. */
  425. if( track->HitTest( ref_pos ) )
  426. return track;
  427. }
  428. }
  429. return NULL;
  430. }
  431. /*
  432. * 1 - Locate zone area by the mouse.
  433. * 2 - Locate zone area by point
  434. * def_pos.x, ref_pos.y.r
  435. *
  436. * If layer == -1, tst layer is not
  437. *
  438. * The search begins to address start_adresse
  439. */
  440. TRACK* Locate_Zone( TRACK* start_adresse, int layer, int typeloc )
  441. {
  442. wxPoint ref_pos = RefPos( typeloc );
  443. return Locate_Zone( start_adresse, ref_pos, layer );
  444. }
  445. TRACK* Locate_Zone( TRACK* start_adresse, const wxPoint& ref_pos, int layer )
  446. {
  447. for( TRACK* Zone = start_adresse; Zone; Zone = Zone->Next() )
  448. {
  449. if( (layer != -1) && (Zone->GetLayer() != layer) )
  450. continue;
  451. if( Zone->HitTest( ref_pos ) )
  452. return Zone;
  453. }
  454. return NULL;
  455. }
  456. /* Find the pad center px, py,
  457. * The layer INDICATED BY masque_layer (bitwise)
  458. * (Runway end)
  459. * The list of pads must already exist.
  460. *
  461. * Returns:
  462. * NULL if no pad located.
  463. * Pointer to the structure corresponding descr_pad if pad found
  464. * (Good position and good layer).
  465. */
  466. D_PAD* Fast_Locate_Pad_Connecte( BOARD* Pcb, const wxPoint& ref_pos,
  467. int masque_layer )
  468. {
  469. for( unsigned i=0; i<Pcb->GetPadsCount(); ++i )
  470. {
  471. D_PAD* pad = Pcb->m_NetInfo->GetPad(i);
  472. if( pad->m_Pos != ref_pos )
  473. continue;
  474. /* Pad found, it must be on the correct layer */
  475. if( pad->m_Masque_Layer & masque_layer )
  476. return pad;
  477. }
  478. return NULL;
  479. }
  480. /* Locate segment with one end that coincides with the point x, y
  481. * Data on layers by masklayer
  482. * Research is done to address start_adr has end_adr
  483. * If end_adr = NULL, end search list
  484. * The segments of track marks with the flag are not DELETED or taken
  485. * into account
  486. */
  487. TRACK* Fast_Locate_Piste( TRACK* start_adr, TRACK* end_adr,
  488. const wxPoint& ref_pos, int MaskLayer )
  489. {
  490. TRACK* PtSegm;
  491. if( start_adr == NULL )
  492. return NULL;
  493. for( PtSegm = start_adr; PtSegm != NULL; PtSegm = PtSegm->Next() )
  494. {
  495. if( PtSegm->GetState( DELETED | BUSY ) == 0 )
  496. {
  497. if( ref_pos == PtSegm->m_Start )
  498. {
  499. if( MaskLayer & PtSegm->ReturnMaskLayer() )
  500. return PtSegm;
  501. }
  502. if( ref_pos == PtSegm->m_End )
  503. {
  504. if( MaskLayer & PtSegm->ReturnMaskLayer() )
  505. return PtSegm;
  506. }
  507. }
  508. if( PtSegm == end_adr )
  509. break;
  510. }
  511. return NULL;
  512. }
  513. /* Locates via through the point x, y, on layer data by masklayer.
  514. * Search is done to address start_adr has end_adr.
  515. * If end_adr = NULL, end search list
  516. * Vias whose parameter has the State or DELETED bit BUSY = 1 are ignored
  517. */
  518. TRACK* Fast_Locate_Via( TRACK* start_adr, TRACK* end_adr,
  519. const wxPoint& pos, int MaskLayer )
  520. {
  521. TRACK* PtSegm;
  522. for( PtSegm = start_adr; PtSegm != NULL; PtSegm = PtSegm->Next() )
  523. {
  524. if( PtSegm->Type() == TYPE_VIA )
  525. {
  526. if( pos == PtSegm->m_Start )
  527. {
  528. if( PtSegm->GetState( BUSY | DELETED ) == 0 )
  529. {
  530. if( MaskLayer & PtSegm->ReturnMaskLayer() )
  531. return PtSegm;
  532. }
  533. }
  534. }
  535. if( PtSegm == end_adr )
  536. break;
  537. }
  538. return NULL;
  539. }