/* Route a trace on the BOARD. * Parameters: * 1 side / 2 sides (0 / 1) * Coord source (row, col) * Coord destination (row, col) * Net_code * Pointer to the ratsnest reference * * Returns: * SUCCESS if routed * TRIVIAL_SUCCESS if pads are connected by overlay (no track needed) * If failure NOSUCCESS * Escape STOP_FROM_ESC if demand * ERR_MEMORY if memory allocation failed. */ static int Autoroute_One_Track( PCB_EDIT_FRAME* pcbframe, wxDC* DC, int two_sides, int row_source, int col_source, int row_target, int col_target, RATSNEST_ITEM* pt_rat ) { int r, c, side, d, apx_dist, nr, nc; int result, skip; int i; long curcell, newcell, buddy, lastopen, lastclos, lastmove; int newdist, olddir, _self; int current_net_code; int marge; LSET padLayerMaskStart; // Mask layers belonging to the starting pad. LSET padLayerMaskEnd; // Mask layers belonging to the ending pad. LSET topLayerMask( g_Route_Layer_TOP ); LSET bottomLayerMask( g_Route_Layer_BOTTOM ); LSET routeLayerMask; // Mask two layers for routing. LSET tab_mask[2]; // Enables the calculation of the mask layer being // tested. (side = TOP or BOTTOM) int start_mask_layer = 0; wxString msg; // @todo this could be a bottle neck LSET all_cu = LSET::AllCuMask( pcbframe->GetBoard()->GetCopperLayerCount() ); wxBusyCursor dummy_cursor; // Set an hourglass cursor while routing a // track result = NOSUCCESS; marge = s_Clearance + ( pcbframe->GetDesignSettings().GetCurrentTrackWidth() / 2 ); // clear direction flags i = RoutingMatrix.m_Nrows * RoutingMatrix.m_Ncols * sizeof(DIR_CELL); if( two_sides ) memset( RoutingMatrix.m_DirSide[TOP], FROM_NOWHERE, i ); memset( RoutingMatrix.m_DirSide[BOTTOM], FROM_NOWHERE, i ); lastopen = lastclos = lastmove = 0; // Set tab_masque[side] for final test of routing. if( two_sides ) tab_mask[TOP] = topLayerMask; tab_mask[BOTTOM] = bottomLayerMask; // Set active layers mask. routeLayerMask = topLayerMask | bottomLayerMask; pt_cur_ch = pt_rat; current_net_code = pt_rat->GetNet(); padLayerMaskStart = pt_cur_ch->m_PadStart->GetLayerSet(); padLayerMaskEnd = pt_cur_ch->m_PadEnd->GetLayerSet(); /* First Test if routing possible ie if the pads are accessible * on the routing layers. */ if( ( routeLayerMask & padLayerMaskStart ) == 0 ) goto end_of_route; if( ( routeLayerMask & padLayerMaskEnd ) == 0 ) goto end_of_route; /* Then test if routing possible ie if the pads are accessible * On the routing grid (1 grid point must be in the pad) */ { int cX = ( RoutingMatrix.m_GridRouting * col_source ) + pcbframe->GetBoard()->GetBoundingBox().GetX(); int cY = ( RoutingMatrix.m_GridRouting * row_source ) + pcbframe->GetBoard()->GetBoundingBox().GetY(); int dx = pt_cur_ch->m_PadStart->GetSize().x / 2; int dy = pt_cur_ch->m_PadStart->GetSize().y / 2; int px = pt_cur_ch->m_PadStart->GetPosition().x; int py = pt_cur_ch->m_PadStart->GetPosition().y; if( ( ( int( pt_cur_ch->m_PadStart->GetOrientation() ) / 900 ) & 1 ) != 0 ) std::swap( dx, dy ); if( ( abs( cX - px ) > dx ) || ( abs( cY - py ) > dy ) ) goto end_of_route; cX = ( RoutingMatrix.m_GridRouting * col_target ) + pcbframe->GetBoard()->GetBoundingBox().GetX(); cY = ( RoutingMatrix.m_GridRouting * row_target ) + pcbframe->GetBoard()->GetBoundingBox().GetY(); dx = pt_cur_ch->m_PadEnd->GetSize().x / 2; dy = pt_cur_ch->m_PadEnd->GetSize().y / 2; px = pt_cur_ch->m_PadEnd->GetPosition().x; py = pt_cur_ch->m_PadEnd->GetPosition().y; if( ( ( int( pt_cur_ch->m_PadEnd->GetOrientation() ) / 900) & 1 ) != 0 ) std::swap( dx, dy ); if( ( abs( cX - px ) > dx ) || ( abs( cY - py ) > dy ) ) goto end_of_route; } // Test the trivial case: direct connection overlay pads. if( row_source == row_target && col_source == col_target && ( padLayerMaskEnd & padLayerMaskStart & all_cu ).any() ) { result = TRIVIAL_SUCCESS; goto end_of_route; } // Placing the bit to remove obstacles on 2 pads to a link. pcbframe->SetStatusText( wxT( "Gen Cells" ) ); PlacePad( pt_cur_ch->m_PadStart, CURRENT_PAD, marge, WRITE_OR_CELL ); PlacePad( pt_cur_ch->m_PadEnd, CURRENT_PAD, marge, WRITE_OR_CELL ); // Regenerates the remaining barriers (which may encroach on the // placement bits precedent) i = pcbframe->GetBoard()->GetPadCount(); for( unsigned ii = 0; ii < pcbframe->GetBoard()->GetPadCount(); ii++ ) { D_PAD* ptr = pcbframe->GetBoard()->GetPad( ii ); if( ( pt_cur_ch->m_PadStart != ptr ) && ( pt_cur_ch->m_PadEnd != ptr ) ) { PlacePad( ptr, ~CURRENT_PAD, marge, WRITE_AND_CELL ); } } InitQueue(); // initialize the search queue apx_dist = RoutingMatrix.GetApxDist( row_source, col_source, row_target, col_target ); // Initialize first search. if( two_sides ) // Preferred orientation. { if( abs( row_target - row_source ) > abs( col_target - col_source ) ) { if( ( padLayerMaskStart & topLayerMask ).any() ) { start_mask_layer = 2; if( SetQueue( row_source, col_source, TOP, 0, apx_dist, row_target, col_target ) == 0 ) { return ERR_MEMORY; } } if( ( padLayerMaskStart & bottomLayerMask ).any() ) { start_mask_layer |= 1; if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist, row_target, col_target ) == 0 ) { return ERR_MEMORY; } } } else { if( ( padLayerMaskStart & bottomLayerMask ).any() ) { start_mask_layer = 1; if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist, row_target, col_target ) == 0 ) { return ERR_MEMORY; } } if( ( padLayerMaskStart & topLayerMask ).any() ) { start_mask_layer |= 2; if( SetQueue( row_source, col_source, TOP, 0, apx_dist, row_target, col_target ) == 0 ) { return ERR_MEMORY; } } } } else if( ( padLayerMaskStart & bottomLayerMask ).any() ) { start_mask_layer = 1; if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist, row_target, col_target ) == 0 ) { return ERR_MEMORY; } } // search until success or we exhaust all possibilities GetQueue( &r, &c, &side, &d, &apx_dist ); for( ; r != ILLEGAL; GetQueue( &r, &c, &side, &d, &apx_dist ) ) { curcell = RoutingMatrix.GetCell( r, c, side ); if( curcell & CURRENT_PAD ) curcell &= ~HOLE; if( (r == row_target) && (c == col_target) // success if layer OK && (tab_mask[side] & padLayerMaskEnd).any() ) { // Remove link. GRSetDrawMode( DC, GR_XOR ); GRLine( pcbframe->GetCanvas()->GetClipBox(), DC, segm_oX, segm_oY, segm_fX, segm_fY, 0, WHITE ); // Generate trace. if( Retrace( pcbframe, DC, row_source, col_source, row_target, col_target, side, current_net_code ) ) { result = SUCCESS; // Success : Route OK } break; // Routing complete. } if( pcbframe->GetCanvas()->GetAbortRequest() ) { result = STOP_FROM_ESC; break; } // report every COUNT new nodes or so #define COUNT 20000 if( ( OpenNodes - lastopen > COUNT ) || ( ClosNodes - lastclos > COUNT ) || ( MoveNodes - lastmove > COUNT ) ) { lastopen = OpenNodes; lastclos = ClosNodes; lastmove = MoveNodes; msg.Printf( wxT( "Activity: Open %d Closed %d Moved %d" ), OpenNodes, ClosNodes, MoveNodes ); pcbframe->SetStatusText( msg ); } _self = 0; if( curcell & HOLE ) { _self = 5; // set 'present' bits for( i = 0; i < 8; i++ ) { selfok2[i].present = 0; if( curcell & selfok2[i].trace ) selfok2[i].present = 1; } } for( i = 0; i < 8; i++ ) // consider neighbors { nr = r + delta[i][0]; nc = c + delta[i][1]; // off the edge? if( nr < 0 || nr >= RoutingMatrix.m_Nrows || nc < 0 || nc >= RoutingMatrix.m_Ncols ) continue; // off the edge if( _self == 5 && selfok2[i].present ) continue; newcell = RoutingMatrix.GetCell( nr, nc, side ); if( newcell & CURRENT_PAD ) newcell &= ~HOLE; // check for non-target hole if( newcell & HOLE ) { if( nr != row_target || nc != col_target ) continue; } // check for traces else if( newcell & HOLE & ~(newmask[i]) ) { continue; } // check blocking on corner neighbors if( delta[i][0] && delta[i][1] ) { // check first buddy buddy = RoutingMatrix.GetCell( r + blocking[i].r1, c + blocking[i].c1, side ); if( buddy & CURRENT_PAD ) buddy &= ~HOLE; if( buddy & HOLE ) continue; // if (buddy & (blocking[i].b1)) continue; // check second buddy buddy = RoutingMatrix.GetCell( r + blocking[i].r2, c + blocking[i].c2, side ); if( buddy & CURRENT_PAD ) buddy &= ~HOLE; if( buddy & HOLE ) continue; // if (buddy & (blocking[i].b2)) continue; } olddir = RoutingMatrix.GetDir( r, c, side ); newdist = d + RoutingMatrix.CalcDist( ndir[i], olddir, ( olddir == FROM_OTHERSIDE ) ? RoutingMatrix.GetDir( r, c, 1 - side ) : 0, side ); // if (a) not visited yet, or (b) we have // found a better path, add it to queue if( !RoutingMatrix.GetDir( nr, nc, side ) ) { RoutingMatrix.SetDir( nr, nc, side, ndir[i] ); RoutingMatrix.SetDist( nr, nc, side, newdist ); if( SetQueue( nr, nc, side, newdist, RoutingMatrix.GetApxDist( nr, nc, row_target, col_target ), row_target, col_target ) == 0 ) { return ERR_MEMORY; } } else if( newdist < RoutingMatrix.GetDist( nr, nc, side ) ) { RoutingMatrix.SetDir( nr, nc, side, ndir[i] ); RoutingMatrix.SetDist( nr, nc, side, newdist ); ReSetQueue( nr, nc, side, newdist, RoutingMatrix.GetApxDist( nr, nc, row_target, col_target ), row_target, col_target ); } } //* Test the other layer. * if( two_sides ) { olddir = RoutingMatrix.GetDir( r, c, side ); if( olddir == FROM_OTHERSIDE ) continue; // useless move, so don't bother if( curcell ) // can't drill via if anything here continue; // check for holes or traces on other side if( ( newcell = RoutingMatrix.GetCell( r, c, 1 - side ) ) != 0 ) continue; // check for nearby holes or traces on both sides for( skip = 0, i = 0; i < 8; i++ ) { nr = r + delta[i][0]; nc = c + delta[i][1]; if( nr < 0 || nr >= RoutingMatrix.m_Nrows || nc < 0 || nc >= RoutingMatrix.m_Ncols ) continue; // off the edge !! if( RoutingMatrix.GetCell( nr, nc, side ) /* & blocking2[i] */ ) { skip = 1; // can't drill via here break; } if( RoutingMatrix.GetCell( nr, nc, 1 - side ) /* & blocking2[i] */ ) { skip = 1; // can't drill via here break; } } if( skip ) // neighboring hole or trace? continue; // yes, can't drill via here newdist = d + RoutingMatrix.CalcDist( FROM_OTHERSIDE, olddir, 0, side ); /* if (a) not visited yet, * or (b) we have found a better path, * add it to queue */ if( !RoutingMatrix.GetDir( r, c, 1 - side ) ) { RoutingMatrix.SetDir( r, c, 1 - side, FROM_OTHERSIDE ); RoutingMatrix.SetDist( r, c, 1 - side, newdist ); if( SetQueue( r, c, 1 - side, newdist, apx_dist, row_target, col_target ) == 0 ) { return ERR_MEMORY; } } else if( newdist < RoutingMatrix.GetDist( r, c, 1 - side ) ) { RoutingMatrix.SetDir( r, c, 1 - side, FROM_OTHERSIDE ); RoutingMatrix.SetDist( r, c, 1 - side, newdist ); ReSetQueue( r, c, 1 - side, newdist, apx_dist, row_target, col_target ); } } // Finished attempt to route on other layer. } end_of_route: PlacePad( pt_cur_ch->m_PadStart, ~CURRENT_PAD, marge, WRITE_AND_CELL ); PlacePad( pt_cur_ch->m_PadEnd, ~CURRENT_PAD, marge, WRITE_AND_CELL ); msg.Printf( wxT( "Activity: Open %d Closed %d Moved %d"), OpenNodes, ClosNodes, MoveNodes ); pcbframe->SetStatusText( msg ); return result; }
/* Route une piste du BOARD. Parametres: 1 face / 2 faces ( 0 / 1) coord source (row,col) coord destination (row,col) net_code pointeur sur le chevelu de reference Retourne : SUCCESS si route trouvee TRIVIAL_SUCCESS si pads connectes par superposition ( pas de piste a tirer) NOSUCCESS si echec STOP_FROM_ESC si Escape demande ERR_MEMORY defaut alloc RAM */ static int Route_1_Trace(WinEDA_PcbFrame * pcbframe, wxDC * DC, int two_sides, int row_source,int col_source, int row_target,int col_target, CHEVELU * pt_chevelu ) { int r, c, side , d, apx_dist, nr, nc; int result, skip; int i; LISTE_PAD * ptr; long curcell, newcell, buddy, lastopen, lastclos, lastmove; int newdist, olddir, _self; int current_net_code; int marge, via_marge; int pad_masque_layer_s; /* Masque des couches appartenant au pad de depart */ int pad_masque_layer_e; /* Masque des couches appartenant au pad d'arrivee */ int masque_layer_TOP = g_TabOneLayerMask[Route_Layer_TOP]; int masque_layer_BOTTOM = g_TabOneLayerMask[Route_Layer_BOTTOM]; int masque_layers; /* Masque des 2 couches de routage */ int tab_mask[2]; /* permet le calcul du Masque de la couche en cours de tst (side = TOP ou BOTTOM)*/ int start_mask_layer = 0; wxString msg; result = NOSUCCESS; marge = g_DesignSettings.m_TrackClearence + (g_DesignSettings.m_CurrentTrackWidth / 2); via_marge = g_DesignSettings.m_TrackClearence + (g_DesignSettings.m_CurrentViaSize / 2); /* clear direction flags */ i = Nrows * Ncols * sizeof(char); memset(Board.m_DirSide[TOP], FROM_NOWHERE, i ); memset(Board.m_DirSide[BOTTOM], FROM_NOWHERE, i ); lastopen = lastclos = lastmove = 0; /* Init tab_masque[side] pour tests de fin de routage */ tab_mask[TOP] = masque_layer_TOP; tab_mask[BOTTOM] = masque_layer_BOTTOM; /* Init masque des couches actives */ masque_layers = masque_layer_TOP | masque_layer_BOTTOM; pt_cur_ch = pt_chevelu; current_net_code = pt_chevelu->m_NetCode; pad_masque_layer_s = pt_cur_ch->pad_start->m_Masque_Layer; pad_masque_layer_e = pt_cur_ch->pad_end->m_Masque_Layer; /* Test 1 Si routage possible c.a.d si les pads sont accessibles sur les couches de routage */ if( (masque_layers & pad_masque_layer_s) == 0 ) goto end_of_route; if( (masque_layers & pad_masque_layer_e) == 0 ) goto end_of_route; /* Test 2 Si routage possible c.a.d si les pads sont accessibles sur la grille de routage ( 1 point de grille doit etre dans le pad)*/ { int cX = (pas_route * col_source) + pcbframe->m_Pcb->m_BoundaryBox.m_Pos.x; int cY = (pas_route * row_source) + pcbframe->m_Pcb->m_BoundaryBox.m_Pos.y; int dx = pt_cur_ch->pad_start->m_Size.x / 2; int dy = pt_cur_ch->pad_start->m_Size.y / 2; int px = pt_cur_ch->pad_start->m_Pos.x; int py = pt_cur_ch->pad_start->m_Pos.y; if ( ((pt_cur_ch->pad_start->m_Orient/900)&1) != 0 ) EXCHG(dx,dy) ; if ( (abs(cX - px) > dx ) || (abs(cY - py) > dy) ) goto end_of_route; cX = (pas_route * col_target) + pcbframe->m_Pcb->m_BoundaryBox.m_Pos.x; cY = (pas_route * row_target) + pcbframe->m_Pcb->m_BoundaryBox.m_Pos.y; dx = pt_cur_ch->pad_end->m_Size.x / 2; dy = pt_cur_ch->pad_end->m_Size.y / 2; px = pt_cur_ch->pad_end->m_Pos.x; py = pt_cur_ch->pad_end->m_Pos.y; if ( ((pt_cur_ch->pad_end->m_Orient/900)&1) != 0 ) EXCHG(dx,dy) ; if ( (abs(cX - px) > dx ) || (abs(cY - py) > dy) ) goto end_of_route; } /* Test du cas trivial: connection directe par superposition des pads */ if( (row_source == row_target) && (col_source == col_target) && ( pad_masque_layer_e & pad_masque_layer_s & g_TabAllCopperLayerMask[g_DesignSettings.m_CopperLayerCount-1]) ) { result = TRIVIAL_SUCCESS; goto end_of_route; } /* Placement du bit de suppression d'obstacle relative aux 2 pads a relier */ pcbframe->Affiche_Message( wxT("Gen Cells") ); Place_1_Pad_Board(pcbframe->m_Pcb, pt_cur_ch->pad_start,CURRENT_PAD ,marge,WRITE_OR_CELL); Place_1_Pad_Board(pcbframe->m_Pcb, pt_cur_ch->pad_end, CURRENT_PAD ,marge,WRITE_OR_CELL); /* Regenere les barrieres restantes (qui peuvent empieter sur le placement des bits precedents) */ ptr = (LISTE_PAD*) pcbframe->m_Pcb->m_Pads; i = pcbframe->m_Pcb->m_NbPads; for( ; i > 0 ; i-- , ptr++) { if((pt_cur_ch->pad_start != *ptr) && (pt_cur_ch->pad_end != *ptr) ) { Place_1_Pad_Board(pcbframe->m_Pcb, *ptr, ~CURRENT_PAD,marge,WRITE_AND_CELL); } } InitQueue(); /* initialize the search queue */ apx_dist = GetApxDist( row_source, col_source, row_target, col_target ); /* Init 1ere recherche */ if(two_sides) /* orientation preferentielle */ { if( abs(row_target-row_source) > abs(col_target-col_source) ) { if( pad_masque_layer_s & masque_layer_TOP ) { start_mask_layer = 2; if(SetQueue( row_source, col_source, TOP, 0, apx_dist, row_target, col_target ) == 0) { return(ERR_MEMORY); } } if( pad_masque_layer_s & masque_layer_BOTTOM ) { start_mask_layer |= 1; if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist, row_target, col_target ) == 0 ) { return(ERR_MEMORY); } } } else { if( pad_masque_layer_s & masque_layer_BOTTOM ) { start_mask_layer = 1; if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist, row_target, col_target ) == 0 ) { return(ERR_MEMORY); } } if( pad_masque_layer_s & masque_layer_TOP ) { start_mask_layer |= 2; if (SetQueue( row_source, col_source, TOP, 0, apx_dist, row_target, col_target ) == 0 ) { return(ERR_MEMORY); } } } } else if( pad_masque_layer_s & masque_layer_BOTTOM ) { start_mask_layer = 1; if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist, row_target, col_target ) == 0 ) { return(ERR_MEMORY); } } /* search until success or we exhaust all possibilities */ GetQueue( &r, &c, &side, &d, &apx_dist ); for ( ; r != ILLEGAL; GetQueue( &r, &c, &side, &d, &apx_dist ) ) { curcell = GetCell( r, c, side ); if(curcell & CURRENT_PAD) curcell &= ~HOLE ; if( (r == row_target) && (c == col_target) /* success si layer OK */ && ( tab_mask[side] & pad_masque_layer_e) ) { /* Efface Liaison */ GRSetDrawMode(DC, GR_XOR); GRLine(&pcbframe->DrawPanel->m_ClipBox, DC, segm_oX, segm_oY, segm_fX, segm_fY, WHITE); /* Generation de la trace */ if( Retrace(pcbframe, DC, row_source, col_source, row_target, col_target, side, current_net_code) ) { result = SUCCESS; /* Success : Route OK */ } break; /* Fin du routage */ } /* report every 300 new nodes or so */ if( (OpenNodes-lastopen > 300) || (ClosNodes-lastclos > 300) || (MoveNodes - lastmove > 300)) { lastopen = (OpenNodes/300)*300; lastclos = (ClosNodes/300)*300; lastmove = (MoveNodes/300)*300; if( pcbframe->DrawPanel->m_AbortRequest ) { result = STOP_FROM_ESC; break; } AFFICHE_ACTIVITE_ROUTE; } _self = 0; if (curcell & HOLE) { _self = 5; /* set 'present' bits */ for (i = 0; i < 8; i++) { selfok2[i].present = 0; if( (curcell & selfok2[i].trace) ) selfok2[i].present = 1; } } for (i = 0; i < 8; i++) /* consider neighbors */ { nr = r+delta[i][0]; nc = c+delta[i][1]; /* off the edge? */ if( nr < 0 || nr >= Nrows || nc < 0 || nc >= Ncols) continue; /* off the edge */ if (_self == 5 && selfok2[i].present) continue; newcell = GetCell( nr, nc, side ); if(newcell & CURRENT_PAD) newcell &= ~HOLE; /* check for non-target hole */ if (newcell & HOLE) { if (nr != row_target || nc != col_target) continue; } /* check for traces */ else if (newcell & HOLE & ~(newmask[i])) continue; /* check blocking on corner neighbors */ if (delta[i][0] && delta[i][1]) { /* check first buddy */ buddy = GetCell( r+blocking[i].r1, c+blocking[i].c1, side ); if(buddy & CURRENT_PAD) buddy &= ~HOLE; if (buddy & HOLE) continue; // if (buddy & (blocking[i].b1)) continue; /* check second buddy */ buddy = GetCell( r+blocking[i].r2, c+blocking[i].c2, side ); if(buddy & CURRENT_PAD) buddy &= ~HOLE; if (buddy & HOLE) continue; // if (buddy & (blocking[i].b2)) continue; } olddir = GetDir( r, c, side ); newdist = d + CalcDist( ndir[i], olddir, (olddir == FROM_OTHERSIDE) ? GetDir( r, c, 1-side ) : 0 , side); /* if (a) not visited yet, or (b) we have */ /* found a better path, add it to queue */ if (!GetDir( nr, nc, side )) { SetDir( nr, nc, side, ndir[i] ); SetDist( nr, nc, side, newdist ); if( SetQueue( nr, nc, side, newdist, GetApxDist( nr, nc, row_target, col_target ), row_target, col_target ) == 0 ) { return(ERR_MEMORY); } } else if (newdist < GetDist( nr, nc, side )) { SetDir( nr, nc, side, ndir[i] ); SetDist( nr, nc, side, newdist ); ReSetQueue( nr, nc, side, newdist, GetApxDist( nr, nc, row_target, col_target ), row_target, col_target ); } } /** etude de l'autre couche **/ if( (two_sides) && ! g_No_Via_Route ) { olddir = GetDir( r, c, side ); if (olddir == FROM_OTHERSIDE) continue; /* useless move, so don't bother */ if (curcell) /* can't drill via if anything here */ continue; /* check for holes or traces on other side */ if( (newcell = GetCell( r, c, 1-side )) != 0 ) continue; /* check for nearby holes or traces on both sides */ for (skip = 0, i = 0; i < 8; i++) { nr = r + delta[i][0]; nc = c + delta[i][1]; if (nr < 0 || nr >= Nrows || nc < 0 || nc >= Ncols) continue; /* off the edge !! */ if (GetCell( nr, nc, side )/* & blocking2[i]*/) { skip = 1; /* can't drill via here */ break; } if (GetCell( nr, nc, 1-side )/* & blocking2[i]*/) { skip = 1; /* can't drill via here */ break; } } if (skip) /* neighboring hole or trace? */ continue; /* yes, can't drill via here */ newdist = d + CalcDist( FROM_OTHERSIDE, olddir, 0 , side); /* if (a) not visited yet, or (b) we have found a better path, add it to queue */ if (!GetDir( r, c, 1-side )) { SetDir( r, c, 1-side, FROM_OTHERSIDE ); SetDist( r, c, 1-side, newdist ); if( SetQueue( r, c, 1-side, newdist, apx_dist, row_target, col_target ) == 0 ) { return(ERR_MEMORY); } } else if (newdist < GetDist( r, c, 1-side )) { SetDir( r, c, 1-side, FROM_OTHERSIDE ); SetDist( r, c, 1-side, newdist ); ReSetQueue( r, c, 1-side, newdist, apx_dist, row_target, col_target ); } } /* Fin de l'exploration de l'autre couche */ } end_of_route: Place_1_Pad_Board(pcbframe->m_Pcb, pt_cur_ch->pad_start,~CURRENT_PAD ,marge,WRITE_AND_CELL); Place_1_Pad_Board(pcbframe->m_Pcb, pt_cur_ch->pad_end, ~CURRENT_PAD ,marge,WRITE_AND_CELL); AFFICHE_ACTIVITE_ROUTE; return(result); }