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.

589 lines
15 KiB

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