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.

1105 lines
42 KiB

  1. /***************************************/
  2. /* AUTOROUTAGE PCB : routine de calcul */
  3. /***************************************/
  4. /* fichier SOLVE.Cpp */
  5. #include "fctsys.h"
  6. #include "gr_basic.h"
  7. #include "common.h"
  8. #include "pcbnew.h"
  9. #include "autorout.h"
  10. #include "protos.h"
  11. #include <fcntl.h>
  12. #include "cell.h"
  13. /* Routines definies ici : */
  14. static int Route_1_Trace( WinEDA_PcbFrame* pcbframe, wxDC* DC, int two_sides, int row_source,
  15. int col_source,
  16. int row_target, int col_target, CHEVELU* pt_chevelu );
  17. static int Retrace( WinEDA_PcbFrame* pcbframe, wxDC* DC, int, int, int, int, int, int net_code );
  18. static void OrCell_Trace( BOARD* pcb, int col, int row, int side, int orient, int current_net_code );
  19. static void Place_Piste_en_Buffer( WinEDA_PcbFrame* pcbframe, wxDC* DC );
  20. /* Variables locales : */
  21. static int segm_oX, segm_oY;
  22. static int segm_fX, segm_fY; /* Origine et fin de la piste en cours de trace */
  23. static CHEVELU* pt_cur_ch;
  24. static int Ncurrent; /* measures of progress */
  25. #define NOSUCCESS 0
  26. #define STOP_FROM_ESC -1
  27. #define ERR_MEMORY -2
  28. #define SUCCESS 1
  29. #define TRIVIAL_SUCCESS 2
  30. /*
  31. ** visit neighboring cells like this (where [9] is on the other side):
  32. **
  33. ** +---+---+---+
  34. ** | 1 | 2 | 3 |
  35. ** +---+---+---+
  36. ** | 4 |[9]| 5 |
  37. ** +---+---+---+
  38. ** | 6 | 7 | 8 |
  39. ** +---+---+---+
  40. */
  41. /* for visiting neighbors on the same side: increments/decrements des coord
  42. * [][0] = row, []{1] = col a ajouter aux coord du point central pour
  43. * obtenir les coord des 8 points voisins */
  44. static int delta[8][2] = {
  45. { 1, -1 }, /* northwest */
  46. { 1, 0 }, /* north */
  47. { 1, 1 }, /* northeast */
  48. { 0, -1 }, /* west */
  49. { 0, 1 }, /* east */
  50. { -1, -1 }, /* southwest */
  51. { -1, 0 }, /* south */
  52. { -1, 1 } /* southeast */
  53. };
  54. static int ndir[8] = { /* for building paths back to source */
  55. FROM_SOUTHEAST, FROM_SOUTH, FROM_SOUTHWEST,
  56. FROM_EAST, FROM_WEST,
  57. FROM_NORTHEAST, FROM_NORTH, FROM_NORTHWEST
  58. };
  59. /* blocking masks for neighboring cells */
  60. #define BLOCK_NORTHEAST ( DIAG_NEtoSW | BENT_StoNE | BENT_WtoNE \
  61. | ANGLE_NEtoSE | ANGLE_NWtoNE \
  62. | SHARP_NtoNE | SHARP_EtoNE | HOLE )
  63. #define BLOCK_SOUTHEAST ( DIAG_SEtoNW | BENT_NtoSE | BENT_WtoSE \
  64. | ANGLE_NEtoSE | ANGLE_SEtoSW \
  65. | SHARP_EtoSE | SHARP_StoSE | HOLE )
  66. #define BLOCK_SOUTHWEST ( DIAG_NEtoSW | BENT_NtoSW | BENT_EtoSW \
  67. | ANGLE_SEtoSW | ANGLE_SWtoNW \
  68. | SHARP_StoSW | SHARP_WtoSW | HOLE )
  69. #define BLOCK_NORTHWEST ( DIAG_SEtoNW | BENT_EtoNW | BENT_StoNW \
  70. | ANGLE_SWtoNW | ANGLE_NWtoNE \
  71. | SHARP_WtoNW | SHARP_NtoNW | HOLE )
  72. #define BLOCK_NORTH ( LINE_VERTICAL | BENT_NtoSE | BENT_NtoSW \
  73. | BENT_EtoNW | BENT_WtoNE \
  74. | BENT_StoNE | BENT_StoNW \
  75. | CORNER_NORTHEAST | CORNER_NORTHWEST \
  76. | ANGLE_NEtoSE | ANGLE_SWtoNW | ANGLE_NWtoNE \
  77. | DIAG_NEtoSW | DIAG_SEtoNW \
  78. | SHARP_NtoNE | SHARP_NtoNW \
  79. | SHARP_EtoNE | SHARP_WtoNW | HOLE )
  80. #define BLOCK_EAST ( LINE_HORIZONTAL | BENT_EtoSW | BENT_EtoNW \
  81. | BENT_NtoSE | BENT_StoNE \
  82. | BENT_WtoNE | BENT_WtoSE \
  83. | CORNER_NORTHEAST | CORNER_SOUTHEAST \
  84. | ANGLE_NEtoSE | ANGLE_SEtoSW | ANGLE_NWtoNE \
  85. | DIAG_NEtoSW | DIAG_SEtoNW \
  86. | SHARP_EtoNE | SHARP_EtoSE \
  87. | SHARP_NtoNE | SHARP_StoSE | HOLE )
  88. #define BLOCK_SOUTH ( LINE_VERTICAL | BENT_StoNE | BENT_StoNW \
  89. | BENT_EtoSW | BENT_WtoSE \
  90. | BENT_NtoSE | BENT_NtoSW \
  91. | CORNER_SOUTHEAST | CORNER_SOUTHWEST \
  92. | ANGLE_NEtoSE | ANGLE_SWtoNW | ANGLE_SEtoSW \
  93. | DIAG_NEtoSW | DIAG_SEtoNW \
  94. | SHARP_StoSE | SHARP_StoSW \
  95. | SHARP_EtoSE | SHARP_WtoSW | HOLE )
  96. #define BLOCK_WEST ( LINE_HORIZONTAL | BENT_WtoNE | BENT_WtoSE \
  97. | BENT_NtoSW | BENT_StoNW \
  98. | BENT_EtoSW | BENT_EtoNW \
  99. | CORNER_SOUTHWEST | CORNER_NORTHWEST \
  100. | ANGLE_SWtoNW | ANGLE_SEtoSW | ANGLE_NWtoNE \
  101. | DIAG_NEtoSW | DIAG_SEtoNW \
  102. | SHARP_WtoSW | SHARP_WtoNW \
  103. | SHARP_NtoNW | SHARP_StoSW | HOLE )
  104. struct block
  105. {
  106. int r1, c1;
  107. long b1;
  108. int r2, c2;
  109. long b2;
  110. };
  111. static struct block blocking[8] = /* blocking masks for diagonal traces */
  112. { { 0, -1,
  113. BLOCK_NORTHEAST,
  114. 1, 0,
  115. BLOCK_SOUTHWEST },
  116. { 0, 0, 0,
  117. 0, 0, 0 },
  118. { 1, 0,
  119. BLOCK_SOUTHEAST,
  120. 0, 1,
  121. BLOCK_NORTHWEST },
  122. { 0, 0, 0,
  123. 0, 0, 0 },
  124. { 0, 0, 0,
  125. 0, 0, 0 },
  126. { 0, -1,
  127. BLOCK_SOUTHEAST,
  128. -1, 0,
  129. BLOCK_NORTHWEST },
  130. { 0, 0, 0,
  131. 0, 0, 0 },
  132. { -1, 0,
  133. BLOCK_NORTHEAST,
  134. 0, 1,
  135. BLOCK_SOUTHWEST } };
  136. /* mask for hole-related blocking effects */
  137. static struct
  138. {
  139. long trace;
  140. int present;
  141. } selfok2[8] = {
  142. { HOLE_NORTHWEST, 0 },
  143. { HOLE_NORTH, 0 },
  144. { HOLE_NORTHEAST, 0 },
  145. { HOLE_WEST, 0 },
  146. { HOLE_EAST, 0 },
  147. { HOLE_SOUTHWEST, 0 },
  148. { HOLE_SOUTH, 0 },
  149. { HOLE_SOUTHEAST, 0 }
  150. };
  151. static long newmask[8] = { /* patterns to mask out in neighbor cells */
  152. 0, CORNER_NORTHWEST | CORNER_NORTHEAST, 0,
  153. CORNER_NORTHWEST | CORNER_SOUTHWEST, CORNER_NORTHEAST | CORNER_SOUTHEAST,
  154. 0, CORNER_SOUTHWEST | CORNER_SOUTHEAST, 0
  155. };
  156. /* Macro d'affichage de l'activite du routeur; */
  157. #define AFFICHE_ACTIVITE_ROUTE \
  158. msg.Printf( wxT( "%5.5d" ), OpenNodes ); \
  159. Affiche_1_Parametre( pcbframe, 24, wxT( "Open" ), msg, WHITE ); \
  160. msg.Printf( wxT( "%5.5d" ), ClosNodes ); \
  161. Affiche_1_Parametre( pcbframe, 32, wxT( "Closed" ), msg, WHITE ); \
  162. msg.Printf( wxT( "%5.5d" ), MoveNodes ); \
  163. Affiche_1_Parametre( pcbframe, 40, wxT( "Moved" ), msg, WHITE ); \
  164. msg.Printf( wxT( "%5.5d" ), MaxNodes ); \
  165. Affiche_1_Parametre( pcbframe, 48, wxT( "Max" ), msg, WHITE ); \
  166. msg.Printf( wxT( "%2.2d" ), (ClosNodes * 50) / (Nrows * Ncols) ); \
  167. Affiche_1_Parametre( pcbframe, 56, wxT( "%" ), msg, CYAN );
  168. /********************************************************/
  169. /* int WinEDA_PcbFrame::Solve(wxDC * DC, int two_sides) */
  170. /********************************************************/
  171. /* route all traces
  172. * Return: 1 si OK
  173. * -1 si Escape (arret en cours de routage) demande
  174. * -2 si defaut alloc memoire
  175. */
  176. int WinEDA_PcbFrame::Solve( wxDC* DC, int two_sides )
  177. {
  178. int current_net_code;
  179. int row_source, col_source, row_target, col_target;
  180. int success, nbsucces = 0, nbunsucces = 0;
  181. EQUIPOT* pt_equipot;
  182. bool stop = FALSE;
  183. wxString msg;
  184. DrawPanel->m_AbortRequest = FALSE;
  185. DrawPanel->m_AbortEnable = TRUE;
  186. Ncurrent = 0;
  187. MsgPanel->EraseMsgBox();
  188. msg.Printf( wxT( "%d " ), m_Pcb->m_NbNoconnect );
  189. Affiche_1_Parametre( this, 72, wxT( "NoConn" ), msg, LIGHTCYAN );
  190. /* go until no more work to do */
  191. GetWork( &row_source, &col_source, &current_net_code,
  192. &row_target, &col_target, &pt_cur_ch ); // 1er chevelu a router
  193. for( ; row_source != ILLEGAL; GetWork( &row_source, &col_source,
  194. &current_net_code, &row_target, &col_target,
  195. &pt_cur_ch ) )
  196. {
  197. /* Tst demande d'arret de routage ( key ESCAPE actionnee ) */
  198. wxYield();
  199. if( DrawPanel->m_AbortRequest )
  200. {
  201. if( IsOK( this, _( "Abort routing?" ) ) )
  202. {
  203. success = STOP_FROM_ESC;
  204. stop = TRUE;
  205. break;
  206. }
  207. else
  208. DrawPanel->m_AbortRequest = 0;
  209. }
  210. Ncurrent++;
  211. pt_equipot = m_Pcb->FindNet( current_net_code );
  212. if( pt_equipot )
  213. {
  214. msg.Printf( wxT( "[%8.8s]" ), pt_equipot->m_Netname.GetData() );
  215. Affiche_1_Parametre( this, 1, wxT( "Net route" ), msg, YELLOW );
  216. msg.Printf( wxT( "%d / %d" ), Ncurrent, Ntotal );
  217. Affiche_1_Parametre( this, 12, wxT( "Activity" ), msg, YELLOW );
  218. }
  219. pt_cur_ch = pt_cur_ch;
  220. segm_oX = m_Pcb->m_BoundaryBox.m_Pos.x + (g_GridRoutingSize * col_source);
  221. segm_oY = m_Pcb->m_BoundaryBox.m_Pos.y + (g_GridRoutingSize * row_source);
  222. segm_fX = m_Pcb->m_BoundaryBox.m_Pos.x + (g_GridRoutingSize * col_target);
  223. segm_fY = m_Pcb->m_BoundaryBox.m_Pos.y + (g_GridRoutingSize * row_target);
  224. /* Affiche Liaison */
  225. GRLine( &DrawPanel->m_ClipBox, DC, segm_oX, segm_oY, segm_fX, segm_fY, 0, WHITE | GR_XOR );
  226. pt_cur_ch->pad_start->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_OR | GR_SURBRILL );
  227. pt_cur_ch->pad_end->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_OR | GR_SURBRILL );
  228. success = Route_1_Trace( this, DC, two_sides, row_source, col_source,
  229. row_target, col_target, pt_cur_ch );
  230. switch( success )
  231. {
  232. case NOSUCCESS:
  233. pt_cur_ch->status |= CH_UNROUTABLE;
  234. nbunsucces++;
  235. break;
  236. case STOP_FROM_ESC:
  237. stop = TRUE;
  238. break;
  239. case ERR_MEMORY:
  240. stop = TRUE;
  241. break;
  242. default:
  243. nbsucces++;
  244. break;
  245. }
  246. msg.Printf( wxT( "%d " ), nbsucces );
  247. Affiche_1_Parametre( this, 61, wxT( "Ok" ), msg, LIGHTGREEN );
  248. msg.Printf( wxT( "%d " ), nbunsucces );
  249. Affiche_1_Parametre( this, 66, wxT( "Fail" ), msg, LIGHTRED );
  250. msg.Printf( wxT( "%d " ), m_Pcb->m_NbNoconnect );
  251. Affiche_1_Parametre( this, 72, wxT( "NoConn" ), msg, LIGHTCYAN );
  252. /* Effacement des affichages de routage sur l'ecran */
  253. pt_cur_ch->pad_start->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_AND );
  254. pt_cur_ch->pad_end->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_AND );
  255. if( stop )
  256. break;
  257. }
  258. DrawPanel->m_AbortEnable = FALSE;
  259. return SUCCESS;
  260. }
  261. /**************************/
  262. /* int Route_1_Trace(xxx) */
  263. /**************************/
  264. /* Route une piste du BOARD.
  265. * Parametres:
  266. * 1 face / 2 faces ( 0 / 1)
  267. * coord source (row,col)
  268. * coord destination (row,col)
  269. * net_code
  270. * pointeur sur le chevelu de reference
  271. *
  272. * Retourne :
  273. * SUCCESS si route trouvee
  274. * TRIVIAL_SUCCESS si pads connectes par superposition ( pas de piste a tirer)
  275. * NOSUCCESS si echec
  276. * STOP_FROM_ESC si Escape demande
  277. * ERR_MEMORY defaut alloc RAM
  278. */
  279. static int Route_1_Trace( WinEDA_PcbFrame* pcbframe, wxDC* DC,
  280. int two_sides, int row_source, int col_source,
  281. int row_target, int col_target, CHEVELU* pt_chevelu )
  282. {
  283. int r, c, side, d, apx_dist, nr, nc;
  284. int result, skip;
  285. int i;
  286. LISTE_PAD* ptr;
  287. long curcell, newcell, buddy, lastopen, lastclos, lastmove;
  288. int newdist, olddir, _self;
  289. int current_net_code;
  290. int marge, via_marge;
  291. int pad_masque_layer_s; /* Masque des couches appartenant au pad de depart */
  292. int pad_masque_layer_e; /* Masque des couches appartenant au pad d'arrivee */
  293. int masque_layer_TOP = g_TabOneLayerMask[Route_Layer_TOP];
  294. int masque_layer_BOTTOM = g_TabOneLayerMask[Route_Layer_BOTTOM];
  295. int masque_layers; /* Masque des 2 couches de routage */
  296. int tab_mask[2];/* permet le calcul du Masque de la couche en cours
  297. * de tst (side = TOP ou BOTTOM)*/
  298. int start_mask_layer = 0;
  299. wxString msg;
  300. result = NOSUCCESS;
  301. marge = g_DesignSettings.m_TrackClearence + (g_DesignSettings.m_CurrentTrackWidth / 2);
  302. via_marge = g_DesignSettings.m_TrackClearence + (g_DesignSettings.m_CurrentViaSize / 2);
  303. /* clear direction flags */
  304. i = Nrows * Ncols * sizeof(char);
  305. memset( Board.m_DirSide[TOP], FROM_NOWHERE, i );
  306. memset( Board.m_DirSide[BOTTOM], FROM_NOWHERE, i );
  307. lastopen = lastclos = lastmove = 0;
  308. /* Init tab_masque[side] pour tests de fin de routage */
  309. tab_mask[TOP] = masque_layer_TOP;
  310. tab_mask[BOTTOM] = masque_layer_BOTTOM;
  311. /* Init masque des couches actives */
  312. masque_layers = masque_layer_TOP | masque_layer_BOTTOM;
  313. pt_cur_ch = pt_chevelu;
  314. current_net_code = pt_chevelu->m_NetCode;
  315. pad_masque_layer_s = pt_cur_ch->pad_start->m_Masque_Layer;
  316. pad_masque_layer_e = pt_cur_ch->pad_end->m_Masque_Layer;
  317. /* Test 1 Si routage possible c.a.d si les pads sont accessibles
  318. * sur les couches de routage */
  319. if( (masque_layers & pad_masque_layer_s) == 0 )
  320. goto end_of_route;
  321. if( (masque_layers & pad_masque_layer_e) == 0 )
  322. goto end_of_route;
  323. /* Test 2 Si routage possible c.a.d si les pads sont accessibles
  324. * sur la grille de routage ( 1 point de grille doit etre dans le pad)*/
  325. {
  326. int cX = (g_GridRoutingSize * col_source) + pcbframe->m_Pcb->m_BoundaryBox.m_Pos.x;
  327. int cY = (g_GridRoutingSize * row_source) + pcbframe->m_Pcb->m_BoundaryBox.m_Pos.y;
  328. int dx = pt_cur_ch->pad_start->m_Size.x / 2;
  329. int dy = pt_cur_ch->pad_start->m_Size.y / 2;
  330. int px = pt_cur_ch->pad_start->m_Pos.x;
  331. int py = pt_cur_ch->pad_start->m_Pos.y;
  332. if( ( (pt_cur_ch->pad_start->m_Orient / 900) & 1 ) != 0 )
  333. EXCHG( dx, dy );
  334. if( (abs( cX - px ) > dx ) || (abs( cY - py ) > dy) )
  335. goto end_of_route;
  336. cX = (g_GridRoutingSize * col_target) + pcbframe->m_Pcb->m_BoundaryBox.m_Pos.x;
  337. cY = (g_GridRoutingSize * row_target) + pcbframe->m_Pcb->m_BoundaryBox.m_Pos.y;
  338. dx = pt_cur_ch->pad_end->m_Size.x / 2;
  339. dy = pt_cur_ch->pad_end->m_Size.y / 2;
  340. px = pt_cur_ch->pad_end->m_Pos.x;
  341. py = pt_cur_ch->pad_end->m_Pos.y;
  342. if( ( (pt_cur_ch->pad_end->m_Orient / 900) & 1 ) != 0 )
  343. EXCHG( dx, dy );
  344. if( (abs( cX - px ) > dx ) || (abs( cY - py ) > dy) )
  345. goto end_of_route;
  346. }
  347. /* Test du cas trivial: connection directe par superposition des pads */
  348. if( (row_source == row_target) && (col_source == col_target)
  349. && ( pad_masque_layer_e & pad_masque_layer_s &
  350. g_TabAllCopperLayerMask[g_DesignSettings.m_CopperLayerCount - 1]) )
  351. {
  352. result = TRIVIAL_SUCCESS;
  353. goto end_of_route;
  354. }
  355. /* Placement du bit de suppression d'obstacle relative aux 2 pads a relier */
  356. pcbframe->Affiche_Message( wxT( "Gen Cells" ) );
  357. Place_1_Pad_Board( pcbframe->m_Pcb, pt_cur_ch->pad_start, CURRENT_PAD, marge, WRITE_OR_CELL );
  358. Place_1_Pad_Board( pcbframe->m_Pcb, pt_cur_ch->pad_end, CURRENT_PAD, marge, WRITE_OR_CELL );
  359. /* Regenere les barrieres restantes (qui peuvent empieter sur le placement
  360. * des bits precedents) */
  361. ptr = (LISTE_PAD*) pcbframe->m_Pcb->m_Pads; i = pcbframe->m_Pcb->m_NbPads;
  362. for( ; i > 0; i--, ptr++ )
  363. {
  364. if( (pt_cur_ch->pad_start != *ptr) && (pt_cur_ch->pad_end != *ptr) )
  365. {
  366. Place_1_Pad_Board( pcbframe->m_Pcb, *ptr, ~CURRENT_PAD, marge, WRITE_AND_CELL );
  367. }
  368. }
  369. InitQueue(); /* initialize the search queue */
  370. apx_dist = GetApxDist( row_source, col_source, row_target, col_target );
  371. /* Init 1ere recherche */
  372. if( two_sides ) /* orientation preferentielle */
  373. {
  374. if( abs( row_target - row_source ) > abs( col_target - col_source ) )
  375. {
  376. if( pad_masque_layer_s & masque_layer_TOP )
  377. {
  378. start_mask_layer = 2;
  379. if( SetQueue( row_source, col_source, TOP, 0, apx_dist,
  380. row_target, col_target ) == 0 )
  381. {
  382. return ERR_MEMORY;
  383. }
  384. }
  385. if( pad_masque_layer_s & masque_layer_BOTTOM )
  386. {
  387. start_mask_layer |= 1;
  388. if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist,
  389. row_target, col_target ) == 0 )
  390. {
  391. return ERR_MEMORY;
  392. }
  393. }
  394. }
  395. else
  396. {
  397. if( pad_masque_layer_s & masque_layer_BOTTOM )
  398. {
  399. start_mask_layer = 1;
  400. if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist,
  401. row_target, col_target ) == 0 )
  402. {
  403. return ERR_MEMORY;
  404. }
  405. }
  406. if( pad_masque_layer_s & masque_layer_TOP )
  407. {
  408. start_mask_layer |= 2;
  409. if( SetQueue( row_source, col_source, TOP, 0, apx_dist,
  410. row_target, col_target ) == 0 )
  411. {
  412. return ERR_MEMORY;
  413. }
  414. }
  415. }
  416. }
  417. else if( pad_masque_layer_s & masque_layer_BOTTOM )
  418. {
  419. start_mask_layer = 1;
  420. if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist,
  421. row_target, col_target ) == 0 )
  422. {
  423. return ERR_MEMORY;
  424. }
  425. }
  426. /* search until success or we exhaust all possibilities */
  427. GetQueue( &r, &c, &side, &d, &apx_dist );
  428. for( ; r != ILLEGAL; GetQueue( &r, &c, &side, &d, &apx_dist ) )
  429. {
  430. curcell = GetCell( r, c, side );
  431. if( curcell & CURRENT_PAD )
  432. curcell &= ~HOLE;
  433. if( (r == row_target) && (c == col_target) /* success si layer OK */
  434. && ( tab_mask[side] & pad_masque_layer_e) )
  435. {
  436. /* Efface Liaison */
  437. GRSetDrawMode( DC, GR_XOR );
  438. GRLine( &pcbframe->DrawPanel->m_ClipBox,
  439. DC,
  440. segm_oX,
  441. segm_oY,
  442. segm_fX,
  443. segm_fY,
  444. 0,
  445. WHITE );
  446. /* Generation de la trace */
  447. if( Retrace( pcbframe, DC, row_source, col_source,
  448. row_target, col_target, side, current_net_code ) )
  449. {
  450. result = SUCCESS; /* Success : Route OK */
  451. }
  452. break; /* Fin du routage */
  453. }
  454. /* report every 300 new nodes or so */
  455. if( (OpenNodes - lastopen > 300) || (ClosNodes - lastclos > 300) ||
  456. (MoveNodes - lastmove > 300) )
  457. {
  458. lastopen = (OpenNodes / 300) * 300; lastclos = (ClosNodes / 300) * 300;
  459. lastmove = (MoveNodes / 300) * 300;
  460. if( pcbframe->DrawPanel->m_AbortRequest )
  461. {
  462. result = STOP_FROM_ESC; break;
  463. }
  464. AFFICHE_ACTIVITE_ROUTE;
  465. }
  466. _self = 0;
  467. if( curcell & HOLE )
  468. {
  469. _self = 5;
  470. /* set 'present' bits */
  471. for( i = 0; i < 8; i++ )
  472. {
  473. selfok2[i].present = 0;
  474. if( (curcell & selfok2[i].trace) )
  475. selfok2[i].present = 1;
  476. }
  477. }
  478. for( i = 0; i < 8; i++ ) /* consider neighbors */
  479. {
  480. nr = r + delta[i][0]; nc = c + delta[i][1];
  481. /* off the edge? */
  482. if( nr < 0 || nr >= Nrows || nc < 0 || nc >= Ncols )
  483. continue;/* off the edge */
  484. if( _self == 5 && selfok2[i].present )
  485. continue;
  486. newcell = GetCell( nr, nc, side );
  487. if( newcell & CURRENT_PAD )
  488. newcell &= ~HOLE;
  489. /* check for non-target hole */
  490. if( newcell & HOLE )
  491. {
  492. if( nr != row_target || nc != col_target )
  493. continue;
  494. }
  495. /* check for traces */
  496. else if( newcell & HOLE & ~(newmask[i]) )
  497. continue;
  498. /* check blocking on corner neighbors */
  499. if( delta[i][0] && delta[i][1] )
  500. {
  501. /* check first buddy */
  502. buddy = GetCell( r + blocking[i].r1, c + blocking[i].c1, side );
  503. if( buddy & CURRENT_PAD )
  504. buddy &= ~HOLE;
  505. if( buddy & HOLE )
  506. continue;
  507. // if (buddy & (blocking[i].b1)) continue;
  508. /* check second buddy */
  509. buddy = GetCell( r + blocking[i].r2, c + blocking[i].c2, side );
  510. if( buddy & CURRENT_PAD )
  511. buddy &= ~HOLE;
  512. if( buddy & HOLE )
  513. continue;
  514. // if (buddy & (blocking[i].b2)) continue;
  515. }
  516. olddir = GetDir( r, c, side );
  517. newdist = d + CalcDist( ndir[i], olddir,
  518. (olddir == FROM_OTHERSIDE) ? GetDir( r,
  519. c,
  520. 1 - side ) : 0, side );
  521. /* if (a) not visited yet, or (b) we have */
  522. /* found a better path, add it to queue */
  523. if( !GetDir( nr, nc, side ) )
  524. {
  525. SetDir( nr, nc, side, ndir[i] );
  526. SetDist( nr, nc, side, newdist );
  527. if( SetQueue( nr, nc, side, newdist,
  528. GetApxDist( nr, nc, row_target, col_target ),
  529. row_target, col_target ) == 0 )
  530. {
  531. return ERR_MEMORY;
  532. }
  533. }
  534. else if( newdist < GetDist( nr, nc, side ) )
  535. {
  536. SetDir( nr, nc, side, ndir[i] );
  537. SetDist( nr, nc, side, newdist );
  538. ReSetQueue( nr, nc, side, newdist,
  539. GetApxDist( nr, nc, row_target, col_target ),
  540. row_target, col_target );
  541. }
  542. }
  543. /** etude de l'autre couche **/
  544. if( (two_sides) && !g_No_Via_Route )
  545. {
  546. olddir = GetDir( r, c, side );
  547. if( olddir == FROM_OTHERSIDE )
  548. continue; /* useless move, so don't bother */
  549. if( curcell ) /* can't drill via if anything here */
  550. continue;
  551. /* check for holes or traces on other side */
  552. if( ( newcell = GetCell( r, c, 1 - side ) ) != 0 )
  553. continue;
  554. /* check for nearby holes or traces on both sides */
  555. for( skip = 0, i = 0; i < 8; i++ )
  556. {
  557. nr = r + delta[i][0]; nc = c + delta[i][1];
  558. if( nr < 0 || nr >= Nrows || nc < 0 || nc >= Ncols )
  559. continue;/* off the edge !! */
  560. if( GetCell( nr, nc, side ) /* & blocking2[i]*/ )
  561. {
  562. skip = 1; /* can't drill via here */
  563. break;
  564. }
  565. if( GetCell( nr, nc, 1 - side ) /* & blocking2[i]*/ )
  566. {
  567. skip = 1; /* can't drill via here */
  568. break;
  569. }
  570. }
  571. if( skip ) /* neighboring hole or trace? */
  572. continue; /* yes, can't drill via here */
  573. newdist = d + CalcDist( FROM_OTHERSIDE, olddir, 0, side );
  574. /* if (a) not visited yet,
  575. * or (b) we have found a better path,
  576. * add it to queue */
  577. if( !GetDir( r, c, 1 - side ) )
  578. {
  579. SetDir( r, c, 1 - side, FROM_OTHERSIDE );
  580. SetDist( r, c, 1 - side, newdist );
  581. if( SetQueue( r, c, 1 - side, newdist, apx_dist, row_target,
  582. col_target ) == 0 )
  583. {
  584. return ERR_MEMORY;
  585. }
  586. }
  587. else if( newdist < GetDist( r, c, 1 - side ) )
  588. {
  589. SetDir( r, c, 1 - side, FROM_OTHERSIDE );
  590. SetDist( r, c, 1 - side, newdist );
  591. ReSetQueue( r, c, 1 - side, newdist, apx_dist, row_target, col_target );
  592. }
  593. } /* Fin de l'exploration de l'autre couche */
  594. }
  595. end_of_route:
  596. Place_1_Pad_Board( pcbframe->m_Pcb, pt_cur_ch->pad_start, ~CURRENT_PAD, marge, WRITE_AND_CELL );
  597. Place_1_Pad_Board( pcbframe->m_Pcb, pt_cur_ch->pad_end, ~CURRENT_PAD, marge, WRITE_AND_CELL );
  598. AFFICHE_ACTIVITE_ROUTE;
  599. return result;
  600. }
  601. static long bit[8][9] = { /* OT=Otherside */
  602. /* N, NE, E, SE, S, SW, W, NW, OT */
  603. /* N */ { LINE_VERTICAL, BENT_StoNE, CORNER_SOUTHEAST, SHARP_StoSE, 0,
  604. SHARP_StoSW, CORNER_SOUTHWEST, BENT_StoNW, (HOLE | HOLE_SOUTH) },
  605. /* NE */ { BENT_NtoSW, DIAG_NEtoSW, BENT_EtoSW, ANGLE_SEtoSW, SHARP_StoSW,
  606. 0, SHARP_WtoSW, ANGLE_SWtoNW, (HOLE | HOLE_SOUTHWEST) },
  607. /* E */ { CORNER_NORTHWEST, BENT_WtoNE, LINE_HORIZONTAL, BENT_WtoSE,
  608. CORNER_SOUTHWEST, SHARP_WtoSW, 0, SHARP_WtoNW, (HOLE | HOLE_WEST) },
  609. /* SE */ { SHARP_NtoNW, ANGLE_NWtoNE, BENT_EtoNW, DIAG_SEtoNW, BENT_StoNW,
  610. ANGLE_SWtoNW, SHARP_WtoNW, 0, (HOLE | HOLE_NORTHWEST) },
  611. /* S */ { 0, SHARP_NtoNE, CORNER_NORTHEAST, BENT_NtoSE, LINE_VERTICAL,
  612. BENT_NtoSW, CORNER_NORTHWEST, SHARP_NtoNW, (HOLE | HOLE_NORTH) },
  613. /* SW */ { SHARP_NtoNE, 0, SHARP_EtoNE, ANGLE_NEtoSE, BENT_StoNE,
  614. DIAG_NEtoSW,
  615. BENT_WtoNE, ANGLE_NWtoNE, (HOLE | HOLE_NORTHEAST) },
  616. /* W */ { CORNER_NORTHEAST, SHARP_EtoNE, 0, SHARP_EtoSE, CORNER_SOUTHEAST,
  617. BENT_EtoSW, LINE_HORIZONTAL, BENT_EtoNW, (HOLE | HOLE_EAST) },
  618. /* NW */ { BENT_NtoSE, ANGLE_NEtoSE, SHARP_EtoSE, 0, SHARP_StoSE,
  619. ANGLE_SEtoSW, BENT_WtoSE, DIAG_SEtoNW, (HOLE | HOLE_SOUTHEAST) }
  620. };
  621. /*****************************************************************/
  622. /* int Retrace (COMMAND * Cmd, int row_source, int col_source */
  623. /* int row_target, int col_target, int target_side, */
  624. /* int current_net_code ) */
  625. /*****************************************************************/
  626. /* work from target back to source, actually laying the traces
  627. * Parametres:
  628. * start on side target_side, aux coordonnees row_target, col_target.
  629. * arrivee sur side masque_layer_start, coord row_source, col_source
  630. * La recherche se fait en sens inverse du routage,
  631. * c.a.d du point d'arrivee (target) vers le point de depart (source)
  632. * du routeur.
  633. *
  634. * target_side = cote (TOP / BOTTOM) de depart
  635. * mask_layer_source = masque des couches d'arrivee
  636. *
  637. * Retourne:
  638. * 0 si erreur
  639. * > 0 si Ok
  640. */
  641. static int Retrace( WinEDA_PcbFrame* pcbframe, wxDC* DC,
  642. int row_source, int col_source,
  643. int row_target, int col_target, int target_side,
  644. int current_net_code )
  645. {
  646. int r0, c0, s0;
  647. int r1, c1, s1; /* row, col, side d'ou on vient */
  648. int r2, c2, s2; /* row, col, side ou on va */
  649. int x, y = -1;
  650. long b;
  651. r1 = row_target;
  652. c1 = col_target; /* start point is target ( end point is source )*/
  653. s1 = target_side;
  654. r0 = c0 = s0 = ILLEGAL;
  655. g_FirstTrackSegment = g_CurrentTrackSegment = NULL;
  656. g_TrackSegmentCount = 0;
  657. do {
  658. /* find where we came from to get here */
  659. r2 = r1; c2 = c1; s2 = s1;
  660. x = GetDir( r1, c1, s1 );
  661. switch( x )
  662. {
  663. case FROM_NORTH:
  664. r2++; break;
  665. case FROM_EAST:
  666. c2++; break;
  667. case FROM_SOUTH:
  668. r2--; break;
  669. case FROM_WEST:
  670. c2--; break;
  671. case FROM_NORTHEAST:
  672. r2++; c2++; break;
  673. case FROM_SOUTHEAST:
  674. r2--; c2++; break;
  675. case FROM_SOUTHWEST:
  676. r2--; c2--; break;
  677. case FROM_NORTHWEST:
  678. r2++; c2--; break;
  679. case FROM_OTHERSIDE:
  680. s2 = 1 - s2; break;
  681. default:
  682. DisplayError( pcbframe, wxT( "Retrace: internal error: no way back" ) );
  683. return 0;
  684. }
  685. if( r0 != ILLEGAL )
  686. y = GetDir( r0, c0, s0 );
  687. /* see if target or hole */
  688. if( ( (r1 == row_target) && (c1 == col_target) )
  689. || (s1 != s0) )
  690. {
  691. int p_dir;
  692. switch( x )
  693. {
  694. case FROM_NORTH:
  695. p_dir = HOLE_NORTH; break;
  696. case FROM_EAST:
  697. p_dir = HOLE_EAST; break;
  698. case FROM_SOUTH:
  699. p_dir = HOLE_SOUTH; break;
  700. case FROM_WEST:
  701. p_dir = HOLE_WEST; break;
  702. case FROM_NORTHEAST:
  703. p_dir = HOLE_NORTHEAST; break;
  704. case FROM_SOUTHEAST:
  705. p_dir = HOLE_SOUTHEAST; break;
  706. case FROM_SOUTHWEST:
  707. p_dir = HOLE_SOUTHWEST; break;
  708. case FROM_NORTHWEST:
  709. p_dir = HOLE_NORTHWEST; break;
  710. case FROM_OTHERSIDE:
  711. default:
  712. DisplayError( pcbframe, wxT( "Retrace: error 1" ) );
  713. return 0;
  714. }
  715. OrCell_Trace( pcbframe->m_Pcb, r1, c1, s1, p_dir, current_net_code );
  716. }
  717. else
  718. {
  719. if( (y == FROM_NORTH || y == FROM_NORTHEAST
  720. || y == FROM_EAST || y == FROM_SOUTHEAST
  721. || y == FROM_SOUTH || y == FROM_SOUTHWEST
  722. || y == FROM_WEST || y == FROM_NORTHWEST)
  723. && (x == FROM_NORTH || x == FROM_NORTHEAST
  724. || x == FROM_EAST || x == FROM_SOUTHEAST
  725. || x == FROM_SOUTH || x == FROM_SOUTHWEST
  726. || x == FROM_WEST || x == FROM_NORTHWEST
  727. || x == FROM_OTHERSIDE)
  728. && ( (b = bit[y - 1][x - 1]) != 0 ) )
  729. {
  730. OrCell_Trace( pcbframe->m_Pcb, r1, c1, s1, b, current_net_code );
  731. if( b & HOLE )
  732. OrCell_Trace( pcbframe->m_Pcb, r2, c2, s2, HOLE, current_net_code );
  733. }
  734. else
  735. {
  736. DisplayError( pcbframe, wxT( "Retrace: error 2" ) );
  737. return 0;
  738. }
  739. }
  740. if( (r2 == row_source) && (c2 == col_source) )
  741. { /* see if source */
  742. int p_dir;
  743. switch( x )
  744. {
  745. case FROM_NORTH:
  746. p_dir = HOLE_SOUTH; break;
  747. case FROM_EAST:
  748. p_dir = HOLE_WEST; break;
  749. case FROM_SOUTH:
  750. p_dir = HOLE_NORTH; break;
  751. case FROM_WEST:
  752. p_dir = HOLE_EAST; break;
  753. case FROM_NORTHEAST:
  754. p_dir = HOLE_SOUTHWEST; break;
  755. case FROM_SOUTHEAST:
  756. p_dir = HOLE_NORTHWEST; break;
  757. case FROM_SOUTHWEST:
  758. p_dir = HOLE_NORTHEAST; break;
  759. case FROM_NORTHWEST:
  760. p_dir = HOLE_SOUTHEAST; break;
  761. case FROM_OTHERSIDE:
  762. default:
  763. DisplayError( pcbframe, wxT( "Retrace: error 3" ) );
  764. return 0;
  765. }
  766. OrCell_Trace( pcbframe->m_Pcb, r2, c2, s2, p_dir, current_net_code );
  767. }
  768. /* move to next cell */
  769. r0 = r1; c0 = c1; s0 = s1;
  770. r1 = r2; c1 = c2; s1 = s2;
  771. } while( !( (r2 == row_source) && (c2 == col_source) ) );
  772. Place_Piste_en_Buffer( pcbframe, DC );
  773. return 1;
  774. }
  775. /*****************************************************************************/
  776. static void OrCell_Trace( BOARD* pcb, int col, int row,
  777. int side, int orient, int current_net_code )
  778. /*****************************************************************************/
  779. /* appelle la routine OrCell et place la piste reelle sur le pcb */
  780. {
  781. int dx0, dy0, dx1, dy1;
  782. TRACK* NewTrack, * OldTrack;
  783. if( orient == HOLE ) /* Placement d'une VIA */
  784. {
  785. NewTrack = new SEGVIA( pcb );
  786. g_TrackSegmentCount++;
  787. NewTrack->Pback = g_CurrentTrackSegment;
  788. if( g_CurrentTrackSegment )
  789. g_CurrentTrackSegment->Pnext = NewTrack;
  790. else
  791. g_FirstTrackSegment = NewTrack;
  792. g_CurrentTrackSegment = NewTrack;
  793. g_CurrentTrackSegment->SetState( SEGM_AR, ON );
  794. g_CurrentTrackSegment->SetLayer( 0x0F );
  795. g_CurrentTrackSegment->m_Start.x = g_CurrentTrackSegment->m_End.x =
  796. pcb->m_BoundaryBox.m_Pos.x +
  797. (g_GridRoutingSize * row);
  798. g_CurrentTrackSegment->m_Start.y = g_CurrentTrackSegment->m_End.y =
  799. pcb->m_BoundaryBox.m_Pos.y +
  800. (g_GridRoutingSize * col);
  801. g_CurrentTrackSegment->m_Width = g_DesignSettings.m_CurrentViaSize;
  802. g_CurrentTrackSegment->m_Shape = g_DesignSettings.m_CurrentViaType;
  803. g_CurrentTrackSegment->m_NetCode = current_net_code;
  804. }
  805. else /* Placement d'un segment standard */
  806. {
  807. NewTrack = new TRACK( pcb );
  808. g_TrackSegmentCount++;
  809. NewTrack->Pback = g_CurrentTrackSegment;
  810. if( g_CurrentTrackSegment )
  811. g_CurrentTrackSegment->Pnext = NewTrack;
  812. else
  813. g_FirstTrackSegment = NewTrack;
  814. g_CurrentTrackSegment = NewTrack;
  815. g_CurrentTrackSegment->SetLayer( Route_Layer_BOTTOM );
  816. if( side == TOP )
  817. g_CurrentTrackSegment->SetLayer( Route_Layer_TOP );
  818. g_CurrentTrackSegment->SetState( SEGM_AR, ON );
  819. g_CurrentTrackSegment->m_End.x = pcb->m_BoundaryBox.m_Pos.x + (g_GridRoutingSize * row);
  820. g_CurrentTrackSegment->m_End.y = pcb->m_BoundaryBox.m_Pos.y + (g_GridRoutingSize * col);
  821. g_CurrentTrackSegment->m_NetCode = current_net_code;
  822. if( g_CurrentTrackSegment->Pback == NULL ) /* Start Piste */
  823. {
  824. g_CurrentTrackSegment->m_Start.x = segm_fX;
  825. g_CurrentTrackSegment->m_Start.y = segm_fY;
  826. /* Replacement sur le centre du pad si hors grille */
  827. dx1 = g_CurrentTrackSegment->m_End.x - g_CurrentTrackSegment->m_Start.x;
  828. dy1 = g_CurrentTrackSegment->m_End.y - g_CurrentTrackSegment->m_Start.y;
  829. dx0 = pt_cur_ch->pad_end->m_Pos.x - g_CurrentTrackSegment->m_Start.x;
  830. dy0 = pt_cur_ch->pad_end->m_Pos.y - g_CurrentTrackSegment->m_Start.y;
  831. /* si aligne: modif du point origine */
  832. if( abs( dx0 * dy1 ) == abs( dx1 * dy0 ) ) /* Alignes ! */
  833. {
  834. g_CurrentTrackSegment->m_Start.x = pt_cur_ch->pad_end->m_Pos.x;
  835. g_CurrentTrackSegment->m_Start.y = pt_cur_ch->pad_end->m_Pos.y;
  836. }
  837. else /* Creation d'un segment suppl raccord */
  838. {
  839. NewTrack = g_CurrentTrackSegment->Copy();
  840. g_TrackSegmentCount++;
  841. NewTrack->Insert( pcb, g_CurrentTrackSegment );
  842. g_CurrentTrackSegment->m_Start.x = pt_cur_ch->pad_end->m_Pos.x;
  843. g_CurrentTrackSegment->m_Start.y = pt_cur_ch->pad_end->m_Pos.y;
  844. NewTrack->m_Start.x = g_CurrentTrackSegment->m_End.x;
  845. NewTrack->m_Start.y = g_CurrentTrackSegment->m_End.y;
  846. g_CurrentTrackSegment = NewTrack;
  847. }
  848. }
  849. else
  850. {
  851. if( g_CurrentTrackSegment->Pback )
  852. {
  853. g_CurrentTrackSegment->m_Start.x = ( (TRACK*) g_CurrentTrackSegment->Pback )->
  854. m_End.x;
  855. g_CurrentTrackSegment->m_Start.y = ( (TRACK*) g_CurrentTrackSegment->Pback )->
  856. m_End.y;
  857. }
  858. }
  859. g_CurrentTrackSegment->m_Width = g_DesignSettings.m_CurrentTrackWidth;
  860. if( (g_CurrentTrackSegment->m_Start.x != g_CurrentTrackSegment->m_End.x)
  861. || (g_CurrentTrackSegment->m_Start.y != g_CurrentTrackSegment->m_End.y) )
  862. {
  863. /* Reduction des segments alignes a 1 seul */
  864. OldTrack = (TRACK*) g_CurrentTrackSegment->Pback;
  865. if( OldTrack && (OldTrack->m_StructType != TYPEVIA) )
  866. {
  867. dx1 = g_CurrentTrackSegment->m_End.x - g_CurrentTrackSegment->m_Start.x;
  868. dy1 = g_CurrentTrackSegment->m_End.y - g_CurrentTrackSegment->m_Start.y;
  869. dx0 = OldTrack->m_End.x - OldTrack->m_Start.x;
  870. dy0 = OldTrack->m_End.y - OldTrack->m_Start.y;
  871. if( abs( dx0 * dy1 ) == abs( dx1 * dy0 ) )/* le dernier segment est en ligne*/
  872. {
  873. OldTrack->m_End.x = g_CurrentTrackSegment->m_End.x;
  874. OldTrack->m_End.y = g_CurrentTrackSegment->m_End.y;
  875. delete g_CurrentTrackSegment;
  876. g_CurrentTrackSegment = OldTrack;
  877. g_CurrentTrackSegment->Pnext = NULL;
  878. g_TrackSegmentCount--;
  879. }
  880. }
  881. }
  882. }
  883. }
  884. /*******************************************/
  885. /* static void Place_Piste_en_Buffer(void) */
  886. /*******************************************/
  887. /* Insere la nouvelle piste creee dans la liste standard des pistes.
  888. * Modifie les points de debut et fin de piste pour qu'ils soient relies
  889. * au centre des pads corresponadants, meme hors grille
  890. */
  891. static void Place_Piste_en_Buffer( WinEDA_PcbFrame* pcbframe, wxDC* DC )
  892. {
  893. TRACK* pt_track;
  894. int dx0, dy0, dx1, dy1;
  895. int marge, via_marge;
  896. WinEDA_DrawPanel* panel = pcbframe->DrawPanel;
  897. marge = g_DesignSettings.m_TrackClearence + (g_DesignSettings.m_CurrentTrackWidth / 2);
  898. via_marge = g_DesignSettings.m_TrackClearence + (g_DesignSettings.m_CurrentViaSize / 2);
  899. /* tst point d'arrivee : doit etre sur pad start */
  900. dx1 = g_CurrentTrackSegment->m_End.x - g_CurrentTrackSegment->m_Start.x;
  901. dy1 = g_CurrentTrackSegment->m_End.y - g_CurrentTrackSegment->m_Start.y;
  902. /* Replacement sur le centre du pad si hors grille */
  903. dx0 = pt_cur_ch->pad_start->m_Pos.x - g_CurrentTrackSegment->m_Start.x;
  904. dy0 = pt_cur_ch->pad_start->m_Pos.y - g_CurrentTrackSegment->m_Start.y;
  905. /* si aligne: modif du point origine */
  906. if( abs( dx0 * dy1 ) == abs( dx1 * dy0 ) ) /* Alignes ! */
  907. {
  908. g_CurrentTrackSegment->m_End.x = pt_cur_ch->pad_start->m_Pos.x;
  909. g_CurrentTrackSegment->m_End.y = pt_cur_ch->pad_start->m_Pos.y;
  910. }
  911. else /* Creation d'un segment suppl raccord */
  912. {
  913. TRACK* NewTrack = g_CurrentTrackSegment->Copy();
  914. NewTrack->Insert( pcbframe->m_Pcb, g_CurrentTrackSegment );
  915. NewTrack->m_End.x = pt_cur_ch->pad_start->m_Pos.x;
  916. NewTrack->m_End.y = pt_cur_ch->pad_start->m_Pos.y;
  917. NewTrack->m_Start.x = g_CurrentTrackSegment->m_End.x;
  918. NewTrack->m_Start.y = g_CurrentTrackSegment->m_End.y;
  919. g_CurrentTrackSegment = NewTrack; g_TrackSegmentCount++;
  920. }
  921. g_FirstTrackSegment->start = Locate_Pad_Connecte( pcbframe->m_Pcb, g_FirstTrackSegment, START );
  922. if( g_FirstTrackSegment->start )
  923. g_FirstTrackSegment->SetState( BEGIN_ONPAD, ON );
  924. g_CurrentTrackSegment->end = Locate_Pad_Connecte( pcbframe->m_Pcb, g_CurrentTrackSegment, END );
  925. if( g_CurrentTrackSegment->end )
  926. g_CurrentTrackSegment->SetState( END_ONPAD, ON );
  927. /* recherche de la zone de rangement et insertion de la nouvelle piste */
  928. pt_track = g_FirstTrackSegment->GetBestInsertPoint( pcbframe->m_Pcb );
  929. g_FirstTrackSegment->Insert( pcbframe->m_Pcb, pt_track );
  930. Trace_Une_Piste( panel, DC, g_FirstTrackSegment, g_TrackSegmentCount, GR_OR );
  931. pcbframe->test_1_net_connexion( DC, g_FirstTrackSegment->m_NetCode );
  932. /* Trace de la forme exacte de la piste en BOARD */
  933. for( pt_track = g_FirstTrackSegment; ; pt_track = (TRACK*) pt_track->Pnext )
  934. {
  935. TraceSegmentPcb( pcbframe->m_Pcb, pt_track, HOLE, marge, WRITE_CELL );
  936. TraceSegmentPcb( pcbframe->m_Pcb, pt_track, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
  937. if( pt_track == g_CurrentTrackSegment )
  938. break;
  939. }
  940. ActiveScreen->SetModify();
  941. }