//following is at least half the algorithm //transforms each point locally //and computes numDist distances out to localLevel away void calcAppAniDel(double *vort, double *dist) { //big for loop. means do everything for every vector in vort. for (int x = 0; x < nx; x++) { for (int y = 0; y < ny; y++) { for (int z = 0; z < nz; z++) { //fprintf(stderr, "%d %d %d\n", x, y, z); //find transform based on this vector. double vX = GetArray(vort, x, y, z, 0); double vY = GetArray(vort, x, y, z, 1); double vZ = GetArray(vort, x, y, z, 2); double vNormSqr = vX*vX + vY*vY + vZ*vZ; //used alot double alpha = calcAlpha(sqrt(vNormSqr)); //used equally alot //fprintf(stderr, "%e %f\n", vNormSqr, alpha); //fprintf(stderr, "%f %f %f\n", vX, vY, vZ); double *metricTensor = calcMetricTensor(vX, vY, vZ, vNormSqr, alpha); //calc distance and save in each point for (int boxX = 0; boxX < numDist; boxX++) { for (int boxY = 0; boxY < numDist; boxY++) { for (int boxZ = 0; boxZ < numDist; boxZ++) { //gridDist is global variable that determines grid spacing //void SetDist(double *a, double v, int i, int j, int k, int l) is function to set each distance double thisDist = 0.0; if (!((0 == boxX - localLevel) && (0 == boxY - localLevel) && (0 == boxZ - localLevel))) { // we don't set the distance to this point, just to all surrounding. // treat current vector tail as origin, compute distances with metricTensor // and put total in thisDist //first compute the array representing the difference between this point and the one //the distance to which is being calculated double *point = (double *)malloc(3 * sizeof(double)); point[0] = (boxX - localLevel) * gridDist; point[1] = (boxY - localLevel) * gridDist; point[2] = (boxZ - localLevel) * gridDist; //fprintf(stderr, "%f %f %f \n", point[0], point[1], point[2]); //first step is metric (3x3) times the point (3x1) resulting in a 3x1 matrix double *firstStep = (double *)malloc(3 * sizeof(double)); firstStep[0] = point[0] * metricTensor[0] + point[1] * metricTensor[1] + point[2] * metricTensor[2]; firstStep[1] = point[0] * metricTensor[3] + point[1] * metricTensor[4] + point[2] * metricTensor[5]; firstStep[2] = point[0] * metricTensor[6] + point[1] * metricTensor[7] + point[2] * metricTensor[8]; //fprintf(stderr, "%f %f %f \n", firstStep[0], firstStep[1], firstStep[2]); //now take the point as a 1x3 matrix times this 3x1 resulting in a 1x1 (scalar) value. thisDist = firstStep[0] * point[0] + firstStep[1] * point[1] + firstStep[2] * point[2] ; if (thisDist < 0.0) { thisDist = sqrt(-thisDist); } else { thisDist = sqrt(thisDist); } //the following lines transforms the dist in L2-norm to L(infinity)-norm //this cheap trick is only going to work for localLevel == 1 //since in that case all 26 points have the same L(infinite)-distance double normalDist = sqrt( point[0] * point[0] + point[1] * point[1] + point[2] * point[2] ); double infDist = abs(boxX - localLevel); if (infDist < abs(boxY - localLevel)) { infDist = abs(boxY - localLevel); } if (infDist < abs(boxZ - localLevel)) { infDist = abs(boxZ - localLevel); } //fprintf(stderr, "%f\n", infDist); thisDist = infDist*thisDist/normalDist; //end L(infinity)-norm conversion free(firstStep); free(point); //fprintf(stderr, "%e \n", thisDist); } SetDist(dist, thisDist, x, y, z, (boxZ + numDist * (boxY + numDist * boxX)) ); } } } //that should be it for this step. free(metricTensor); } } } }
//put into arrays, check orientation... then sort. int averageStoreDistances(double *dists, int *aSegs, double *aDists, double *vort) { //okay, go through the whole big array of distances, setting each on the first pass, then adding, then /2 //also store the distances and the point indices they connect int countStore = 0; for (int x = 0; x < nx; x++) { for (int y = 0; y < ny; y++) { for (int z = 0; z < nz; z++) { //fprintf(stderr, "another point %d %d %d\n", x, y, z); for (int boxX = 0; boxX < numDist; boxX++) { for (int boxY = 0; boxY < numDist; boxY++) { for (int boxZ = 0; boxZ < numDist; boxZ++) { if (!((0==boxX - localLevel)&&(0==boxY - localLevel)&&(0==boxZ - localLevel))) { double thisDist = GetDist(dists, x, y, z, (boxZ + numDist * (boxY + numDist * boxX)) ); //now find other distance this is to. int otherX = (nx + x + boxX - localLevel) % nx; int otherY = (ny + y + boxY - localLevel) % ny; int otherZ = (nz + z + boxZ - localLevel) % nz; int otherBoxX = numDist - boxX - 1; int otherBoxY = numDist - boxY - 1; int otherBoxZ = numDist - boxZ - 1; double otherDist = GetDist(dists, otherX, otherY, otherZ, (otherBoxZ + numDist * (otherBoxY + numDist * otherBoxX)) ); double newDist = (thisDist + otherDist)/2.0; SetDist(dists, newDist, x, y, z, (boxZ + numDist * (boxY + numDist * boxX))); SetDist(dists, newDist, otherX, otherY, otherZ, (otherBoxZ + numDist * (otherBoxY + numDist * otherBoxX)) ); if ((z + nz * (y + ny * x)) < (otherZ + nz * (otherY + ny * otherX)) ) { //fprintf(stderr, "(%d %d %d) (%d %d %d) %e\n", x, y, z, otherX, otherY, otherZ, newDist); //determine orientation now instead of later //throw out poorly defined orientations as well double vX = GetArray(vort, x, y, z, 0); double vY = GetArray(vort, x, y, z, 1); double vZ = GetArray(vort, x, y, z, 2); double signOrient = orientation(x,y,z,otherX,otherY,otherZ,vX,vY,vZ); vX = GetArray(vort, otherX, otherY, otherZ, 0); vY = GetArray(vort, otherX, otherY, otherZ, 1); vZ = GetArray(vort, otherX, otherY, otherZ, 2); double signBackOrient = orientation(otherX,otherY,otherZ,x,y,z,vX,vY,vZ); //fprintf(stderr, "%f %f \n", signOrient,signBackOrient); if (signOrient > 0.0 && signBackOrient < 0.0) { SetAlphaDist(aDists, newDist, countStore); SetAlphaSeg(aSegs, x, countStore, 0, 0); SetAlphaSeg(aSegs, y, countStore, 1, 0); SetAlphaSeg(aSegs, z, countStore, 2, 0); SetAlphaSeg(aSegs, otherX, countStore, 0, 1); SetAlphaSeg(aSegs, otherY, countStore, 1, 1); SetAlphaSeg(aSegs, otherZ, countStore, 2, 1); countStore++; } else if (signOrient < 0.0 && signBackOrient > 0.0) { SetAlphaDist(aDists, newDist, countStore); SetAlphaSeg(aSegs, otherX, countStore, 0, 0); SetAlphaSeg(aSegs, otherY, countStore, 1, 0); SetAlphaSeg(aSegs, otherZ, countStore, 2, 0); SetAlphaSeg(aSegs, x, countStore, 0, 1); SetAlphaSeg(aSegs, y, countStore, 1, 1); SetAlphaSeg(aSegs, z, countStore, 2, 1); countStore++; } } } } } } } } } return countStore; }
/* 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); }