00001 #include "SUMA_suma.h"
00002 
00003 #undef STAND_ALONE
00004 
00005 #if defined SUMA_SurfSmooth_STAND_ALONE
00006 #define STAND_ALONE
00007 #elif defined SUMA_getPatch_STANDALONE
00008 #define STAND_ALONE 
00009 #elif defined SUMA_SurfQual_STANDALONE
00010 #define STAND_ALONE
00011 #endif
00012 
00013 #ifdef STAND_ALONE
00014 
00015 SUMA_SurfaceViewer *SUMAg_cSV = NULL; 
00016 SUMA_SurfaceViewer *SUMAg_SVv = NULL; 
00017 
00018 int SUMAg_N_SVv = 0; 
00019 SUMA_DO *SUMAg_DOv = NULL;   
00020 int SUMAg_N_DOv = 0; 
00021 SUMA_CommonFields *SUMAg_CF = NULL; 
00022 #else
00023 extern SUMA_CommonFields *SUMAg_CF;
00024 extern SUMA_DO *SUMAg_DOv;
00025 extern SUMA_SurfaceViewer *SUMAg_SVv;
00026 extern int SUMAg_N_SVv; 
00027 extern int SUMAg_N_DOv;  
00028 #endif
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 #define DBG 1
00044 #define DoCheck 1
00045 
00046 #if 0 
00047 int SUMA_GEOMCOMP_NI_MODE = NI_BINARY_MODE;
00048 #endif
00049 
00050 
00051 
00052 
00053 
00054 
00055 
00056 int SUMA_Subdivide_Mesh(float **NodeListp, int *N_Nodep, int **FaceSetListp, int *N_FaceSetp, float maxarea)
00057 {
00058    static char FuncName[]={"SUMA_Subdivide_Mesh"};
00059    int in, it, N_NodeAlloc, N_FaceSetAlloc, N_Node, N_FaceSet, it3, in0, in1, in2, inc3, inc, itn, itn3;
00060    float c[3];
00061    float *NodeList = NULL, a, *n1, *n2, *n0;
00062    int *FaceSetList = NULL;
00063    SUMA_SurfaceObject SObuf, *SO=NULL;
00064    SUMA_Boolean LocalHead = YUP;
00065    
00066    SUMA_ENTRY;
00067    
00068    SO = &SObuf;
00069    
00070    N_NodeAlloc = N_Node = *N_Nodep;
00071    N_FaceSetAlloc = N_FaceSet = *N_FaceSetp;
00072    NodeList = *NodeListp;
00073    FaceSetList = *FaceSetListp;
00074    SO->NodeList = NodeList; SO->FaceSetList = FaceSetList;
00075    if (!NodeList || !FaceSetList) { SUMA_SL_Err("NULL input"); SUMA_RETURN(NOPE); }
00076    
00077    it = 0; 
00078    while (it < N_FaceSet) {
00079       it3 = 3*it; 
00080       in0 = FaceSetList[it3]; in1 = FaceSetList[it3+1]; in2 = FaceSetList[it3+2]; 
00081       n0 = &(NodeList[3*in0]); n1 = &(NodeList[3*in1]); n2 = &(NodeList[3*in2]);   
00082       SUMA_TRI_AREA(n0, n1, n2, a); 
00083       if (a > maxarea) {
00084          if (N_NodeAlloc <= N_Node) { 
00085             N_NodeAlloc += 20000;
00086             NodeList = (float *)SUMA_realloc(NodeList, N_NodeAlloc * 3 * sizeof(float));
00087             
00088             N_FaceSetAlloc += 40000;
00089             FaceSetList = (int *)SUMA_realloc(FaceSetList, N_FaceSetAlloc * 3 * sizeof(int));
00090             if (!NodeList || !FaceSetList) { SUMA_SL_Crit("Failed to realloc"); SUMA_RETURN(NOPE); }
00091             SO->NodeList = NodeList; SO->FaceSetList = FaceSetList;
00092          }
00093          SUMA_FACE_CENTROID(SO, it, c); 
00094          inc = N_Node; inc3 = inc*3;  ++N_Node; 
00095          NodeList[inc3] = c[0]; NodeList[inc3+1] = c[1]; NodeList[inc3+2] = c[2];   
00096          FaceSetList[it3+2] = inc; 
00097          itn = N_FaceSet; itn3 = 3 * itn; ++N_FaceSet;  
00098          FaceSetList[itn3] = inc; FaceSetList[itn3+1] = in1; FaceSetList[itn3+2] = in2;
00099          itn = N_FaceSet; itn3 = 3 * itn; ++N_FaceSet;  
00100          FaceSetList[itn3] = inc; FaceSetList[itn3+1] = in2; FaceSetList[itn3+2] = in0; 
00101       } else {
00102          ++it;
00103       }
00104    }
00105    
00106    
00107    FaceSetList = (int *)SUMA_realloc(FaceSetList, N_FaceSet * 3 * sizeof(int));
00108    NodeList = (float *)SUMA_realloc(NodeList, N_Node * 3 * sizeof(float));
00109    
00110    *NodeListp = NodeList;
00111    *FaceSetListp = FaceSetList;
00112    *N_FaceSetp = N_FaceSet;
00113    *N_Nodep = N_Node;
00114    
00115    SUMA_RETURN(YUP);
00116 }
00117 
00118 
00119 
00120 
00121 
00122 
00123 
00124 
00125 
00126 
00127 
00128 
00129 
00130 
00131 
00132 SUMA_VTI *SUMA_CreateVTI(int N_TriIndex, int *TriIndex)
00133 {
00134    static char FuncName[]={"SUMA_CreateVTI"};
00135    SUMA_VTI *vti = NULL;
00136    
00137    SUMA_ENTRY;
00138    if (!N_TriIndex) {
00139       SUMA_SL_Err("Nothing to do !");
00140       SUMA_RETURN(vti);
00141    }
00142    
00143    vti = (SUMA_VTI *)SUMA_malloc(sizeof(SUMA_VTI));
00144    vti->N_TriIndex = N_TriIndex;
00145    if (TriIndex ) {
00146       vti->TriIndex = TriIndex;
00147    }else {
00148       
00149       vti->TriIndex = (int *)SUMA_calloc(N_TriIndex, sizeof(int));
00150       if (!vti->TriIndex) {
00151          SUMA_SL_Crit("Failed to allocate for vti->TriIndex");
00152          SUMA_RETURN(NULL);
00153       }
00154    }
00155    vti->N_IntersectedVoxels = (int *)SUMA_calloc(N_TriIndex, sizeof(int));
00156    vti->IntersectedVoxels = (int **)SUMA_calloc(N_TriIndex, sizeof(int*));
00157    if (!vti->N_IntersectedVoxels || !vti->IntersectedVoxels) {
00158          SUMA_SL_Crit("Failed to allocate for vti's innerds");
00159          SUMA_RETURN(NULL);
00160    }
00161 
00162    SUMA_RETURN(vti);
00163 }
00164 
00165 SUMA_VTI * SUMA_FreeVTI(SUMA_VTI *vti)
00166 {
00167    static char FuncName[]={"SUMA_FreeVTI"};
00168    int i;
00169    
00170    SUMA_ENTRY;
00171    
00172    if (!vti) SUMA_RETURN(NULL);
00173    if (vti->TriIndex) SUMA_free(vti->TriIndex);
00174    if (vti->IntersectedVoxels) {
00175       for (i=0; i<vti->N_TriIndex; ++i) {
00176          if (vti->IntersectedVoxels[i]) free(vti->IntersectedVoxels[i]);
00177       }
00178       SUMA_free(vti->IntersectedVoxels);
00179    }
00180    if (vti->N_IntersectedVoxels) SUMA_free(vti->N_IntersectedVoxels);    
00181    SUMA_free(vti);
00182      
00183    SUMA_RETURN(NULL);
00184 }     
00185 
00186 
00187 
00188 
00189 
00190 
00191 
00192 
00193 
00194 
00195 
00196 
00197 
00198 
00199 SUMA_VTI *SUMA_GetVoxelsIntersectingTriangle(   SUMA_SurfaceObject *SO, SUMA_VOLPAR *VolPar, float *NodeIJKlist,
00200                                                 SUMA_VTI *vti )
00201 {
00202    static char FuncName[]={"SUMA_GetVoxelsIntersectingTriangle"};
00203    int ti, nx, ny, nz, nxy, nxyz, N_inbox, n1, n2, n3, nt, nt3, nijk, nf;
00204    int N_alloc, N_realloc, en, *voxelsijk=NULL, N_voxels1d = 0, *voxels1d = NULL;
00205    int *TriIndex=NULL, N_TriIndex;
00206    float dxyz[3];
00207    float tol_dist = 0; 
00208    float *p1, *p2, *p3, min_v[3], max_v[3], p[3], dist;
00209    FILE *fp=NULL;
00210    SUMA_Boolean LocalHead = YUP;
00211    
00212    SUMA_ENTRY;
00213       
00214    if (SO->FaceSetDim != 3 || SO->NodeDim != 3) {
00215       SUMA_SL_Err("SO->FaceSetDim != 3 || SO->NodeDim != 3"); 
00216       SUMA_RETURN(NULL);
00217    }
00218    if (!vti) {
00219       SUMA_SL_Err("vti must be non NULL");
00220       SUMA_RETURN(NULL);
00221    }
00222    if (vti->N_TriIndex <= 0) {
00223       SUMA_SL_Err("vti must be initialized");
00224       SUMA_RETURN(NULL);
00225    }
00226    
00227    TriIndex = vti->TriIndex;
00228    N_TriIndex = vti->N_TriIndex;
00229    
00230    nx = VolPar->nx; ny = VolPar->ny; nz = VolPar->nz; nxy = nx * ny; nxyz = nx * ny * nz;
00231    
00232    if (LocalHead) {
00233       fp = fopen("SUMA_GetVoxelsIntersectingTriangle.1D","w");
00234       if (fp) fprintf(fp, "# Voxels from %s that intersect the triangles \n", VolPar->filecode);
00235    }   
00236    
00237    N_alloc = 2000; 
00238    N_realloc = 0;
00239    voxelsijk = (int *)SUMA_malloc(sizeof(int)*N_alloc*3);
00240    if (!voxelsijk) { SUMA_SL_Crit("Failed to Allocate!"); SUMA_RETURN(NULL);  }   
00241    dxyz[0] = VolPar->dx; dxyz[1] = VolPar->dy; dxyz[2] = VolPar->dz;
00242    for (ti=0; ti<N_TriIndex; ++ti) {
00243       if (LocalHead) fprintf(SUMA_STDERR,"%s: Now processing %dth triangle\n", FuncName, ti);
00244       nf = TriIndex[ti];
00245       if (LocalHead) fprintf(SUMA_STDERR,"\t\tindexed %d, \n", nf);
00246       n1 = SO->FaceSetList[SO->FaceSetDim*nf]; n2 = SO->FaceSetList[SO->FaceSetDim*nf+1]; n3 = SO->FaceSetList[SO->FaceSetDim*nf+2];
00247       if (LocalHead) fprintf(SUMA_STDERR,"\t\tmade up of  nodes %d, %d. %d . \n", n1, n2, n3);
00248       
00249       p1 = &(NodeIJKlist[3*n1]); p2 = &(NodeIJKlist[3*n2]); p3 = &(NodeIJKlist[3*n3]); 
00250       SUMA_TRIANGLE_BOUNDING_BOX(p1, p2, p3, min_v, max_v);
00251       
00252       
00253       en =((int)(max_v[0] - min_v[0] + 5) * (int)(max_v[1] - min_v[1] + 5) * (int)(max_v[2] - min_v[2] + 5)); 
00254       if ( en > N_alloc) {
00255          ++N_realloc; if (N_realloc > 5) { SUMA_SL_Warn("Reallocating, increase limit to improve speed.\nEither triangles too large or grid too small"); }
00256          N_alloc = 2*en;
00257          voxelsijk = (int *)SUMA_realloc(voxelsijk, 3*N_alloc*sizeof(int));
00258          if (!voxelsijk) { SUMA_SL_Crit("Failed to Allocate!"); SUMA_RETURN(NULL); }
00259       } 
00260       
00261       N_inbox = 0;
00262       if (!SUMA_VoxelsInBox(voxelsijk, &N_inbox, min_v, max_v)) {
00263          SUMA_SL_Err("Unexpected error!"); SUMA_RETURN(NULL); 
00264       }
00265       if (!N_inbox) { SUMA_SL_Err("Unexpected error, no voxels in box!"); SUMA_RETURN(NULL);  }
00266       if (N_inbox >= N_alloc) { SUMA_SL_Err("Allocation trouble!"); SUMA_RETURN(NULL);  }
00267       if (LocalHead) fprintf(SUMA_STDERR,"\t\t%d nodes in box\n", N_inbox);
00268       
00269       
00270       if (voxels1d) {
00271          SUMA_SL_Err("NULL pointer expected here");
00272          SUMA_RETURN(NULL);
00273       }
00274       if (LocalHead) fprintf(SUMA_STDERR,"\t\tShit man, %d nodes in box\n", N_inbox);
00275       voxels1d = (int *)malloc(N_inbox * sizeof(int)); 
00276       if (LocalHead) fprintf(SUMA_STDERR,"\t\tWTF man, %d nodes in box\n", N_inbox);
00277       N_voxels1d=0;
00278       if (!voxels1d) {
00279          SUMA_SL_Crit("Failed to allocate voxels1d");
00280          SUMA_RETURN(NULL);
00281       }
00282       
00283       if (LocalHead) fprintf(SUMA_STDERR,"%s:\t\tabout to process %d voxels\n", FuncName, N_inbox);
00284       for (nt=0; nt < N_inbox; ++nt) {
00285          nt3 = 3*nt;
00286          if (voxelsijk[nt3] < nx &&  voxelsijk[nt3+1] < ny &&  voxelsijk[nt3+2] < nz) {
00287             nijk = SUMA_3D_2_1D_index(voxelsijk[nt3], voxelsijk[nt3+1], voxelsijk[nt3+2], nx , nxy);  
00288             { 
00289                
00290                p[0] = (float)voxelsijk[nt3]; p[1] = (float)voxelsijk[nt3+1]; p[2] = (float)voxelsijk[nt3+2]; 
00291                SUMA_DIST_FROM_PLANE(p1, p2, p3, p, dist);
00292                
00293                if (tol_dist && SUMA_ABS(dist) < tol_dist) dist = tol_dist; 
00294 
00295 
00296 
00297 
00298 
00299 
00300 
00301 
00302 
00303                if (!(SUMA_IS_STRICT_NEG(VolPar->Hand * dist))) { 
00304                   
00305                   if (SUMA_isVoxelIntersect_Triangle (p, dxyz, p1, p2, p3)) {
00306                      
00307                      if (LocalHead) fprintf(SUMA_STDERR,"nt %d, N_voxels1d %d\n", nt, N_voxels1d);
00308                      voxels1d[N_voxels1d] = nijk; ++N_voxels1d;
00309                      if (fp) fprintf(fp, "%d %d %d\n", voxelsijk[nt3], voxelsijk[nt3+1], voxelsijk[nt3+2]);
00310                   } 
00311                }
00312                
00313             }
00314          }
00315       }
00316       
00317       vti->IntersectedVoxels[ti] = voxels1d; 
00318       vti->N_IntersectedVoxels[ti] = N_voxels1d;
00319       voxels1d = NULL; N_voxels1d = 0; 
00320    }
00321    
00322    if (LocalHead) {
00323       if (fp) fclose(fp); fp = NULL;
00324    } 
00325    SUMA_RETURN(vti);
00326 }
00327 
00328 
00329 
00330 
00331 
00332  
00333 int SUMA_isSelfIntersect(SUMA_SurfaceObject *SO, int StopAt)
00334 {
00335    static char FuncName[]={"SUMA_isSelfIntersect"};
00336    float *NodePos = NULL, *p1=NULL, *p2=NULL, *p3 = NULL, p[3], *ep1=NULL, *ep2=NULL;
00337    int hit = 0, k, t1, t2, it, it3, n1, n2, n3;
00338    SUMA_MT_INTERSECT_TRIANGLE *MTI = NULL;
00339    SUMA_Boolean LocalHead = NOPE;
00340    
00341    SUMA_ENTRY;
00342    
00343    if (!SO->EL) {
00344       SUMA_SL_Err("NULL SO->EL");
00345       SUMA_RETURN(-1);
00346    }
00347    
00348    if (StopAt < 1) StopAt = 1;
00349    
00350    hit = 0; k = 0;
00351    while (k < SO->EL->N_EL) {
00352          t1 = SO->EL->ELps[k][1]; t2 = SO->EL->ELps[SUMA_MIN_PAIR(k+1, SO->EL->N_EL-1)][1];
00353          ep1 = &(SO->NodeList[3*SO->EL->EL[k][0]]); ep2 = &(SO->NodeList[3*SO->EL->EL[k][1]]);
00354          
00355          MTI = SUMA_MT_intersect_triangle(ep1, ep2, SO->NodeList, SO->N_Node, SO->FaceSetList, SO->N_FaceSet, MTI); 
00356          for (it=0; it<SO->N_FaceSet; ++it) {
00357             if (MTI->isHit[it] && it != t1 && it != t2) {
00358                
00359                
00360                it3 = SO->FaceSetDim*it;
00361                n1 = SO->FaceSetList[it3]; n2 = SO->FaceSetList[it3+1]; n3 = SO->FaceSetList[it3+2];
00362                p1 = &(SO->NodeList[SO->NodeDim*n1]); p2 = &(SO->NodeList[SO->NodeDim*n2]); p3 = &(SO->NodeList[SO->NodeDim*n3]);   
00363                SUMA_FROM_BARYCENTRIC(MTI->u[it], MTI->v[it], p1, p2, p3, p);
00364                if (p[0] > ep1[0] && p[0] < ep2[0]) {
00365                   if (p[1] > ep1[1] && p[1] < ep2[1]) {
00366                      if (p[2] > ep1[2] && p[2] < ep2[2]) {
00367                         
00368                         if (LocalHead) fprintf(SUMA_STDERR,"%s: Triangle %d (%d, %d, %d) was hit by segment formed by nodes [%d, %d]\n", 
00369                            FuncName, it, n1, n2, n3, SO->EL->EL[k][0], SO->EL->EL[k][1]);
00370                            ++ hit;
00371                         break;
00372                      }
00373                   }
00374                }
00375             }
00376          }
00377          if (hit >= StopAt) break;
00378          
00379          if (SO->EL->ELps[k][2] > 0) {
00380                k += SO->EL->ELps[k][2];
00381          } else ++k;
00382    }
00383    
00384    if (MTI) MTI = SUMA_Free_MT_intersect_triangle(MTI); 
00385    
00386    if (LocalHead) {
00387       if (!hit) {
00388          SUMA_LH("Surface does not self intersect.");
00389       } else {
00390          SUMA_LH("Surface self intersects.");
00391       }
00392    }
00393    SUMA_RETURN(hit);
00394 }
00395 
00396 
00397 
00398 
00399 
00400 
00401 
00402 
00403 
00404 
00405 
00406 
00407 
00408                
00409 int SUMA_VoxelNeighbors (int ijk, int ni, int nj, int nk, SUMA_VOX_NEIGHB_TYPES ntype, int *nl)
00410 {
00411    static char FuncName[]={"SUMA_VoxelNeighbors"};
00412    int i, j, k;
00413    int nij, N_n;
00414    
00415    SUMA_ENTRY;
00416    
00417    N_n = 0; nij = ni * nj;
00418    
00419    
00420    SUMA_1D_2_3D_index(ijk, i, j, k, ni, nij);
00421    
00422    if (i >= ni || i < 0) { SUMA_SL_Err("Voxel out of bounds along i direction"); SUMA_RETURN(N_n); }
00423    if (j >= nj || j < 0) { SUMA_SL_Err("Voxel out of bounds along j direction"); SUMA_RETURN(N_n); }
00424    if (k >= nk || k < 0) { SUMA_SL_Err("Voxel out of bounds along k direction"); SUMA_RETURN(N_n); }
00425   
00426    
00427    if (i-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i-1, j, k, ni, nij); ++N_n; }
00428    if (j-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i, j-1, k, ni, nij); ++N_n; } 
00429    if (k-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i, j, k-1, ni, nij); ++N_n; } 
00430    if (i+1 < ni) { nl[N_n] = SUMA_3D_2_1D_index(i+1, j, k, ni, nij); ++N_n; } 
00431    if (j+1 < nj) { nl[N_n] = SUMA_3D_2_1D_index(i, j+1, k, ni, nij); ++N_n; } 
00432    if (k+1 < nk) { nl[N_n] = SUMA_3D_2_1D_index(i, j, k+1, ni, nij); ++N_n; } 
00433    
00434    if ( ntype < SUMA_VOX_NEIGHB_EDGE) { SUMA_RETURN(N_n); }
00435    
00436    
00437    if (i-1 >= 0 && j-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i-1, j-1, k, ni, nij); ++N_n; }
00438    if (i-1 >= 0 && j+1 < nj) { nl[N_n] = SUMA_3D_2_1D_index(i-1, j+1, k, ni, nij); ++N_n; }
00439    if (i-1 >= 0 && k-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i-1, j, k-1, ni, nij); ++N_n; }
00440    if (i-1 >= 0 && k+1 < nk) { nl[N_n] = SUMA_3D_2_1D_index(i-1, j, k+1, ni, nij); ++N_n; }
00441    if (j-1 >= 0 && k-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i, j-1, k-1, ni, nij); ++N_n; } 
00442    if (j-1 >= 0 && k+1 < nk) { nl[N_n] = SUMA_3D_2_1D_index(i, j-1, k+1, ni, nij); ++N_n; } 
00443    if (i+1 < ni && j-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i+1, j-1, k, ni, nij); ++N_n; }
00444    if (i+1 < ni && j+1 < nj) { nl[N_n] = SUMA_3D_2_1D_index(i+1, j+1, k, ni, nij); ++N_n; }
00445    if (i+1 < ni && k-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i+1, j, k-1, ni, nij); ++N_n; }
00446    if (i+1 < ni && k+1 < nk) { nl[N_n] = SUMA_3D_2_1D_index(i+1, j, k+1, ni, nij); ++N_n; }
00447    if (j+1 < nj && k-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i, j+1, k-1, ni, nij); ++N_n; } 
00448    if (j+1 < nj && k+1 < nk) { nl[N_n] = SUMA_3D_2_1D_index(i, j+1, k+1, ni, nij); ++N_n; } 
00449    
00450    if ( ntype < SUMA_VOX_NEIGHB_CORNER) { SUMA_RETURN(N_n); }
00451    
00452    
00453    if (i-1 >= 0 && j-1 >= 0 && k-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i-1, j-1, k-1, ni, nij); ++N_n; }
00454    if (i-1 >= 0 && j-1 >= 0 && k+1 < nk) { nl[N_n] = SUMA_3D_2_1D_index(i-1, j-1, k+1, ni, nij); ++N_n; }
00455    if (i-1 >= 0 && j+1 < nj && k-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i-1, j+1, k-1, ni, nij); ++N_n; }
00456    if (i-1 >= 0 && j+1 < nj && k+1 < nk) { nl[N_n] = SUMA_3D_2_1D_index(i-1, j+1, k+1, ni, nij); ++N_n; }
00457    if (i+1 < ni && j-1 >= 0 && k-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i+1, j-1, k-1, ni, nij); ++N_n; }
00458    if (i+1 < ni && j-1 >= 0 && k+1 < nk) { nl[N_n] = SUMA_3D_2_1D_index(i+1, j-1, k+1, ni, nij); ++N_n; }
00459    if (i+1 < ni && j+1 < nj && k-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i+1, j+1, k-1, ni, nij); ++N_n; }
00460    if (i+1 < ni && j+1 < nj && k+1 < nk) { nl[N_n] = SUMA_3D_2_1D_index(i+1, j+1, k+1, ni, nij); ++N_n; }
00461 
00462    
00463    SUMA_RETURN(N_n);
00464 }
00465 
00466 
00467 
00468 
00469 
00470 
00471 
00472 
00473 
00474 
00475 
00476 
00477 
00478 
00479 
00480 
00481 byte *SUMA_FillToVoxelMask(byte *ijkmask, int ijkseed, int ni, int nj, int nk, int *N_in, byte *usethisisin) 
00482 {
00483    static char FuncName[]={"SUMA_FillToVoxelMask"};
00484    byte *isin = NULL, *visited=NULL;
00485    DList*candlist=NULL;
00486    DListElmt *dothiselm=NULL;
00487    int dothisvoxel, itmp;
00488    int nl[50], N_n, in ,neighb, nijk, i, j, k, nij;
00489    SUMA_Boolean LocalHead = NOPE;
00490    
00491    SUMA_ENTRY;
00492    
00493    *N_in = 0;
00494    
00495    if (!ijkmask) {
00496       SUMA_SL_Err("Nothing to do");
00497       SUMA_RETURN(NULL);
00498    }
00499    if (ijkmask[ijkseed]) {
00500       SUMA_SL_Err("Seed is on mask. Bad business.");
00501       SUMA_RETURN(NULL);
00502    }
00503    
00504    nij = ni * nj;
00505    nijk = ni * nj * nk;
00506    
00507    if (LocalHead) {
00508       SUMA_1D_2_3D_index (ijkseed, i, j, k, ni, nij);
00509       fprintf(SUMA_STDERR,"%s:\nSeed is %d %d %d\n", FuncName, i, j, k); 
00510    }
00511    candlist = (DList*)SUMA_malloc(sizeof(DList));
00512    visited = (byte *)SUMA_calloc(nijk, sizeof(byte));
00513    if (!visited || !candlist) {
00514       SUMA_SL_Crit("Failed to allocate for visited or candlist");  
00515       SUMA_RETURN(NULL);  
00516    }
00517    
00518    if (usethisisin) isin = usethisisin;
00519    else {
00520       isin = (byte *)SUMA_calloc(nijk, sizeof(byte));
00521       if (!isin) {
00522          SUMA_SL_Crit("Failed to allocate");
00523          SUMA_RETURN(NULL);
00524       }
00525    }
00526    
00527    dothisvoxel = ijkseed;
00528    dlist_init(candlist, NULL);
00529    
00530    
00531    isin[dothisvoxel] = 1; ++(*N_in); 
00532    visited[dothisvoxel] = 1;  
00533    dlist_ins_next(candlist, dlist_tail(candlist), (void *)dothisvoxel); 
00534    
00535    while (dlist_size(candlist)) {
00536       
00537       dothiselm = dlist_head(candlist); dothisvoxel = (int) dothiselm->data;
00538       N_n = SUMA_VoxelNeighbors (dothisvoxel, ni, nj, nk, SUMA_VOX_NEIGHB_FACE, nl);
00539       
00540       dlist_remove(candlist, dothiselm, (void*)&itmp);
00541       
00542       for (in=0; in<N_n; ++in) { 
00543          neighb = nl[in];
00544          if (!ijkmask[neighb]) {
00545             isin[neighb] = 1; ++(*N_in); 
00546             
00547             if (!visited[neighb]) {
00548                dlist_ins_next(candlist, dlist_tail(candlist), (void *)neighb);
00549                visited[neighb] = 1;   
00550             }
00551          }
00552       }
00553    }
00554    
00555    if (visited) SUMA_free(visited); visited = NULL;
00556    if (candlist) { dlist_destroy(candlist); SUMA_free(candlist); candlist  = NULL; }
00557 
00558    
00559    SUMA_RETURN(isin);
00560 }
00561 
00562 
00563 
00564 
00565 
00566 
00567 SUMA_Boolean SUMA_VoxelsInBox(int *voxelsijk, int *N_in, float *c1, float *c2)
00568 {
00569    static char FuncName[]={"SUMA_VoxelsInBox"};
00570    int n3, i, j, k;
00571    
00572    SUMA_ENTRY;
00573    
00574    if (!voxelsijk) { 
00575       SUMA_SL_Err("NULL voxelsijk");
00576       SUMA_RETURN(NOPE); 
00577    }
00578    
00579    *N_in = 0;
00580    
00581    #if 0
00582    for (k = SUMA_ROUND(c1[2]); k <= SUMA_ROUND(c2[2]); ++k) {
00583       for (j = SUMA_ROUND(c1[1]); j <= SUMA_ROUND(c2[1]); ++j) {
00584          for (i = SUMA_ROUND(c1[0]); i <= SUMA_ROUND(c2[0]); ++i) {
00585             n3 = 3*(*N_in);
00586             voxelsijk[n3] = i; voxelsijk[n3+1] = j; voxelsijk[n3+2] = k; 
00587             ++(*N_in); 
00588          }
00589       }
00590    }
00591    #else
00592    for (k = (int)(c1[2]); k <= SUMA_CEIL(c2[2]); ++k) {
00593       for (j = (int)(c1[1]); j <= SUMA_CEIL(c2[1]); ++j) {
00594          for (i = (int)(c1[0]); i <= SUMA_CEIL(c2[0]); ++i) {
00595             n3 = 3*(*N_in);
00596             voxelsijk[n3] = i; voxelsijk[n3+1] = j; voxelsijk[n3+2] = k; 
00597             ++(*N_in); 
00598          }
00599       }
00600    }
00601    #endif     
00602    SUMA_RETURN(YUP); 
00603 }
00604 
00605 
00606 
00607 
00608 
00609 
00610 
00611 
00612 
00613 
00614 
00615 
00616 
00617 
00618 
00619 
00620 
00621 
00622                      
00623 SUMA_Boolean SUMA_ApplyAffine (float *NodeList, int N_Node, float M[][4], float *center)
00624 {
00625    static char FuncName[] = {"SUMA_ApplyAffine"};
00626    float **XYZo, **Mr, **XYZn, D[3];
00627    int i, i3, idbg = 0;
00628    SUMA_Boolean LocalHead = NOPE;
00629    
00630    SUMA_ENTRY;
00631    
00632    if (!NodeList || N_Node <=0) { 
00633       SUMA_SL_Err("Bad Entries.\n");
00634       SUMA_RETURN(NOPE);
00635    }
00636    
00637    Mr = (float **)SUMA_allocate2D(3, 3, sizeof(float));
00638    XYZn = (float **)SUMA_allocate2D(3, 1, sizeof(float));
00639    XYZo = (float **)SUMA_allocate2D(3, 1, sizeof(float));
00640    
00641    SUMA_LH("Forming Mr");
00642    Mr[0][0] = M[0][0]; Mr[0][1] = M[0][1]; Mr[0][2] = M[0][2]; 
00643    Mr[1][0] = M[1][0]; Mr[1][1] = M[1][1]; Mr[1][2] = M[1][2]; 
00644    Mr[2][0] = M[2][0]; Mr[2][1] = M[2][1]; Mr[2][2] = M[2][2];
00645    D[0] = M[0][3]; D[1] = M[1][3]; D[2] = M[2][3];
00646    
00647    SUMA_LH("Transforming");
00648    if (LocalHead ) {
00649       i3 = 3*idbg;
00650       fprintf (SUMA_STDERR,"In: %f %f %f\n", NodeList[i3], NodeList[i3+1], NodeList[i3+2]);
00651    }
00652    for (i=0; i< N_Node; ++i) {
00653       i3 = 3 * i;
00654       if (!center) {
00655          XYZo[0][0] = NodeList[i3]; XYZo[1][0] = NodeList[i3+1]; XYZo[2][0] = NodeList[i3+2];
00656       } else {
00657          XYZo[0][0] = NodeList[i3] - center[0]; XYZo[1][0] = NodeList[i3+1] - center[1]; XYZo[2][0] = NodeList[i3+2] - center[2];
00658       }   
00659 
00660       SUMA_MULT_MAT(Mr, XYZo, XYZn, 3, 3, 1, float,float,float);
00661       
00662       if (!center) { 
00663          NodeList[i3] = XYZn[0][0]+D[0]; NodeList[i3+1] = XYZn[1][0]+D[1]; NodeList[i3+2] = XYZn[2][0]+D[2]; 
00664       } else {
00665          NodeList[i3] = XYZn[0][0]+D[0] + center[0]; NodeList[i3+1] = XYZn[1][0]+D[1]+ center[1]; NodeList[i3+2] = XYZn[2][0]+D[2]+ center[2]; 
00666       }
00667       
00668    }
00669    if (LocalHead ) {
00670       i3 = 3*idbg;
00671       fprintf (SUMA_STDERR,"Out: %f %f %f\n", NodeList[i3], NodeList[i3+1], NodeList[i3+2]);
00672    }
00673    SUMA_LH("Done");
00674    
00675    SUMA_free2D((char**)Mr, 3);
00676    SUMA_free2D((char**)XYZn, 3);
00677    SUMA_free2D((char**)XYZo, 3);
00678    
00679    SUMA_RETURN(YUP);
00680 }
00681 
00682 SUMA_Boolean SUMA_getoffsets (int n, SUMA_SurfaceObject *SO, float *Off, float lim) 
00683 {
00684    static char FuncName[]={"SUMA_getoffsets"};
00685    int i, ni, iseg;
00686    float Off_tmp;
00687    SUMA_Boolean Visit = NOPE;
00688    static SUMA_Boolean LocalHead = NOPE;
00689    
00690    SUMA_ENTRY;
00691    
00692    #if DoCheck
00693    if (!SO->FN || !SO->EL) {
00694       SUMA_SL_Err("SO->FN &/| SO->EL are NULL.\n");
00695       SUMA_RETURN(NOPE);
00696    }
00697    #endif
00698    
00699    #if DBG
00700    if (LocalHead) fprintf(SUMA_STDERR,"%s: Working node %d, %d neighbs. lim = %f\n", 
00701                                     FuncName, n, SO->FN->N_Neighb[n], lim);
00702    #endif
00703    
00704    for (i=0; i < SO->FN->N_Neighb[n]; ++i) {
00705       ni = SO->FN->FirstNeighb[n][i]; 
00706       iseg = SUMA_FindEdge (SO->EL, n, SO->FN->FirstNeighb[n][i]);
00707       #if DoCheck
00708       if (iseg < 0) {
00709          SUMA_SL_Err("Failed to find segment");
00710          SUMA_RETURN(NOPE);
00711       }
00712       #endif
00713       
00714       Off_tmp = Off[n] + SO->EL->Le[iseg];   
00715 
00716                                              
00717       Visit = NOPE;
00718       if (Off[ni] < 0 || Off_tmp < Off[ni]) { 
00719          if (Off_tmp < lim) { 
00720             Visit = YUP;
00721             Off[ni] = Off_tmp;
00722          } 
00723       } 
00724       
00725       #if DBG
00726       if (LocalHead) fprintf(SUMA_STDERR,"%s: %d --> %d. Visit %d, Current %f, Old %f\n", 
00727          FuncName, n, ni, Visit, Off_tmp, Off[ni]);
00728       #endif
00729       
00730       #if 0
00731          { int jnk; fprintf(SUMA_STDOUT,"Pausing ..."); jnk = getchar(); fprintf(SUMA_STDOUT,"\n"); }
00732       #endif
00733 
00734       if (Visit) { 
00735          if (!SUMA_getoffsets (ni, SO, Off, lim))  {
00736             SUMA_SL_Err("Failed in SUMA_getoffsets");
00737             SUMA_RETURN (NOPE);
00738          }
00739       }
00740    }
00741 
00742    SUMA_RETURN(YUP);
00743 }
00744 
00745 
00746 
00747 
00748 
00749 
00750 
00751 
00752 
00753 
00754 
00755 
00756            
00757    
00758 SUMA_GET_OFFSET_STRUCT *SUMA_Initialize_getoffsets (int N_Node)
00759 {
00760    static char FuncName[]={"SUMA_Initialize_getoffsets"};
00761    int i;
00762    SUMA_GET_OFFSET_STRUCT *OffS = NULL;
00763    
00764    SUMA_ENTRY;
00765    
00766    if (N_Node <= 0) {
00767       SUMA_SL_Err("Bad values for N_Node");
00768       SUMA_RETURN (OffS);
00769    }
00770    
00771    OffS = (SUMA_GET_OFFSET_STRUCT *)SUMA_malloc(sizeof(SUMA_GET_OFFSET_STRUCT));
00772    if (!OffS) {
00773       SUMA_SL_Err("Failed to allocate for OffS");
00774       SUMA_RETURN (OffS);
00775    }
00776    
00777    OffS->OffVect = (float *) SUMA_malloc(N_Node * sizeof(float));
00778    OffS->LayerVect = (int *) SUMA_malloc(N_Node * sizeof(int));
00779    OffS->N_Nodes = N_Node;
00780    
00781    if (!OffS->LayerVect || !OffS->OffVect) {
00782       SUMA_SL_Err("Failed to allocate for OffS->LayerVect &/| OffS->OffVect");
00783       SUMA_free(OffS);
00784       SUMA_RETURN (OffS);
00785    }
00786    
00787    
00788    for (i=0; i< N_Node; ++i) {
00789       OffS->OffVect[i] = 0.0;
00790       OffS->LayerVect[i] = -1;
00791    }
00792    
00793    
00794    OffS->N_layers = 1;
00795    OffS->layers = (SUMA_NODE_NEIGHB_LAYER *) SUMA_malloc(OffS->N_layers * sizeof(SUMA_NODE_NEIGHB_LAYER));
00796    OffS->layers[0].N_AllocNodesInLayer = 1;
00797    OffS->layers[0].NodesInLayer = (int *) SUMA_malloc(OffS->layers[0].N_AllocNodesInLayer * sizeof(int));
00798    OffS->layers[0].N_NodesInLayer = 0;   
00799    
00800    SUMA_RETURN (OffS);
00801    
00802 }
00803 
00804 
00805 
00806 
00807 
00808 
00809 
00810 
00811 
00812 
00813 
00814 
00815 
00816 
00817 
00818 SUMA_Boolean SUMA_AddNodeToLayer (int n, int LayInd, SUMA_GET_OFFSET_STRUCT *OffS)
00819 {
00820    static char FuncName[]={"SUMA_AddNodeToLayer"};
00821    static SUMA_Boolean LocalHead = NOPE;
00822    
00823    
00824    if (LayInd > OffS->N_layers) { 
00825       SUMA_SL_Err("LayInd > OffS->N_layers. This should not be!");
00826       SUMA_RETURN(NOPE);
00827    } else if (LayInd == OffS->N_layers) { 
00828       SUMA_LH("Adding layer");
00829       OffS->N_layers += 1;
00830       OffS->layers = (SUMA_NODE_NEIGHB_LAYER *) SUMA_realloc(OffS->layers, OffS->N_layers*sizeof(SUMA_NODE_NEIGHB_LAYER));
00831       OffS->layers[LayInd].N_AllocNodesInLayer = 200;
00832       OffS->layers[LayInd].NodesInLayer = (int *) SUMA_malloc(OffS->layers[LayInd].N_AllocNodesInLayer * sizeof(int));
00833       OffS->layers[LayInd].N_NodesInLayer = 0;
00834    }
00835    
00836    OffS->layers[LayInd].N_NodesInLayer += 1;
00837    
00838    if (OffS->layers[LayInd].N_NodesInLayer ==  OffS->layers[LayInd].N_AllocNodesInLayer) { 
00839       SUMA_LH("reallocating neighbors");
00840       OffS->layers[LayInd].N_AllocNodesInLayer += 200;
00841       OffS->layers[LayInd].NodesInLayer = (int *) SUMA_realloc (OffS->layers[LayInd].NodesInLayer, OffS->layers[LayInd].N_AllocNodesInLayer * sizeof(int));
00842    }
00843    
00844    OffS->layers[LayInd].NodesInLayer[OffS->layers[LayInd].N_NodesInLayer - 1] = n;
00845    
00846    SUMA_RETURN(YUP); 
00847 }
00848 
00849 
00850 
00851 
00852 
00853 
00854 
00855 
00856 
00857 
00858 SUMA_GET_OFFSET_STRUCT * SUMA_Free_getoffsets (SUMA_GET_OFFSET_STRUCT *OffS) 
00859 {
00860    static char FuncName[]={"SUMA_Free_getoffsets"};
00861    int i = 0;
00862    static SUMA_Boolean LocalHead = NOPE;
00863    
00864    SUMA_ENTRY;
00865    
00866    if (!OffS) SUMA_RETURN(NULL);
00867    
00868    if (OffS->layers) {
00869       for (i=0; i< OffS->N_layers; ++i) if (OffS->layers[i].NodesInLayer) SUMA_free(OffS->layers[i].NodesInLayer);
00870       SUMA_free(OffS->layers);
00871    }
00872    
00873    if (OffS->OffVect) SUMA_free(OffS->OffVect);
00874    if (OffS->LayerVect) SUMA_free(OffS->LayerVect);
00875    SUMA_free(OffS); OffS = NULL;
00876    
00877    SUMA_RETURN(NULL);
00878 }
00879 
00880 
00881 
00882 
00883 
00884 
00885 
00886 
00887 
00888 
00889 
00890 
00891 
00892 
00893 SUMA_Boolean SUMA_Recycle_getoffsets (SUMA_GET_OFFSET_STRUCT *OffS)
00894 {
00895    static char FuncName[]={"SUMA_Recycle_getoffsets"};
00896    int i, j;
00897    static SUMA_Boolean LocalHead = NOPE;
00898    
00899    for (i=0; i < OffS->N_layers; ++i) {
00900       
00901       for (j=0; j < OffS->layers[i].N_NodesInLayer; ++j) {
00902          OffS->LayerVect[OffS->layers[i].NodesInLayer[j]] = -1;
00903       }
00904       
00905       OffS->layers[i].N_NodesInLayer = 0;
00906    }
00907    
00908    SUMA_RETURN(YUP);
00909 }
00910 
00911 
00912 
00913 
00914 
00915 
00916 
00917 
00918 
00919 
00920 
00921 
00922 
00923 
00924 
00925 
00926 
00927 
00928 
00929 
00930 
00931 
00932 
00933 
00934 
00935 
00936 
00937 
00938 
00939 
00940 
00941 
00942 
00943    
00944    
00945 float ** SUMA_CalcNeighbDist (SUMA_SurfaceObject *SO) 
00946 {
00947    static char FuncName[]={"SUMA_CalcNeighbDist"};
00948    float **DistFirstNeighb=NULL, *a, *b;
00949    int i, j;
00950    static SUMA_Boolean LocalHead = NOPE;
00951    
00952    SUMA_ENTRY;
00953    
00954    if (!SO) { SUMA_RETURN(NULL); }
00955    if (!SO->FN) { SUMA_RETURN(NULL); }
00956    
00957    DistFirstNeighb = (float **)SUMA_allocate2D(SO->FN->N_Node, SO->FN->N_Neighb_max, sizeof(float));
00958    if (!DistFirstNeighb) {
00959       SUMA_SL_Crit("Failed to allocate for DistFirstNeighb");
00960       SUMA_RETURN(NULL);
00961    }
00962    for (i=0; i < SO->FN->N_Node; ++i) {
00963       a = &(SO->NodeList[3*SO->FN->NodeId[i]]);
00964       for (j=0; j < SO->FN->N_Neighb[i]; ++j) {
00965          b = &(SO->NodeList[3*SO->FN->FirstNeighb[i][j]]);
00966          SUMA_SEG_LENGTH(a, b, DistFirstNeighb[i][j]);
00967          if (SO->FN->NodeId[i] == 5 && SO->FN->FirstNeighb[i][j] == 133092) {
00968             fprintf (SUMA_STDERR, "%f %f %f\n%f %f %f\n%f\n", 
00969                SO->NodeList[3*SO->FN->NodeId[i]], SO->NodeList[3*SO->FN->NodeId[i]+1], SO->NodeList[3*SO->FN->NodeId[i]+2],
00970                SO->NodeList[3*SO->FN->FirstNeighb[i][j]], SO->NodeList[3*SO->FN->FirstNeighb[i][j]+1], 
00971                SO->NodeList[3*SO->FN->FirstNeighb[i][j]+2], DistFirstNeighb[i][j]);
00972          }
00973       }
00974    }
00975    
00976    SUMA_RETURN (DistFirstNeighb);
00977 }
00978 
00979 
00980 
00981 
00982 
00983 
00984 
00985 
00986 
00987 
00988 
00989 
00990 
00991 
00992 
00993 
00994 
00995 
00996 
00997 
00998 
00999 
01000 
01001 
01002 
01003 
01004 
01005 
01006 
01007 
01008 
01009 
01010 
01011 
01012 
01013 
01014 
01015 
01016 
01017 
01018 
01019 
01020 
01021 
01022 
01023 
01024 
01025 
01026 
01027 
01028 
01029 
01030 
01031 
01032 
01033 
01034 
01035 
01036 
01037 
01038 
01039 
01040 
01041 
01042 
01043 
01044 
01045 
01046 
01047 
01048 
01049 
01050 SUMA_Boolean SUMA_getoffsets2 (int n, SUMA_SurfaceObject *SO, float lim, SUMA_GET_OFFSET_STRUCT *OffS, int *CoverThisNode, int N_CoverThisNode) 
01051 {
01052    static char FuncName[]={"SUMA_getoffsets2"};
01053    int LayInd, il, n_il, n_jne, k, n_prec = -1, n_k, jne, iseg=0;
01054    float Off_tmp, Seg, *a, *b, minSeg, SegPres; 
01055    SUMA_Boolean Visit = NOPE;
01056    SUMA_Boolean AllDone = NOPE;
01057    static SUMA_Boolean LocalHead = NOPE;
01058    
01059    SUMA_ENTRY;
01060    
01061    if (!OffS) {
01062       SUMA_SL_Err("NULL OffS");
01063       SUMA_RETURN(NOPE);
01064    }
01065    
01066    
01067    OffS->OffVect[n] = 0.0;   
01068    OffS->LayerVect[n] = 0;   
01069    OffS->layers[0].N_NodesInLayer = 1;
01070    OffS->layers[0].NodesInLayer[0] = n;
01071    if (CoverThisNode) { 
01072       if (CoverThisNode[n]) {
01073          CoverThisNode[n] = 0; --N_CoverThisNode;
01074       }
01075    }
01076    LayInd = 1;  
01077    AllDone = NOPE;
01078    while (!AllDone) {
01079       
01080       AllDone = YUP; 
01081       for (il=0; il < OffS->layers[LayInd - 1].N_NodesInLayer; ++il) { 
01082          n_il =  OffS->layers[LayInd - 1].NodesInLayer[il]; 
01083          for (jne=0; jne < SO->FN->N_Neighb[n_il]; ++jne) { 
01084             n_jne = SO->FN->FirstNeighb[n_il][jne];        
01085             if (OffS->LayerVect[n_jne] < 0) { 
01086                OffS->LayerVect[n_jne] =  LayInd;    
01087                OffS->OffVect[n_jne] = 0.0;          
01088                SUMA_AddNodeToLayer (n_jne, LayInd, OffS);   
01089                minSeg = 100000.0;
01090                n_prec = -1; 
01091                Seg = 0.0;
01092                SegPres = 0.0;
01093                for (k=0; k < SO->FN->N_Neighb[n_jne]; ++k) {   
01094                   n_k = SO->FN->FirstNeighb[n_jne][k];
01095                   if (OffS->LayerVect[n_k] == LayInd - 1) { 
01096                      if (n_prec < 0) n_prec = SO->FN->FirstNeighb[n_jne][0];
01097                      a = &(SO->NodeList[3*n_k]); b = &(SO->NodeList[3*n_jne]);
01098                      
01099 
01100 
01101 
01102                      SUMA_SEG_LENGTH_SQ (a, b, Seg);                    
01103                      if (OffS->OffVect[n_prec] + Seg < minSeg) {
01104                         minSeg = Seg + OffS->OffVect[n_prec];
01105                         SegPres = Seg;
01106                         n_prec = n_k;
01107                      }
01108                   }
01109                }
01110                
01111                if (n_prec < 0) { 
01112                   SUMA_SL_Crit("No precursor found for node.");
01113                   OffS = SUMA_Free_getoffsets (OffS);
01114                   SUMA_RETURN(NOPE);
01115                } else {
01116                   OffS->OffVect[n_jne] = OffS->OffVect[n_prec] + sqrt(SegPres); SegPres = 0.0;
01117                   if (!CoverThisNode) {
01118                      if (OffS->OffVect[n_jne] < lim) { 
01119                         AllDone = NOPE;
01120                      }
01121                   } else {
01122                      if (CoverThisNode[n_jne]) {
01123                         CoverThisNode[n_jne] = 0; --N_CoverThisNode;
01124                      }
01125                      if (N_CoverThisNode > 0) {
01126                         AllDone = NOPE;
01127                      }
01128                   }
01129                }
01130             } 
01131             
01132          } 
01133       
01134       }     
01135       ++LayInd;
01136    } 
01137    
01138    SUMA_RETURN(YUP);
01139 }
01140 
01141 void SUMA_Free_Offset_ll_Datum(void *data)
01142 {
01143    static char FuncName[]={"SUMA_Free_Offset_ll_Datum"};
01144    SUMA_OFFSET_LL_DATUM *dt;
01145    
01146    SUMA_ENTRY;
01147    
01148    if (data) {
01149       dt = (SUMA_OFFSET_LL_DATUM *)data; 
01150       SUMA_free(dt);
01151    }
01152    
01153    SUMA_RETURNe;
01154 }   
01155 
01156 SUMA_OFFSET_LL_DATUM *SUMA_New_Offset_ll_Datum(int n, int layer)
01157 {
01158    static char FuncName[]={"SUMA_New_Offset_ll_Datum"};
01159    SUMA_OFFSET_LL_DATUM * datum = NULL;
01160    
01161    SUMA_ENTRY;
01162    
01163    datum = (SUMA_OFFSET_LL_DATUM *)SUMA_malloc(sizeof(SUMA_OFFSET_LL_DATUM));
01164    datum->ni = n;
01165    datum->layer = layer;
01166    datum->off = -1.0;
01167    
01168    SUMA_RETURN(datum);
01169 }
01170 #define SUMA_BEGINNING_OF_LAYER(list, LayInd, Elm) {   \
01171    SUMA_OFFSET_LL_DATUM * m_dat = NULL; \
01172    DListElmt *m_Elm = NULL;   \
01173    do {  \
01174      if (m_Elm) m_Elm = m_Elm->next;   \
01175      else m_Elm =  dlist_head(list); \
01176      m_dat = (SUMA_OFFSET_LL_DATUM *)m_Elm->data; \
01177    } while(m_dat->layer != LayInd && m_Elm != dlist_tail(list));   \
01178    if (m_dat->layer != LayInd) Elm = NULL;  \
01179    else Elm = m_Elm; \
01180 } 
01181 #define SUMA_FIND_ELMENT_FOR_NODE(list, n_jne, Elm){  \
01182    SUMA_OFFSET_LL_DATUM * m_dat = NULL; \
01183    DListElmt *m_Elm = NULL;   \
01184    do {  \
01185      if (m_Elm) m_Elm = m_Elm->next;   \
01186      else m_Elm =  dlist_head(list); \
01187      m_dat = (SUMA_OFFSET_LL_DATUM *)m_Elm->data; \
01188    } while(m_dat->ni != n_jne && m_Elm != dlist_tail(list));   \
01189    if (m_dat->ni != n_jne) Elm = NULL;  \
01190    else Elm = m_Elm; \
01191 }
01192 DList * SUMA_getoffsets_ll (int n, SUMA_SurfaceObject *SO, float lim, int *CoverThisNode, int N_CoverThisNode) 
01193 {
01194    static char FuncName[]={"SUMA_getoffsets_ll"};
01195    int LayInd, il, n_il, n_jne, k, n_prec = -1, n_k, jne, iseg=0;
01196    float Off_tmp, Seg, *a, *b, minSeg, SegPres; 
01197    SUMA_Boolean Visit = NOPE;
01198    SUMA_Boolean AllDone = NOPE;
01199    SUMA_OFFSET_LL_DATUM * n_dat = NULL, *dat = NULL, *dat_nk = NULL, *dat_prec = NULL, *dat_ne=NULL;
01200    DList *list = NULL;
01201    DListElmt *elm = NULL, *elm_prec = NULL, *elm_ne=NULL, *elm_nk=NULL;
01202    static SUMA_Boolean LocalHead = NOPE;
01203    
01204    SUMA_ENTRY;
01205    
01206    
01207    
01208    SUMA_LH("Initializing list ...");
01209    list = (DList *)SUMA_malloc(sizeof(DList));
01210    dlist_init(list, SUMA_Free_Offset_ll_Datum);
01211    
01212    
01213    SUMA_LH("New OffsetDatum");
01214    n_dat = SUMA_New_Offset_ll_Datum(n, 0);
01215    n_dat->off = 0.0;   
01216    dlist_ins_next(list, dlist_tail(list), (void*)n_dat);
01217    
01218    if (CoverThisNode) { 
01219       if (CoverThisNode[n]) {
01220          CoverThisNode[n] = 0; --N_CoverThisNode;
01221       }
01222    }
01223    LayInd = 1;  
01224    AllDone = NOPE;
01225    while (!AllDone) {
01226       AllDone = YUP; 
01227       elm = NULL;
01228          do {
01229             if (!elm) { SUMA_BEGINNING_OF_LAYER(list, (LayInd-1), elm); }
01230             else elm = elm->next;
01231             if (!elm) {
01232                SUMA_SL_Err("Could not find beginning of layer!");
01233                SUMA_RETURN(NULL);
01234             }
01235             dat = (SUMA_OFFSET_LL_DATUM *)elm->data;
01236             if (dat->layer == LayInd -1) {
01237                n_il = dat->ni;
01238                for (jne=0; jne < SO->FN->N_Neighb[n_il]; ++jne) { 
01239                   n_jne = SO->FN->FirstNeighb[n_il][jne];        
01240                   SUMA_FIND_ELMENT_FOR_NODE(list, n_jne, elm_ne);
01241                   if (!elm_ne) { 
01242                      dat_ne = SUMA_New_Offset_ll_Datum(n_jne, LayInd); 
01243                      dat_ne->off = 0.0;
01244                      dlist_ins_next(list, dlist_tail(list), (void*)dat_ne);
01245                      minSeg = 100000.0;
01246                      n_prec = -1; 
01247                      Seg = 0.0;
01248                      SegPres = 0.0;
01249                      for (k=0; k < SO->FN->N_Neighb[n_jne]; ++k) {   
01250                         n_k = SO->FN->FirstNeighb[n_jne][k];
01251                         SUMA_FIND_ELMENT_FOR_NODE(list, n_k, elm_nk); 
01252                         if (n_prec < 0 && elm_nk) { 
01253                            n_prec = n_k; elm_prec = elm_nk; 
01254                            dat_prec = (SUMA_OFFSET_LL_DATUM *)elm_prec->data;
01255                         }
01256                         if (elm_nk) {
01257                            dat_nk = (SUMA_OFFSET_LL_DATUM *)elm_nk->data;
01258                            if (dat_nk->layer == LayInd - 1) { 
01259                               a = &(SO->NodeList[3*n_k]); b = &(SO->NodeList[3*n_jne]);
01260                               
01261 
01262 
01263 
01264                               SUMA_SEG_LENGTH_SQ (a, b, Seg);                    
01265                               if (dat_prec->off + Seg < minSeg) {
01266                                  minSeg = Seg + dat_prec->off;
01267                                  SegPres = Seg;
01268                                  n_prec = n_k;
01269                                  elm_prec = elm_nk;
01270                                  dat_prec = dat_nk;
01271                               }
01272                            }
01273                         } 
01274                      }
01275                      if (n_prec < 0) { 
01276                         SUMA_SL_Crit("No precursor found for node.");
01277                         SUMA_RETURN(NULL);
01278                      } else {
01279                         dat_ne->off = dat_prec->off + sqrt(SegPres); SegPres = 0.0;
01280                         if (!CoverThisNode) {
01281                            if (dat_ne->off < lim) { 
01282                               AllDone = NOPE;
01283                            }
01284                         } else {
01285                            if (CoverThisNode[n_jne]) {
01286                               CoverThisNode[n_jne] = 0; --N_CoverThisNode;
01287                            }
01288                            if (N_CoverThisNode > 0) {
01289                               AllDone = NOPE;
01290                            }
01291                         }
01292                      }
01293                   } 
01294                } 
01295             } 
01296          }  while (dat->layer == (LayInd-1) && elm != dlist_tail(list));
01297       
01298       ++LayInd;
01299    } 
01300    
01301    SUMA_RETURN(list);
01302 }
01303 
01304 typedef struct {
01305    SUMA_SurfaceObject *SO;
01306    SUMA_SurfaceObject *SOref;
01307    SUMA_COMM_STRUCT *cs;
01308    double Vref;
01309    double Rref;
01310    double V;
01311    double R;
01312    float *tmpList;
01313 } SUMA_VolDiffDataStruct; 
01314 typedef struct {
01315    SUMA_SurfaceObject *SO;
01316    SUMA_SurfaceObject *SOref;
01317    SUMA_COMM_STRUCT *cs;
01318    double Aref;
01319    double Rref;
01320    double A;
01321    double R;
01322    float *tmpList;
01323 } SUMA_AreaDiffDataStruct; 
01324 
01325 
01326 
01327 
01328 
01329 
01330 
01331 
01332 
01333 
01334 
01335 
01336 
01337 
01338 
01339 
01340 double SUMA_NewAreaAtRadius(SUMA_SurfaceObject *SO, double r, double Rref, float *tmpList)
01341 {
01342    static char FuncName[]={"SUMA_NewAreaAtRadius"};
01343    double Dr, A=0.0,  Un, U[3], Dn, P2[2][3], c[3];
01344    float *fp;
01345    int i;
01346    SUMA_Boolean LocalHead = NOPE;
01347 
01348    SUMA_ENTRY;
01349 
01350    
01351    Dr = ( Rref - r ) / Rref;
01352 
01353    
01354    for (i=0; i<SO->N_Node; ++i) {
01355       
01356       fp = &(SO->NodeList[3*i]); SUMA_UNIT_VEC(SO->Center, fp, U, Un);
01357       Dn = Dr*Un + Un;
01358       if (Un) {
01359          SUMA_COPY_VEC(SO->Center, c, 3, float, double);
01360          SUMA_POINT_AT_DISTANCE_NORM(U, c, Dn, P2);
01361          tmpList[3*i] = (float)P2[0][0]; tmpList[3*i+1] = (float)P2[0][1]; tmpList[3*i+2] = (float)P2[0][2];
01362       } else {
01363          SUMA_SL_Err("Identical points!\n"
01364                      "No coordinates modified");
01365          SUMA_RETURN(0);
01366       }
01367    }
01368 
01369 
01370    
01371    fp = SO->NodeList;
01372    SO->NodeList = tmpList; 
01373    A = fabs((double)SUMA_Mesh_Area(SO, NULL, -1));
01374    SO->NodeList = fp; fp = NULL;   
01375 
01376    SUMA_RETURN(A);
01377 } 
01378 
01379 
01380 
01381 
01382 
01383 
01384 
01385 
01386 
01387 
01388 
01389 
01390 
01391 
01392 
01393 
01394 double SUMA_NewVolumeAtRadius(SUMA_SurfaceObject *SO, double r, double Rref, float *tmpList)
01395 {
01396    static char FuncName[]={"SUMA_NewVolumeAtRadius"};
01397    double Dr, V=0.0,  Un, U[3], Dn, P2[2][3], c[3];
01398    float *fp;
01399    int i;
01400    SUMA_Boolean LocalHead = NOPE;
01401 
01402    SUMA_ENTRY;
01403 
01404    
01405    Dr = ( Rref - r ) / Rref;
01406 
01407    
01408    for (i=0; i<SO->N_Node; ++i) {
01409       
01410       fp = &(SO->NodeList[3*i]); SUMA_UNIT_VEC(SO->Center, fp, U, Un);
01411       Dn = Dr*Un + Un;
01412       if (Un) {
01413          SUMA_COPY_VEC(SO->Center, c, 3, float, double);
01414          SUMA_POINT_AT_DISTANCE_NORM(U, c, Dn, P2);
01415          tmpList[3*i] = (float)P2[0][0]; tmpList[3*i+1] = (float)P2[0][1]; tmpList[3*i+2] = (float)P2[0][2];
01416       } else {
01417          SUMA_SL_Err("Identical points!\n"
01418                      "No coordinates modified");
01419          SUMA_RETURN(0);
01420       }
01421    }
01422 
01423 
01424    
01425    fp = SO->NodeList;
01426    SO->NodeList = tmpList; 
01427    V = fabs((double)SUMA_Mesh_Volume(SO, NULL, -1));
01428    SO->NodeList = fp; fp = NULL;   
01429 
01430    SUMA_RETURN(V);
01431 } 
01432 
01433 double SUMA_AreaDiff(double r, void *fvdata)
01434 {
01435    static char FuncName[]={"SUMA_AreaDiff"};
01436    double da, *fp, Dr, A;
01437    static int ncall=0;
01438    int i;
01439    static double Rref = 0.0, Aref = 0.0;
01440    SUMA_SurfaceObject *SO, *SOref;
01441    SUMA_COMM_STRUCT *cs=NULL;
01442    SUMA_AreaDiffDataStruct *fdata = (SUMA_AreaDiffDataStruct*)fvdata ;
01443    SUMA_Boolean LocalHead = NOPE;
01444 
01445    SUMA_ENTRY;
01446    
01447    if (!fdata) {
01448       SUMA_LH("Reset");
01449       Rref = 0.0; Aref = 0.0;
01450       ncall = 0;
01451       SUMA_RETURN(0.0);
01452    }
01453    
01454    SO = fdata->SO;
01455    SOref = fdata->SOref;
01456    cs = fdata->cs;
01457    
01458    if (!ncall) {
01459       SUMA_LH("Initializing, calculating Aref and Rref");
01460       Aref = fdata->Aref;
01461       Rref = fdata->Rref;
01462       if (LocalHead) { fprintf(SUMA_STDERR,"%s: Reference volume = %f, radius = %f \n", FuncName, Aref, Rref); }
01463       if (cs->Send) { 
01464          if (!SUMA_SendToSuma (SOref, cs, (void *)SO->NodeList, SUMA_NODE_XYZ, 1)) {
01465          SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
01466          }
01467       }
01468    }
01469    
01470    A = SUMA_NewAreaAtRadius(SO, r, Rref, fdata->tmpList);
01471    da = Aref - A; 
01472    if (LocalHead) {
01473       fprintf(SUMA_STDERR,"%s: Call %d, A = %f, Aref = %f, da = %f\n", FuncName,ncall, A, Aref, da);
01474    }
01475       
01476    
01477    if (cs->Send) { 
01478       if (!SUMA_SendToSuma (SOref, cs, (void *)fdata->tmpList, SUMA_NODE_XYZ, 1)) {
01479       SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
01480       }
01481    }
01482 
01483    ++ncall;
01484    
01485    SUMA_RETURN(da);
01486 }
01487 
01488 double SUMA_VolDiff(double r, void *fvdata)
01489 {
01490    static char FuncName[]={"SUMA_VolDiff"};
01491    double dv, *fp, Dr, V;
01492    static int ncall=0;
01493    int i;
01494    static double Rref = 0.0, Vref = 0.0;
01495    SUMA_SurfaceObject *SO, *SOref;
01496    SUMA_COMM_STRUCT *cs=NULL;
01497    SUMA_VolDiffDataStruct *fdata = (SUMA_VolDiffDataStruct*)fvdata ;
01498    SUMA_Boolean LocalHead = NOPE;
01499 
01500    SUMA_ENTRY;
01501    
01502    if (!fdata) {
01503       SUMA_LH("Reset");
01504       Rref = 0.0; Vref = 0.0;
01505       ncall = 0;
01506       SUMA_RETURN(0.0);
01507    }
01508    
01509    SO = fdata->SO;
01510    SOref = fdata->SOref;
01511    cs = fdata->cs;
01512    
01513    if (!ncall) {
01514       SUMA_LH("Initializing, calculating Vref and Rref");
01515       Vref = fdata->Vref;
01516       Rref = fdata->Rref;
01517       if (LocalHead) { fprintf(SUMA_STDERR,"%s: Reference volume = %f, radius = %f \n", FuncName, Vref, Rref); }
01518       if (cs->Send) { 
01519          if (!SUMA_SendToSuma (SOref, cs, (void *)SO->NodeList, SUMA_NODE_XYZ, 1)) {
01520          SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
01521          }
01522       }
01523    }
01524    
01525    V = SUMA_NewVolumeAtRadius(SO, r, Rref, fdata->tmpList);
01526    dv = Vref - V; 
01527       
01528    
01529    if (cs->Send) { 
01530       if (!SUMA_SendToSuma (SOref, cs, (void *)fdata->tmpList, SUMA_NODE_XYZ, 1)) {
01531       SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
01532       }
01533    }
01534 
01535    ++ncall;
01536    
01537    SUMA_RETURN(dv);
01538 }
01539  
01540 
01541 
01542 
01543 
01544 
01545 
01546 
01547 
01548 double SUMA_BinaryZeroSearch(double a, double b, double(*f)(double x, void *data), void *fdata, int Nitermax, double tol) {
01549    static char FuncName[]={"SUMA_BinaryZeroSearch"};
01550    int Niter;
01551    double x, fx;
01552    SUMA_Boolean done;
01553    SUMA_Boolean LocalHead = NOPE;
01554 
01555    SUMA_ENTRY;
01556    
01557    if (Nitermax < 0) Nitermax = 1000;
01558 
01559    x = 0.0;
01560    Niter = 0;
01561    done = NOPE;
01562    while(!done && Niter < Nitermax) {
01563       x = (a+b)/2.0;
01564       fx = (*f)(x, fdata);
01565       if (LocalHead) fprintf(SUMA_STDERR,"%s: %d\ta=%.4f\tb=%.4f\tx=%.4f\tfx=%.4f\n", 
01566                                           FuncName, Niter, a, b, x, fx);
01567       if (fx < 0) a = x;
01568       else b = x;
01569       if (fabs(fx) < tol) done = YUP;
01570       ++Niter;
01571    }
01572    
01573    if (!done) {
01574       SUMA_SL_Warn(  "Reached iteration limit\n"
01575                      "without converging.\n");
01576    }
01577    
01578    SUMA_RETURN(x);
01579 }
01580 
01581 
01582 
01583 
01584 
01585 
01586 
01587 
01588 
01589 
01590 
01591 
01592 SUMA_Boolean SUMA_GetAreaDiffRange(SUMA_AreaDiffDataStruct *fdata, double *ap, double *bp)
01593 {
01594    static char FuncName[]={"SUMA_GetAreaDiffRange"};
01595    double a = 0.0, b = 0.0, nat=0, nbt=0, An, Bn;
01596    SUMA_Boolean LocalHead = NOPE;
01597 
01598    SUMA_ENTRY;
01599 
01600    
01601    fdata->Aref = fabs((double)SUMA_Mesh_Area(fdata->SOref, NULL, -1));
01602    SUMA_SO_RADIUS(fdata->SOref, fdata->Rref);
01603    fdata->A = fabs((double)SUMA_Mesh_Area(fdata->SO, NULL, -1));
01604    SUMA_SO_RADIUS(fdata->SO, fdata->R);
01605 
01606    
01607    if (fdata->Aref - fdata->A < 0) { 
01608       a = fdata->R; 
01609       An = fdata->A;
01610       b = fdata->Rref;
01611       do {
01612          SUMA_LH("Looking for b");
01613          b *= 1.3;  
01614          Bn = SUMA_NewAreaAtRadius(fdata->SO, b, fdata->Rref, fdata->tmpList);
01615          ++nbt;
01616       } while ( fdata->Aref - Bn < 0 && nbt < 200);
01617    }else{
01618       b = fdata->R; 
01619       Bn = fdata->A;
01620       a = fdata->Rref;
01621       do {
01622          SUMA_LH("Looking for a");
01623          a *= 0.7;
01624          An = SUMA_NewAreaAtRadius(fdata->SO, a, fdata->Rref, fdata->tmpList);
01625          ++nat;
01626       } while ( fdata->Aref -  An> 0 && nat < 200);
01627    }
01628 
01629    *ap = a; *bp = b;
01630 
01631    if (nat >= 200 || nbt >= 200) {
01632       SUMA_SL_Err("Failed to find segment.");
01633       SUMA_RETURN(NOPE);
01634    }
01635 
01636    if (LocalHead) {
01637       fprintf (SUMA_STDERR,"%s:\nChosen range is [%f %f] with Areas [%f %f], reference Area is %f\n", 
01638             FuncName, a, b, An, Bn, fdata->Aref);
01639    }
01640    
01641    SUMA_RETURN(YUP); 
01642 }
01643 
01644 
01645 
01646 
01647 
01648 
01649 SUMA_Boolean SUMA_GetVolDiffRange(SUMA_VolDiffDataStruct *fdata, double *ap, double *bp)
01650 {
01651    static char FuncName[]={"SUMA_GetVolDiffRange"};
01652    double a = 0.0, b = 0.0, nat=0, nbt=0;
01653    SUMA_Boolean LocalHead = NOPE;
01654 
01655    SUMA_ENTRY;
01656 
01657    
01658    fdata->Vref = fabs((double)SUMA_Mesh_Volume(fdata->SOref, NULL, -1));
01659    SUMA_SO_RADIUS(fdata->SOref, fdata->Rref);
01660    fdata->V = fabs((double)SUMA_Mesh_Volume(fdata->SO, NULL, -1));
01661    SUMA_SO_RADIUS(fdata->SO, fdata->R);
01662 
01663    
01664    if (fdata->Vref - fdata->V < 0) { 
01665       a = fdata->R; 
01666       b = fdata->Rref;
01667       do {
01668          SUMA_LH("Looking for b");
01669          b *= 1.3; ++nbt; 
01670       } while ( fdata->Vref - SUMA_NewVolumeAtRadius(fdata->SO, b, fdata->Rref, fdata->tmpList) < 0 && nbt < 200);
01671    }else{
01672       b = fdata->R; 
01673       a = fdata->Rref;
01674       do {
01675          SUMA_LH("Looking for a");
01676          a *= 0.7; ++nat;
01677       } while ( fdata->Vref - SUMA_NewVolumeAtRadius(fdata->SO, a, fdata->Rref, fdata->tmpList) > 0 && nat < 200);
01678    }
01679 
01680    *ap = a; *bp = b;
01681 
01682    if (nat >= 200 || nbt >= 200) {
01683       SUMA_SL_Err("Failed to find segment.");
01684       SUMA_RETURN(NOPE);
01685    }
01686 
01687    SUMA_RETURN(YUP); 
01688 }
01689 
01690 
01691 
01692 
01693 
01694 
01695 
01696 
01697 
01698 
01699 
01700 SUMA_Boolean SUMA_EquateSurfaceAreas(SUMA_SurfaceObject *SO, SUMA_SurfaceObject *SOref, float tol, SUMA_COMM_STRUCT *cs)
01701 {
01702    static char FuncName[]={"SUMA_EquateSurfaceAreas"};
01703    int iter, i, iter_max, ndiv;
01704    double a, b, d;
01705    SUMA_AreaDiffDataStruct fdata;
01706    SUMA_Boolean LocalHead = NOPE;
01707    
01708    SUMA_ENTRY;
01709 
01710    if (!SO || !SOref) { SUMA_SL_Err("NULL surfaces"); SUMA_RETURN(NOPE); }
01711    if (SO->N_Node != SOref->N_Node || SO->N_FaceSet != SOref->N_FaceSet) { SUMA_SL_Err("Surfaces not isotopic"); SUMA_RETURN(NOPE); }
01712    
01713    if (LocalHead) {
01714       fprintf(SUMA_STDERR, "%s:\n"
01715                            " SO    Center: %f, %f, %f\n"
01716                            " SOref Center: %f, %f, %f\n"
01717                            , FuncName, 
01718                            SO->Center[0], SO->Center[1], SO->Center[2],
01719                            SOref->Center[0], SOref->Center[1], SOref->Center[2]);  
01720    }
01721      
01722    
01723    fdata.SO = SO; fdata.SOref = SOref; fdata.cs = cs;
01724    fdata.tmpList = (float *)SUMA_malloc(SOref->NodeDim * SOref->N_Node * sizeof(float));
01725    if (!fdata.tmpList) {
01726       SUMA_SL_Err("Failed to allocate");
01727       SUMA_RETURN(0);
01728    }
01729 
01730    if (!SUMA_GetAreaDiffRange(&fdata, &a, &b)) {
01731       SUMA_SL_Err("Failed to get range");
01732       SUMA_RETURN(NOPE);
01733    }
01734    
01735    if (LocalHead) {
01736       fprintf(SUMA_STDERR,"%s:\na = %f\tb=%f\n", FuncName, a, b);
01737    }      
01738    SUMA_BinaryZeroSearch(a, b, SUMA_AreaDiff, &fdata, 500, tol);  
01739    
01740    
01741    SUMA_free(SO->NodeList); SO->NodeList = fdata.tmpList; fdata.tmpList = NULL;
01742        
01743    SUMA_RETURN(YUP);
01744 }
01745 
01746 
01747 
01748 
01749 
01750 
01751 
01752 
01753 
01754 
01755 
01756 SUMA_Boolean SUMA_EquateSurfaceVolumes(SUMA_SurfaceObject *SO, SUMA_SurfaceObject *SOref, float tol, SUMA_COMM_STRUCT *cs)
01757 {
01758    static char FuncName[]={"SUMA_EquateSurfaceVolumes"};
01759    int iter, i, iter_max, ndiv;
01760    double a, b, d;
01761    SUMA_VolDiffDataStruct fdata;
01762    SUMA_Boolean LocalHead = NOPE;
01763    
01764    SUMA_ENTRY;
01765 
01766    if (!SO || !SOref) { SUMA_SL_Err("NULL surfaces"); SUMA_RETURN(NOPE); }
01767    if (SO->N_Node != SOref->N_Node || SO->N_FaceSet != SOref->N_FaceSet) { SUMA_SL_Err("Surfaces not isotopic"); SUMA_RETURN(NOPE); }
01768    
01769    if (LocalHead) {
01770       fprintf(SUMA_STDERR, "%s:\n"
01771                            " SO    Center: %f, %f, %f\n"
01772                            " SOref Center: %f, %f, %f\n"
01773                            , FuncName, 
01774                            SO->Center[0], SO->Center[1], SO->Center[2],
01775                            SOref->Center[0], SOref->Center[1], SOref->Center[2]);  
01776    }
01777      
01778    
01779    fdata.SO = SO; fdata.SOref = SOref; fdata.cs = cs;
01780    fdata.tmpList = (float *)SUMA_malloc(SOref->NodeDim * SOref->N_Node * sizeof(float));
01781    if (!fdata.tmpList) {
01782       SUMA_SL_Err("Failed to allocate");
01783       SUMA_RETURN(0);
01784    }
01785 
01786    if (!SUMA_GetVolDiffRange(&fdata, &a, &b)) {
01787       SUMA_SL_Err("Failed to get range");
01788       SUMA_RETURN(NOPE);
01789    }
01790    
01791    if (LocalHead) {
01792       fprintf(SUMA_STDERR,"%s:\na = %f\tb=%f\n", FuncName, a, b);
01793    }      
01794    SUMA_BinaryZeroSearch(a, b, SUMA_VolDiff, &fdata, 500, tol);  
01795    
01796    
01797    SUMA_free(SO->NodeList); SO->NodeList = fdata.tmpList; fdata.tmpList = NULL;
01798        
01799    SUMA_RETURN(YUP);
01800 }
01801 
01802 
01803 
01804 
01805 
01806 
01807 
01808 
01809 
01810 
01811 
01812 
01813 
01814 
01815 
01816 
01817 SUMA_Boolean SUMA_ProjectSurfaceToSphere(SUMA_SurfaceObject *SO, SUMA_SurfaceObject *SOref ,float radius, SUMA_COMM_STRUCT *cs)
01818 {
01819    static char FuncName[]={"SUMA_ProjectSurfaceToSphere"};
01820    int i=0, j=0, cnt = 0, istrt, istp;
01821    struct timeval start_time, start_time_all;
01822    float etime_GetOffset, etime_GetOffset_all, ave_dist= 0.0, dj = 0.0, ave_dist_ref= 0.0, *a=NULL;
01823    float P2[2][3], U[3], Un;
01824    SUMA_Boolean LocalHead = NOPE;
01825    
01826    SUMA_ENTRY;
01827 
01828    if (!SO || !SOref) { SUMA_SL_Err("NULL surface"); SUMA_RETURN(NOPE); }
01829    
01830    if (LocalHead) {
01831       fprintf(SUMA_STDERR, "%s:\n"
01832                            " SO    Center: %f, %f, %f\n"
01833                            " radius = %f\n", FuncName, 
01834                            SO->Center[0], SO->Center[1], SO->Center[2],
01835                            radius);  
01836    }
01837       
01838    #ifdef FROM_THIS_NODE
01839    istrt = FROM_THIS_NODE;
01840    istp = TO_THIS_NODE+1;
01841    #else
01842    istrt = 0;
01843    istp = SO->N_Node;
01844    #endif
01845    ave_dist_ref =  radius;
01846    for (i =istrt ; i<istp; ++i) {
01847       if (i == 0) {
01848          SUMA_etime(&start_time,0);
01849       }
01850       
01851 
01852 
01853       a = &(SO->NodeList[3*i]); SUMA_UNIT_VEC(SO->Center, a, U, Un);
01854       if (Un) {
01855          SUMA_POINT_AT_DISTANCE_NORM(U, SO->Center, ave_dist_ref, P2);
01856          SO->NodeList[3*i] = P2[0][0]; SO->NodeList[3*i+1] = P2[0][1]; SO->NodeList[3*i+2] = P2[0][2];
01857       } else {
01858             SUMA_SL_Err("Identical points!\n"
01859                         "No coordinates modified");
01860       }
01861       
01862       if (LocalHead) {
01863          if (! (i%999)) {
01864             a = &(SO->NodeList[3*i]);
01865             SUMA_SEG_LENGTH(a, SO->Center, dj);
01866             fprintf(SUMA_STDERR, "%s:\n"
01867                            "node i=%d, avg_dist_ref = %f\ncnt = %d\n"
01868                            "Check on P2: New dist =%f ?=? %f\n", 
01869                            FuncName, i, ave_dist_ref, cnt, dj, ave_dist_ref);
01870             etime_GetOffset = SUMA_etime(&start_time,1);
01871             fprintf(SUMA_STDERR, "%s: Search to %f mm took %f seconds for %d nodes.\n"
01872                   "Projected completion time: %f minutes\n",
01873                   FuncName, radius, etime_GetOffset, i+1,
01874                   etime_GetOffset * SO->N_Node / 60.0 / (i+1));
01875          }
01876       }
01877       if (! (i%99) && cs) {
01878          if (cs->Send) { 
01879             if (!SUMA_SendToSuma (SOref, cs, (void *)SO->NodeList, SUMA_NODE_XYZ, 1)) {
01880             SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
01881             }
01882          }
01883       }
01884       
01885       #ifdef FROM_THIS_NODE
01886       {
01887          FILE *fid=NULL;
01888          char *outname=NULL, tmp[20];
01889          int ii;
01890          if (cs->Send) { 
01891             if (!SUMA_SendToSuma (SOref, cs, (void *)SO->NodeList, SUMA_NODE_XYZ, 1)) {
01892             SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
01893             }
01894          }
01895          sprintf(tmp,"offset_n%d", FROM_THIS_NODE);
01896          outname = SUMA_Extension("", ".1D", YUP);
01897          outname = SUMA_append_replace_string(outname, "offset.1D", "", 1);
01898          fid = fopen(outname, "w"); free(outname); outname = NULL;
01899          if (!fid) {
01900             SUMA_SL_Err("Could not open file for writing.\nCheck file permissions, disk space.\n");
01901          } else {
01902             fprintf (fid,"#Column 1 = Node index\n"
01903                          "#column 2 = Neighborhood layer\n"
01904                          "#Column 3 = Distance from node %d\n", 99);
01905             for (ii=0; ii<SO->N_Node; ++ii) {
01906                if (OffS->LayerVect[ii] >= 0) {
01907                   fprintf(fid,"%d\t%d\t%f\n", ii, OffS->LayerVect[ii], OffS->OffVect[ii]);
01908                }
01909             }
01910             fclose(fid);
01911          }
01912          { int jnk; fprintf(SUMA_STDOUT,"Pausing, next node is %d...", i+1); jnk = getchar(); fprintf(SUMA_STDOUT,"\n"); }
01913       }
01914       #endif
01915              
01916       
01917    }   
01918    
01919    
01920    SUMA_RETURN(YUP);
01921 }
01922 
01923 
01924 
01925 
01926 
01927 
01928 
01929 
01930 
01931 
01932 
01933 
01934 
01935 
01936 
01937 
01938 
01939 
01940 
01941 
01942 SUMA_Boolean SUMA_EquateSurfaceSize(SUMA_SurfaceObject *SO, SUMA_SurfaceObject *SOref, float max_off, SUMA_COMM_STRUCT *cs)
01943 {
01944    static char FuncName[]={"SUMA_EquateSurfaceSize"};
01945    int i=0, j=0, cnt = 0, istrt, istp;
01946    struct timeval start_time, start_time_all;
01947    float etime_GetOffset, etime_GetOffset_all, ave_dist= 0.0, dj = 0.0, ave_dist_ref= 0.0, *a=NULL;
01948    float P2[2][3], U[3], Un;
01949    SUMA_GET_OFFSET_STRUCT *OffS = NULL;
01950    SUMA_Boolean LocalHead = NOPE;
01951    
01952    SUMA_ENTRY;
01953 
01954    if (!SO || !SOref) { SUMA_SL_Err("NULL surfaces"); SUMA_RETURN(NOPE); }
01955    if (SO->N_Node != SOref->N_Node || SO->N_FaceSet != SOref->N_FaceSet) { SUMA_SL_Err("Surfaces not isotopic"); SUMA_RETURN(NOPE); }
01956    
01957    if (LocalHead) {
01958       fprintf(SUMA_STDERR, "%s:\n"
01959                            " SO    Center: %f, %f, %f\n"
01960                            " SOref Center: %f, %f, %f\n"
01961                            " max_off = %f\n", FuncName, 
01962                            SO->Center[0], SO->Center[1], SO->Center[2],
01963                            SOref->Center[0], SOref->Center[1], SOref->Center[2],
01964                            max_off);  
01965    }
01966       
01967    OffS = SUMA_Initialize_getoffsets (SOref->N_Node);
01968    #ifdef FROM_THIS_NODE
01969    istrt = FROM_THIS_NODE;
01970    istp = TO_THIS_NODE+1;
01971    #else
01972    istrt = 0;
01973    istp = SOref->N_Node;
01974    #endif
01975    for (i =istrt ; i<istp; ++i) {
01976       if (i == 0) {
01977          SUMA_etime(&start_time,0);
01978       }
01979       SUMA_getoffsets2 (i, SOref, max_off, OffS, NULL, 0);
01980       
01981       a = &(SOref->NodeList[3*i]); SUMA_SEG_LENGTH(a, SOref->Center, ave_dist_ref); 
01982       cnt = 1;
01983       #ifdef FROM_THIS_NODE
01984             fprintf(SUMA_STDERR, "%s: Considering the following %d neighbors to:\n"
01985                                  "i=%d; [%f, %f, %f]; d[%d] = %f\n", FuncName, OffS->N_Nodes,
01986                                     i, SOref->NodeList[3*i], SOref->NodeList[3*i+1], SOref->NodeList[3*i+2], 
01987                                     cnt, ave_dist_ref);
01988       #endif
01989       for (j=0; j<OffS->N_Nodes; ++j)
01990       {
01991          
01992          if (i!=j && OffS->LayerVect[j] >= 0 && OffS->OffVect[j] <= max_off)
01993          {
01994             
01995             a = &(SOref->NodeList[3*j]); SUMA_SEG_LENGTH(a, SOref->Center, dj);
01996             ave_dist_ref += dj;
01997             ++cnt;
01998             #ifdef FROM_THIS_NODE
01999                fprintf(SUMA_STDERR, ""
02000                                  "j=%d; [%f, %f, %f]; d[%d] = %f\n",
02001                                     j, SOref->NodeList[3*j], SOref->NodeList[3*j+1], SOref->NodeList[3*j+2], 
02002                                     cnt, dj);
02003             #endif
02004          }
02005       }
02006       ave_dist_ref /=  (float)cnt;
02007       
02008 
02009 
02010       a = &(SO->NodeList[3*i]); SUMA_UNIT_VEC(SO->Center, a, U, Un);
02011       if (Un) {
02012          SUMA_POINT_AT_DISTANCE_NORM(U, SO->Center, ave_dist_ref, P2);
02013          SO->NodeList[3*i] = P2[0][0]; SO->NodeList[3*i+1] = P2[0][1]; SO->NodeList[3*i+2] = P2[0][2];
02014       } else {
02015             SUMA_SL_Err("Identical points!\n"
02016                         "No coordinates modified");
02017       }
02018       
02019       if (LocalHead) {
02020          if (! (i%999)) {
02021             a = &(SO->NodeList[3*i]);
02022             SUMA_SEG_LENGTH(a, SOref->Center, dj);
02023             fprintf(SUMA_STDERR, "%s:\n"
02024                            "node i=%d, avg_dist_ref = %f\ncnt = %d\n"
02025                            "Check on P2: New dist =%f ?=? %f\n", 
02026                            FuncName, i, ave_dist_ref, cnt, dj, ave_dist_ref);
02027             etime_GetOffset = SUMA_etime(&start_time,1);
02028             fprintf(SUMA_STDERR, "%s: Search to %f mm took %f seconds for %d nodes.\n"
02029                   "Projected completion time: %f minutes\n",
02030                   FuncName, max_off, etime_GetOffset, i+1,
02031                   etime_GetOffset * SO->N_Node / 60.0 / (i+1));
02032          }
02033       }
02034       if (! (i%99) && cs) {
02035          if (cs->Send) { 
02036             if (!SUMA_SendToSuma (SOref, cs, (void *)SO->NodeList, SUMA_NODE_XYZ, 1)) {
02037             SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
02038             }
02039          }
02040       }
02041       
02042       #ifdef FROM_THIS_NODE
02043       {
02044          FILE *fid=NULL;
02045          char *outname=NULL, tmp[20];
02046          int ii;
02047          if (cs->Send) { 
02048             if (!SUMA_SendToSuma (SOref, cs, (void *)SO->NodeList, SUMA_NODE_XYZ, 1)) {
02049             SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
02050             }
02051          }
02052          sprintf(tmp,"offset_n%d", FROM_THIS_NODE);
02053          outname = SUMA_Extension("", ".1D", YUP);
02054          outname = SUMA_append_replace_string(outname, "offset.1D", "", 1);
02055          fid = fopen(outname, "w"); free(outname); outname = NULL;
02056          if (!fid) {
02057             SUMA_SL_Err("Could not open file for writing.\nCheck file permissions, disk space.\n");
02058          } else {
02059             fprintf (fid,"#Column 1 = Node index\n"
02060                          "#column 2 = Neighborhood layer\n"
02061                          "#Column 3 = Distance from node %d\n", 99);
02062             for (ii=0; ii<SO->N_Node; ++ii) {
02063                if (OffS->LayerVect[ii] >= 0) {
02064                   fprintf(fid,"%d\t%d\t%f\n", ii, OffS->LayerVect[ii], OffS->OffVect[ii]);
02065                }
02066             }
02067             fclose(fid);
02068          }
02069          { int jnk; fprintf(SUMA_STDOUT,"Pausing, next node is %d...", i+1); jnk = getchar(); fprintf(SUMA_STDOUT,"\n"); }
02070       }
02071       #endif
02072              
02073       
02074       SUMA_Recycle_getoffsets (OffS);
02075       
02076    }   
02077    
02078    
02079    SUMA_Free_getoffsets(OffS); OffS = NULL;
02080    
02081    SUMA_RETURN(YUP);
02082 }
02083 
02084 
02085 
02086 
02087 
02088 
02089 
02090 
02091 
02092 
02093 
02094 
02095 float ** SUMA_Chung_Smooth_Weights (SUMA_SurfaceObject *SO)
02096 {
02097    static char FuncName[]={"SUMA_Chung_Smooth_Weights"};
02098    float **wgt=NULL, *coord_nbr=NULL, *cotan=NULL, *tfp=NULL;
02099    float dv[3], p[3], q[3];
02100    float area, area_p, area_q, dot_p, dot_q;
02101    int i, j, k, n, j3p1, j3m1, n3, j3=0, nj, nj3, i_dbg;
02102    SUMA_Boolean LocalHead = NOPE;
02103    
02104    SUMA_ENTRY;
02105 
02106    if (!SO) {
02107       SUMA_SL_Err("Null SO");
02108       SUMA_RETURN(NULL);
02109    }
02110    if (!SO->FN) {
02111       SUMA_SL_Err("Null SO->FN");
02112       SUMA_RETURN(NULL);
02113    }
02114    
02115    i_dbg = -1; 
02116    
02117 
02118 
02119 
02120 
02121    
02122    wgt = (float **)SUMA_allocate2D(SO->N_Node, SO->FN->N_Neighb_max, sizeof(float));  
02123    coord_nbr = (float *)SUMA_malloc((SO->FN->N_Neighb_max + 2) * sizeof(float) * 3);  
02124    cotan = (float *)SUMA_malloc(SO->FN->N_Neighb_max * sizeof(float)); 
02125    if (!wgt || !coord_nbr || !cotan) {
02126       SUMA_SL_Crit("Failed to allocate for wgt &/|coord_nbr &/|cotan");
02127       SUMA_RETURN(NULL);
02128    }
02129    
02130    for (n=0; n < SO->N_Node; ++n) {
02131       n3 = 3 * n;
02132       
02133       for (j=0; j<SO->FN->N_Neighb[n]; ++j) {
02134          j3 = 3 * (j+1);
02135          nj = SO->FN->FirstNeighb[n][j]; nj3 = 3 * nj;
02136          coord_nbr[j3] = SO->NodeList[nj3] - SO->NodeList[n3];
02137          coord_nbr[j3+1] = SO->NodeList[nj3+1] - SO->NodeList[n3+1];
02138          coord_nbr[j3+2] = SO->NodeList[nj3+2] - SO->NodeList[n3+2];
02139       }  
02140       
02141 
02142    
02143       for (k=0; k < 3; ++k) coord_nbr[k] = coord_nbr[j3+k];  
02144       j3 = 3 * ( SO->FN->N_Neighb[n] + 1);
02145       for (k=0; k < 3; ++k) coord_nbr[j3+k] = coord_nbr[3+k];
02146       if (LocalHead && n == i_dbg) { SUMA_disp_vect (coord_nbr, 3 * (SO->FN->N_Neighb[n] + 2)) ;  }
02147       
02148       
02149       area = 0.0;
02150       for (j=1; j<=SO->FN->N_Neighb[n]; ++j) { 
02151          j3 = 3 * j; j3p1 = 3 * (j+1); j3m1 = 3 * (j-1);
02152          for (k=0; k < 3; ++k) dv[k] = coord_nbr[j3p1+k] - coord_nbr[j3+k]; 
02153          tfp = &(coord_nbr[j3p1]);
02154          dot_p = SUMA_MT_DOT (tfp, dv);
02155          SUMA_MT_CROSS(p, tfp, dv);
02156          for (k=0; k < 3; ++k) dv[k] = coord_nbr[j3m1+k] - coord_nbr[j3+k]; 
02157          tfp = &(coord_nbr[j3m1]);
02158          dot_q = SUMA_MT_DOT (tfp, dv);
02159          SUMA_MT_CROSS(q, tfp, dv);
02160          
02161          SUMA_NORM(area_p, p); 
02162          SUMA_NORM(area_q, q); 
02163          
02164          cotan[j-1] = dot_p/area_p + dot_q/area_q;
02165          area += area_p/2.0;
02166          if (LocalHead && n == i_dbg) {
02167             fprintf (SUMA_STDERR,"[%d->%d] area_p, area_q = %f, %f\n",
02168                                   n, SO->FN->FirstNeighb[n][j-1],
02169                                   area_p / 2.0,  area_q / 2.0);
02170          }
02171       }
02172       
02173       for (j=0; j<SO->FN->N_Neighb[n]; ++j) {
02174          wgt[n][j] = cotan[j]/area;
02175       }
02176       if (LocalHead && n == i_dbg) {
02177          fprintf (SUMA_STDERR,"%s: Weight Results for neighbors of %d (matlab node %d):\n",
02178                               FuncName, n, n+1);
02179          SUMA_disp_vect (wgt[n], SO->FN->N_Neighb[n]);
02180       }
02181    }  
02182 
02183    
02184    if (coord_nbr) SUMA_free(coord_nbr); coord_nbr = NULL;
02185    if (cotan) SUMA_free(cotan); cotan = NULL;
02186 
02187    SUMA_RETURN(wgt);
02188 }
02189 
02190 
02191 
02192 
02193 
02194 
02195 
02196 
02197 
02198 
02199 
02200 
02201 
02202 
02203 
02204 
02205 
02206 
02207 
02208 
02209 
02210 
02211 
02212 
02213 
02214 
02215 
02216    
02217 SUMA_Boolean  SUMA_Taubin_Smooth_TransferFunc (float l, float m, int N, FILE *Out)
02218 {
02219    static char FuncName[]={"SUMA_Taubin_Smooth_TransferFunc"};
02220    FILE *Outp = NULL;
02221    int i, imax = 100;
02222    float fk, k;
02223    SUMA_Boolean LocalHead = NOPE;
02224    
02225    SUMA_ENTRY;
02226 
02227    if (N % 2) {
02228       SUMA_SL_Err("N_iter must be even");
02229       SUMA_RETURN(NOPE);
02230    }
02231    
02232    if (!Out) Outp = stdout;
02233    else Outp = Out;
02234    
02235    k = 0.0;
02236    for (i=0; i< imax; ++i) {
02237       fk = pow( ( ( 1-m*k ) * ( 1-l*k ) ) , N / 2 );
02238       fprintf (Outp,"%f %f\n", k, fk);
02239       k += (float)i/(float)imax;
02240    }
02241    
02242    
02243    SUMA_RETURN(YUP);
02244 }
02245 
02246 
02247 
02248 
02249 
02250 
02251 
02252 
02253 
02254 
02255 
02256 
02257 
02258 
02259 
02260 
02261 
02262 
02263 
02264 
02265 
02266 
02267 
02268 
02269  
02270 SUMA_Boolean SUMA_Taubin_Smooth_Coef (float k, float *l, float *m)
02271 {
02272    static char FuncName[]={"SUMA_Taubin_Smooth_Coef"};
02273    int i;
02274    float ls[2], delta;
02275    SUMA_Boolean Done = NOPE;
02276    SUMA_Boolean LocalHead = NOPE;
02277    
02278    SUMA_ENTRY;
02279    
02280    if (k < 0) { SUMA_SL_Err("k < 0"); SUMA_RETURN(NOPE); }
02281    
02282    
02283 
02284    delta = ( k * k - 12.0 * k + 20 );
02285    if (delta < 0) { SUMA_SL_Err("Delta is < 0 for specified k"); SUMA_RETURN(NOPE); }
02286    
02287    ls[0] = ( -k + sqrt(delta) ) / ( 10 - 6 * k );
02288    ls[1] = ( -k - sqrt(delta) ) / ( 10 - 6 * k );
02289    if (ls[0] < 0 && ls[1] < 0) { SUMA_SL_Err("No positive solution for l"); SUMA_RETURN(NOPE); }
02290    
02291    if (ls[1] > ls[0]) { 
02292       *l = ls[0]; ls[0] = ls[1]; ls[1] = *l;
02293    }
02294    
02295    Done = NOPE;
02296    i = 0;
02297    while (!Done && i < 2) {
02298       
02299       *l = ls[i]; 
02300       *m = *l / ( k * *l - 1.0 );
02301       if (*m < 0) Done = YUP;
02302       ++i;
02303    }
02304    
02305    if (!Done) { SUMA_SL_Err("No good solutions found."); SUMA_RETURN(NOPE); }
02306    
02307    if ( ! ( ( *m < -1.0 * *l ) && ( -1.0 * *l < 0 ) ) ) {
02308       SUMA_SL_Err("Solution did not meet m < -l < 0"); SUMA_RETURN(NOPE);
02309    }
02310    
02311    SUMA_RETURN(YUP);
02312 }
02313 
02314 
02315 
02316 
02317 
02318 
02319 
02320 
02321 
02322 
02323 
02324 
02325 
02326 
02327 
02328 
02329 
02330 
02331 
02332 
02333 
02334 
02335 
02336 
02337 
02338 
02339 
02340 
02341 
02342 
02343 
02344 
02345 
02346 
02347 
02348 
02349 
02350 
02351 
02352 
02353 
02354 
02355 
02356 
02357 
02358 
02359 
02360 
02361 
02362 
02363 float * SUMA_Taubin_Smooth (SUMA_SurfaceObject *SO, float **wgt, 
02364                             float lambda, float mu, float *fin_orig, 
02365                             int N_iter, int vpn, SUMA_INDEXING_ORDER d_order,
02366                             float *fout_final_user, SUMA_COMM_STRUCT *cs, 
02367                             byte *nmask)
02368 {
02369    static char FuncName[]={"SUMA_Taubin_Smooth"};
02370    float *fout_final=NULL, *fbuf=NULL, *fin=NULL, *fout=NULL, *fin_next=NULL, *ftmp=NULL;
02371    float fp, dfp, fpj;
02372    int i, n , k, j, niter, vnk, n_offset, DoThis; 
02373    SUMA_Boolean LocalHead = NOPE;
02374    
02375    SUMA_ENTRY;
02376 
02377    if (N_iter % 2) {
02378       SUMA_SL_Err("N_iter must be an even number\n");
02379       SUMA_RETURN(NULL);
02380    }
02381    
02382    if (!SO || !fin_orig) {
02383       SUMA_SL_Err("NULL SO or fin_orig\n");
02384       SUMA_RETURN(NULL);
02385    }
02386    if (!SO->FN) {
02387       SUMA_SL_Err("NULL SO->FN\n");
02388       SUMA_RETURN(NULL);
02389    }
02390    
02391    if (vpn < 1) {
02392       SUMA_SL_Err("vpn < 1\n");
02393       SUMA_RETURN(NULL);
02394    }  
02395    
02396    if (fout_final_user == fin_orig) {
02397       SUMA_SL_Err("fout_final_user == fin_orig");
02398       SUMA_RETURN(NULL);
02399    }
02400    
02401    if (!fout_final_user) { 
02402       fout_final = (float *)SUMA_calloc(SO->N_Node * vpn, sizeof(float));
02403       if (!fout_final) {
02404          SUMA_SL_Crit("Failed to allocate for fout_final\n");
02405          SUMA_RETURN(NULL);
02406       }
02407    }else {
02408       fout_final = fout_final_user; 
02409    }
02410    
02411    if (d_order == SUMA_COLUMN_MAJOR) {
02412          SUMA_SL_Warn("SUMA_COLUMN_MAJOR has not been thoroughly tested.");
02413    }
02414    
02415    if (cs->Send) {
02416       if(vpn != 3) {
02417          SUMA_SL_Warn("It does not look like you are smoothing coordinates!\nCommunication halted.");
02418          cs->Send = NOPE;
02419       }
02420       if (d_order == SUMA_COLUMN_MAJOR) {
02421          SUMA_SL_Warn("Talking with SUMA_COLUMN_MAJOR has not been tested.");
02422       }
02423    }
02424    
02425    
02426    fbuf = (float *)SUMA_calloc(SO->N_Node * vpn, sizeof(float));
02427    if (!fbuf) {
02428       SUMA_SL_Crit("Failed to allocate for fbuf\n");
02429       SUMA_RETURN(NULL);
02430    }
02431    
02432    if (LocalHead) {
02433       fprintf (SUMA_STDERR,"%s: Mu = %f, Lambda = %f\nShould have M(%f)< -L(%f) < 0\nN_iter=%d\n", 
02434          FuncName, mu, lambda, mu, -lambda, N_iter);
02435    }
02436    
02437    if (cs->Send) { 
02438       if (!SUMA_SendToSuma (SO, cs, (void *)fin_orig, SUMA_NODE_XYZ, 1)) {
02439          SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
02440       }
02441    }
02442    
02443    fin_next = fin_orig;
02444    switch (d_order) {
02445       case SUMA_COLUMN_MAJOR:
02446          for (niter=0; niter < N_iter; ++niter) {
02447             if ( niter % 2 ) { 
02448                fin = fin_next; 
02449                fout = fout_final; 
02450                fin_next = fout_final; 
02451             } else { 
02452                
02453                fin = fin_next;
02454                fout = fbuf; 
02455                fin_next = fbuf; 
02456             }
02457             for (k=0; k < vpn; ++k) {
02458                n_offset = k * SO->N_Node;  
02459                for (n=0; n < SO->N_Node; ++n) {
02460                   DoThis = 1;
02461                   if (nmask && !nmask[n]) DoThis = 0;
02462                   vnk = n+n_offset; 
02463                   if (DoThis) {
02464                      fp = fin[vnk]; 
02465                      dfp = 0.0;
02466                      for (j=0; j < SO->FN->N_Neighb[n]; ++j) { 
02467                         fpj = fin[SO->FN->FirstNeighb[n][j]+n_offset]; 
02468                         if (wgt) dfp += wgt[n][j] * (fpj - fp); 
02469                         else dfp += (fpj - fp); 
02470                      }
02471                      if (niter%2) { 
02472                         if (wgt) fout[vnk] = fin[vnk] + mu * dfp;
02473                         else fout[vnk] = fin[vnk] + mu * dfp / (float)SO->FN->N_Neighb[n];   
02474                      }else{ 
02475                        if (wgt) fout[vnk] = fin[vnk] + lambda * dfp;
02476                        else fout[vnk] = fin[vnk] + lambda * dfp / (float)SO->FN->N_Neighb[n];  
02477                      }
02478                   } else {
02479                      fout[vnk] = fin[vnk];
02480                   }      
02481                }   
02482             }
02483             if (cs->Send) {
02484                
02485 
02486                if (!niter) { 
02487                   ftmp = (float *) SUMA_malloc(3*SO->N_Node*sizeof(float));
02488                   if (!ftmp) { SUMA_SL_Err("Failed to allocate. Communication Off.\n"); cs->Send = NOPE; }
02489                }
02490                if (ftmp) {
02491                   for (i=0; i<SO->N_Node; ++i) { ftmp[3*i] = fout[i]; ftmp[3*i+1] = fout[i+SO->N_Node];  ftmp[3*i+2] = fout[i+2*SO->N_Node];}
02492                   if (!SUMA_SendToSuma (SO, cs, (void *)ftmp, SUMA_NODE_XYZ, 1)) {
02493                      SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
02494                   }
02495                }
02496                if (niter == N_iter -1) { 
02497                   if (ftmp) { SUMA_free(ftmp); ftmp = NULL; }
02498                }
02499             }
02500          }
02501          break;
02502       case SUMA_ROW_MAJOR:
02503          for (niter=0; niter < N_iter; ++niter) {
02504             if ( niter % 2 ) { 
02505                fin = fin_next; 
02506                fout = fout_final; 
02507                fin_next = fout_final; 
02508             } else { 
02509                
02510                fin = fin_next;
02511                fout = fbuf; 
02512                fin_next = fbuf; 
02513             }
02514             for (n=0; n < SO->N_Node; ++n) {
02515                DoThis = 1;
02516                if (nmask && !nmask[n]) DoThis = 0;
02517                vnk = n * vpn; 
02518                for (k=0; k < vpn; ++k) {
02519                   if (DoThis) {
02520                      fp = fin[vnk]; 
02521                      dfp = 0.0;
02522                      for (j=0; j < SO->FN->N_Neighb[n]; ++j) { 
02523                         fpj = fin[SO->FN->FirstNeighb[n][j]*vpn+k]; 
02524                         if (wgt) dfp += wgt[n][j] * (fpj - fp); 
02525                         else dfp += (fpj - fp); 
02526                      }
02527                      if (niter%2) { 
02528                         if (wgt) fout[vnk] = fin[vnk] + mu * dfp;
02529                         else fout[vnk] = fin[vnk] + mu * dfp / (float)SO->FN->N_Neighb[n];   
02530                      }else{ 
02531                        if (wgt) fout[vnk] = fin[vnk] + lambda * dfp;
02532                        else fout[vnk] = fin[vnk] + lambda * dfp / (float)SO->FN->N_Neighb[n];  
02533                      }
02534                   } else {
02535                      fout[vnk] = fin[vnk];
02536                   } 
02537                   ++vnk; 
02538                } 
02539             }
02540             if (cs->Send) {
02541                if (!SUMA_SendToSuma (SO, cs, (void *)fout, SUMA_NODE_XYZ, 1)) {
02542                   SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
02543                }
02544             }
02545          }
02546          break;
02547       default:
02548          SUMA_SL_Err("Bad Major, very bad.\n");
02549          SUMA_RETURN(NULL);
02550          break;
02551    }
02552    
02553    if (fbuf) SUMA_free(fbuf); fbuf = NULL;
02554       
02555    SUMA_RETURN(fout);
02556 }
02557 
02558 
02559 
02560 
02561 
02562 
02563 SUMA_Boolean SUMA_GetOffset2Offset (SUMA_GET_OFFSET_STRUCT *GOS, SUMA_OFFSET_STRUCT *OS) 
02564 {
02565    static char FuncName[]={"SUMA_GetOffset2Offset"};
02566    int il, jl, noffs;
02567    SUMA_Boolean LocalHead = NOPE;
02568    
02569    SUMA_ENTRY;
02570    
02571    if (!GOS || !OS) {
02572       SUMA_SL_Err("NULL input"); SUMA_RETURN(NOPE);
02573    }
02574    
02575    OS->N_Neighb = 0; 
02576    for (il=1; il<GOS->N_layers; ++il) {
02577       OS->N_Neighb += GOS->layers[il].N_NodesInLayer;
02578    }
02579    OS->Neighb_ind = (int *)SUMA_malloc(OS->N_Neighb * sizeof(int));
02580    OS->Neighb_dist = (float *)SUMA_malloc(OS->N_Neighb * sizeof(float));
02581    if (!OS->Neighb_ind || !OS->Neighb_dist) {
02582       SUMA_SL_Crit("Failed to allocate.");
02583       SUMA_RETURN(NOPE);
02584    }
02585    
02586    noffs = 0;
02587    for (il=1; il<GOS->N_layers; ++il) {
02588       for (jl=0; jl<GOS->layers[il].N_NodesInLayer; ++jl) {
02589          OS->Neighb_ind[noffs] = GOS->layers[il].NodesInLayer[jl]; 
02590          OS->Neighb_dist[noffs] = GOS->OffVect[OS->Neighb_ind[noffs]];
02591          ++noffs;
02592       }
02593    }
02594    
02595    SUMA_RETURN(YUP);
02596 }
02597 
02598 char * SUMA_ShowOffset_Info (SUMA_GET_OFFSET_STRUCT *OffS, int detail)
02599 {
02600    static char FuncName[]={"SUMA_ShowOffset_Info"};
02601    SUMA_STRING *SS = NULL;
02602    int ii, *ltmp=NULL, *imap = NULL;
02603    char *s=NULL;   
02604 
02605    SUMA_ENTRY;
02606 
02607    SS = SUMA_StringAppend (NULL, NULL);
02608 
02609    if (!OffS) {
02610       SS = SUMA_StringAppend (SS,"#NULL offset structure.\n");
02611    } else {
02612       SS = SUMA_StringAppend_va (SS,"#Node Offsets (graph distance) from node %d\n", OffS->layers[0].NodesInLayer[0]);
02613       SS = SUMA_StringAppend_va (SS,"#Column 0 = Node index\n"
02614                                     "#column 1 = Neighborhood layer\n"
02615                                     "#Column 2 = Distance from node %d\n", OffS->layers[0].NodesInLayer[0]);
02616       ltmp = (int *)SUMA_malloc(OffS->N_Nodes*sizeof(int)); 
02617       if (!ltmp) {
02618          SUMA_SL_Crit("Failed to allocate for ltmp");
02619          SUMA_RETURN(NULL);
02620       }
02621       for (ii=0; ii<OffS->N_Nodes; ++ii) ltmp[ii] = OffS->LayerVect[ii]; 
02622       imap = SUMA_z_dqsort(ltmp,OffS->N_Nodes); 
02623       for (ii=0; ii<OffS->N_Nodes; ++ii) {
02624          if (OffS->LayerVect[imap[ii]] >= 0) {
02625             SS = SUMA_StringAppend_va (SS,"%6d\t%6d\t%f\n", imap[ii], OffS->LayerVect[imap[ii]], OffS->OffVect[imap[ii]]);
02626          }
02627       }
02628    }
02629    if (ltmp) SUMA_free(ltmp); ltmp = NULL;
02630    if (imap) SUMA_free(imap); imap = NULL;
02631    SUMA_SS2S(SS,s);
02632 
02633    SUMA_RETURN(s);
02634 }
02635 
02636 char * SUMA_ShowOffset_ll_Info (DList *list, int detail)
02637 {
02638    static char FuncName[]={"SUMA_ShowOffset_ll_Info"};
02639    SUMA_STRING *SS = NULL;
02640    DListElmt *elm = NULL;
02641    SUMA_OFFSET_LL_DATUM *dat=NULL;
02642    int ii;
02643    char *s=NULL;   
02644 
02645    SUMA_ENTRY;
02646 
02647    SS = SUMA_StringAppend (NULL, NULL);
02648 
02649    if (!list) {
02650       SS = SUMA_StringAppend (SS,"#NULL offset list.\n");
02651    } else {
02652       do {
02653          if (!elm) elm = dlist_head(list); 
02654          else elm = elm->next;
02655          dat = (SUMA_OFFSET_LL_DATUM *)elm->data;
02656          if (elm == dlist_head(list)) {
02657             SS = SUMA_StringAppend_va (SS,"#Node Offsets (graph distance) from node %d\n", dat->ni);
02658             SS = SUMA_StringAppend_va (SS,"#Column 0 = Node index\n"
02659                                        "#column 1 = Neighborhood layer\n"
02660                                        "#Column 2 = Distance from node %d\n", dat->ni);
02661          }
02662          SS = SUMA_StringAppend_va (SS,"%6d\t%6d\t%f\n", dat->ni, dat->layer, dat->off);
02663       } while (elm != dlist_tail(list));
02664    }
02665    SUMA_SS2S(SS,s);
02666 
02667    SUMA_RETURN(s);
02668 }
02669 
02670 
02671 
02672 
02673 
02674 
02675 
02676 
02677 
02678 
02679 
02680 
02681 
02682 
02683 
02684 
02685 
02686 
02687 
02688 
02689 
02690 
02691 
02692 
02693 
02694 
02695 
02696 
02697 
02698  
02699 SUMA_OFFSET_STRUCT *SUMA_FormNeighbOffset ( SUMA_SurfaceObject *SO, float OffsetLim)
02700 {
02701    static char FuncName[]={"SUMA_FormNeighbOffset"};
02702    int i, ii, il, jl, noffs, ShowNode = 4;
02703    SUMA_GET_OFFSET_STRUCT *OffS = NULL;
02704    struct  timeval start_time;
02705    float etime_GetOffset, mean_N_Neighb, dist, dist_norm;   
02706    SUMA_OFFSET_STRUCT *OffS_out=NULL;
02707    SUMA_Boolean LocalHead = NOPE;
02708    
02709    SUMA_ENTRY;
02710    if (!SO) { SUMA_SL_Err("NULL SO"); SUMA_RETURN(NULL); }
02711    if (!SO->FN) {
02712       SUMA_SL_Err("NULL SO->FN");
02713       SUMA_RETURN(NULL);
02714    }
02715    OffS_out = (SUMA_OFFSET_STRUCT *)SUMA_malloc(SO->N_Node * sizeof(SUMA_OFFSET_STRUCT));
02716    
02717    SUMA_etime(&start_time,0);
02718    
02719    OffS = SUMA_Initialize_getoffsets (SO->N_Node);
02720    mean_N_Neighb = 0;
02721    dist_norm = 1.1 * OffsetLim;
02722    for (i=0; i < SO->N_Node; ++i) {
02723       SUMA_getoffsets2 (i, SO, OffsetLim, OffS, NULL, 0);
02724       
02725       OffS_out[i].N_Neighb = 0; 
02726       for (il=1; il<OffS->N_layers; ++il) {
02727          OffS_out[i].N_Neighb += OffS->layers[il].N_NodesInLayer;
02728       }
02729       OffS_out[i].Neighb_ind = (int *)SUMA_malloc(OffS_out[i].N_Neighb * sizeof(int));
02730       OffS_out[i].Neighb_dist = (float *)SUMA_malloc(OffS_out[i].N_Neighb * sizeof(float));
02731       mean_N_Neighb += OffS_out[i].N_Neighb;
02732       noffs = 0;
02733       for (il=1; il<OffS->N_layers; ++il) {
02734          for (jl=0; jl<OffS->layers[il].N_NodesInLayer; ++jl) {
02735             OffS_out[i].Neighb_ind[noffs] = OffS->layers[il].NodesInLayer[jl]; 
02736             #if 1
02737             
02738             OffS_out[i].Neighb_dist[noffs] = OffS->OffVect[OffS_out[i].Neighb_ind[noffs]];
02739             #else
02740             dist = OffS->OffVect[OffS_out[i].Neighb_ind[noffs]];
02741             if (dist > OffsetLim) OffS_out[i].Neighb_dist[noffs] = 0;
02742             else OffS_out[i].Neighb_dist[noffs] = (dist ); 
02743             #endif
02744             ++noffs;
02745          }
02746       }
02747       
02748       
02749       if (0) {
02750          if (i == ShowNode) {
02751             FILE *fid=NULL;
02752             char *outname=NULL;
02753             outname = SUMA_Extension("SomethingOffset", ".1D", YUP);
02754             outname = SUMA_append_replace_string(outname, "offset.1D", "", 1);
02755             fid = fopen(outname, "w"); free(outname); outname = NULL;
02756             if (!fid) {
02757                SUMA_SL_Err("Could not open file for writing.\nCheck file permissions, disk space.\n");
02758             } else {
02759                fprintf (fid,"#Column 1 = Node index\n"
02760                             "#column 2 = Neighborhood layer\n"
02761                             "#Column 3 = Distance from node %d\n", ShowNode);
02762                for (ii=0; ii<SO->N_Node; ++ii) {
02763                   if (OffS->LayerVect[ii] >= 0) {
02764                      fprintf(fid,"%d\t%d\t%f\n", ii, OffS->LayerVect[ii], OffS->OffVect[ii]);
02765                   }
02766                }
02767                fclose(fid);
02768             }
02769          }
02770       }
02771                
02772       if (i == 99) {
02773          etime_GetOffset = SUMA_etime(&start_time,1);
02774          fprintf(SUMA_STDERR, "%s: Search to %f mm took %f seconds for %d nodes.\n"
02775                               "Projected completion time: %f minutes\n"
02776                               "Projected memory need for structure %f MB", 
02777                               FuncName, OffsetLim, etime_GetOffset, i+1, 
02778                               etime_GetOffset * SO->N_Node / 60.0 / (i+1),
02779                               (mean_N_Neighb / (i+1) * 8 + 12)* SO->N_Node/1000000.0);
02780       }
02781       SUMA_Recycle_getoffsets (OffS);
02782    }
02783    SUMA_Free_getoffsets(OffS); OffS = NULL;
02784    
02785    etime_GetOffset = SUMA_etime(&start_time,1);
02786    fprintf(SUMA_STDERR, "%s: Search to %f mm took %f seconds for %d nodes.\n"
02787                         "Mean number of neighbors per node: %f\n",
02788                         FuncName, OffsetLim, etime_GetOffset, SO->N_Node, mean_N_Neighb / SO->N_Node);
02789    
02790    SUMA_RETURN(OffS_out);           
02791 } 
02792 
02793 
02794 
02795 
02796 
02797 
02798 SUMA_OFFSET_STRUCT * SUMA_free_NeighbOffset (SUMA_SurfaceObject *SO, SUMA_OFFSET_STRUCT *OffS_out)
02799 {
02800    static char FuncName[]={"SUMA_free_NeighbOffset"};
02801    int i;
02802    SUMA_ENTRY;
02803 
02804    if (!SO) {
02805       SUMA_S_Err("NULL SO!");
02806       SUMA_RETURN(NULL);
02807    }
02808    if (!OffS_out) SUMA_RETURN(NULL);
02809    for (i=0; i < SO->N_Node; ++i) {
02810       OffS_out[i].N_Neighb = 0;
02811       if (OffS_out[i].Neighb_dist) SUMA_free(OffS_out[i].Neighb_dist); OffS_out[i].Neighb_dist = NULL;
02812       if (OffS_out[i].Neighb_ind) SUMA_free(OffS_out[i].Neighb_ind); OffS_out[i].Neighb_ind = NULL;
02813    }
02814    SUMA_free(OffS_out); 
02815    SUMA_RETURN(NULL);
02816 }
02817 
02818 
02819 
02820 
02821 
02822 
02823 
02824 float *SUMA_Offset_GeomSmooth( SUMA_SurfaceObject *SO, int N_iter, float OffsetLim, float *fin_orig, 
02825                               int vpn, SUMA_INDEXING_ORDER d_order, float *fout_final_user,
02826                               SUMA_COMM_STRUCT *cs)
02827 {
02828    
02829    static char FuncName[]= {"SUMA_Offset_GeomSmooth"};
02830    float *fout_final=NULL, *fbuf=NULL, *fin_next=NULL, *fin=NULL, *fout=NULL;
02831    int niter=0, i, il,jl, j, ii,  noffs;
02832    struct  timeval start_time;
02833    float etime_GetOffset, weight_tot;   
02834    SUMA_OFFSET_STRUCT *OffS_out=NULL;
02835    SUMA_Boolean LocalHead = NOPE;
02836    
02837    SUMA_ENTRY;
02838    if (!SO) { SUMA_SL_Err("NULL SO"); SUMA_RETURN(NULL); }
02839    if (!SO->FN) {
02840       SUMA_SL_Err("NULL SO->FN");
02841       SUMA_RETURN(NULL);
02842    }   
02843    if (N_iter % 2) {
02844       SUMA_SL_Err("N_iter must be an even number\n");
02845       SUMA_RETURN(NULL);
02846    }
02847    if (vpn < 1) {
02848       SUMA_SL_Err("vpn < 1\n");
02849       SUMA_RETURN(NULL);
02850    }  
02851    
02852    if (fout_final_user == fin_orig) {
02853       SUMA_SL_Err("fout_final_user == fin_orig");
02854       SUMA_RETURN(NULL);
02855    }
02856    
02857    if (!fout_final_user) { 
02858       fout_final = (float *)SUMA_calloc(SO->N_Node * vpn, sizeof(float));
02859       if (!fout_final) {
02860          SUMA_SL_Crit("Failed to allocate for fout_final\n");
02861          SUMA_RETURN(NULL);
02862       }
02863    }else {
02864       fout_final = fout_final_user; 
02865    }
02866    
02867    
02868    fbuf = (float *)SUMA_calloc(SO->N_Node * vpn, sizeof(float));
02869    if (!fbuf) {
02870       SUMA_SL_Crit("Failed to allocate for fbuf\n");
02871       SUMA_RETURN(NULL);
02872    }
02873    
02874    
02875    if (cs->Send) { 
02876       if (!SUMA_SendToSuma (SO, cs, (void *)fin_orig, SUMA_NODE_XYZ, 1)) {
02877          SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
02878       }
02879    }
02880    SUMA_LH("Calculating OffS_out ...");
02881    OffS_out = SUMA_FormNeighbOffset (SO, OffsetLim);
02882    fin_next = fin_orig;
02883    switch (d_order) {
02884       case SUMA_ROW_MAJOR:
02885          for (niter=0; niter < N_iter; ++niter) {
02886             if ( niter % 2 ) { 
02887                fin = fin_next; 
02888                fout = fout_final; 
02889                fin_next = fout_final; 
02890             } else { 
02891                
02892                fin = fin_next;
02893                fout = fbuf; 
02894                fin_next = fbuf; 
02895             }
02896             
02897             SUMA_etime(&start_time,0);
02898             
02899             for (i=0; i < SO->N_Node; ++i) {
02900                for (j=0; j < vpn; ++j) {
02901                   
02902                   fout[i*vpn+j] = fin[i*vpn+j];
02903                   for (il=0; il<OffS_out[i].N_Neighb; ++il) {
02904                      fout[i*vpn+j] += fin[OffS_out[i].Neighb_ind[il]*vpn+j];
02905                   }
02906                   fout[i*vpn+j] /= (OffS_out[i].N_Neighb+1);  
02907                }
02908             }
02909             
02910             etime_GetOffset = SUMA_etime(&start_time,1);
02911             fprintf(SUMA_STDERR, "%s: Smoothing at dist %f took %f seconds for %d nodes.\n",
02912                            FuncName, OffsetLim, etime_GetOffset, SO->N_Node);
02913             
02914             if (cs->Send) {
02915                if (!SUMA_SendToSuma (SO, cs, (void *)fout, SUMA_NODE_XYZ, 1)) {
02916                   SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
02917                }
02918             }
02919          }
02920          break;
02921       case SUMA_COLUMN_MAJOR:
02922          SUMA_SL_Err("Column Major not implemented");
02923          SUMA_RETURN(NULL);
02924          break;
02925       default:
02926          SUMA_SL_Err("Bad Major, very bad.\n");
02927          SUMA_RETURN(NULL);
02928          break;
02929    }
02930    
02931    if (fbuf) SUMA_free(fbuf); fbuf = NULL;
02932 
02933    
02934    OffS_out = SUMA_free_NeighbOffset (SO, OffS_out);
02935       
02936    SUMA_RETURN(fout);    
02937 }
02938 
02939 float *SUMA_NN_GeomSmooth( SUMA_SurfaceObject *SO, int N_iter, float *fin_orig, 
02940                            int vpn, SUMA_INDEXING_ORDER d_order, float *fout_final_user,
02941                            SUMA_COMM_STRUCT *cs)
02942 {
02943    static char FuncName[]= {"SUMA_NN_GeomSmooth"};
02944    float *fout_final=NULL, *fbuf=NULL, *fin_next=NULL, *fin=NULL, *fout=NULL;
02945    int niter=0;
02946 
02947    SUMA_ENTRY;
02948    if (!SO) { SUMA_SL_Err("NULL SO"); SUMA_RETURN(NULL); }
02949    if (!SO->FN) {
02950       SUMA_SL_Err("NULL SO->FN");
02951       SUMA_RETURN(NULL);
02952    }   
02953    if (N_iter % 2) {
02954       SUMA_SL_Err("N_iter must be an even number\n");
02955       SUMA_RETURN(NULL);
02956    }
02957    if (vpn < 1) {
02958       SUMA_SL_Err("vpn < 1\n");
02959       SUMA_RETURN(NULL);
02960    }  
02961    
02962    if (fout_final_user == fin_orig) {
02963       SUMA_SL_Err("fout_final_user == fin_orig");
02964       SUMA_RETURN(NULL);
02965    }
02966    
02967    if (!fout_final_user) { 
02968       fout_final = (float *)SUMA_calloc(SO->N_Node * vpn, sizeof(float));
02969       if (!fout_final) {
02970          SUMA_SL_Crit("Failed to allocate for fout_final\n");
02971          SUMA_RETURN(NULL);
02972       }
02973    }else {
02974       fout_final = fout_final_user; 
02975    }
02976    
02977    
02978    fbuf = (float *)SUMA_calloc(SO->N_Node * vpn, sizeof(float));
02979    if (!fbuf) {
02980       SUMA_SL_Crit("Failed to allocate for fbuf\n");
02981       SUMA_RETURN(NULL);
02982    }
02983    
02984    
02985    if (cs->Send) { 
02986       if (!SUMA_SendToSuma (SO, cs, (void *)fin_orig, SUMA_NODE_XYZ, 1)) {
02987          SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
02988       }
02989    }
02990    
02991    fin_next = fin_orig;
02992    switch (d_order) {
02993       case SUMA_ROW_MAJOR:
02994          for (niter=0; niter < N_iter; ++niter) {
02995             if ( niter % 2 ) { 
02996                fin = fin_next; 
02997                fout = fout_final; 
02998                fin_next = fout_final; 
02999             } else { 
03000                
03001                fin = fin_next;
03002                fout = fbuf; 
03003                fin_next = fbuf; 
03004             }
03005             fout = SUMA_SmoothAttr_Neighb ( fin, vpn*SO->N_Node, 
03006                                                  fout, SO->FN, vpn);
03007             if (cs->Send) {
03008                if (!SUMA_SendToSuma (SO, cs, (void *)fout, SUMA_NODE_XYZ, 1)) {
03009                   SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
03010                }
03011             }
03012          }
03013          break;
03014       case SUMA_COLUMN_MAJOR:
03015          SUMA_SL_Err("Column Major not implemented");
03016          SUMA_RETURN(NULL);
03017          break;
03018       default:
03019          SUMA_SL_Err("Bad Major, very bad.\n");
03020          SUMA_RETURN(NULL);
03021          break;
03022    }
03023    
03024    if (fbuf) SUMA_free(fbuf); fbuf = NULL;
03025 
03026    SUMA_RETURN(fout);    
03027 }
03028         
03029 
03030 
03031 
03032 
03033 
03034 
03035 
03036 
03037 
03038 
03039 
03040 
03041 
03042 
03043 
03044 
03045 
03046 
03047 
03048 
03049 
03050 
03051 
03052 
03053 
03054 
03055 
03056 
03057 
03058 
03059 
03060 
03061 
03062 
03063 
03064 
03065 
03066 
03067 
03068 float * SUMA_Chung_Smooth (SUMA_SurfaceObject *SO, float **wgt, 
03069                            int N_iter, float FWHM, float *fin_orig, 
03070                            int vpn, SUMA_INDEXING_ORDER d_order, float *fout_final_user,
03071                            SUMA_COMM_STRUCT *cs)
03072 {
03073    static char FuncName[]={"SUMA_Chung_Smooth"};
03074    float *fout_final = NULL, *fbuf=NULL, *fin=NULL, *fout=NULL, *fin_next = NULL;
03075    float delta_time, fp, dfp, fpj, minfn=0.0, maxfn=0.0;
03076    int n , k, j, niter, vnk, os;
03077    SUMA_Boolean LocalHead = NOPE;
03078    
03079    SUMA_ENTRY;
03080 
03081    if (N_iter % 2) {
03082       SUMA_SL_Err("N_iter must be an even number\n");
03083       SUMA_RETURN(NULL);
03084    }
03085    
03086    if (!SO || !wgt || !fin_orig) {
03087       SUMA_SL_Err("NULL SO or wgt or fin_orig\n");
03088       SUMA_RETURN(NULL);
03089    }
03090    if (!SO->FN) {
03091       SUMA_SL_Err("NULL SO->FN\n");
03092       SUMA_RETURN(NULL);
03093    }
03094    
03095    if (vpn < 1) {
03096       SUMA_SL_Err("vpn < 1\n");
03097       SUMA_RETURN(NULL);
03098    }  
03099    
03100    if (fout_final_user == fin_orig) {
03101       SUMA_SL_Err("fout_final_user == fin_orig");
03102       SUMA_RETURN(NULL);
03103    }
03104    
03105    if (!fout_final_user) { 
03106       fout_final = (float *)SUMA_calloc(SO->N_Node * vpn, sizeof(float));
03107       if (!fout_final) {
03108          SUMA_SL_Crit("Failed to allocate for fout_final\n");
03109          SUMA_RETURN(NULL);
03110       }
03111    }else {
03112       fout_final = fout_final_user; 
03113    }
03114    
03115    
03116    fbuf = (float *)SUMA_calloc(SO->N_Node * vpn, sizeof(float));
03117    if (!fbuf) {
03118       SUMA_SL_Crit("Failed to allocate for fbuf\n");
03119       SUMA_RETURN(NULL);
03120    }
03121    
03122    
03123    if (cs->Send) { 
03124       if (!SUMA_SendToSuma (SO, cs, (void *)fin_orig, SUMA_NODE_RGBAb, 1)) {
03125          SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
03126       }
03127    }
03128    
03129    fin_next = fin_orig;
03130    delta_time= (FWHM * FWHM)/(16*N_iter*log(2));
03131    switch (d_order) {
03132       case SUMA_COLUMN_MAJOR:
03133          for (niter=0; niter < N_iter; ++niter) {
03134             if ( niter % 2 ) { 
03135                fin = fin_next; 
03136                fout = fout_final; 
03137                fin_next = fout_final; 
03138             } else { 
03139                
03140                fin = fin_next;
03141                fout = fbuf; 
03142                fin_next = fbuf; 
03143             }
03144             for (k=0; k < vpn; ++k) {
03145                os = SO->N_Node*k;   
03146                for (n=0; n < SO->N_Node; ++n) {
03147                   vnk = n+os; 
03148                   fp = fin[vnk]; 
03149                   dfp = 0.0;
03150                   if (SO->FN->N_Neighb[n]) minfn = maxfn = fin[SO->FN->FirstNeighb[n][0]+os];
03151                   for (j=0; j < SO->FN->N_Neighb[n]; ++j) {
03152                      fpj = fin[SO->FN->FirstNeighb[n][j]+os]; 
03153                      if (fpj < minfn) minfn = fpj;
03154                      if (fpj > maxfn) maxfn = fpj;
03155                      dfp += wgt[n][j] * (fpj - fp); 
03156                   }
03157                   fout[vnk] = fin[vnk] + delta_time * dfp;
03158                   if (fout[vnk] < minfn) fout[vnk] = minfn;
03159                   if (fout[vnk] > maxfn) fout[vnk] = maxfn;
03160                } 
03161                  
03162                if (cs->Send) {
03163                   if (!SUMA_SendToSuma (SO, cs, (void *)fout, SUMA_NODE_RGBAb, 1)) {
03164                      SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
03165                   }
03166                }
03167             } 
03168          }
03169          break;
03170       case SUMA_ROW_MAJOR:
03171          SUMA_SL_Err("Row Major not implemented");
03172          SUMA_RETURN(NULL);
03173          break;
03174       default:
03175          SUMA_SL_Err("Bad Major, very bad.\n");
03176          SUMA_RETURN(NULL);
03177          break;
03178    }
03179    
03180    if (fbuf) SUMA_free(fbuf); fbuf = NULL;
03181                
03182    SUMA_RETURN(fout);
03183 }
03184 
03185 #ifdef SUMA_SurfSmooth_STAND_ALONE
03186 void usage_SUMA_SurfSmooth ()
03187    {
03188       static char FuncName[]={"usage_SUMA_SurfSmooth"};
03189       char * s = NULL, *st = NULL;
03190       s = SUMA_help_basics();
03191       st = SUMA_help_talk();
03192       printf ("\nUsage:  SurfSmooth <-spec SpecFile> <-surf_A insurf> <-met method> \n"
03193               "\n"
03194               "   Some methods require additional options detailed below.\n"
03195               "   I recommend using the -talk_suma option to watch the \n"
03196               "   progression of the smoothing in real-time in suma.\n"
03197               "\n"
03198               "   Method specific options:\n"
03199               "      LB_FEM: <-input inData.1D> <-fwhm f>\n"
03200               "              This method is used to filter data\n"
03201               "              on the surface.\n"
03202               "      LM: [-kpb k] [-lm l m] [-surf_out surfname]\n"
03203               "          This method is used to filter the surface's\n"
03204               "          geometry (node coordinates).\n"
03205               "      NN_geom: smooth by averaging coordinates of \n"
03206               "               nearest neighbors.\n"
03207               "               This method causes shrinkage of surface\n"
03208               "               and is meant for test purposes only.\n"
03209               "\n"
03210               "   Common options:\n"
03211               "      [-Niter N] [-output out.1D] [-h/-help] \n"
03212               "      [-add_index] [-ni_text|-ni_binary] [-talk_suma]\n\n"
03213               "\n"
03214               "   Detailed usage:\n"
03215               "      -spec SpecFile: Name of specfile containing surface of interest.\n"
03216               "                      If the surface does not have a spec file, use the \n"
03217               "                      program quickspec to create one.\n"
03218               "      -surf_A insurf: Name of surface of interest. \n"
03219               "                      NOTE: i_TYPE inSurf option is now obsolete.\n"
03220               "      -met method: name of smoothing method to use. Choose from:\n"
03221               "                 LB_FEM: The method by Chung et al. 03.\n"
03222               "                         This method is used for filtering \n"
03223               "                         data on the surface not for smoothing the\n"
03224               "                         surface's geometry per se. See References below.\n"
03225               "                 LM: The smoothing method proposed by G. Taubin 2000\n"
03226               "                     This method is used for smoothing\n"
03227               "                     a surface's geometry. See References below.\n"
03228               "                 NN_geom: A simple nearest neighbor coordinate smoothing.\n"
03229               "                          This interpolation method causes surface shrinkage\n"
03230               "                          that might need to be corrected with the -match_*\n"
03231               "                          options below. \n" 
03232               "\n"
03233               "   Options for LB_FEM:\n"
03234               "      -input inData.1D: file containing data (in 1D format)\n"
03235               "                        Each column in inData.1D is processed separately.\n"
03236               "                        The number of rows must equal the number of\n"
03237               "                        nodes in the surface. You can select certain\n"
03238               "                        columns using the [] notation adopted by AFNI's\n"
03239               "                        programs.\n"
03240               "      -fwhm f: Full Width at Half Maximum in surface coordinate units (usuallly mm)\n"
03241               "               of an equivalent Gaussian filter had the surface been flat.\n"
03242               "               With curved surfaces, the equation used to estimate FWHM is \n"
03243               "               an approximation. \n"
03244               "               Blurring on the surface depends on the geodesic instead \n"
03245               "               of the Euclidean disntaces. See Ref #1 for more details \n"
03246               "               on this parameter.\n"
03247               "\n"
03248               "   Options for LM:\n"
03249               "      -kpb k: Band pass frequency (default is 0.1).\n"
03250               "              values should be in the range 0 < k < 10\n"
03251               "              -lm and -kpb options are mutually exclusive.\n"
03252               "      -lm l m: Lambda and Mu parameters. Sample values are:\n"
03253               "               0.6307 and -.6732\n"
03254               "      NOTE: -lm and -kpb options are mutually exclusive.\n"
03255               "      -surf_out surfname: Writes the surface with smoothed coordinates\n"
03256               "                          to disk. For SureFit and 1D formats, only the\n"
03257               "                          coord file is written out.\n"
03258               "      NOTE: -surf_out and -output are mutually exclusive.\n"  
03259               "\n"
03260               "   Options for NN_geom:\n"
03261               "      -match_size r: Adjust node coordinates of smoothed surface to \n"
03262               "                   approximates the original's size.\n"
03263               "                   Node i on the filtered surface is repositioned such \n"
03264               "                   that |c i| = 1/N sum(|cr j|) where\n"
03265               "                   c and cr are the centers of the smoothed and original\n"
03266               "                   surfaces, respectively.\n"
03267               "                   N is the number of nodes that are within r [surface \n"
03268               "                   coordinate units] along the surface (geodesic) from node i.\n"
03269               "                   j is one of the nodes neighboring i.\n"
03270               "      -match_vol tol: Adjust node coordinates of smoothed surface to \n"
03271               "                   approximates the original's volume.\n"
03272               "                   Nodes on the filtered surface are repositioned such\n"
03273               "                   that the volume of the filtered surface equals, \n"
03274               "                   within tolerance tol, that of the original surface. \n"
03275               "                   See option -vol in SurfaceMetrics for information about\n"
03276               "                   and calculation of the volume of a closed surface.\n"
03277               "      -match_area tol: Adjust node coordinates of smoothed surface to \n"
03278               "                   approximates the original's surface.\n"
03279               "                   Nodes on the filtered surface are repositioned such\n"
03280               "                   that the surface of the filtered surface equals, \n"
03281               "                   within tolerance tol, that of the original surface. \n"
03282               "      -match_sphere rad: Project nodes of smoothed surface to a sphere\n"
03283               "                   of radius rad. Projection is carried out along the \n"
03284               "                   direction formed by the surface's center and the node.\n"
03285               "\n"
03286               "   Common options:\n"
03287               "      -Niter N: Number of smoothing iterations (default is 100)\n"
03288               "                For practical reasons, this number must be a multiple of 2\n"
03289               "          NOTE: For LB_FEM method, the number of iterations controls the\n"
03290               "                iteration steps (dt in Ref #1).\n"
03291               "                dt = fwhm*fwhm / (16*Niter*log(2));\n"
03292               "                dt must satisfy conditions that depend on the internodal\n"
03293               "                distance and the spatial derivatives of the signals being \n"
03294               "                filtered on the surface.\n"
03295               "                As a rule of thumb, if increasing Niter does not alter\n"
03296               "                the results then your choice is fine (smoothing has converged).\n"
03297               "                For an example of the artifact caused by small Niter see:\n"
03298               "          http://afni.nimh.nih.gov/sscc/staff/ziad/SUMA/SuSmArt/DSart.html\n"
03299               "      -output out.1D: Name of output file. \n"
03300               "                      The default is inData_sm.1D with LB_FEM method\n"
03301               "                      and NodeList_sm.1D with LM method.\n" 
03302               "      -add_index : Output the node index in the first column.\n"
03303               "                   This is not done by default.\n"
03304               "\n"
03305               "%s"
03306               "\n"
03307               "%s"
03308               "\n"
03309               "   Sample commands lines for data smoothing:\n"
03310               "      SurfSmooth  -spec quick.spec -surf_A NodeList.1D -met LB_FEM   \\\n"
03311               "                  -input in.1D -Niter 100 -fwhm 8 -add_index         \\\n"
03312               "                  -output in_sm8.1D \n"
03313               "         This command filters (on the surface) the data in in.1D\n"
03314               "         and puts the output in in_sm8.1D with the first column \n"
03315               "         containing the node index and the second containing the \n"
03316               "         filtered version of in.1D.\n"
03317               "\n"
03318               "         The surface used in this example had no spec file, so \n"
03319               "         a quick.spec was created using:\n"
03320               "         quickspec -tn 1D NodeList.1D FaceSetList.1D \n"
03321               "\n"
03322               "         You can colorize the input and output data using ScaleToMap:\n"
03323               "         ScaleToMap  -input in.1D 0 1 -cmap BGYR19       \\\n"
03324               "                     -clp MIN MAX > in.1D.col            \\\n"
03325               "         ScaleToMap  -input in_sm8.1D 0 1 -cmap BGYR19   \\\n"
03326               "                     -clp MIN MAX > in_sm8.1D.col        \\\n"
03327               "\n"
03328               "         For help on using ScaleToMap see ScaleToMap -help\n"
03329               "         Note that the MIN MAX represent the minimum and maximum\n"
03330               "         values in in.1D. You should keep them constant in both \n"
03331               "         commands in order to be able to compare the resultant colorfiles.\n"
03332               "         You can import the .col files with the 'c' command in SUMA.\n"
03333               "\n"
03334               "         You can send the data to SUMA with each iteration.\n"
03335               "         To do so, start SUMA with these options:\n"
03336               "         suma -spec quick.spec -niml &\n"
03337               "         and add these options to SurfSmooth's command line above:\n"
03338               "         -talk_suma -refresh_rate 5\n" 
03339               "\n"
03340               "   Sample commands lines for surface smoothing:\n"
03341               "      SurfSmooth  -spec quick.spec -surf_A NodeList.1D -met LM    \\\n"
03342               "                  -output NodeList_sm100.1D -Niter 100 -kpb 0.1   \n"
03343               "         This command smoothes the surface's geometry. The smoothed\n"
03344               "         node coordinates are written out to NodeList_sm100.1D. \n"
03345               "\n"
03346               "   Sample command for considerable surface smoothing and inflation\n"
03347               "   back to original volume:\n"
03348               "       SurfSmooth  -spec quick.spec -surf_A NodeList.1D -met NN_geom \\\n"
03349               "                   -output NodeList_inflated_mvol.1D -Niter 1500 \\\n"
03350               "                   -match_vol 0.01\n" 
03351               "   Sample command for considerable surface smoothing and inflation\n"
03352               "   back to original area:\n"
03353               "       SurfSmooth  -spec quick.spec -surf_A NodeList.1D -met NN_geom \\\n"
03354               "                   -output NodeList_inflated_marea.1D -Niter 1500 \\\n"
03355               "                   -match_area 0.01\n" 
03356               "\n"
03357               "   References: \n"
03358               "      (1) M.K. Chung et al.   Deformation-based surface morphometry\n"
03359               "                              applied to gray matter deformation. \n"
03360               "                              Neuroimage 18 (2003) 198-213\n"
03361               "          M.K. Chung   Statistical morphometry in computational\n"
03362               "                       neuroanatomy. Ph.D. thesis, McGill Univ.,\n"
03363               "                       Montreal, Canada\n"
03364               "      (2) G. Taubin.       Mesh Signal Processing. \n"
03365               "                           Eurographics 2000.\n"
03366               "\n"
03367               "   See Also:   \n"
03368               "       ScaleToMap to colorize the output, however it is better\n"
03369               "       to load surface datasets directly into SUMA and colorize\n"
03370               "       them interactively."
03371               "\n"
03372               "\n", st, s); SUMA_free(s); s = NULL; SUMA_free(st); st = NULL;
03373        s = SUMA_New_Additions(0, 1); printf("%s\n", s);SUMA_free(s); s = NULL;
03374        printf("       Ziad S. Saad SSCC/NIMH/NIH ziad@nih.gov     \n");
03375        exit (0);
03376    }
03377 
03378 
03379 #define SURFSMOOTH_MAX_SURF 1  
03380 
03381 typedef enum { SUMA_NO_METH, SUMA_LB_FEM, SUMA_LM, SUMA_BRUTE_FORCE, SUMA_NN_GEOM} SUMA_SMOOTHING_METHODS;
03382 
03383 typedef struct {
03384    float OffsetLim;
03385    float lim;
03386    float fwhm;
03387    float kpb;
03388    float l;
03389    float m;
03390    int ShowNode;
03391    int Method;
03392    int dbg;
03393    int N_iter;
03394    int AddIndex;
03395    int insurf_method; 
03396 
03397 
03398 
03399    SUMA_SO_File_Type iType;
03400    char *vp_name;
03401    char *sv_name;
03402    char *if_name;
03403    char *if_name2;
03404    char *in_name;
03405    char *out_name;   
03406    char *ShowOffset_DBG;
03407    char *surf_out;
03408    char *surf_names[SURFSMOOTH_MAX_SURF];
03409    char *spec_file;
03410    int MatchMethod;
03411 } SUMA_SURFSMOOTH_OPTIONS;
03412 
03413 
03414 
03415 
03416 
03417 
03418 
03419 
03420 
03421 
03422 
03423 SUMA_SURFSMOOTH_OPTIONS *SUMA_SurfSmooth_ParseInput (char *argv[], int argc, SUMA_GENERIC_ARGV_PARSE *ps)
03424 {
03425    static char FuncName[]={"SUMA_SurfSmooth_ParseInput"}; 
03426    SUMA_SURFSMOOTH_OPTIONS *Opt=NULL;
03427    int kar, i, ind;
03428    char *outname;
03429    SUMA_Boolean brk = NOPE;
03430    SUMA_Boolean LocalHead = NOPE;
03431 
03432    SUMA_ENTRY;
03433    
03434    Opt = (SUMA_SURFSMOOTH_OPTIONS *)SUMA_malloc(sizeof(SUMA_SURFSMOOTH_OPTIONS));
03435    
03436    kar = 1;
03437    Opt->OffsetLim = 10.0;
03438    Opt->MatchMethod = 0;
03439    Opt->lim = 1000000.0;
03440    Opt->fwhm = -1;
03441    Opt->ShowNode = -1;
03442    Opt->Method = SUMA_NO_METH;
03443    Opt->dbg = 0;
03444    Opt->if_name = NULL;
03445    Opt->if_name2 = NULL;
03446    Opt->in_name = NULL;
03447    Opt->out_name = NULL;
03448    Opt->vp_name = NULL; 
03449    Opt->sv_name = NULL;
03450    Opt->surf_out = NULL;
03451    Opt->ShowOffset_DBG = NULL;
03452    Opt->iType = SUMA_FT_NOT_SPECIFIED;
03453    Opt->N_iter = 100;
03454    Opt->kpb = -1.0;
03455    Opt->l = -1.0;
03456    Opt->m = -1.0;
03457    Opt->AddIndex = 0;
03458    Opt->insurf_method = 0;
03459    Opt->spec_file = NULL;
03460    for (i=0; i<SURFSMOOTH_MAX_SURF; ++i) { Opt->surf_names[i] = NULL; }
03461    outname = NULL;
03462         brk = NOPE;
03463         while (kar < argc) { 
03464                 
03465                 if (strcmp(argv[kar], "-h") == 0 || strcmp(argv[kar], "-help") == 0) {
03466                          usage_SUMA_SurfSmooth();
03467           exit (0);
03468                 }
03469                 
03470                 SUMA_SKIP_COMMON_OPTIONS(brk, kar);
03471 
03472       #if 0 
03473       if (!brk && strcmp(argv[kar], "-ni_text") == 0)
03474                 {
03475          SUMA_GEOMCOMP_NI_MODE = NI_TEXT_MODE;
03476          brk = YUP;
03477       }
03478       
03479       if (!brk && strcmp(argv[kar], "-ni_binary") == 0)
03480                 {
03481          SUMA_GEOMCOMP_NI_MODE = NI_BINARY_MODE;
03482          brk = YUP;
03483       }
03484       
03485                 if (!brk && strcmp(argv[kar], "-sh") == 0)
03486                 {
03487                         kar ++;
03488                         if (kar >= argc)  {
03489                                 fprintf (SUMA_STDERR, "need argument after -sh \n");
03490                                 exit (1);
03491                         }
03492                         if (strcmp(argv[kar],"localhost") != 0) {
03493             Opt->suma_host_name = SUMA_copy_string(argv[kar]);
03494          }else {
03495            fprintf (SUMA_STDERR, "localhost is the default for -sh\nNo need to specify it.\n");
03496          }
03497 
03498                         brk = YUP;
03499                 }       
03500       if (!brk && strcmp(argv[kar], "-refresh_rate") == 0)
03501                 {
03502                         kar ++;
03503                         if (kar >= argc)  {
03504                                 fprintf (SUMA_STDERR, "need argument after -refresh_rate \n");
03505                                 exit (1);
03506                         }
03507                         Opt->rps = atof(argv[kar]);
03508          if (Opt->rps <= 0) {
03509             fprintf (SUMA_STDERR, "Bad value (%f) for refresh_rate\n", Opt->rps);
03510                                 exit (1);
03511          }
03512 
03513                         brk = YUP;
03514                 }
03515       
03516       if (!brk && (strcmp(argv[kar], "-talk_suma") == 0)) {
03517                         Opt->talk_suma = 1; 
03518                         brk = YUP;
03519                 }
03520       
03521       #endif
03522       if (!brk && strcmp(argv[kar], "-dist") == 0)
03523                 {
03524                         kar ++;
03525                         if (kar >= argc)  {
03526                                 fprintf (SUMA_STDERR, "need argument after -dist \n");
03527                                 exit (1);
03528                         }
03529                         Opt->OffsetLim = atof(argv[kar]);
03530          if (Opt->OffsetLim <= 0) {
03531             fprintf (SUMA_STDERR, "Bad value (%f) for refresh_rate\n", Opt->OffsetLim);
03532                                 exit (1);
03533          }
03534 
03535                         brk = YUP;
03536                 }
03537      
03538       if (!brk && (strcmp(argv[kar], "-dbg_n") == 0)) {
03539          kar ++;
03540                         if (kar+1 >= argc)  {
03541                                 fprintf (SUMA_STDERR, "need 2 arguments after -dbg_n \n");
03542                                 exit (1);
03543                         }
03544                         Opt->ShowNode = atoi(argv[kar]); kar ++;
03545          Opt->ShowOffset_DBG = argv[kar];
03546                         brk = YUP;
03547                 }
03548       
03549       if (!brk && (strcmp(argv[kar], "-Niter") == 0)) {
03550          kar ++;
03551                         if (kar >= argc)  {
03552                                 fprintf (SUMA_STDERR, "need 1 arguments after -Niter \n");
03553                                 exit (1);
03554                         }
03555                         Opt->N_iter = atoi(argv[kar]);
03556                         brk = YUP;
03557                 }
03558       
03559       if (!brk && (strcmp(argv[kar], "-kpb") == 0)) {
03560          kar ++;
03561                         if (kar >= argc)  {
03562                                 fprintf (SUMA_STDERR, "need 1 arguments after -kpb \n");
03563                                 exit (1);
03564                         }
03565          if (Opt->l != -1.0  || Opt->m != -1.0) {
03566             fprintf (SUMA_STDERR, "options -lm and -kpb are mutually exclusive\n");
03567                                 exit (1);
03568          }
03569                         Opt->kpb = atof(argv[kar]); 
03570                         brk = YUP;
03571                 }
03572       
03573       if (!brk && (strcmp(argv[kar], "-surf_out") == 0)) {
03574          kar ++;
03575                         if (kar >= argc)  {
03576                                 fprintf (SUMA_STDERR, "need 1 arguments after -surf_out\n");
03577                                 exit (1);
03578                         }
03579          if (outname) {
03580             fprintf (SUMA_STDERR, "-output and -surf_out are mutually exclusive.\n");
03581             exit(1);
03582          }
03583                         Opt->surf_out = argv[kar]; 
03584                         brk = YUP;
03585                 }
03586       
03587       if (!brk && (strcmp(argv[kar], "-lm") == 0)) {
03588          kar ++;
03589                         if (kar+1 >= argc)  {
03590                                 fprintf (SUMA_STDERR, "need 2 arguments after -lm \n");
03591                                 exit (1);
03592                         }
03593          if (Opt->kpb != -1.0) {
03594             fprintf (SUMA_STDERR, "options -lm and -kpb are mutually exclusive\n");
03595                                 exit (1);
03596          }
03597                         Opt->l = atof(argv[kar]); kar ++;
03598          Opt->m = atof(argv[kar]);  
03599                         brk = YUP;
03600                 }
03601       
03602       if (!brk && (strcmp(argv[kar], "-input") == 0)) {
03603          kar ++;
03604                         if (kar >= argc)  {
03605                                 fprintf (SUMA_STDERR, "need argument after -input \n");
03606                                 exit (1);
03607                         }
03608                         Opt->in_name = argv[kar];
03609                         brk = YUP;
03610                 }
03611       
03612       if (!brk && (strcmp(argv[kar], "-output") == 0)) {
03613          kar ++;
03614                         if (kar >= argc)  {
03615                                 fprintf (SUMA_STDERR, "need argument after -output\n");
03616                                 exit (1);
03617                         }
03618                         if (Opt->surf_out) {
03619             fprintf (SUMA_STDERR, "options -surf_out and -output are mutually exclusive\n");
03620                                 exit (1);
03621          }
03622          outname = argv[kar];
03623                         brk = YUP;
03624                 }
03625       
03626       if (!brk && (strcmp(argv[kar], "-add_index") == 0)) {
03627                         Opt->AddIndex = 1;
03628                         brk = YUP;
03629                 }
03630       
03631       if (!brk && (strcmp(argv[kar], "-i_fs") == 0)) {
03632          SUMA_SL_Err("Option -i_fs is obsolete.\nUse -spec and -surf_A instead.\n");
03633          exit(1);
03634          kar ++;
03635                         if (kar >= argc)  {
03636                                 fprintf (SUMA_STDERR, "need argument after -i_fs \n");
03637                                 exit (1);
03638                         }
03639                         Opt->if_name = argv[kar];
03640          Opt->iType = SUMA_FREE_SURFER;
03641          if (!Opt->insurf_method) Opt->insurf_method = 1;
03642          else {
03643             fprintf (SUMA_STDERR, "already specified input surface.\n");
03644             exit(1);
03645          }
03646                         brk = YUP;
03647                 }
03648       
03649       if (!brk && (strcmp(argv[kar], "-i_sf") == 0)) {
03650          SUMA_SL_Err("Option -i_sf is obsolete.\nUse -spec and -surf_A instead.\n");
03651          exit(1);
03652          kar ++;
03653                         if (kar+1 >= argc)  {
03654                                 fprintf (SUMA_STDERR, "need 2 argument after -i_sf\n");
03655                                 exit (1);
03656                         }
03657                         Opt->if_name = argv[kar]; kar ++;
03658          Opt->if_name2 = argv[kar];
03659          Opt->iType = SUMA_SUREFIT;
03660          if (!Opt->insurf_method) Opt->insurf_method = 1;
03661          else {
03662             fprintf (SUMA_STDERR, "already specified input surface.\n");
03663             exit(1);
03664          }
03665                         brk = YUP;
03666                 }
03667       
03668       if (!brk && (strcmp(argv[kar], "-i_vec") == 0)) {
03669          SUMA_SL_Err("Option -i_vec is obsolete.\nUse -spec and -surf_A instead.\n");
03670          exit(1);
03671          kar ++;
03672                         if (kar+1 >= argc)  {
03673                                 fprintf (SUMA_STDERR, "need 2 argument after -i_vec\n");
03674                                 exit (1);
03675                         }
03676                         Opt->if_name = argv[kar]; kar ++;
03677          Opt->if_name2 = argv[kar];
03678          Opt->iType = SUMA_VEC;
03679          if (!Opt->insurf_method) Opt->insurf_method = 1;
03680          else {
03681             fprintf (SUMA_STDERR, "already specified input surface.\n");
03682             exit(1);
03683          }
03684                         brk = YUP;
03685                 }
03686       
03687       if (!brk && (strcmp(argv[kar], "-i_dx") == 0)) {
03688          SUMA_SL_Err("Option -i_ply is obsolete.\nUse -spec and -surf_A instead.\n");
03689          exit(1);
03690          kar ++;
03691                         if (kar >= argc)  {
03692                                 fprintf (SUMA_STDERR, "need argument after -i_dx\n ");
03693                                 exit (1);
03694                         }
03695                         Opt->if_name = argv[kar];
03696          Opt->iType = SUMA_OPENDX_MESH;
03697          if (!Opt->insurf_method) Opt->insurf_method = 1;
03698          else {
03699             fprintf (SUMA_STDERR, "already specified input surface.\n");
03700             exit(1);
03701          }
03702                         brk = YUP;
03703                 }
03704       
03705       if (!brk && (strcmp(argv[kar], "-i_ply") == 0)) {
03706          SUMA_SL_Err("Option -i_ply is obsolete.\nUse -spec and -surf_A instead.\n");
03707          exit(1);
03708          kar ++;
03709                         if (kar >= argc)  {
03710                                 fprintf (SUMA_STDERR, "need argument after -i_ply\n ");
03711                                 exit (1);
03712                         }
03713                         Opt->if_name = argv[kar];
03714          Opt->iType = SUMA_PLY;
03715          if (!Opt->insurf_method) Opt->insurf_method = 1;
03716          else {
03717             fprintf (SUMA_STDERR, "already specified input surface.\n");
03718             exit(1);
03719          }
03720                         brk = YUP;
03721                 }
03722       
03723       if (!brk && (strcmp(argv[kar], "-spec") == 0)) {
03724          kar ++;
03725                         if (kar >= argc)  {
03726                                 fprintf (SUMA_STDERR, "need argument after -spec \n");
03727                                 exit (1);
03728                         }
03729                         Opt->spec_file = argv[kar];
03730          if (!Opt->insurf_method) Opt->insurf_method = 2;
03731          else {
03732             fprintf (SUMA_STDERR, "already specified spec file.\n");
03733             exit(1);
03734          }
03735                         brk = YUP;
03736                 }
03737       
03738       if (!brk && (strncmp(argv[kar], "-surf_", 6) == 0)) {
03739                         if (kar + 1>= argc)  {
03740                                 fprintf (SUMA_STDERR, "need argument after -surf_X SURF_NAME \n");
03741                                 exit (1);
03742                         }
03743                         ind = argv[kar][6] - 'A';
03744          if (ind < 0 || ind >= SURFSMOOTH_MAX_SURF) {
03745             fprintf (SUMA_STDERR, "-surf_X SURF_NAME option is out of range,\n"
03746                                   "   only surf_A allowed.\n");
03747                                 exit (1);
03748          }
03749          kar ++;
03750          Opt->surf_names[ind] = argv[kar];
03751                         if (Opt->insurf_method && Opt->insurf_method != 2) {
03752             fprintf (SUMA_STDERR, "-surf_X SURF_NAME option must be used with -spec option.\n");
03753             exit(1);
03754          }
03755          brk = YUP;
03756                 }
03757       
03758       
03759       if (!brk && (strcmp(argv[kar], "-lim") == 0)) {
03760          kar ++;
03761                         if (kar >= argc)  {
03762                                 fprintf (SUMA_STDERR, "need argument after -lim \n");
03763                                 exit (1);
03764                         }
03765                         Opt->lim = atof(argv[kar]);
03766                         brk = YUP;
03767                 }
03768       
03769       if (!brk && (strcmp(argv[kar], "-match_size") == 0)) {
03770          kar ++;
03771                         if (kar >= argc)  {
03772                                 fprintf (SUMA_STDERR, "need argument after -match_size \n");
03773                                 exit (1);
03774                         }
03775                         Opt->lim = atof(argv[kar]);
03776          Opt->MatchMethod = 1;
03777                         brk = YUP;
03778                 }
03779       
03780       if (!brk && (strcmp(argv[kar], "-match_vol") == 0)) {
03781          kar ++;
03782                         if (kar >= argc)  {
03783                                 fprintf (SUMA_STDERR, "need argument after -match_vol \n");
03784                                 exit (1);
03785                         }
03786                         Opt->lim = atof(argv[kar]);
03787          Opt->MatchMethod = 2;
03788                         brk = YUP;
03789                 }
03790       
03791       if (!brk && (strcmp(argv[kar], "-match_area") == 0)) {
03792          kar ++;
03793                         if (kar >= argc)  {
03794                                 fprintf (SUMA_STDERR, "need argument after -match_area \n");
03795                                 exit (1);
03796                         }
03797                         Opt->lim = atof(argv[kar]);
03798          Opt->MatchMethod = 3;
03799                         brk = YUP;
03800                 }
03801       
03802       if (!brk && (strcmp(argv[kar], "-match_sphere") == 0)) {
03803          kar ++;
03804                         if (kar >= argc)  {
03805                                 fprintf (SUMA_STDERR, "need argument after -match_sphere \n");
03806                                 exit (1);
03807                         }
03808                         Opt->lim = atof(argv[kar]);
03809          Opt->MatchMethod = 4;
03810                         brk = YUP;
03811                 }
03812       
03813       if (!brk && (strcmp(argv[kar], "-fwhm") == 0)) {
03814          kar ++;
03815                         if (kar >= argc)  {
03816                                 fprintf (SUMA_STDERR, "need argument after -fwhm \n");
03817                                 exit (1);
03818                         }
03819                         Opt->fwhm = atof(argv[kar]);
03820                         brk = YUP;
03821                 }
03822       
03823       if (!brk && (strcmp(argv[kar], "-met") == 0)) {
03824          kar ++;
03825                         if (kar >= argc)  {
03826                                 fprintf (SUMA_STDERR, "need argument after -met \n");
03827                                 exit (1);
03828                         }
03829                         if (strcmp(argv[kar], "LB_FEM") == 0)  Opt->Method = SUMA_LB_FEM;
03830          else if (strcmp(argv[kar], "LM") == 0)  Opt->Method = SUMA_LM;
03831          else if (strcmp(argv[kar], "BF") == 0)  Opt->Method = SUMA_BRUTE_FORCE;
03832          else if (strcmp(argv[kar], "NN_geom") == 0)  Opt->Method = SUMA_NN_GEOM;
03833          else {
03834             fprintf (SUMA_STDERR, "Method %s not supported.\n", argv[kar]);
03835                                 exit (1);
03836          }
03837                         brk = YUP;
03838                 }
03839       
03840       if (!brk && !ps->arg_checked[kar]) {
03841                         fprintf (SUMA_STDERR,"Error %s:\nOption %s not understood. Try -help for usage\n", FuncName, argv[kar]);
03842                         exit (1);
03843                 } else {        
03844                         brk = NOPE;
03845                         kar ++;
03846                 }
03847    }
03848 
03849    if (Opt->N_iter < 1) {
03850       fprintf (SUMA_STDERR,"Error %s:\nWith -Niter N option, N must be > 1\n", FuncName);
03851       exit (1);
03852    }
03853    
03854    if ( (Opt->N_iter % 2) &&
03855         (Opt->Method == SUMA_LB_FEM || Opt->Method == SUMA_LM) ) {
03856       fprintf (SUMA_STDERR, "Number of iterations must be a multiple of 2.\n%d is not a multiple of 2.\n", Opt->N_iter);
03857       exit(1);
03858    }
03859    
03860    if (Opt->ShowNode < 0 && Opt->ShowOffset_DBG) {
03861       fprintf (SUMA_STDERR,"Error %s:\nBad debug node index (%d) in option -dbg_n\n", FuncName, Opt->ShowNode);
03862       exit (1);
03863    }
03864    
03865    if (Opt->insurf_method == 1) {
03866       SUMA_SL_Err("Obsolete method for surface specification.\nShould not have gotten here.");
03867       exit(1);
03868    }
03869       
03870    
03871    if (0 && Opt->in_name && !SUMA_filexists(Opt->in_name)) {
03872       fprintf (SUMA_STDERR,"Error %s:\n%s not found.\n", FuncName, Opt->if_name);
03873       exit(1);
03874    }
03875    
03876    if (Opt->Method == SUMA_NO_METH) {
03877       fprintf (SUMA_STDERR,"Error %s:\nNo method was specified.\n", FuncName);
03878       exit(1);  
03879    }
03880    
03881    if (ps->cs->talk_suma && Opt->insurf_method != 2) {
03882       fprintf (SUMA_STDERR,   "must specify surface using -spec option\n"
03883                               "if you whish to talk to suma.\n");
03884       exit(1); 
03885    }
03886    
03887    if (0 && ps->cs->talk_suma && Opt->Method != SUMA_LB_FEM) {
03888       fprintf (SUMA_STDERR,   "talk option only valid with -LB_FEM\n");
03889       exit(1); 
03890    }
03891    
03892    if (Opt->insurf_method == 2) {
03893       if (!Opt->surf_names[0] || !Opt->spec_file) {
03894          fprintf (SUMA_STDERR,   "failed to specify either -spec or -surf_X options.\n");
03895          exit(1);  
03896       }
03897    }
03898     
03899    if (outname) {
03900       if (SUMA_filexists(outname)) {
03901          fprintf (SUMA_STDERR,"Error %s:\noutput file %s exists.\n", FuncName, outname);
03902          exit(1);
03903       }
03904       Opt->out_name = SUMA_copy_string(outname);
03905    } else {
03906       switch (Opt->Method) {
03907          case SUMA_LB_FEM:
03908             
03909             Opt->out_name = SUMA_Extension(Opt->in_name, ".1D", YUP); 
03910             Opt->out_name = SUMA_append_replace_string(Opt->out_name,"_sm", "", 1); 
03911             Opt->out_name = SUMA_append_replace_string(Opt->out_name,".1D", "", 1); 
03912             break;
03913          case SUMA_LM:
03914             
03915             Opt->out_name = SUMA_copy_string("NodeList_sm.1D");
03916             break;
03917          case SUMA_BRUTE_FORCE:
03918             
03919             Opt->out_name = SUMA_copy_string("NodeList_Offsetsm.1D");
03920             break;
03921          case SUMA_NN_GEOM:
03922             
03923             Opt->out_name = SUMA_copy_string("NodeList_NNsm.1D");
03924             break;
03925          default:
03926             fprintf (SUMA_STDERR,"Error %s:\nNot ready for this option here.\n", FuncName);
03927             exit(1);
03928             break;
03929       }
03930       if (SUMA_filexists(Opt->out_name)) {
03931          fprintf (SUMA_STDERR,"Error %s:\noutput file %s exists.\n", FuncName, Opt->out_name);
03932          exit(1);
03933       }
03934    }
03935 
03936    
03937    switch (Opt->Method) {
03938       case SUMA_LB_FEM:
03939          if (!Opt->in_name) {
03940             fprintf (SUMA_STDERR,"Error %s:\ninput data not specified.\n", FuncName);
03941             exit(1);
03942          }
03943          if (Opt->fwhm ==  -1.0) {
03944             fprintf (SUMA_STDERR,"Error %s:\n-fwhm option must be used with -met LB_FEM.\n", FuncName); 
03945             exit(1);
03946          }else if (Opt->fwhm <= 0.0) {
03947             fprintf (SUMA_STDERR,"Error %s:\nFWHM must be > 0\n", FuncName);
03948             exit(1);
03949          }
03950          if (Opt->kpb >= 0) {
03951             fprintf (SUMA_STDERR,"Error %s:\n-kpb option is not valid with -met LB_FEM.\n", FuncName); 
03952             exit(1);
03953          }         
03954          
03955          break;
03956       case SUMA_BRUTE_FORCE:
03957          
03958          break;
03959       case SUMA_LM:
03960          
03961          if ( (Opt->l != -1.0 || Opt->m != -1.0) && Opt->kpb != -1.0) {
03962             fprintf (SUMA_STDERR,"Error %s:\nYou cannot mix options -kpb and -lm \n", FuncName);
03963             exit(1);
03964          }
03965          if (Opt->kpb != -1.0 && (Opt->kpb < 0.000001 || Opt->kpb > 10)) {
03966             fprintf (SUMA_STDERR,"Error %s:\nWith -kpb k option, you should satisfy 0 < k < 10\n", FuncName);
03967             exit(1);
03968          }
03969          if (Opt->l == -1.0 && Opt->m == -1.0 && Opt->kpb == -1.0) {
03970             Opt->kpb = 0.1;
03971          }
03972 
03973          if (Opt->l == -1.0 || Opt->m == -1.0) { 
03974             if (!SUMA_Taubin_Smooth_Coef (Opt->kpb, &(Opt->l), &(Opt->m))) {
03975                SUMA_SL_Err("Failed to find smoothing coefficients");
03976                exit(1);            
03977             }
03978          } 
03979 
03980          if (Opt->in_name) {
03981             fprintf (SUMA_STDERR,"Error %s:\nOption -input not valid with -met LM.\n", FuncName);
03982             exit(1);
03983          }
03984          
03985          if (Opt->fwhm !=  -1.0) {
03986             fprintf (SUMA_STDERR,"Error %s:\nOption -fwhm not valid with -met LM.\n", FuncName);
03987             exit(1);
03988          }
03989          
03990          break;
03991       case SUMA_NN_GEOM:
03992          if (Opt->in_name) {
03993             fprintf (SUMA_STDERR,"Error %s:\nOption -input not valid with -met NN_geom.\n", FuncName);
03994             exit(1);
03995          }
03996          
03997          if (0 && Opt->lim > 1000) {
03998             fprintf (SUMA_STDERR,"Error %s:\n-lim option not specified.\n", FuncName);
03999             exit(1);
04000          }
04001          
04002          if (Opt->fwhm !=  -1.0) {
04003             fprintf (SUMA_STDERR,"Error %s:\nOption -fwhm not valid with -met NN_geom.\n", FuncName);
04004             exit(1);
04005          }
04006          break;
04007          
04008       default:
04009          fprintf (SUMA_STDERR,"Error %s:\nNot ready for this option here.\n", FuncName);
04010          exit(1);
04011          break;
04012    }
04013    
04014    SUMA_RETURN (Opt);
04015 }
04016 
04017 int main (int argc,char *argv[])
04018 {    
04019    static char FuncName[]={"SurfSmooth"}; 
04020         int kar, icol, nvec, ncol=0, i, ii;
04021    float *data_old = NULL, *far = NULL;
04022    float **DistFirstNeighb;
04023    void *SO_name = NULL;
04024    SUMA_SurfaceObject *SO = NULL, *SOnew = NULL;
04025    MRI_IMAGE *im = NULL;
04026    SUMA_SFname *SF_name = NULL;
04027    struct  timeval start_time, start_time_all;
04028    float etime_GetOffset, etime_GetOffset_all;   
04029    SUMA_GET_OFFSET_STRUCT *OffS = NULL;
04030    SUMA_SURFSMOOTH_OPTIONS *Opt;  
04031    FILE *fileout=NULL; 
04032    float **wgt=NULL, *dsmooth=NULL;
04033    SUMA_INDEXING_ORDER d_order=SUMA_NO_ORDER;
04034    SUMA_COMM_STRUCT *cs = NULL;
04035         SUMA_SurfSpecFile Spec; 
04036    SUMA_GENERIC_ARGV_PARSE *ps=NULL;
04037    SUMA_Boolean LocalHead = NOPE;
04038    
04039         SUMA_mainENTRY;
04040    SUMA_STANDALONE_INIT;
04041    
04042    
04043         
04044         SUMAg_DOv = SUMA_Alloc_DisplayObject_Struct (SUMA_MAX_DISPLAYABLE_OBJECTS);
04045    ps = SUMA_Parse_IO_Args(argc, argv, "-o;-i;-sv;-talk;");
04046    
04047    if (argc < 6)
04048        {
04049           usage_SUMA_SurfSmooth();
04050           exit (1);
04051        }
04052    
04053    Opt = SUMA_SurfSmooth_ParseInput (argv, argc, ps);
04054    cs = ps->cs;
04055    if (!cs) exit(1);
04056    
04057    
04058    if (Opt->insurf_method == 1) { 
04059       SUMA_SL_Err("Input in this method is no longer supported.\n");
04060       exit(1);
04061    } else { 
04062       int SO_read = -1;
04063       
04064       if (!SUMA_Read_SpecFile (Opt->spec_file, &Spec)) {
04065                         fprintf(SUMA_STDERR,"Error %s: Error in SUMA_Read_SpecFile\n", FuncName);
04066                         exit(1);
04067                 }
04068       SO_read = SUMA_spec_select_surfs(&Spec, Opt->surf_names, SURFSMOOTH_MAX_SURF, 0);
04069       if ( SO_read != 1 )
04070       {
04071               fprintf(SUMA_STDERR,"Error %s: Found %d surfaces, expected only 1.\n", FuncName,  SO_read);
04072          exit(1);
04073       }
04074       
04075       if (!SUMA_LoadSpec_eng(&Spec, SUMAg_DOv, &SUMAg_N_DOv, Opt->sv_name, 0, SUMAg_CF->DsetList) ) {
04076               fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_LoadSpec_eng\n", FuncName);
04077          exit(1);
04078       }
04079       
04080       SO = SUMA_find_named_SOp_inDOv(Opt->surf_names[0], SUMAg_DOv, SUMAg_N_DOv);
04081    }
04082    
04083    if (!SO) {
04084       fprintf (SUMA_STDERR,"Error %s: Failed to read input surface.\n", FuncName);
04085       exit (1);
04086    }
04087 
04088    if (Opt->ShowNode >= 0 && Opt->ShowNode >= SO->N_Node) {
04089       fprintf (SUMA_STDERR,"Error %s: Requesting debugging info for a node index (%d) \n"
04090                            "that does not exist in a surface of %d nodes.\nRemember, indexing starts at 0.\n", 
04091                            FuncName, Opt->ShowNode, SO->N_Node);
04092       exit (1);
04093    }
04094    
04095       
04096    
04097    if (!SO->EL || !SO->FN) {
04098       
04099 
04100       SUMA_SLP_Err("Unexpexted NULL SO->EL or SO->FN");
04101       exit(1); 
04102    }
04103 
04104    
04105    
04106    if (ps->cs->talk_suma) {
04107       cs->istream = SUMA_GEOMCOMP_LINE;
04108       
04109       if (Opt->Method == SUMA_LB_FEM) { 
04110          if (!SUMA_SendToSuma (SO, cs, NULL, SUMA_NO_DSET_TYPE, 0)) {
04111             SUMA_SL_Err("Failed to initialize SUMA_SendToSuma");
04112             cs->Send = NOPE;
04113             ps->cs->talk_suma = NOPE;
04114          }
04115       }else if (Opt->Method == SUMA_LM) { 
04116          if (!SUMA_SendToSuma (SO, cs, NULL, SUMA_NO_DSET_TYPE, 0)) {
04117             SUMA_SL_Err("Failed to initialize SUMA_SendToSuma");
04118             cs->Send = NOPE;
04119             ps->cs->talk_suma = NOPE;
04120          }
04121       }else if (Opt->Method == SUMA_NN_GEOM) { 
04122          if (!SUMA_SendToSuma (SO, cs, NULL, SUMA_NO_DSET_TYPE, 0)) {
04123             SUMA_SL_Err("Failed to initialize SUMA_SendToSuma");
04124             cs->Send = NOPE;
04125             ps->cs->talk_suma = NOPE;
04126          }
04127       }else if (Opt->Method == SUMA_BRUTE_FORCE) { 
04128          if (!SUMA_SendToSuma (SO, cs, NULL, SUMA_NO_DSET_TYPE, 0)) {
04129             SUMA_SL_Err("Failed to initialize SUMA_SendToSuma");
04130             cs->Send = NOPE;
04131             ps->cs->talk_suma = NOPE;
04132          }
04133       }else {
04134          SUMA_SL_Err("Can't talk to suma with the chosen method.\n");
04135          ps->cs->talk_suma = NOPE;
04136       }
04137    }
04138   
04139    ncol = 3; 
04140    switch (Opt->Method) {
04141       case SUMA_LB_FEM: 
04142          
04143          {
04144             
04145             im = mri_read_1D (Opt->in_name);
04146 
04147             if (!im) {
04148                SUMA_SL_Err("Failed to read 1D file");
04149                exit(1);
04150             }
04151 
04152             far = MRI_FLOAT_PTR(im);
04153             nvec = im->nx;
04154             ncol = im->ny;
04155             d_order = SUMA_COLUMN_MAJOR;
04156             
04157             if (!nvec) {
04158                SUMA_SL_Err("Empty file");
04159                exit(1);
04160             }
04161             if (nvec != SO->N_Node) {
04162                fprintf(SUMA_STDERR, "Error %s:\n"
04163                                     "Expecting 1D file to have %d rows\n"
04164                                     "                    found %d rows instead.\n",
04165                                      FuncName, SO->N_Node, nvec);
04166                exit(1); 
04167             }
04168             if (LocalHead) SUMA_etime(&start_time,0);
04169             wgt = SUMA_Chung_Smooth_Weights(SO);
04170             if (!wgt) {
04171                SUMA_SL_Err("Failed to compute weights.\n");
04172                exit(1);
04173             }
04174             
04175             if (LocalHead) {
04176                etime_GetOffset = SUMA_etime(&start_time,1);
04177                fprintf(SUMA_STDERR, "%s: weight computation took %f seconds for %d nodes.\n"
04178                                  "Projected time per 100000 nodes is: %f minutes\n", 
04179                                        FuncName, etime_GetOffset, SO->N_Node, 
04180                                        etime_GetOffset * 100000 / 60.0 / (SO->N_Node));
04181             }
04182             
04183             
04184             dsmooth = SUMA_Chung_Smooth (SO, wgt, Opt->N_iter, Opt->fwhm, far, ncol, SUMA_COLUMN_MAJOR, NULL, cs);
04185             
04186             if (LocalHead) {
04187                etime_GetOffset = SUMA_etime(&start_time,1);
04188                fprintf(SUMA_STDERR, "%s: Total processing took %f seconds for %d nodes.\n"
04189                                  "Projected time per 100000 nodes is: %f minutes\n", 
04190                                        FuncName, etime_GetOffset, SO->N_Node, 
04191                                        etime_GetOffset * 100000 / 60.0 / (SO->N_Node));
04192             }
04193             
04194             #if 0
04195             
04196             fileout = fopen(Opt->out_name, "w");
04197             if (Opt->AddIndex) SUMA_disp_vecmat (dsmooth, SO->N_Node, ncol, 1, d_order, fileout, YUP);
04198             else SUMA_disp_vecmat (dsmooth, SO->N_Node, ncol, 1, d_order, fileout, NOPE);
04199             fclose(fileout); fileout = NULL;
04200 
04201             if (dsmooth) SUMA_free(dsmooth); dsmooth = NULL;
04202             #endif
04203             if (wgt) SUMA_free2D ((char **)wgt, SO->N_Node); wgt = NULL;
04204          }
04205          break;
04206          
04207       case SUMA_NN_GEOM:
04208          
04209          {
04210             if (LocalHead) SUMA_etime(&start_time,0);
04211             
04212             d_order =  SUMA_ROW_MAJOR; 
04213             
04214             dsmooth = SUMA_NN_GeomSmooth( SO, Opt->N_iter, SO->NodeList,
04215                                           3, d_order, NULL, cs);
04216             if (0 && LocalHead) {
04217                SUMA_LH("See dsmooth.1D");
04218                SUMA_disp_vecmat (dsmooth, SO->N_Node, 3, 1,  d_order, NULL, YUP);
04219             }
04220             if (!dsmooth) {
04221                SUMA_SL_Err("Failed in SUMA_NN_Geom_Smooth");
04222                exit(1);
04223             }
04224             
04225             
04226          }
04227          break;  
04228       case SUMA_BRUTE_FORCE:
04229          
04230          {
04231             if (LocalHead) SUMA_etime(&start_time,0);
04232             
04233             d_order =  SUMA_ROW_MAJOR; 
04234             
04235             SUMA_etime(&start_time_all,0);
04236             dsmooth = SUMA_Offset_GeomSmooth( SO, Opt->N_iter, Opt->OffsetLim, SO->NodeList,
04237                                               3, d_order, NULL, cs);
04238             if (0 && LocalHead) {
04239                SUMA_LH("See dsmooth.1D");
04240                SUMA_disp_vecmat (dsmooth, SO->N_Node, 3, 1,  d_order, NULL, YUP);
04241             }
04242             if (!dsmooth) {
04243                SUMA_SL_Err("Failed in SUMA_Offset_Geom_Smooth");
04244                exit(1);
04245             }
04246             
04247             
04248             
04249             etime_GetOffset_all = SUMA_etime(&start_time_all,1);
04250             fprintf(SUMA_STDERR, "%s: Done.\nSearch to %f mm took %f minutes for %d nodes.\n" , 
04251                                  FuncName, Opt->lim, etime_GetOffset_all / 60.0 , SO->N_Node);
04252 
04253          }
04254          break;
04255       case SUMA_LM:
04256          
04257          {
04258             
04259             if (LocalHead) SUMA_etime(&start_time,0);
04260             
04261             d_order =  SUMA_ROW_MAJOR; 
04262             dsmooth = SUMA_Taubin_Smooth (SO, NULL, 
04263                             Opt->l, Opt->m, SO->NodeList, 
04264                             Opt->N_iter, 3, d_order,
04265                             NULL, cs, NULL); 
04266 
04267             if (LocalHead) {
04268                etime_GetOffset = SUMA_etime(&start_time,1);
04269                fprintf(SUMA_STDERR, "%s: Total processing took %f seconds for %d nodes.\n"
04270                                     "Projected time per 100000 nodes is: %f minutes\n", 
04271                                        FuncName, etime_GetOffset, SO->N_Node, 
04272                                        etime_GetOffset * 100000 / 60.0 / (SO->N_Node));
04273             }
04274             
04275          }
04276          break;
04277       default:
04278          SUMA_SL_Err("Bad method, should not be here.");
04279          exit(1);
04280          break;
04281    }
04282    
04283    
04284    if (Opt->Method == SUMA_BRUTE_FORCE || Opt->Method == SUMA_NN_GEOM)
04285    {
04286       if (Opt->MatchMethod) {   
04287          SUMA_LH("Fixing shrinkage...");
04288          
04289          SOnew = SUMA_CreateChildSO( SO,
04290                                      dsmooth, SO->N_Node,
04291                                      NULL, -1,
04292                                      0); 
04293 
04294          
04295 
04296          switch (Opt->MatchMethod) {
04297             case 1:
04298                if (!SUMA_EquateSurfaceSize(SOnew, SO, Opt->lim, cs)) {
04299                   SUMA_SL_Warn("Failed to fix surface size.\nTrying to finish ...");
04300                }
04301 
04302                
04303                if (cs->Send) {
04304                   SUMA_LH("Sending last fix to SUMA ...");
04305                   if (!SUMA_SendToSuma (SO, cs, (void *)SOnew->NodeList, SUMA_NODE_XYZ, 1)) {
04306                      SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
04307                   }
04308                }
04309 
04310                
04311                dsmooth = SOnew->NodeList; 
04312                SOnew->NodeList = NULL; 
04313                SUMA_Free_Surface_Object(SOnew); SOnew=NULL;
04314 
04315                break;
04316             case 2:
04317                if (!SUMA_EquateSurfaceVolumes(SOnew, SO, Opt->lim, cs)) {
04318                   SUMA_SL_Warn("Failed to fix surface size.\nTrying to finish ...");
04319                }
04320 
04321                
04322                if (cs->Send) {
04323                   SUMA_LH("Sending last fix to SUMA ...");
04324                   if (!SUMA_SendToSuma (SO, cs, (void *)SOnew->NodeList, SUMA_NODE_XYZ, 1)) {
04325                      SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
04326                   }
04327                }
04328                
04329                dsmooth = SOnew->NodeList; 
04330                SOnew->NodeList = NULL; 
04331                SUMA_Free_Surface_Object(SOnew); SOnew=NULL;
04332                break;
04333             case 3:
04334                if (!SUMA_EquateSurfaceAreas(SOnew, SO, Opt->lim, cs)) {
04335                   SUMA_SL_Warn("Failed to fix surface size.\nTrying to finish ...");
04336                }
04337 
04338                
04339                if (cs->Send) {
04340                   SUMA_LH("Sending last fix to SUMA ...");
04341                   if (!SUMA_SendToSuma (SO, cs, (void *)SOnew->NodeList, SUMA_NODE_XYZ, 1)) {
04342                      SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
04343                   }
04344                }
04345                
04346                dsmooth = SOnew->NodeList; 
04347                SOnew->NodeList = NULL; 
04348                SUMA_Free_Surface_Object(SOnew); SOnew=NULL;
04349                break;
04350             case 4:
04351                if (!SUMA_ProjectSurfaceToSphere(SOnew, SO, Opt->lim, cs)) {
04352                   SUMA_SL_Warn("Failed to fix surface size.\nTrying to finish ...");
04353                }
04354 
04355                
04356                if (cs->Send) {
04357                   SUMA_LH("Sending last fix to SUMA ...");
04358                   if (!SUMA_SendToSuma (SO, cs, (void *)SOnew->NodeList, SUMA_NODE_XYZ, 1)) {
04359                      SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
04360                   }
04361                }
04362 
04363                
04364                dsmooth = SOnew->NodeList; 
04365                SOnew->NodeList = NULL; 
04366                SUMA_Free_Surface_Object(SOnew); SOnew=NULL;
04367                break;
04368             case 0:
04369                break;
04370             default:
04371                SUMA_SL_Err("Huh ?");
04372                break;   
04373          }
04374       }
04375       if (LocalHead) {
04376          etime_GetOffset = SUMA_etime(&start_time,1);
04377          fprintf(SUMA_STDERR, "%s: Total processing took %f seconds for %d nodes.\n"
04378                               "Projected time per 100000 nodes is: %f minutes\n", 
04379                                  FuncName, etime_GetOffset, SO->N_Node, 
04380                                  etime_GetOffset * 100000 / 60.0 / (SO->N_Node));
04381       }
04382 
04383    }
04384    
04385    
04386    if (Opt->surf_out) {
04387       if (!dsmooth) {
04388          SUMA_SL_Err("NULL dsmooth for geometry smoothing. Either failed to smooth or logical error.");
04389          exit(1);
04390       }
04391        
04392       SUMA_free(SO->NodeList); SO->NodeList = dsmooth; dsmooth = NULL; 
04393       switch (SO->FileType) {
04394          case SUMA_SUREFIT:
04395             SF_name = (SUMA_SFname *) SUMA_malloc(sizeof(SUMA_SFname));
04396             sprintf(SF_name->name_coord,"%s", Opt->surf_out);
04397             SF_name->name_topo[0] = '\0'; 
04398             SO_name = (void *)SF_name;
04399             if (!SUMA_Save_Surface_Object (SO_name, SO, SUMA_SUREFIT, SUMA_ASCII, NULL)) {
04400                fprintf (SUMA_STDERR,"Error %s: Failed to write surface object.\n", FuncName);
04401                exit (1);
04402             }
04403             break;
04404          case SUMA_VEC:
04405             SF_name = (SUMA_SFname *) SUMA_malloc(sizeof(SUMA_SFname));
04406             sprintf(SF_name->name_coord,"%s", Opt->surf_out);
04407             SF_name->name_topo[0] = '\0';
04408             SO_name = (void *)SF_name;
04409             if (!SUMA_Save_Surface_Object (SO_name, SO, SUMA_VEC, SUMA_ASCII, NULL)) {
04410                fprintf (SUMA_STDERR,"Error %s: Failed to write surface object.\n", FuncName);
04411                exit (1);
04412             }
04413             break;
04414          case SUMA_FREE_SURFER:
04415             SO_name = (void *)Opt->surf_out; 
04416             if (!SUMA_Save_Surface_Object (SO_name, SO, SUMA_FREE_SURFER, SUMA_ASCII, NULL)) {
04417                fprintf (SUMA_STDERR,"Error %s: Failed to write surface object.\n", FuncName);
04418                exit (1);
04419             }
04420             break;
04421          case SUMA_FREE_SURFER_PATCH:
04422             fprintf (SUMA_STDERR,"Error %s: No support for writing Free Surfer patches.\n", FuncName);
04423             exit (1);  
04424             break;
04425          case SUMA_PLY:
04426             SO_name = (void *)Opt->surf_out; 
04427             if (!SUMA_Save_Surface_Object (SO_name, SO, SUMA_PLY, SUMA_FF_NOT_SPECIFIED, NULL)) {
04428                fprintf (SUMA_STDERR,"Error %s: Failed to write surface object.\n", FuncName);
04429                exit (1);
04430             }
04431             break;
04432          case SUMA_OPENDX_MESH:
04433             SO_name = (void *)Opt->surf_out; 
04434             if (!SUMA_Save_Surface_Object (SO_name, SO, SUMA_OPENDX_MESH, SUMA_ASCII, NULL)) {
04435                fprintf (SUMA_STDERR,"Error %s: Failed to write surface object.\n", FuncName);
04436                exit (1);
04437             }
04438             break;  
04439          default:
04440             fprintf (SUMA_STDERR,"Error %s: Bad format.\n", FuncName);
04441             exit(1);
04442       }
04443    } else {
04444       if (!dsmooth) {
04445          SUMA_SL_Err("NULL dsmooth for data smoothing. Either failed to smooth or logical error.");
04446          exit(1);
04447       }      
04448       fileout = fopen(Opt->out_name, "w");
04449       if (Opt->AddIndex) SUMA_disp_vecmat (dsmooth, SO->N_Node, ncol, 1, d_order, fileout, YUP);
04450       else SUMA_disp_vecmat (dsmooth, SO->N_Node, ncol, 1, d_order, fileout, NOPE);
04451       fclose(fileout); fileout = NULL;
04452    }
04453 
04454 
04455 
04456    
04457    if (cs->Send && !cs->GoneBad) {
04458       
04459       if (Opt->Method == SUMA_LB_FEM) {
04460          if (!SUMA_SendToSuma (SO, cs, NULL, SUMA_NODE_RGBAb, 2)) {
04461             SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCleanup failed");
04462          }
04463       }else if (Opt->Method == SUMA_LM) {
04464          if (!SUMA_SendToSuma (SO, cs, NULL, SUMA_NODE_XYZ, 2)) {
04465             SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCleanup failed");
04466          }
04467       }else if (Opt->Method == SUMA_NN_GEOM) {
04468          if (!SUMA_SendToSuma (SO, cs, NULL, SUMA_NODE_XYZ, 2)) {
04469             SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCleanup failed");
04470          }
04471       }
04472    }   
04473       
04474    
04475    SUMA_LH("clean up");
04476    if (SO->NodeList != dsmooth) {
04477       SUMA_LH("Freeing dsmooth...:");
04478       if (dsmooth) SUMA_free(dsmooth); dsmooth = NULL;
04479       SUMA_LH("Done:");
04480    }
04481    mri_free(im); im = NULL;   
04482    if (cs) cs = NULL; 
04483    if (SF_name) SUMA_free(SF_name);
04484    if (Opt->insurf_method == 1) { if (SO) SUMA_Free_Surface_Object(SO); }
04485    if (data_old) SUMA_free(data_old);  
04486    if (Opt->out_name) SUMA_free(Opt->out_name); Opt->out_name = NULL;
04487    if (Opt) SUMA_free(Opt);
04488         if (ps) SUMA_FreeGenericArgParse(ps); ps = NULL;
04489    if (!SUMA_Free_Displayable_Object_Vect (SUMAg_DOv, SUMAg_N_DOv)) {
04490       SUMA_SL_Err("DO Cleanup Failed!");
04491    }
04492 
04493    exit(0);
04494 }
04495 #endif
04496 
04497 #ifdef SUMA_getPatch_STANDALONE
04498 #define SURFPATCH_MAX_SURF 10  
04499 
04500 void usage_SUMA_getPatch ()
04501    {
04502       static char FuncName[]={"usage_SUMA_getPatch"};
04503       char * s = NULL;
04504       s = SUMA_help_basics();
04505       printf ( "\nUsage:\n"
04506                "  SurfPatch <-spec SpecFile> <-surf_A insurf> <-surf_B insurf> ...\n"
04507                "            <-input nodefile inode ilabel> <-prefix outpref>  \n"
04508                "            [-hits min_hits] [-masklabel msk] [-vol]\n"
04509                "\n"
04510                "Usage 1:\n"
04511                "  The program creates a patch of surface formed by nodes \n"
04512                "  in nodefile.\n"
04513                "  Mandatory parameters:\n"
04514                "     -spec SpecFile: Spec file containing input surfaces.\n"
04515                "     -surf_X: Name of input surface X where X is a character\n"
04516                "              from A to Z. If surfaces are specified using two\n"
04517                "              files, use the name of the node coordinate file.\n"
04518                "     -input nodefile inode ilabel: \n"
04519                "            nodefile is the file containing nodes defining the patch.\n"
04520                "            inode is the index of the column containing the nodes\n"
04521                "            ilabel is the index of the column containing labels of\n"
04522                "                   the nodes in column inode. If you want to use\n"
04523                "                   all the nodes in column indode, then set this \n"
04524                "                   parameter to -1 (default). \n"
04525                "                   If ilabel is not equal to 0 then the corresponding \n"
04526                "                   node is used in creating the patch.\n"
04527                "                   See -masklabel option for one more variant.\n"
04528                "     -prefix outpref: Prefix of output patch. If more than one surface\n"
04529                "                      are entered, then the prefix will have _X added\n"
04530                "                      to it, where X is a character from A to Z.\n"
04531                "                      Output format depends on the input surface's.\n"
04532                "                      With that setting, checking on pre-existing files\n"
04533                "                      is only done before writing the new patch, which is\n"
04534                "                      annoying. You can set the output type ahead of time\n"
04535                "                      using -out_type option. This way checking for pre-existing\n"
04536                "                      output files can be done at the outset.\n"
04537                "\n" 
04538                "  Optional parameters:\n"
04539                "     -out_type TYPE: Type of all output patches, regardless of input surface type.\n"
04540                "                     Choose from: FreeSurfer, SureFit, 1D and Ply.\n"
04541                "     -hits min_hits: Minimum number of nodes specified for a triangle\n"
04542                "                     to be made a part of the patch (1 <= min_hits <= 3)\n"
04543                "                     default is 2.\n"
04544                "     -masklabel msk: If specified, then only nodes that are labeled with\n"
04545                "                     with msk are considered for the patch.\n"
04546                "                     This option is useful if you have an ROI dataset file\n"
04547                "                     and whish to create a patch from one out of many ROIs\n"
04548                "                     in that file. This option must be used with ilabel \n"
04549                "                     specified (not = -1)\n"
04550                "\n"
04551                "Usage 2:\n"
04552                "  The program can also be used to calculate the volume between the same patch\n"
04553                "  on two isotopic surfaces. See -vol option below.\n"
04554                "      -vol: Calculate the volume formed by the patch on surf_A and\n"
04555                "            and surf_B. For this option, you must specify two and\n"
04556                "            only two surfaces with surf_A and surf_B options.\n"
04557                "      -vol_only: Only calculate the volume, don't write out patches.\n"
04558                "\n"
04559                "%s"
04560                "\n",s); SUMA_free(s); s = NULL;
04561        s = SUMA_New_Additions(0, 1); printf("%s\n", s);SUMA_free(s); s = NULL;
04562        printf("       Ziad S. Saad SSCC/NIMH/NIH ziad@nih.gov     \n");
04563        exit (0);
04564    }
04565 
04566 typedef struct {
04567    SUMA_SO_File_Type iType;
04568    SUMA_SO_File_Type oType;
04569    char *out_prefix;
04570    char *sv_name;
04571    char *surf_names[SURFPATCH_MAX_SURF];
04572    int N_surf;
04573    char *spec_file;
04574    char *in_name;
04575    int minhits;
04576    int thislabel;
04577    int labelcol;
04578    int nodecol;
04579    int DoVol;
04580    int VolOnly;
04581 } SUMA_GETPATCH_OPTIONS;
04582 
04583 
04584 
04585 
04586 
04587 
04588 
04589 
04590 
04591 
04592 
04593 SUMA_GETPATCH_OPTIONS *SUMA_GetPatch_ParseInput (char *argv[], int argc)
04594 {
04595    static char FuncName[]={"SUMA_GetPatch_ParseInput"}; 
04596    SUMA_GETPATCH_OPTIONS *Opt=NULL;
04597    int kar, i, ind;
04598    char *outprefix;
04599    SUMA_Boolean brk = NOPE;
04600    SUMA_Boolean LocalHead = NOPE;
04601 
04602    SUMA_ENTRY;
04603    
04604    Opt = (SUMA_GETPATCH_OPTIONS *)SUMA_malloc(sizeof(SUMA_GETPATCH_OPTIONS));
04605 
04606    kar = 1;
04607    Opt->iType = SUMA_FT_NOT_SPECIFIED;
04608    Opt->out_prefix = NULL;
04609    Opt->sv_name = NULL;
04610    Opt->spec_file = NULL;
04611    Opt->in_name = NULL;
04612    Opt->minhits = 2;
04613    Opt->labelcol = -1;
04614    Opt->nodecol = -1;
04615    Opt->thislabel = -1;
04616    Opt->N_surf = -1;
04617    Opt->DoVol = 0;
04618    Opt->VolOnly = 0;
04619    Opt->oType = SUMA_FT_NOT_SPECIFIED;
04620    for (i=0; i<SURFPATCH_MAX_SURF; ++i) { Opt->surf_names[i] = NULL; }
04621         brk = NOPE;
04622    
04623         while (kar < argc) { 
04624                 
04625                 if (strcmp(argv[kar], "-h") == 0 || strcmp(argv[kar], "-help") == 0) {
04626                          usage_SUMA_getPatch();
04627           exit (0);
04628                 }
04629                 
04630       SUMA_SKIP_COMMON_OPTIONS(brk, kar);
04631       
04632       if (!brk && (strcmp(argv[kar], "-spec") == 0)) {
04633          kar ++;
04634                         if (kar >= argc)  {
04635                                 fprintf (SUMA_STDERR, "need argument after -spec \n");
04636                                 exit (1);
04637                         }
04638                         Opt->spec_file = argv[kar];
04639                         brk = YUP;
04640                 }
04641       
04642       if (!brk && (strcmp(argv[kar], "-hits") == 0)) {
04643          kar ++;
04644                         if (kar >= argc)  {
04645                                 fprintf (SUMA_STDERR, "need argument after -hits \n");
04646                                 exit (1);
04647                         }
04648                         Opt->minhits = atoi(argv[kar]);
04649                         brk = YUP;
04650                 }
04651       
04652       if (!brk && (strcmp(argv[kar], "-masklabel") == 0)) {
04653          kar ++;
04654                         if (kar >= argc)  {
04655                                 fprintf (SUMA_STDERR, "need argument after -masklabel \n");
04656                                 exit (1);
04657                         }
04658                         Opt->thislabel = atoi(argv[kar]);
04659                         brk = YUP;
04660                 }
04661       
04662       if (!brk && (strcmp(argv[kar], "-vol") == 0)) {
04663                         Opt->DoVol = 1;
04664                         brk = YUP;
04665                 }
04666       
04667       if (!brk && (strcmp(argv[kar], "-vol_only") == 0)) {
04668                         Opt->DoVol = 1;
04669          Opt->VolOnly = 1;
04670                         brk = YUP;
04671                 }
04672       
04673       if (!brk && (strcmp(argv[kar], "-prefix") == 0)) {
04674          kar ++;
04675                         if (kar >= argc)  {
04676                                 fprintf (SUMA_STDERR, "need argument after -prefix \n");
04677                                 exit (1);
04678                         }
04679                         Opt->out_prefix = SUMA_copy_string(argv[kar]);
04680                         brk = YUP;
04681                 }
04682       
04683       if (!brk && (strcmp(argv[kar], "-out_type") == 0)) {
04684          kar ++;
04685                         if (kar >= argc)  {
04686                                 fprintf (SUMA_STDERR, "need argument after -out_type \n");
04687                                 exit (1);
04688                         }
04689                         Opt->oType = SUMA_guess_surftype_argv(argv[kar]);
04690                         brk = YUP;
04691                 }
04692 
04693       if (!brk && (strcmp(argv[kar], "-input") == 0)) {
04694          kar ++;
04695                         if (kar+2 >= argc)  {
04696                                 fprintf (SUMA_STDERR, "need 3 arguments after -input \n");
04697                                 exit (1);
04698                         }
04699                         Opt->in_name = argv[kar]; kar ++;
04700          Opt->nodecol = atoi(argv[kar]); kar ++;
04701          Opt->labelcol = atoi(argv[kar]); 
04702                         brk = YUP;
04703                 }
04704       
04705       if (!brk && (strncmp(argv[kar], "-surf_", 6) == 0)) {
04706                         if (kar + 1>= argc)  {
04707                                 fprintf (SUMA_STDERR, "need argument after -surf_X SURF_NAME \n");
04708                                 exit (1);
04709                         }
04710                         ind = argv[kar][6] - 'A';
04711          if (ind < 0 || ind >= SURFPATCH_MAX_SURF) {
04712             fprintf (SUMA_STDERR, "-surf_X SURF_NAME option is out of range.\n");
04713                                 exit (1);
04714          }
04715          kar ++;
04716          Opt->surf_names[ind] = argv[kar];
04717          Opt->N_surf = ind+1;
04718          brk = YUP;
04719                 }
04720       
04721       if (!brk) {
04722                         fprintf (SUMA_STDERR,"Error %s:\nOption %s not understood. Try -help for usage\n", FuncName, argv[kar]);
04723                         exit (1);
04724                 } else {        
04725                         brk = NOPE;
04726                         kar ++;
04727                 }
04728       
04729    }
04730    
04731    
04732    if (!Opt->out_prefix) Opt->out_prefix = SUMA_copy_string("SurfPatch");
04733    
04734    if (Opt->thislabel >= 0 && Opt->labelcol < 0) {
04735       SUMA_SL_Err("Cannot use -masklabel without specifying ilabel in -input option");
04736       exit(1);
04737    } 
04738    if (Opt->minhits < 1 || Opt->minhits > 3) {
04739       SUMA_SL_Err("minhits must be > 0 and < 3");
04740       exit(1);
04741    }
04742    if (Opt->N_surf < 1) {
04743       SUMA_SL_Err("No surface specified.");
04744       exit(1);
04745    }
04746    if (!Opt->in_name) {
04747       SUMA_SL_Err("No input specified.");
04748       exit(1);
04749    }
04750    if (Opt->DoVol && Opt->N_surf != 2) {
04751       SUMA_SL_Err("Must specify 2 and only 2 surfaces with -vol options");
04752       exit(1);
04753    }
04754    SUMA_RETURN (Opt);
04755      
04756 }
04757 
04758 int main (int argc,char *argv[])
04759 {    
04760    static char FuncName[]={"SurfPatch"};
04761    SUMA_GETPATCH_OPTIONS *Opt; 
04762    char *ppref=NULL, ext[5]; 
04763    float *far=NULL;
04764    MRI_IMAGE *im = NULL;
04765    int SO_read = -1;
04766    int *NodePatch=NULL, N_NodePatch=-1, *FaceSetList=NULL , N_FaceSet = -1;          
04767    int i, inodeoff=-1, ilabeloff=-1, nvec, ncol, cnt;
04768    SUMA_SurfaceObject *SO = NULL;
04769    SUMA_PATCH *ptch = NULL; 
04770    SUMA_SurfSpecFile Spec;
04771    SUMA_INDEXING_ORDER d_order;
04772    void *SO_name = NULL;
04773    SUMA_Boolean exists = NOPE;
04774    SUMA_SO_File_Type typetmp;
04775    SUMA_Boolean LocalHead = NOPE;
04776         
04777    SUMA_mainENTRY;
04778    
04779    SUMA_STANDALONE_INIT;
04780    
04781    
04782         
04783         SUMAg_DOv = SUMA_Alloc_DisplayObject_Struct (SUMA_MAX_DISPLAYABLE_OBJECTS);
04784    
04785    if (argc < 4)
04786        {
04787           usage_SUMA_getPatch();
04788           exit (1);
04789        }
04790    
04791    Opt = SUMA_GetPatch_ParseInput (argv, argc);
04792    
04793    if (Opt->oType != SUMA_FT_NOT_SPECIFIED && !Opt->VolOnly) { 
04794       for (i=0; i < Opt->N_surf; ++i) {
04795          if (Opt->N_surf > 1) {
04796             sprintf(ext, "_%c", 65+i);
04797             ppref = SUMA_append_string(Opt->out_prefix, ext);
04798          } else {
04799             ppref = SUMA_copy_string(Opt->out_prefix);
04800          }
04801          
04802          SO_name = SUMA_Prefix2SurfaceName(ppref, NULL, NULL, Opt->oType, &exists);
04803          if (exists) {
04804             fprintf(SUMA_STDERR,"Error %s:\nOutput file(s) %s* on disk.\nWill not overwrite.\n", FuncName, ppref);
04805             exit(1);
04806          }
04807          if (ppref) SUMA_free(ppref); ppref = NULL; 
04808          if (SO_name) SUMA_free(SO_name); SO_name = NULL;
04809       } 
04810    }
04811    
04812    
04813    if (!SUMA_Read_SpecFile (Opt->spec_file, &Spec)) {
04814                 fprintf(SUMA_STDERR,"Error %s: Error in SUMA_Read_SpecFile\n", FuncName);
04815                 exit(1);
04816         }
04817    SO_read = SUMA_spec_select_surfs(&Spec, Opt->surf_names, SURFPATCH_MAX_SURF, 0);
04818    if ( SO_read != Opt->N_surf )
04819    {
04820            if (SO_read >=0 )
04821          fprintf(SUMA_STDERR,"Error %s:\nFound %d surfaces, expected %d.\n", FuncName,  SO_read, Opt->N_surf);
04822       exit(1);
04823    }
04824    
04825    if (!SUMA_LoadSpec_eng(&Spec, SUMAg_DOv, &SUMAg_N_DOv, Opt->sv_name, 0, SUMAg_CF->DsetList) ) {
04826            fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_LoadSpec_eng\n", FuncName);
04827       exit(1);
04828    }
04829    
04830    
04831    im = mri_read_1D (Opt->in_name);
04832 
04833    if (!im) {
04834       SUMA_SL_Err("Failed to read 1D file");
04835       exit(1);
04836    }
04837 
04838    far = MRI_FLOAT_PTR(im);
04839    nvec = im->nx;
04840    ncol = im->ny;
04841    d_order = SUMA_COLUMN_MAJOR;
04842 
04843    if (!nvec) {
04844       SUMA_SL_Err("Empty file");
04845       exit(1);
04846    }
04847    
04848    NodePatch = (int *)SUMA_malloc(sizeof(int)*nvec);
04849    if (!NodePatch) {
04850       SUMA_SL_Crit("Failed to allocate.");
04851       exit(1);
04852    }
04853    inodeoff = Opt->nodecol*nvec;
04854    if (Opt->labelcol < 0) {  
04855       for (i=0; i<nvec; ++i) {
04856          NodePatch[i] = far[i+inodeoff];
04857       }
04858       N_NodePatch = nvec;
04859    } else {
04860       ilabeloff =  Opt->labelcol*nvec;
04861       if (Opt->thislabel < 0) { 
04862          cnt = 0;
04863          for (i=0; i<nvec; ++i) {
04864             if (far[i+ilabeloff]) {
04865                NodePatch[cnt] = far[i+inodeoff];
04866                ++cnt;
04867             }
04868          }
04869          N_NodePatch = cnt;     
04870       } else { 
04871          cnt = 0;
04872          for (i=0; i<nvec; ++i) {
04873             if (far[i+ilabeloff] == Opt->thislabel) {
04874                NodePatch[cnt] = far[i+inodeoff];
04875                ++cnt;
04876             }
04877          }
04878          N_NodePatch = cnt;    
04879       }
04880       NodePatch = (int *) SUMA_realloc(NodePatch , sizeof(int)*N_NodePatch);
04881    }
04882    
04883    
04884    mri_free(im); im = NULL;   
04885    
04886    if (Opt->DoVol) {
04887       SUMA_SurfaceObject *SO1 = SUMA_find_named_SOp_inDOv(Opt->surf_names[0], SUMAg_DOv, SUMAg_N_DOv);
04888       SUMA_SurfaceObject *SO2 = SUMA_find_named_SOp_inDOv(Opt->surf_names[1], SUMAg_DOv, SUMAg_N_DOv);
04889       double Vol = 0.0;
04890       
04891       if (!SO1 || !SO2) {
04892          SUMA_SL_Err("Failed to load surfaces.");
04893          exit(1);
04894       }
04895       
04896       Vol = SUMA_Pattie_Volume(SO1, SO2, NodePatch, N_NodePatch, NULL, Opt->minhits);
04897       fprintf (SUMA_STDERR,"Volume = %f\n", fabs(Vol));
04898    }
04899    
04900    
04901    if (!Opt->VolOnly) {
04902       FaceSetList = NULL;
04903       N_FaceSet = -1;
04904       for (i=0; i < Opt->N_surf; ++i) {
04905          
04906          SO = SUMA_find_named_SOp_inDOv(Opt->surf_names[i], SUMAg_DOv, SUMAg_N_DOv);
04907          if (!SO) {
04908             fprintf (SUMA_STDERR,"Error %s:\n"
04909                                  "Failed to find surface %s\n"
04910                                  "in spec file. Use full name.\n",
04911                                  FuncName, Opt->surf_names[i]);
04912             exit(1);
04913          }
04914          
04915          if (!SO->MF) {
04916             SUMA_SL_Warn ("NULL MF");
04917          }
04918          ptch = SUMA_getPatch (NodePatch, N_NodePatch, SO->FaceSetList, SO->N_FaceSet, SO->MF, Opt->minhits);
04919          if (!ptch) {
04920             SUMA_SL_Err("Failed to form patch.");
04921             exit(1);
04922          }
04923          if (LocalHead) SUMA_ShowPatch(ptch, NULL);
04924 
04925          
04926          if (Opt->N_surf > 1) {
04927             sprintf(ext, "_%c", 65+i);
04928             ppref = SUMA_append_string(Opt->out_prefix, ext);
04929          } else {
04930             ppref = SUMA_copy_string(Opt->out_prefix);
04931          }
04932          
04933          typetmp = SO->FileType;
04934          if (Opt->oType != SUMA_FT_NOT_SPECIFIED) SO->FileType = Opt->oType;
04935          SO_name = SUMA_Prefix2SurfaceName(ppref, NULL, NULL, SO->FileType, &exists);
04936          if (ppref) SUMA_free(ppref); ppref = NULL;
04937          
04938          FaceSetList = SO->FaceSetList;
04939          N_FaceSet = SO->N_FaceSet;
04940          
04941          SO->FaceSetList = ptch->FaceSetList;
04942          SO->N_FaceSet = ptch->N_FaceSet; 
04943          if (!SUMA_Save_Surface_Object (SO_name, SO, SO->FileType, SUMA_ASCII, NULL)) {
04944                fprintf (SUMA_STDERR,"Error %s: Failed to write surface object.\n", FuncName);
04945                exit (1);
04946          }
04947          
04948          SO->FileType = typetmp;
04949          SO->FaceSetList = FaceSetList; FaceSetList = NULL;
04950          SO->N_FaceSet = N_FaceSet; N_FaceSet = -1;
04951          if (SO_name) SUMA_free(SO_name); SO_name = NULL;
04952          if (ptch) SUMA_freePatch(ptch); ptch = NULL;
04953       }
04954    } 
04955    
04956    SUMA_LH("clean up");
04957    if (Opt->out_prefix) SUMA_free(Opt->out_prefix); Opt->out_prefix = NULL;
04958    if (Opt) SUMA_free(Opt);   
04959    if (!SUMA_Free_Displayable_Object_Vect (SUMAg_DOv, SUMAg_N_DOv)) {
04960       SUMA_SL_Err("DO Cleanup Failed!");
04961    }
04962    
04963    if (!SUMA_Free_CommonFields(SUMAg_CF)) {SUMA_SL_Err("SUMAg_CF Cleanup Failed!");}
04964    
04965    SUMA_RETURN(0);
04966 } 
04967 #endif
04968 
04969 
04970 
04971 
04972 
04973 
04974 
04975 
04976 
04977 
04978 
04979 
04980 
04981 
04982 
04983 int SUMA_OrientTriangles (float *NodeList, int N_Node, int *FaceSetList, int N_FaceSet, int orient, int Force)
04984 {
04985    static char FuncName[]={"SUMA_OrientTriangles"};
04986    int i, j, ip, negdot, posdot, sgn, NP, ND, n1, n2, n3, flip;
04987    float d1[3], d2[3], c[3], tc[3], U[3], dot, *norm, mag;
04988    FILE *fout = NULL;
04989    SUMA_Boolean LocalHead = NOPE;
04990    
04991    SUMA_ENTRY;
04992    
04993    
04994    if (!NodeList || !FaceSetList || !N_Node || !N_FaceSet) {
04995       SUMA_SL_Err("Null or no input");
04996       SUMA_RETURN(0);
04997    }
04998    norm = (float *)SUMA_calloc(3*N_FaceSet, sizeof(float));
04999    if (!norm) {
05000       SUMA_SL_Crit("Failed to allocate for norm"); SUMA_RETURN(0);
05001    }
05002    if (Force) {
05003       SUMA_SL_Warn("Using Force option! You might destroy triangulation consistency of surface!");
05004    }
05005    NP = ND = 3;
05006    
05007    c[0] = c[1] = c[2];
05008    for (i=0; i < N_Node; ++i) {
05009       ip = ND * i; c[0] += NodeList[ip]; c[1] += NodeList[ip+1]; c[2] += NodeList[ip+2];    
05010    }
05011    c[0] /= N_Node; c[1] /= N_Node; c[2] /= N_Node;
05012    
05013    
05014    if (0 && LocalHead) {
05015       SUMA_SL_Note("Writing SUMA_OrientTriangles.1D");
05016       fout = fopen("SUMA_OrientTriangles.1D", "w");
05017    }
05018    negdot = 0; posdot = 0;
05019    for (i=0; i < N_FaceSet; i++) {
05020       ip = NP * i;
05021       n1 = FaceSetList[ip]; n2 = FaceSetList[ip+1]; n3 = FaceSetList[ip+2];   
05022       tc[0] = (NodeList[3*n1]   + NodeList[3*n2]   + NodeList[3*n3]  )/3; 
05023       tc[1] = (NodeList[3*n1+1] + NodeList[3*n2+1] + NodeList[3*n3+1])/3; 
05024       tc[2] = (NodeList[3*n1+2] + NodeList[3*n2+2] + NodeList[3*n3+2])/3; 
05025       
05026       for (j=0; j < 3; j++) {
05027          d1[j] = NodeList[(ND*n1)+j] - NodeList[(ND*n2)+j];
05028          d2[j] = NodeList[(ND*n2)+j] - NodeList[(ND*n3)+j];
05029       }
05030       norm[ip] = d1[1]*d2[2] - d1[2]*d2[1];
05031       norm[ip+1] = d1[2]*d2[0] - d1[0]*d2[2];
05032       norm[ip+2] = d1[0]*d2[1] - d1[1]*d2[0];
05033       
05034       
05035       U[0] = tc[0] - c[0]; U[1] = tc[1] - c[1]; U[2] = tc[2] - c[2];
05036       SUMA_DOTP_VEC(U, &(norm[ip]), dot, 3, float, float);
05037       if (dot < 0) {
05038          ++negdot;
05039          if (0 && LocalHead) { fprintf (SUMA_STDERR,"%s: Triangle %d has a negative dot product %f\nc  =[%.3f %.3f %.3f]\ntc =[%.3f %.3f %.3f]\nnorm=[%.3f %.3f %.3f]\n",
05040                       FuncName, i, dot, c[0], c[1], c[2], tc[0], tc[1], tc[2], norm[ip+0], norm[ip+1], norm[ip+2]); }
05041          
05042       } else {
05043          if (fout) { 
05044                SUMA_NORM_VEC(norm,3,mag); if (!mag) mag = 1; mag /= 5; 
05045                if (fout) fprintf (fout,"%.3f %.3f %.3f %.3f %.3f %.3f\n", tc[0], tc[1], tc[2], tc[0]+norm[ip+0]/mag, tc[1]+norm[ip+1]/mag, tc[2]+norm[ip+2]/mag);
05046          }
05047          ++posdot;
05048       }      
05049       
05050       if (Force) {
05051          if ( (dot < 0 && orient > 0) || (dot > 0 && orient < 0)) {
05052             n1 = FaceSetList[ip]; FaceSetList[ip] = FaceSetList[ip+2]; FaceSetList[ip+2] = n1;  
05053          }
05054       }
05055    }
05056    if (fout) fclose(fout); fout = NULL;
05057    flip = 0; sgn = 0;
05058    if (posdot >= negdot) {
05059       SUMA_LH("Normals appear to point away from center");
05060       sgn = 1;
05061       if (orient < 0) flip = 1;
05062    } else {
05063       SUMA_LH("Normals appear to point towards center");
05064       sgn = -1;
05065       if (orient > 0) flip = 1;
05066    }
05067    if (LocalHead) {
05068       fprintf(SUMA_STDERR,"%s:\n Found %d positive dot products and %d negative ones.\n", FuncName, posdot, negdot);
05069    }
05070    
05071    if (flip && !Force) {
05072       SUMA_LH("Flipping");
05073       for (i=0; i < N_FaceSet; i++) {
05074          ip = NP * i;
05075          n1 = FaceSetList[ip]; FaceSetList[ip] = FaceSetList[ip+2]; FaceSetList[ip+2] = n1;
05076       }
05077    }
05078    
05079    if (norm) SUMA_free(norm); norm = NULL;
05080    
05081    SUMA_RETURN(sgn);
05082 }
05083 
05084 
05085 
05086 
05087 
05088 
05089 
05090 
05091 
05092 
05093 
05094 
05095 
05096 SUMA_SurfaceObject *SUMA_Patch2Surf(float *NodeList, int N_NodeList, int *PatchFaces, int N_PatchFaces, int PatchDim)
05097 {
05098    static char FuncName[]={"SUMA_Patch2Surf"};
05099    SUMA_SurfaceObject *SO=NULL;
05100    int i = 0, cnt = 0;
05101    int *imask = NULL;
05102    int N_Node = 0;
05103    SUMA_Boolean LocalHead = NOPE;
05104    
05105    SUMA_ENTRY;
05106    
05107    if (!NodeList || !PatchFaces) {
05108       SUMA_SL_Err("Null input");
05109       SUMA_RETURN(SO);
05110    }
05111    
05112    imask = (int*)SUMA_calloc(N_NodeList , sizeof(int));
05113    if (!imask) {
05114       SUMA_SL_Err("Failed to allocate");
05115       SUMA_RETURN(SO);
05116    }  
05117    
05118    SO = SUMA_Alloc_SurfObject_Struct(1);
05119    if (!SO) {
05120       SUMA_SL_Err("Failed to allocate");
05121       SUMA_RETURN(SO);
05122    }
05123    SO->N_FaceSet = N_PatchFaces;
05124    SO->N_Node = 0;
05125    for (i=0; i<3*N_PatchFaces; ++i) {
05126       if (!imask[PatchFaces[i]]) {
05127          imask[PatchFaces[i]] = -1;
05128          ++SO->N_Node;
05129       }
05130    }
05131    if (LocalHead) {
05132       fprintf (SUMA_STDERR,"%s: %d nodes in patch\n", FuncName, SO->N_Node);
05133    }
05134    SO->NodeList = (float *)SUMA_malloc(sizeof(float)*3*SO->N_Node);
05135    SO->FaceSetList = (int *)SUMA_malloc(sizeof(int)*PatchDim*N_PatchFaces);
05136    if (!SO->NodeList || !SO->FaceSetList) {
05137       SUMA_SL_Err("Failed to allocate");
05138       SUMA_RETURN(SO);
05139    }
05140    SO->NodeDim = 3;
05141    SO->FaceSetDim = PatchDim;
05142    
05143    cnt = 0;
05144    for (i=0; i<3*N_PatchFaces; ++i) {
05145       if (imask[PatchFaces[i]] < 0) {
05146          imask[PatchFaces[i]] = cnt;
05147          SO->NodeList[3*cnt  ] = NodeList[3*PatchFaces[i]  ];
05148          SO->NodeList[3*cnt+1] = NodeList[3*PatchFaces[i]+1];
05149          SO->NodeList[3*cnt+2] = NodeList[3*PatchFaces[i]+2];
05150          ++cnt;
05151       }
05152       SO->FaceSetList[i] = imask[PatchFaces[i]];
05153    }
05154    
05155    SUMA_RETURN(SO);
05156 }
05157 
05158 
05159 
05160 
05161 
05162 
05163 
05164 
05165 
05166 
05167 
05168 
05169 SUMA_Boolean *SUMA_MaskOfNodesInPatch(SUMA_SurfaceObject *SO, int *N_NodesUsedInPatch)
05170 {
05171    static char FuncName[]={"SUMA_MaskOfNodesInPatch"};
05172    int k;
05173    SUMA_Boolean *NodesInPatchMesh = NULL;
05174 
05175    SUMA_ENTRY;
05176 
05177    *N_NodesUsedInPatch = 0;
05178 
05179    if (!SO) {
05180       SUMA_SL_Err("NULL SO");
05181       SUMA_RETURN(NULL);
05182    }
05183    if (!SO->FaceSetList || !SO->N_FaceSet) {
05184       SUMA_SL_Err("NULL or empty SO->FaceSetList");
05185       SUMA_RETURN(NULL);
05186    }
05187 
05188    NodesInPatchMesh = (SUMA_Boolean *)SUMA_calloc(SO->N_Node, sizeof(SUMA_Boolean)); 
05189    if (!NodesInPatchMesh) {
05190       SUMA_SL_Crit("Failed to allocate for NodesInPatchMesh");
05191       SUMA_RETURN(NULL);
05192    }
05193    for (k=0; k<SO->FaceSetDim*SO->N_FaceSet; ++k) {
05194       if (!NodesInPatchMesh[SO->FaceSetList[k]]) { 
05195          ++*N_NodesUsedInPatch;
05196          NodesInPatchMesh[SO->FaceSetList[k]] = 1;         
05197       }
05198    }
05199 
05200    SUMA_RETURN(NodesInPatchMesh);  
05201 }
05202 
05203 
05204 
05205 
05206 
05207 
05208 
05209 
05210 
05211 
05212 
05213 
05214 
05215 
05216 
05217 
05218 
05219 
05220 
05221 
05222 
05223 SUMA_PATCH * SUMA_getPatch (  int *NodesSelected, int N_Nodes, 
05224                               int *Full_FaceSetList, int N_Full_FaceSetList, 
05225                               SUMA_MEMBER_FACE_SETS *Memb, int MinHits)
05226 {
05227    int * BeenSelected;
05228    int i, j, node, ip, ip2, NP;
05229    SUMA_PATCH *Patch;
05230    static char FuncName[]={"SUMA_getPatch"};
05231    
05232    SUMA_ENTRY;
05233    
05234    NP = 3;
05235    BeenSelected = (int *)SUMA_calloc (N_Full_FaceSetList, sizeof(int));
05236    Patch = (SUMA_PATCH *)SUMA_malloc(sizeof(SUMA_PATCH));
05237    
05238    if (!BeenSelected || !Patch) {
05239       fprintf (SUMA_STDERR,"Error %s: Could not allocate for BeenSelected or patch.\n", FuncName);
05240       SUMA_RETURN(NULL);
05241    }
05242    
05243    Patch->N_FaceSet = 0; 
05244    for (i=0; i < N_Nodes; ++i) {
05245       node = NodesSelected[i];
05246       for (j=0; j < Memb->N_Memb[node]; ++j) {
05247          if (!BeenSelected[Memb->NodeMemberOfFaceSet[node][j]]) {
05248             
05249             ++ Patch->N_FaceSet;
05250          }
05251          ++ BeenSelected[Memb->NodeMemberOfFaceSet[node][j]];
05252       }   
05253    }
05254    
05255    
05256    
05257    Patch->FaceSetList = (int *) SUMA_calloc (Patch->N_FaceSet * 3, sizeof(int));
05258    Patch->FaceSetIndex = (int *) SUMA_calloc (Patch->N_FaceSet, sizeof(int));
05259    Patch->nHits = (int *) SUMA_calloc (Patch->N_FaceSet, sizeof(int));
05260    
05261    if (!Patch->FaceSetList || !Patch->FaceSetIndex || !Patch->nHits) {
05262       fprintf (SUMA_STDERR,"Error %s: Could not allocate for Patch->FaceSetList || Patch_FaceSetIndex.\n", FuncName);
05263       SUMA_RETURN(NULL);
05264    }
05265    
05266    j=0;
05267    for (i=0; i < N_Full_FaceSetList; ++i) {
05268       if (BeenSelected[i] >= MinHits) {
05269          Patch->nHits[j] = BeenSelected[i];
05270          Patch->FaceSetIndex[j] = i;
05271          ip = NP * j;
05272          ip2 = NP * i;
05273          Patch->FaceSetList[ip] = Full_FaceSetList[ip2];
05274          Patch->FaceSetList[ip+1] = Full_FaceSetList[ip2+1];
05275          Patch->FaceSetList[ip+2] = Full_FaceSetList[ip2+2];
05276          ++j;
05277       }
05278    }
05279    
05280    
05281 
05282 
05283    Patch->N_FaceSet = j;
05284    
05285    if (BeenSelected) SUMA_free(BeenSelected);
05286    
05287    SUMA_RETURN(Patch);   
05288 }
05289 
05290 
05291 
05292 
05293 
05294 
05295 
05296 
05297 
05298 SUMA_Boolean SUMA_freePatch (SUMA_PATCH *Patch) 
05299 {
05300    static char FuncName[]={"SUMA_freePatch"};
05301    
05302    SUMA_ENTRY;
05303    
05304    
05305    if (Patch->FaceSetIndex) SUMA_free(Patch->FaceSetIndex);
05306    if (Patch->FaceSetList) SUMA_free(Patch->FaceSetList);
05307    if (Patch->nHits) SUMA_free(Patch->nHits);
05308    if (Patch) SUMA_free(Patch);
05309    SUMA_RETURN(YUP);
05310    
05311 }
05312 
05313 SUMA_Boolean SUMA_ShowPatch (SUMA_PATCH *Patch, FILE *Out) 
05314 {
05315    static char FuncName[]={"SUMA_freePatch"};
05316    int ip, i;
05317    
05318    SUMA_ENTRY;
05319    
05320    if (!Out) Out = stderr;
05321    
05322    fprintf (Out, "Patch Contains %d triangles:\n", Patch->N_FaceSet);
05323    fprintf (Out, "FaceIndex (nHits): FaceSetList[0..2]\n");
05324    for (i=0; i < Patch->N_FaceSet; ++i) {
05325       ip = 3 * i;   
05326       fprintf (Out, "%d(%d):   %d %d %d\n",
05327             Patch->FaceSetIndex[i], Patch->nHits[i], Patch->FaceSetList[ip],
05328             Patch->FaceSetList[ip+1], Patch->FaceSetList[ip+2]);
05329    }
05330    
05331    SUMA_RETURN(YUP);
05332 }
05333 
05334 
05335 
05336 
05337 
05338 
05339 
05340 SUMA_CONTOUR_EDGES * SUMA_GetContour (SUMA_SurfaceObject *SO, int *Nodes, int N_Node, int *N_ContEdges, int ContourMode, SUMA_PATCH *UseThisPatch)
05341 {
05342    static char FuncName[]={"SUMA_GetContour"};
05343    SUMA_EDGE_LIST * SEL=NULL;
05344    SUMA_PATCH *Patch = NULL;
05345    int i, Tri, Tri1, Tri2, sHits;
05346    SUMA_CONTOUR_EDGES *CE = NULL;
05347    SUMA_Boolean *isNode=NULL;
05348    SUMA_Boolean LocalHead = NOPE;
05349    
05350    SUMA_ENTRY;
05351 
05352    *N_ContEdges = -1;
05353    
05354    
05355    if (!SO->MF) {
05356       SUMA_SLP_Err("Member FaceSet not created.\n");
05357       SUMA_RETURN(CE);
05358    }  
05359 
05360    
05361    isNode = (SUMA_Boolean *) SUMA_calloc(SO->N_Node, sizeof(SUMA_Boolean));
05362    if (!isNode) {
05363       SUMA_SLP_Crit("Failed to allocate for isNode");
05364       SUMA_RETURN(CE);
05365    }
05366    
05367    for (i=0; i < N_Node; ++i) isNode[Nodes[i]] = YUP;
05368   
05369    if (UseThisPatch) {
05370       SUMA_LH("Using passed patch");
05371       Patch = UseThisPatch;
05372    } else { 
05373       SUMA_LH("Creating patch");
05374       switch (ContourMode) {
05375          case 0:
05376             Patch = SUMA_getPatch (Nodes, N_Node, SO->FaceSetList, SO->N_FaceSet, SO->MF, 2);
05377             break;
05378          case 1:
05379             Patch = SUMA_getPatch (Nodes, N_Node, SO->FaceSetList, SO->N_FaceSet, SO->MF, 1);
05380             break;
05381          default:
05382             SUMA_SL_Err("Bad contour mode"); SUMA_RETURN(NULL);
05383             break;
05384       }
05385    }
05386    if (LocalHead) SUMA_ShowPatch (Patch,NULL);
05387    
05388    if (Patch->N_FaceSet) {
05389       SEL = SUMA_Make_Edge_List_eng (Patch->FaceSetList, Patch->N_FaceSet, SO->N_Node, SO->NodeList, 0, NULL);
05390    
05391       if (0 && LocalHead) SUMA_Show_Edge_List (SEL, NULL);
05392       
05393       CE = (SUMA_CONTOUR_EDGES *) SUMA_malloc(SEL->N_EL * sizeof(SUMA_CONTOUR_EDGES));
05394       if (!CE) {
05395          SUMA_SLP_Crit("Failed to allocate for CE");
05396          SUMA_RETURN(CE);
05397       }
05398    
05399       switch (ContourMode) {
05400          case 0: 
05401             
05402             i = 0;
05403             *N_ContEdges = 0;
05404             while (i < SEL->N_EL) {
05405                if (SEL->ELps[i][2] == 2) {
05406                   Tri1 = SEL->ELps[i][1];
05407                   Tri2 = SEL->ELps[i+1][1];
05408                   sHits = Patch->nHits[Tri1] + Patch->nHits[Tri2];
05409                   if (sHits == 5 || sHits == 4) { 
05410                      
05411                                                  
05412                      
05413                      if (isNode[SEL->EL[i][0]] && isNode[SEL->EL[i][1]]) {
05414                         CE[*N_ContEdges].n1 = SEL->EL[i][0];
05415                         CE[*N_ContEdges].n2 = SEL->EL[i][1];
05416                         ++ *N_ContEdges;
05417 
05418                         if (LocalHead) {
05419                            fprintf (SUMA_STDERR,"%s: Found edge made up of nodes [%d %d]\n",
05420                               FuncName, SEL->EL[i][0], SEL->EL[i][1]);
05421                         }
05422                      }
05423                   }
05424                }
05425 
05426                if (SEL->ELps[i][2] > 0) {
05427                   i += SEL->ELps[i][2];
05428                } else {
05429                   i ++;
05430                }
05431             }
05432             break;
05433          case 1: 
05434             i = 0;
05435             *N_ContEdges = 0;
05436             while (i < SEL->N_EL) {
05437                if (SEL->ELps[i][2] == 1) {
05438                   CE[*N_ContEdges].n1 = SEL->EL[i][0];
05439                   CE[*N_ContEdges].n2 = SEL->EL[i][1];
05440                   ++ *N_ContEdges;
05441                   if (LocalHead) {
05442                            fprintf (SUMA_STDERR,"%s: Found edge made up of nodes [%d %d]\n",
05443                               FuncName, SEL->EL[i][0], SEL->EL[i][1]);
05444                   }
05445                }
05446                if (SEL->ELps[i][2] > 0) {
05447                   i += SEL->ELps[i][2];
05448                } else {
05449                   i ++;
05450                }
05451             }
05452             break;
05453          default:
05454             SUMA_SL_Err("Bad ContourMode");
05455             SUMA_RETURN(NULL);
05456             break;            
05457       }
05458       
05459       
05460       if (! *N_ContEdges) {
05461          SUMA_free(CE); CE = NULL;
05462          SUMA_RETURN(CE);
05463       }else {
05464          CE = (SUMA_CONTOUR_EDGES *) SUMA_realloc (CE, *N_ContEdges * sizeof(SUMA_CONTOUR_EDGES));
05465          if (!CE) {
05466             SUMA_SLP_Crit("Failed to reallocate for CE");
05467             SUMA_RETURN(CE);
05468          }
05469       }
05470          
05471       SUMA_free_Edge_List (SEL); 
05472    }
05473    
05474    if (!UseThisPatch) {
05475       SUMA_freePatch (Patch); 
05476    }
05477    Patch = NULL;
05478    
05479    SUMA_free(isNode);
05480    
05481    SUMA_RETURN(CE);
05482 }
05483 
05484 
05485 
05486 
05487 
05488 
05489 
05490 
05491 
05492 
05493 
05494 
05495 
05496 
05497 
05498 
05499 
05500 
05501 
05502 
05503 
05504 
05505 
05506 
05507 
05508 
05509 
05510 
05511 
05512 
05513 
05514 
05515 
05516 
05517 
05518 
05519 
05520 double SUMA_Pattie_Volume (SUMA_SurfaceObject *SO1, SUMA_SurfaceObject *SO2, int *Nodes, int N_Node, SUMA_SurfaceObject *UseThisSO, int minPatchHits)
05521 {
05522    static char FuncName[]={"SUMA_Pattie_Volume"};
05523    double Vol = 0.0;
05524    int N_ContEdges=0, i,  i3, n, NodesPerPatch, *NewIndex = NULL, inew3, cnt, n1, n2, trouble;
05525    SUMA_PATCH *P1 = NULL;
05526    FILE *fid=NULL;
05527    SUMA_CONTOUR_EDGES *CE = NULL;
05528    SUMA_SurfaceObject *SOc = NULL;
05529    SUMA_SURF_NORM SN;
05530    SUMA_Boolean LocalHead = NOPE;
05531    
05532    SUMA_ENTRY;
05533    
05534    if (!SO1 || !SO2 || !Nodes || !N_Node) {
05535       SUMA_SL_Err("Bad input.");
05536       SUMA_RETURN(Vol);
05537    }
05538    if (SO1->N_Node != SO2->N_Node || SO1->N_FaceSet != SO2->N_FaceSet) {
05539       SUMA_SL_Err("Surfaces Not Isotopic");
05540       SUMA_RETURN(Vol);
05541    }
05542    
05543    
05544    SUMA_LH("Forming patch...");
05545    P1 = SUMA_getPatch (Nodes, N_Node, SO1->FaceSetList, SO1->N_FaceSet, SO1->MF, minPatchHits);
05546    if (!P1) {
05547       SUMA_SL_Err("Failed to create patches.\n");
05548       SUMA_RETURN(Vol);
05549    }
05550    if (!P1->N_FaceSet) {
05551       SUMA_SL_Err("No patch could be formed");
05552       SUMA_RETURN(Vol);
05553    }
05554    
05555    SUMA_LH("Forming contour...");
05556    CE = SUMA_GetContour (SO1, Nodes, N_Node, &N_ContEdges, 1, P1);
05557    if (!N_ContEdges) {
05558       SUMA_SL_Err("No contour edges found.\n"
05559                   "It looks like patches form\n"
05560                   "closed surfaces.\n");
05561       SUMA_RETURN(Vol);
05562    }
05563    if (LocalHead) {
05564       fprintf(SUMA_STDERR,"%s:\n Found %d contour segments.\n", FuncName, N_ContEdges);
05565    }
05566    
05567    
05568    SUMA_LH("Creating Mapping Index...");
05569    NewIndex = (int *)SUMA_malloc(SO1->N_Node * sizeof(int));
05570    if (!NewIndex) {
05571       SUMA_SL_Crit("Failed to allocate for NewIndex");
05572       SUMA_RETURN(Vol);
05573    }
05574    SUMA_INIT_VEC(NewIndex, SO1->N_Node, -1, int);
05575    NodesPerPatch = 0;
05576    for (i=0; i < P1->N_FaceSet; ++i) {
05577       i3 = 3*i;
05578       n = P1->FaceSetList[i3];   if (NewIndex[n] < 0) { NewIndex[n] = NodesPerPatch; ++NodesPerPatch; }   
05579       n = P1->FaceSetList[i3+1]; if (NewIndex[n] < 0) { NewIndex[n] = NodesPerPatch; ++NodesPerPatch; }   
05580       n = P1->FaceSetList[i3+2]; if (NewIndex[n] < 0) { NewIndex[n] = NodesPerPatch; ++NodesPerPatch; }
05581    }
05582    if (LocalHead) {
05583       fprintf(SUMA_STDERR,"%s:\n"
05584                   "Number of nodes in patch (%d), in N_Node (%d)\n"
05585                   , FuncName, NodesPerPatch, N_Node);
05586    }
05587    if (NodesPerPatch != N_Node) {
05588       fprintf(SUMA_STDERR, "Note:\n"
05589                            "Have %d nodes in patch, %d nodes in input.\n", NodesPerPatch, N_Node);
05590    }
05591    
05592    
05593    SUMA_LH("Building composite surface...");
05594    if (UseThisSO) { 
05595       SOc = UseThisSO;
05596       if (SOc->NodeList || SOc->FaceSetList) {
05597          SUMA_SL_Err("You want me to use a filled SurfaceObject structure!\n"
05598                      "How rude!");
05599          SUMA_RETURN(Vol);
05600       }
05601    } else {
05602       SOc = SUMA_Alloc_SurfObject_Struct(1);
05603    }
05604    SOc->N_Node = NodesPerPatch*2;
05605    SOc->N_FaceSet = P1->N_FaceSet*2+2*N_ContEdges;
05606    SOc->NodeDim = 3;
05607    SOc->FaceSetDim = 3;
05608    SOc->NodeList = (float *)SUMA_malloc(SOc->NodeDim*SOc->N_Node*sizeof(float));
05609    SOc->FaceSetList = (int *)SUMA_malloc(SOc->FaceSetDim*SOc->N_FaceSet*sizeof(int));
05610    
05611    for (i=0; i<SO1->N_Node; ++i) {
05612       if (NewIndex[i] >=0) { 
05613          i3 = 3*i;
05614          inew3 = 3 * NewIndex[i];
05615          SOc->NodeList[inew3  ] = SO1->NodeList[i3  ];
05616          SOc->NodeList[inew3+1] = SO1->NodeList[i3+2];
05617          SOc->NodeList[inew3+2] = SO1->NodeList[i3+1];
05618          inew3 = 3 * (NewIndex[i]+NodesPerPatch);
05619          SOc->NodeList[inew3  ] = SO2->NodeList[i3  ];
05620          SOc->NodeList[inew3+1] = SO2->NodeList[i3+2];
05621          SOc->NodeList[inew3+2] = SO2->NodeList[i3+1];
05622       }
05623    }
05624    
05625    cnt = 0;
05626    for (i=0; i<P1->N_FaceSet; ++i) {
05627       i3 = 3*i;
05628       n = P1->FaceSetList[i3  ]; SOc->FaceSetList[cnt] = NewIndex[n]; ++cnt;
05629       n = P1->FaceSetList[i3+1]; SOc->FaceSetList[cnt] = NewIndex[n]; ++cnt;
05630       n = P1->FaceSetList[i3+2]; SOc->FaceSetList[cnt] = NewIndex[n]; ++cnt;                     
05631    }
05632    for (i=0; i<P1->N_FaceSet; ++i) { 
05633       i3 = 3*i;
05634       n = P1->FaceSetList[i3  ]; SOc->FaceSetList[cnt] = NewIndex[n]+NodesPerPatch; ++cnt;
05635       n = P1->FaceSetList[i3+1]; SOc->FaceSetList[cnt] = NewIndex[n]+NodesPerPatch; ++cnt;
05636       n = P1->FaceSetList[i3+2]; SOc->FaceSetList[cnt] = NewIndex[n]+NodesPerPatch; ++cnt;                     
05637    }
05638    
05639    
05640    for (i=0; i<N_ContEdges; ++i) {
05641       n1 = NewIndex[CE[i].n1]; n2 = NewIndex[CE[i].n2];
05642       SOc->FaceSetList[cnt] = n1; ++cnt;
05643       SOc->FaceSetList[cnt] = n2; ++cnt;
05644       SOc->FaceSetList[cnt] = n2+NodesPerPatch; ++cnt;
05645       SOc->FaceSetList[cnt] = n1; ++cnt;
05646       SOc->FaceSetList[cnt] = n2+NodesPerPatch; ++cnt;
05647       SOc->FaceSetList[cnt] = n1+NodesPerPatch; ++cnt;
05648    }
05649    
05650    
05651    if (!SUMA_SurfaceMetrics_eng(SOc, "EdgeList", NULL, 0, SUMAg_CF->DsetList)){
05652       SUMA_SL_Err("Failed to create EdgeList");
05653       SUMA_RETURN(Vol);
05654    }
05655    
05656    
05657    if (SOc->EL->max_N_Hosts != 2 || SOc->EL->min_N_Hosts != 2) {
05658       SUMA_SL_Err("Created surface is not a closed one.\n"
05659                   "Or patches have tessellation problems.");
05660       SUMA_RETURN(Vol);
05661    }
05662    
05663    
05664    if (!SUMA_MakeConsistent(SOc->FaceSetList, SOc->N_FaceSet, SOc->EL, 0, &trouble)) {
05665       SUMA_SL_Err("Failed to make surface consistent");
05666       SUMA_RETURN(Vol);
05667    }
05668    
05669    
05670    SN = SUMA_SurfNorm(SOc->NodeList,  SOc->N_Node, SOc->FaceSetList, SOc->N_FaceSet );
05671    SOc->NodeNormList = SN.NodeNormList;
05672    SOc->FaceNormList = SN.FaceNormList;
05673 
05674    if (!SUMA_SurfaceMetrics_eng(SOc, "PolyArea", NULL, 0, SUMAg_CF->DsetList)){
05675       SUMA_SL_Err("Failed to create EdgeList");
05676       SUMA_RETURN(Vol);
05677    }
05678       
05679    
05680    if (LocalHead) {
05681       fid = fopen("Junk_NodeList.1D", "w");
05682       SUMA_disp_vecmat (SOc->NodeList, SOc->N_Node, SOc->NodeDim, 1, SUMA_ROW_MAJOR, fid, NOPE);
05683       fclose(fid);
05684       fid = fopen("Junk_FaceSetList.1D", "w");
05685       SUMA_disp_vecdmat(SOc->FaceSetList, SOc->N_FaceSet, SOc->FaceSetDim, 1, SUMA_ROW_MAJOR, fid , NOPE);
05686       fclose(fid);
05687    }
05688    
05689    
05690    SUMA_LH("Calculating volume");
05691    Vol = SUMA_Mesh_Volume(SOc, NULL, -1);
05692    if (LocalHead) {
05693       fprintf (SUMA_STDERR,"%s:\n"
05694                            "Volume = %f\n", FuncName, Vol);
05695    }
05696    
05697    
05698    SUMA_LH("Cleanup");
05699    if (P1) SUMA_freePatch(P1); P1 = NULL;
05700    if (NewIndex) SUMA_free(NewIndex); NewIndex = NULL;
05701    if (SOc != UseThisSO) SUMA_Free_Surface_Object(SOc); SOc = NULL;
05702    if (CE) SUMA_free(CE); CE=NULL;
05703    
05704    SUMA_RETURN(Vol);
05705 }
05706 
05707 
05708 
05709 
05710 
05711 
05712 
05713 
05714 
05715 
05716 
05717 
05718 
05719 
05720 
05721 
05722 
05723 
05724 
05725 
05726 
05727 
05728 
05729 
05730 
05731 
05732 
05733 
05734 
05735 
05736 
05737 
05738 
05739 
05740 
05741 
05742 
05743 double SUMA_Mesh_Volume(SUMA_SurfaceObject *SO, int *FSI, int N_FaceSet) 
05744 {
05745    static char FuncName[]={"SUMA_Mesh_Volume"};
05746    double Vol = 0.0, c[3], anx, any, anz, sx, sy, sz, kx, ky, kz, kt;
05747    float *pa = NULL;
05748    int i, fc;
05749    SUMA_Boolean LocalHead = NOPE;
05750    
05751    SUMA_ENTRY;
05752    
05753    if (!SO) { SUMA_SL_Err("NULL SO"); SUMA_RETURN(Vol);  }
05754    if (!SO->FaceNormList) { SUMA_SL_Err("NULL SO->FaceNormList"); SUMA_RETURN(Vol);  }
05755    if (!SO->PolyArea) { 
05756       if (!SUMA_SurfaceMetrics_eng (SO, "PolyArea", NULL, 0, SUMAg_CF->DsetList)) {
05757          SUMA_SL_Err("Failed to compute SO->PolyArea"); SUMA_RETURN(Vol);  
05758       }
05759    }
05760    pa = SO->PolyArea;
05761    
05762    if (FSI || N_FaceSet != -1) {
05763       SUMA_SL_Err("FSI and N_FaceSet are two stupid options never to be used.\nUse NULL and -1, respectively.");
05764       SUMA_RETURN(Vol);
05765    }
05766    
05767    if (!FSI) { 
05768       N_FaceSet = SO->N_FaceSet;    
05769    }
05770 
05771    
05772    
05773    kx = ky = kz = sx = sy = sz = 0.0;
05774    for (i=0; i<N_FaceSet; ++i) {
05775       if (FSI) fc = FSI[i];
05776       else fc = i;
05777       SUMA_FACE_CENTROID(SO, fc, c);
05778       #if 0 
05779          if (LocalHead) fprintf(SUMA_STDERR,"Area: %f , normal (%f, %f, %f)\n", 
05780                pa[fc], SO->FaceNormList[3*fc], SO->FaceNormList[3*fc+1], SO->FaceNormList[3*fc+2]);
05781       #endif
05782       anx = pa[fc] * SO->FaceNormList[3*fc];   kx += anx;  sx += c[0] * anx;
05783       any = pa[fc] * SO->FaceNormList[3*fc+1]; ky += any;  sy += c[1] * any;
05784       anz = pa[fc] * SO->FaceNormList[3*fc+2]; kz += anz;  sz += c[2] * anz;
05785    }
05786    kt = (kx+ky+kz); 
05787 
05788 
05789    if (fabs(kt) < 1e-15) { 
05790       SUMA_SL_Warn("Weight constants sum to ~= 0.\n"
05791                    "Volume measurements may be off.\n"
05792                    "If your surface's axes are along\n"
05793                    "the X, Y and Z directions, as you \n"
05794                    "could have with a box's surface, rotating\n"
05795                    "the surface will solve the problem.");
05796       fprintf(SUMA_STDERR, "%s:\n"
05797                            "kx + ky + kz = kt\n"
05798                            "%f + %f + %f = %f\n"
05799                            "sx, sy, sz = %f, %f, %f\n",
05800                            FuncName, kx, ky, kz, kx+ky+kz, sx, sy, sz);   }
05801    kx /= kt;
05802    ky /= kt;
05803    kz /= kt;
05804    if (LocalHead) {
05805       fprintf(SUMA_STDERR, "%s:\n"
05806                            "%f + %f + %f = %f\n"
05807                            "sx, sy, sz = %f, %f, %f\n",
05808                            FuncName, kx, ky, kz, kx+ky+kz, sx, sy, sz);
05809    }
05810    Vol = kx * sx + ky *sy + kz * sz;
05811    
05812    SUMA_RETURN(Vol);
05813 }
05814 
05815 
05816 
05817 
05818 
05819 
05820 double SUMA_Mesh_Area(SUMA_SurfaceObject *SO, int *FaceSets, int N_FaceSet) 
05821 {
05822    static char FuncName[]={"SUMA_Mesh_Area"};
05823    double A = 0.0, a = 0.0;
05824    int i, i3;
05825    float *n0, *n1, *n2;
05826    SUMA_Boolean LocalHead = NOPE;
05827    
05828    SUMA_ENTRY;
05829 
05830    if (!SO) { SUMA_SL_Err("NULL SO"); SUMA_RETURN(A);  }
05831    if (!SO->FaceSetList) { SUMA_SL_Err("NULL SO->FaceSetList"); SUMA_RETURN(A);  }
05832       
05833    if (!FaceSets ) { 
05834       if (N_FaceSet != -1) {
05835          SUMA_SL_Err("With NULL FaceSets, use -1 for N_FaceSet");
05836          SUMA_RETURN(A);
05837       }
05838       N_FaceSet = SO->N_FaceSet; 
05839       FaceSets = SO->FaceSetList;    
05840    }else {
05841       if (N_FaceSet < 0) {
05842          SUMA_SL_Err("N_FaceSet < 0");
05843          SUMA_RETURN(A);
05844       }
05845    }
05846 
05847    A = 0.0;
05848    if (SO->PolyArea) {
05849       for (i=0;  i<N_FaceSet; ++i) {
05850          i3 = 3*i;
05851          n0 = &(SO->NodeList[3*FaceSets[i3]]);
05852          n1 = &(SO->NodeList[3*FaceSets[i3+1]]);
05853          n2 = &(SO->NodeList[3*FaceSets[i3+2]]);
05854          SUMA_TRI_AREA( n0, n1, n2, a);
05855          SO->PolyArea[i] = (float)a;
05856          A += a;
05857       }
05858    } else {
05859       for (i=0;  i<N_FaceSet; ++i) {
05860          i3 = 3*i;
05861          n0 = &(SO->NodeList[3*FaceSets[i3]]);
05862          n1 = &(SO->NodeList[3*FaceSets[i3+1]]);
05863          n2 = &(SO->NodeList[3*FaceSets[i3+2]]);
05864          SUMA_TRI_AREA( n0, n1, n2, a);
05865          A += a;
05866       }
05867    }
05868    if (LocalHead) {
05869       fprintf(SUMA_STDERR,"%s:\n   A = %f\n", FuncName, A);
05870    }
05871    SUMA_RETURN(A);
05872 }
05873 
05874 
05875 
05876 
05877 
05878 
05879 
05880 
05881 
05882 
05883 
05884 
05885 
05886 
05887 
05888 
05889 
05890 
05891 
05892 
05893 
05894 
05895 
05896 
05897 float * SUMA_Plane_Equation (float * P1, float *P2, float *P3, float *usethisEq)
05898 {
05899    float *Eq;
05900    static char FuncName[] = {"SUMA_Plane_Equation"}; 
05901     
05902    SUMA_ENTRY;
05903    if (usethisEq) Eq = usethisEq;
05904    else Eq = (float *) SUMA_calloc(4,sizeof(float));
05905    if (!Eq)
05906       {
05907          fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
05908          SUMA_RETURN (NULL);
05909       }
05910    
05911    Eq[0] = P1[1] * (P2[2]-P3[2]) 
05912          + P2[1] * (P3[2]-P1[2]) 
05913          + P3[1] * (P1[2]-P2[2]);
05914          
05915    Eq[1] = P1[2] * (P2[0]-P3[0]) 
05916          + P2[2] * (P3[0]-P1[0]) 
05917          + P3[2] * (P1[0]-P2[0]);
05918          
05919    Eq[2] = P1[0] * (P2[1]-P3[1]) 
05920          + P2[0] * (P3[1]-P1[1]) 
05921          + P3[0] * (P1[1]-P2[1]);
05922          
05923    Eq[3] =  - P1[0] * (P2[1] * P3[2] - P3[1] * P2[2]) 
05924             - P2[0] * (P3[1] * P1[2] - P1[1] * P3[2]) 
05925             - P3[0] * (P1[1] * P2[2] - P2[1] * P1[2]);
05926 
05927    SUMA_RETURN (Eq);
05928 }
05929 
05930 
05931 
05932 
05933 
05934 
05935 
05936 
05937 
05938 
05939 
05940 
05941 
05942 
05943 
05944 
05945 
05946 
05947 
05948 
05949 
05950 
05951 
05952 
05953 
05954  
05955 SUMA_SURF_PLANE_INTERSECT *SUMA_Surf_Plane_Intersect (SUMA_SurfaceObject *SO, float *PlaneEq)
05956 {
05957    static char FuncName[]={"SUMA_Surf_Plane_Intersect"};
05958    int  i, k , k3, i3, n1, n2;
05959    float DT_ABVBEL, DT_POSNEG, u;
05960    float *NodePos;
05961    SUMA_SURF_PLANE_INTERSECT *SPI;
05962    struct  timeval start_time, start_time2;
05963    SUMA_Boolean LocalHead = NOPE;
05964    SUMA_Boolean  Hit;
05965    
05966    SUMA_ENTRY;
05967    
05968    
05969    SUMA_etime(&start_time2,0);
05970       
05971    if (LocalHead)   fprintf(SUMA_STDERR, "%s : Determining intersecting segments ...\n", FuncName);
05972    
05973    
05974 
05975 
05976 
05977 
05978 
05979    SPI = SUMA_Allocate_SPI (SO);
05980    if (!SPI) {
05981       fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_Allocate_SPI\n", FuncName);
05982       SUMA_RETURN (SPI);
05983    }
05984    
05985    
05986    NodePos = (float *) SUMA_calloc (SO->N_Node , sizeof(float));
05987 
05988    if (!NodePos )
05989       {
05990          fprintf (SUMA_STDERR, "Error %s: Could not allocate in SUMA_Surf_Plane_Intersect\n", FuncName);
05991          SUMA_free_SPI (SPI); SPI = NULL;
05992          SUMA_RETURN (SPI);
05993       }
05994 
05995       
05996    
05997    SUMA_etime(&start_time,0);
05998                            
05999    
06000    for (k=0;k<SO->N_Node; ++k)
06001       {
06002          k3 = 3*k;
06003          NodePos[k] = PlaneEq[0] * SO->NodeList[k3] + PlaneEq[1] * SO->NodeList[k3+1] 
06004                      +PlaneEq[2] * SO->NodeList[k3+2] + PlaneEq[3] ;
06005       }
06006       
06007    
06008    DT_ABVBEL = SUMA_etime(&start_time,1);
06009                               
06010    
06011    
06012 
06013 
06014 
06015 
06016 
06017    
06018    
06019    SUMA_etime(&start_time,0);
06020    
06021    
06022 
06023 
06024 
06025 
06026    SPI->N_IntersEdges = 0;
06027    SPI->N_IntersTri = 0;
06028    SPI->N_NodesInMesh = 0;
06029    k=0; 
06030    Hit = NOPE;
06031    while (k < SO->EL->N_EL)
06032       {
06033          
06034          
06035    
06036          if (SUMA_SIGN(NodePos[SO->EL->EL[k][0]]) != SUMA_SIGN(NodePos[SO->EL->EL[k][1]]) ) {
06037             Hit = YUP;
06038             
06039             u = -NodePos[SO->EL->EL[k][0]] / (NodePos[SO->EL->EL[k][1]] - NodePos[SO->EL->EL[k][0]]);
06040             i3 = 3 * k;
06041             n1 = 3 * SO->EL->EL[k][0];
06042             n2 = 3 * SO->EL->EL[k][1];
06043             
06044             SPI->IntersNodes[i3] = SO->NodeList[n1] + u * ( SO->NodeList[n2] - SO->NodeList[n1] ); ++i3; ++n2; ++n1;
06045             SPI->IntersNodes[i3] = SO->NodeList[n1] + u * ( SO->NodeList[n2] - SO->NodeList[n1] ); ++i3; ++n2; ++n1;
06046             SPI->IntersNodes[i3] = SO->NodeList[n1] + u * ( SO->NodeList[n2] - SO->NodeList[n1] ); ++i3; ++n2; ++n1;
06047             
06048             
06049 
06050 
06051 
06052                
06053             
06054             SPI->IntersEdges[SPI->N_IntersEdges] = k;
06055             ++SPI->N_IntersEdges;
06056             
06057             
06058             SPI->isEdgeInters[k] = YUP;
06059                   
06060             
06061             if (!SPI->isTriHit[SO->EL->ELps[k][1]]) {
06062                SPI->IntersTri[SPI->N_IntersTri] = SO->EL->ELps[k][1];
06063                ++(SPI->N_IntersTri);
06064                SPI->isTriHit[SO->EL->ELps[k][1]] = YUP;
06065             }
06066             
06067             
06068             if (!SPI->isNodeInMesh[SO->EL->EL[k][0]]) {
06069                SPI->isNodeInMesh[SO->EL->EL[k][0]] = YUP;
06070                ++(SPI->N_NodesInMesh);
06071             }
06072             if (!SPI->isNodeInMesh[SO->EL->EL[k][1]]) {
06073                SPI->isNodeInMesh[SO->EL->EL[k][1]] = YUP;
06074                ++(SPI->N_NodesInMesh);
06075             } 
06076          } else {
06077             Hit = NOPE;
06078          }
06079             
06080             
06081             if (SO->EL->ELps[k][2] > 0) {
06082                if (Hit) { 
06083                   i3 = 3 * k;
06084                   for (i=1; i < SO->EL->ELps[k][2]; ++i) {
06085                      SPI->isEdgeInters[k+i] = YUP;
06086                      n1 = 3 * (k+i);
06087                      SPI->IntersNodes[n1] = SPI->IntersNodes[i3]; ++i3; ++n1;
06088                      SPI->IntersNodes[n1] = SPI->IntersNodes[i3]; ++i3; ++n1;
06089                      SPI->IntersNodes[n1] = SPI->IntersNodes[i3]; ++i3; ++n1;
06090                      
06091 
06092 
06093 
06094                      if (!SPI->isTriHit[SO->EL->ELps[k+i][1]]) {
06095                         SPI->IntersTri[SPI->N_IntersTri] = SO->EL->ELps[k+i][1];
06096                         ++(SPI->N_IntersTri);
06097                         SPI->isTriHit[SO->EL->ELps[k+i][1]] = YUP;   
06098                      }
06099                   }
06100                }
06101                k += SO->EL->ELps[k][2];
06102             } else ++k;
06103       }
06104             
06105       
06106    
06107    DT_POSNEG = SUMA_etime(&start_time,1);
06108    
06109    if (LocalHead) fprintf (SUMA_STDERR, "%s: Found %d intersect segments, %d intersected triangles, %d nodes in mesh (exec time %f + %f = %f secs).\n", 
06110       FuncName, SPI->N_IntersEdges, SPI->N_IntersTri, SPI->N_NodesInMesh, DT_ABVBEL, DT_POSNEG, DT_ABVBEL + DT_POSNEG);
06111    
06112 
06113 if (NodePos) SUMA_free (NodePos);
06114    
06115 
06116 SUMA_RETURN (SPI);
06117 }
06118 
06119 
06120 
06121 
06122 
06123 
06124 
06125 
06126 
06127 
06128 
06129 
06130 
06131 SUMA_ROI_DATUM *SUMA_Surf_Plane_Intersect_ROI (SUMA_SurfaceObject *SO, int Nfrom, int Nto, float *P)
06132 {
06133    static char FuncName[]={"SUMA_Surf_Plane_Intersect_ROI"};
06134    SUMA_ROI_DATUM *ROId=NULL;
06135    SUMA_Boolean LocalHead = NOPE;
06136    int N_left;
06137    SUMA_SURF_PLANE_INTERSECT *SPI = NULL;
06138    SUMA_ROI *ROIe = NULL, *ROIt = NULL, *ROIn = NULL, *ROIts = NULL;
06139    float *Eq = NULL;
06140    
06141    SUMA_Boolean DrawIntersEdges=NOPE; 
06142    SUMA_Boolean DrawIntersTri = NOPE; 
06143    SUMA_Boolean DrawIntersNodeStrip = NOPE;  
06144    SUMA_Boolean DrawIntersTriStrip=NOPE; 
06145    
06146    SUMA_ENTRY;
06147    
06148    
06149    Eq = SUMA_Plane_Equation ( &(SO->NodeList[3*Nfrom]), 
06150                               P,
06151                               &(SO->NodeList[3*Nto]) , NULL);
06152    
06153    if (!Eq) {
06154       fprintf(SUMA_STDOUT,"Error %s: Failed in SUMA_Plane_Equation.\n", FuncName);
06155       SUMA_RETURN(ROId);
06156    } 
06157    
06158    if (LocalHead) fprintf (SUMA_STDERR, "%s: Computing Intersection with Surface.\n", FuncName);
06159    SPI = SUMA_Surf_Plane_Intersect (SO, Eq);
06160    if (!SPI) {
06161       fprintf(SUMA_STDOUT,"Error %s: Failed in SUMA_Surf_Plane_Intersect.\n", FuncName);
06162       SUMA_RETURN(ROId);
06163    }
06164    
06165    if (DrawIntersEdges) {
06166       
06167       ROIe =  SUMA_AllocateROI (SO->idcode_str, SUMA_ROI_EdgeGroup, "SurfPlane Intersection - Edges", SPI->N_IntersEdges, SPI->IntersEdges);
06168       if (!ROIe) {
06169          fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AllocateROI.\n", FuncName);
06170       } else {
06171          if (!SUMA_AddDO (SUMAg_DOv, &SUMAg_N_DOv, (void *)ROIe, ROIO_type, SUMA_LOCAL)) {
06172             fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AddDO.\n", FuncName);
06173          }
06174       }
06175    }
06176    
06177    if (DrawIntersTri) {
06178       
06179       ROIt =  SUMA_AllocateROI (SO->idcode_str, SUMA_ROI_FaceGroup, "SurfPlane Intersection - Triangles", SPI->N_IntersTri, SPI->IntersTri);
06180       if (!ROIt) {
06181          fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AllocateROI.\n", FuncName);
06182       } else {
06183          if (!SUMA_AddDO (SUMAg_DOv, &SUMAg_N_DOv, (void *)ROIt, ROIO_type, SUMA_LOCAL)) {
06184             fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AddDO.\n", FuncName);
06185          }
06186       }
06187    }
06188 
06189    
06190    ROId = SUMA_AllocROIDatum ();
06191    ROId->Type = SUMA_ROI_NodeSegment;
06192 
06193    
06194    N_left = SPI->N_NodesInMesh;
06195    ROId->nPath = SUMA_Dijkstra (SO, Nfrom, Nto, SPI->isNodeInMesh, &N_left, 1, &(ROId->nDistance), &(ROId->N_n));
06196    if (ROId->nDistance < 0 || !ROId->nPath) {
06197       fprintf(SUMA_STDERR,"\aError %s: Failed in fast SUMA_Dijkstra.\n*** Two points are not connected by intersection. Repeat last selection.\n", FuncName);
06198 
06199       
06200       if (SPI) SUMA_free_SPI (SPI); 
06201       SPI = NULL;
06202       if (ROId) SUMA_FreeROIDatum (ROId);
06203       SUMA_RETURN(NULL);   
06204    }
06205    
06206    if (LocalHead) fprintf (SUMA_STDERR, "%s: Shortest inter nodal distance along edges between nodes %d <--> %d (%d nodes) is %f.\n", 
06207       FuncName, Nfrom, Nto, ROId->N_n, ROId->nDistance);
06208    
06209 
06210    #if 0
06211    
06212       
06213 
06214 
06215 
06216 
06217 
06218       
06219       
06220       
06221 
06222       
06223 
06224 
06225 
06226       
06227 
06228 
06229 
06230       
06231       ROId->tPath = SUMA_IntersectionStrip (SO, SPI, ROId->nPath, ROId->N_n, &(ROId->tDistance), 2.5 *ROId->nDistance, &(ROId->N_t));                      
06232       if (!ROId->tPath) {
06233          fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_IntersectionStrip. Proceeding\n", FuncName);
06234          
06235          
06236 
06237       } else {
06238          
06239          {
06240             int *tPath_tmp=NULL, i_tmp=0;
06241             tPath_tmp = (int *)SUMA_calloc (ROId->N_t, sizeof(int));
06242             if (!tPath_tmp) {
06243                SUMA_RegisterMessage (SUMAg_CF->MessageList, "Failed to allocate for tpath_tmp", FuncName, SMT_Critical, SMA_LogAndPopup);
06244                SUMA_RETURN(NULL);
06245             }
06246             for (i_tmp=0; i_tmp<ROId->N_t; ++i_tmp) tPath_tmp[i_tmp] = ROId->tPath[i_tmp];
06247             SUMA_free(ROId->tPath);
06248             ROId->tPath = tPath_tmp;
06249          } 
06250 
06251          fprintf (SUMA_STDERR, "%s: Shortest inter nodal distance along surface between nodes %d <--> %d is %f.\nTiangle 1 is %d\n", 
06252             FuncName, Nfrom, Nto, ROId->tDistance, ROId->tPath[0]);
06253 
06254          if (DrawIntersTriStrip) {
06255             
06256             ROIts =  SUMA_AllocateROI (SO->idcode_str, SUMA_ROI_FaceGroup, "SurfPlane Intersection - Triangles- Shortest", ROId->N_t, ROId->tPath);
06257             if (!ROIts) {
06258                fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AllocateROI.\n", FuncName);
06259                if (ROIn) SUMA_freeROI(ROIn);
06260                if (ROIts) SUMA_freeROI(ROIts);
06261                if (ROId) SUMA_FreeROIDatum (ROId);
06262                SUMA_RETURN(NULL);   
06263             }
06264             if (!SUMA_AddDO (SUMAg_DOv, &SUMAg_N_DOv, (void *)ROIts, ROIO_type, SUMA_LOCAL)) {
06265                fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AddDO.\n", FuncName);
06266                if (ROIn) SUMA_freeROI(ROIn);
06267                if (ROIts) SUMA_freeROI(ROIts);
06268                if (ROId) SUMA_FreeROIDatum (ROId);
06269                SUMA_RETURN(NULL);
06270             }
06271          }
06272 
06273          if (ROId->nPath && DrawIntersNodeStrip) {
06274             #if 0
06275                
06276                for (ii=0; ii < ROId->N_n; ++ii) fprintf(SUMA_STDERR," %d\t", ROId->nPath[ii]);
06277             #endif
06278 
06279             
06280             ROIn =  SUMA_AllocateROI (SO->idcode_str, SUMA_ROI_NodeGroup, "SurfPlane Intersection - Nodes", ROId->N_n, ROId->nPath);
06281             if (!ROIn) {
06282                fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AllocateROI.\n", FuncName);
06283                if (ROIn) SUMA_freeROI(ROIn);
06284                if (ROIts) SUMA_freeROI(ROIts);
06285                if (ROId) SUMA_FreeROIDatum (ROId);
06286                SUMA_RETURN(NULL);
06287             }
06288             if (!SUMA_AddDO (SUMAg_DOv, &SUMAg_N_DOv, (void *)ROIn, ROIO_type, SUMA_LOCAL)) {
06289                fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AddDO.\n", FuncName);
06290                if (ROIn) SUMA_freeROI(ROIn);
06291                if (ROIts) SUMA_freeROI(ROIts);
06292                if (ROId) SUMA_FreeROIDatum (ROId);
06293                SUMA_RETURN(NULL);
06294             }
06295 
06296          }
06297       }                        
06298    #endif
06299    
06300    if (LocalHead) fprintf(SUMA_STDERR,"%s: Freeing Eq...\n", FuncName);
06301    if (Eq) SUMA_free(Eq);
06302 
06303    if (LocalHead) fprintf(SUMA_STDERR,"%s: Freeing SPI...\n", FuncName);
06304    if (SPI) SUMA_free_SPI (SPI);
06305    
06306    if (LocalHead) fprintf(SUMA_STDERR,"%s:Done Freeing...\n", FuncName);      
06307    
06308    SUMA_RETURN(ROId);
06309 }
06310 
06311 
06312 
06313 
06314 
06315 
06316 
06317 
06318 
06319 
06320 
06321 
06322 
06323 
06324 
06325 
06326 
06327 
06328 
06329 
06330 
06331 #define SUMA_MAX_BRANCHES 300
06332 
06333 
06334 SUMA_TRI_BRANCH* SUMA_AssignTriBranch (SUMA_SurfaceObject *SO, SUMA_SURF_PLANE_INTERSECT *SPI, 
06335                                        int Nx, int *BranchCount, SUMA_Boolean DoCopy)
06336 {
06337    static char FuncName[]={"SUMA_AssignTriBranch"};
06338    int *IntersEdgesCopy = NULL, N_IntersEdgesCopy, i_Branch, E1, kedge, i, 
06339          N_iBranch[SUMA_MAX_BRANCHES], NBlist[SUMA_MAX_BRANCHES], iBranch = 0, 
06340          N_Branch, Bcnt, ilist, j, ivisit, *VisitationOrder, TriCheck;
06341    SUMA_Boolean Local_IntersEdgesCopy = NOPE;
06342    int *TriBranch = NULL; 
06343 
06344 
06345    SUMA_TRI_BRANCH *Bv = NULL;
06346    SUMA_Boolean LocalHead = NOPE;
06347    
06348    SUMA_ENTRY;
06349 
06350 
06351    i_Branch = 0;
06352    
06353    
06354 
06355 
06356 
06357    VisitationOrder = (int *)SUMA_calloc (SO->N_FaceSet, sizeof (int)); 
06358    TriBranch = (int *)SUMA_calloc (SO->EL->N_EL / 3,  sizeof(int));
06359    
06360    if (!VisitationOrder || !TriBranch) {
06361       fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
06362       if (TriBranch) SUMA_free(TriBranch);
06363       if (VisitationOrder) SUMA_free(VisitationOrder);
06364       SUMA_RETURN (NULL);   
06365    }
06366    
06367    N_IntersEdgesCopy = SPI->N_IntersEdges;
06368    if (DoCopy) {
06369       IntersEdgesCopy = (int *) SUMA_calloc (N_IntersEdgesCopy, sizeof (int));
06370       Local_IntersEdgesCopy = YUP;
06371       for (i=0; i < N_IntersEdgesCopy; ++i) {
06372          IntersEdgesCopy[i] = SPI->IntersEdges[i];
06373       }
06374    }else {
06375       Local_IntersEdgesCopy = NOPE;
06376       IntersEdgesCopy = SPI->IntersEdges;
06377    }
06378 
06379    if (!IntersEdgesCopy) {
06380      fprintf (SUMA_STDERR, "Error %s: Failed to allocate for or receive IntersEdgesCopy.\n", FuncName);
06381      if (TriBranch) SUMA_free(TriBranch);
06382      if (VisitationOrder) SUMA_free(VisitationOrder);
06383      SUMA_RETURN (NULL);
06384    }
06385 
06386    ivisit = 0;
06387    while (N_IntersEdgesCopy) {
06388    
06389       if (!i_Branch && Nx >= 0) {
06390          
06391          E1 = -1;
06392          i=0;
06393          while (i < N_IntersEdgesCopy && E1 < 0) {
06394             if ( (SO->EL->EL[IntersEdgesCopy[i]][0] == Nx) || (SO->EL->EL[IntersEdgesCopy[i]][1] == Nx) ) {
06395                E1 = IntersEdgesCopy[i];
06396                kedge = i;
06397             }  
06398             ++i;
06399          }
06400       }else {
06401          
06402          
06403          E1 = SUMA_Find_Edge_Nhost (SO->EL, IntersEdgesCopy, N_IntersEdgesCopy, &kedge, 1);
06404       }      
06405 
06406       if (E1 < 0) { 
06407             kedge = 0;
06408             E1 = IntersEdgesCopy[kedge];
06409             if (LocalHead) fprintf (SUMA_STDERR, "%s: No 1 host edge edge found.\n", FuncName);
06410       }else {
06411             if (LocalHead) fprintf (SUMA_STDERR, "%s: Found edge.\n", FuncName);
06412       }
06413       
06414       
06415       --(N_IntersEdgesCopy);
06416       if (LocalHead) fprintf (SUMA_STDERR, "%s: kedge = %d, N_IntersEdgesCopy = %d.\n", FuncName, kedge, N_IntersEdgesCopy);
06417       IntersEdgesCopy[kedge] = IntersEdgesCopy[N_IntersEdgesCopy];
06418 
06419       
06420       ++i_Branch;   
06421       if (i_Branch > SUMA_MAX_BRANCHES-1) {
06422          fprintf (SUMA_STDERR, "Error %s: No more than %d branches allowed.\n", FuncName, SUMA_MAX_BRANCHES);
06423          SUMA_RETURN (NULL); 
06424       } 
06425       
06426       
06427       if (LocalHead) fprintf (SUMA_STDERR, "%s: Marking triangle %d with branch %d.\n", FuncName, SO->EL->ELps[E1][1], i_Branch);
06428       TriBranch[SO->EL->ELps[E1][1]] = i_Branch;
06429       VisitationOrder[ivisit] = SO->EL->ELps[E1][1]; ++ivisit;
06430       
06431       if (LocalHead) fprintf (SUMA_STDERR, "%s: Called recursive SUMA_Mark_Tri.\n", FuncName);
06432       if (!SUMA_Mark_Tri (SO->EL, E1, i_Branch, TriBranch, IntersEdgesCopy, &(N_IntersEdgesCopy), VisitationOrder, &ivisit)) {
06433          fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_Mark_Tri.\n", FuncName);
06434       }
06435       if (LocalHead) fprintf (SUMA_STDERR, "%s: Returned from recursive SUMA_Mark_Tri.\n", FuncName);
06436 
06437       
06438    }
06439 
06440    if (Local_IntersEdgesCopy) {
06441       if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing IntersEdgesCopy.\n", FuncName);
06442       SUMA_free(IntersEdgesCopy); 
06443    }else {
06444       
06445       SPI->N_IntersEdges = N_IntersEdgesCopy;
06446    }
06447 
06448    
06449 
06450    N_Branch = i_Branch;
06451 
06452    
06453    for (i=0; i <= N_Branch; ++i) N_iBranch[i] = 0; 
06454    if (LocalHead) fprintf (SUMA_STDERR, "%s: Searching all %d intersected triangles.\n", FuncName, SPI->N_IntersTri);
06455    Bcnt = 0;
06456    for (i=0; i < SO->N_FaceSet; ++i) {
06457       if (TriBranch[i]) {
06458          
06459          ++Bcnt;
06460          N_iBranch[TriBranch[i]] = N_iBranch[TriBranch[i]] + 1;
06461       }
06462    }
06463    
06464    #if 0
06465       fprintf (SUMA_STDERR, "Values in N_iBranch, idiot proof:\n");
06466       SUMA_disp_dvect (N_iBranch, N_Branch+1);
06467       fprintf (SUMA_STDERR, "\n");
06468    #endif
06469    
06470    if (LocalHead) fprintf (SUMA_STDERR, "%s: Found %d triangles belonging to a branch out of %d intersected triangles.\n", FuncName, Bcnt, SPI->N_IntersTri);
06471      
06472    
06473    Bv = (SUMA_TRI_BRANCH *) SUMA_malloc (sizeof(SUMA_TRI_BRANCH)*(N_Branch+1)); 
06474    if (!Bv) {
06475       fprintf (SUMA_STDERR, "Error %s: Could not allocate for Bv.\n", FuncName);
06476       SUMA_RETURN (NULL);
06477    }
06478    
06479    
06480    for (i=0; i<= N_Branch; ++i) { 
06481       Bv[i].list = NULL;
06482       Bv[i].N_list = 0;
06483    } 
06484    
06485    Bcnt = 0;
06486    for (i=0; i<= N_Branch; ++i) { 
06487       if (N_iBranch[i]) {
06488          
06489          if (LocalHead) fprintf (SUMA_STDERR, "%s: Allocating for %d elements, Old Branch %d, New Branch %d.\n", FuncName, N_iBranch[i], i, Bcnt); 
06490          Bv[Bcnt].list = (int *) SUMA_calloc (N_iBranch[i]+1, sizeof(int));
06491          Bv[Bcnt].N_list = N_iBranch[i];
06492          Bv[Bcnt].iBranch = Bcnt;
06493          NBlist[i] = Bcnt; 
06494          ++Bcnt;
06495       }
06496       
06497    }
06498    
06499    
06500    *BranchCount = Bcnt;
06501    
06502    
06503    if (LocalHead) fprintf (SUMA_STDERR, "%s: Filling up branches...\n", FuncName);
06504    for (i=0; i <= N_Branch; ++i) N_iBranch[i] = 0; 
06505    for (i=0; i < SPI->N_IntersTri; ++i) { 
06506       TriCheck = TriBranch[VisitationOrder[i]]; 
06507       if (TriCheck) {
06508          Bcnt = NBlist[TriCheck]; 
06509          #if 0
06510          fprintf (SUMA_STDERR,"%s: Tricheck = %d\n", FuncName, TriCheck); */
06511          if (Bcnt >= *BranchCount) {
06512             fprintf (SUMA_STDERR, "\aError %s: BranchCount = %d <= Bcnt = %d.\n", FuncName, *BranchCount, Bcnt);
06513          }
06514          if (N_iBranch[Bcnt] >= Bv[Bcnt].N_list) {
06515             fprintf (SUMA_STDERR, "\aError %s: Bcnt = %d. N_iBranch[Bcnt] = %d >= Bv[Bcnt].N_list = %d\n", FuncName, Bcnt, N_iBranch[Bcnt], Bv[Bcnt].N_list);
06516          }
06517          #endif
06518          Bv[Bcnt].list[N_iBranch[Bcnt]] = VisitationOrder[i]; 
06519          N_iBranch[Bcnt] += 1; 
06520       }
06521    }
06522    
06523    if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing ...\n", FuncName);
06524    if (VisitationOrder) SUMA_free(VisitationOrder);
06525    if (TriBranch) SUMA_free(TriBranch);
06526    SUMA_RETURN (Bv);    
06527 }
06528 
06529 
06530 
06531 
06532 SUMA_Boolean SUMA_show_STB (SUMA_TRI_BRANCH *B, FILE *Out)
06533 {
06534    static char FuncName[]={"SUMA_show_STB"};
06535    int i;
06536    
06537    SUMA_ENTRY;
06538   
06539    if (!Out) Out = SUMA_STDERR;
06540    
06541    if (!B) {
06542       fprintf (Out, "%s: Empy structure.\n", FuncName);
06543    }
06544    
06545    fprintf (Out, "%s:\tBranch #%d. %d elements in list\nlist:\t", FuncName, B->iBranch, B->N_list);
06546    for (i=0; i < B->N_list; ++i) {
06547       fprintf (Out, "%d\t", B->list[i]);
06548    }
06549    fprintf (Out, "\n");
06550    
06551    SUMA_RETURN (YUP);
06552 }
06553 
06554 
06555 
06556 
06557 
06558 void SUMA_free_STB (SUMA_TRI_BRANCH *Bv, int N_Bv) 
06559 {
06560 
06561    static char FuncName[]={"SUMA_free_STB"};
06562    int i;
06563    
06564    SUMA_ENTRY;
06565    
06566    for (i=0; i < N_Bv; ++i) {
06567       if (Bv[i].list) SUMA_free(Bv[i].list);
06568    }
06569    if (Bv) SUMA_free(Bv);
06570    
06571    SUMA_RETURNe;
06572     
06573 }
06574 
06575 
06576 
06577 
06578 
06579 
06580 
06581 
06582 
06583 
06584 SUMA_SURF_PLANE_INTERSECT * SUMA_Allocate_SPI (SUMA_SurfaceObject *SO) 
06585 {
06586    static char FuncName[]={"SUMA_Allocate_SPI"};
06587    int i;
06588    SUMA_SURF_PLANE_INTERSECT *SPI = NULL;
06589    
06590    SUMA_ENTRY;
06591    
06592    SPI = (SUMA_SURF_PLANE_INTERSECT *) SUMA_malloc(sizeof(SUMA_SURF_PLANE_INTERSECT));
06593    if (!SPI) {
06594       fprintf (SUMA_STDERR, "Error %s: Could not allocate for SPI\n", FuncName);
06595       SUMA_RETURN (SPI);
06596    }
06597    
06598    SPI->IntersEdges = (int *) SUMA_calloc (SO->EL->N_EL, sizeof(int)); 
06599    SPI->IntersNodes = (float *) SUMA_calloc (3 * SO->EL->N_EL, sizeof(float));
06600    SPI->isEdgeInters = (SUMA_Boolean *) SUMA_calloc (SO->EL->N_EL, sizeof(SUMA_Boolean));
06601    SPI->IntersTri = (int *) SUMA_calloc (SO->N_FaceSet, sizeof(int));
06602    SPI->isNodeInMesh = (SUMA_Boolean *) SUMA_calloc (SO->N_Node, sizeof(SUMA_Boolean));
06603    SPI->isTriHit = (SUMA_Boolean *) SUMA_calloc (SO->N_FaceSet, sizeof(SUMA_Boolean));
06604 
06605    if (!SPI->IntersEdges || !SPI->IntersTri || !SPI->IntersNodes || !SPI->isTriHit || !SPI->isEdgeInters)
06606       {
06607          fprintf (SUMA_STDERR, "Error %s: Could not allocate \n", FuncName);
06608          SUMA_RETURN (SPI);
06609       }
06610    
06611    SPI->N_IntersEdges = 0;
06612    SPI->N_IntersTri = 0;
06613    SPI->N_NodesInMesh = 0;  
06614    SUMA_RETURN (SPI);
06615 }
06616 
06617 
06618 
06619 
06620 void SUMA_free_SPI (SUMA_SURF_PLANE_INTERSECT *SPI)
06621 {
06622    static char FuncName[]={"SUMA_free_SPI"};
06623    
06624    SUMA_ENTRY;
06625    
06626    if (!SPI) SUMA_RETURNe;
06627    if (SPI->IntersTri) SUMA_free(SPI->IntersTri);
06628    if (SPI->IntersNodes) SUMA_free(SPI->IntersNodes);
06629    if (SPI->IntersEdges) SUMA_free(SPI->IntersEdges);
06630    if (SPI->isNodeInMesh) SUMA_free(SPI->isNodeInMesh); 
06631    if (SPI->isTriHit) SUMA_free (SPI->isTriHit);
06632    if (SPI->isEdgeInters) SUMA_free (SPI->isEdgeInters);
06633      
06634    if (SPI) SUMA_free(SPI);
06635    
06636    SUMA_RETURNe;
06637 }
06638 
06639 
06640 
06641 
06642 SUMA_Boolean SUMA_Show_SPI (SUMA_SURF_PLANE_INTERSECT *SPI, FILE * Out, SUMA_SurfaceObject *SO)
06643 {
06644    static char FuncName[]={"SUMA_Show_SPI"};
06645    int i;
06646    
06647    SUMA_ENTRY;
06648    
06649    if (!Out) Out = SUMA_STDERR;
06650    
06651    if (!SPI) {
06652       fprintf (Out,"Error %s: NULL POINTER.\n", FuncName);
06653    }
06654    
06655    fprintf (Out,"Intersection Edges: %d\n[", SPI->N_IntersEdges);
06656    for (i=0; i < SPI->N_IntersEdges; ++i) {
06657       fprintf (Out, "%d, %d\n", SO->EL->EL[SPI->IntersEdges[i]][0], SO->EL->EL[SPI->IntersEdges[i]][1]);
06658    }
06659    fprintf (Out," ]\n");
06660    
06661    fprintf (Out,"Intersection Nodes: %d\n[", SPI->N_IntersEdges);
06662    for (i=0; i < SO->EL->N_EL; ++i) {
06663       if (SPI->isEdgeInters[i]) fprintf (Out, "%f, %f, %f, ", SPI->IntersNodes[3*i], SPI->IntersNodes[3*i+1], SPI->IntersNodes[3*i+2]);
06664    }
06665    fprintf (Out," ]\n");
06666    
06667    fprintf (Out,"Intersected Triangles: %d\n[", SPI->N_IntersTri);
06668    for (i=0; i < SPI->N_IntersTri; ++i) {
06669       fprintf (Out, "t%d\t", SPI->IntersTri[i]);
06670    }
06671    fprintf (Out," ]\n");
06672    SUMA_RETURN(YUP);
06673 }
06674 
06675 #define NO_LOG
06676 SUMA_Boolean SUMA_Mark_Tri (SUMA_EDGE_LIST  *EL, int E1, int iBranch, int *TriBranch, int *IsInter, int *N_IsInter, int *VisitationOrder, int *ivisit)
06677 {
06678    static char FuncName[]={"SUMA_Mark_Tri"};
06679    int Tri = -1, Found, k, kedge = 0, E2, Ntri = 0;
06680    static int In = 0;
06681    SUMA_Boolean LocalHead = NOPE;
06682    
06683    
06684    
06685    
06686    ++In;
06687    if (LocalHead) fprintf (SUMA_STDERR, "%s: Entered #%d.\n", FuncName, In);
06688    
06689    
06690    if (EL->ELps[E1][2] != 2) { 
06691       
06692       if (LocalHead) fprintf (SUMA_STDERR, "%s: reached end of branch.\n", FuncName);
06693       kedge = 0;
06694       Found = NOPE;
06695       while (!Found && kedge < *N_IsInter) {
06696          if (IsInter[kedge] == E1) {
06697             Found = YUP;
06698             *N_IsInter = *N_IsInter - 1;
06699             IsInter[kedge] = IsInter[*N_IsInter];
06700          } else ++kedge;
06701       }
06702       return (YUP);
06703    }else {
06704       Tri = EL->ELps[E1][1];
06705       if (TriBranch[Tri]) { 
06706          Tri = EL->ELps[E1+1][1];
06707       }
06708       if (LocalHead) fprintf (SUMA_STDERR, "%s: moving on to triangle %d.\n", FuncName, Tri);
06709    }
06710    
06711    if (!TriBranch[Tri]) { 
06712       
06713       TriBranch[Tri] = iBranch;
06714       VisitationOrder[*ivisit] = Tri;
06715       ++(*ivisit);
06716       
06717       Found = NOPE; 
06718       k = 0;
06719       while (!Found && k < 3) {
06720          E2 = EL->Tri_limb[Tri][k]; 
06721          if (LocalHead) {
06722             fprintf (SUMA_STDERR, "%s: Trying edge E2 %d (%d %d), tiangle %d, edge %d.\n", 
06723                      FuncName, E2, EL->EL[E2][0], EL->EL[E2][1], Tri, k);
06724          }
06725          while (EL->ELps[E2][2] < 0) { 
06726             E2--;
06727          }
06728          if (LocalHead) fprintf (SUMA_STDERR, "%s: E2 changed to %d. E1 is %d\n", FuncName, E2, E1);
06729          if (E2 != E1) {
06730             
06731             kedge = 0;
06732             while (!Found && kedge < *N_IsInter) {
06733                if (IsInter[kedge] == E2) {
06734                   Found = YUP;
06735                   if (LocalHead) fprintf (SUMA_STDERR, "%s: E2 is intersected.\n", FuncName);
06736                }
06737                else ++kedge;
06738             }
06739          }
06740          ++k;
06741       }
06742       
06743       if (!Found) {
06744          fprintf (SUMA_STDERR, "Error %s: No second edge found.\n", FuncName);
06745          return (NOPE);
06746       } else {
06747          if (LocalHead) fprintf (SUMA_STDERR, "%s: Removing E2 from List and calling SUMA_Mark_Tri.\n", FuncName);
06748          
06749          *N_IsInter = *N_IsInter - 1;
06750          IsInter[kedge] = IsInter[*N_IsInter];
06751          
06752          
06753          if (!SUMA_Mark_Tri (EL, E2, iBranch, TriBranch, IsInter, N_IsInter, VisitationOrder, ivisit)) {
06754             fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_Mark_Tri.\n", FuncName);
06755             return (NOPE);
06756          } 
06757          return (YUP);
06758       }
06759    } else {
06760       if (TriBranch[Tri] != iBranch) {
06761          fprintf (SUMA_STDERR, "\a%s: Branches colliding, Must weld %d to %d.\n", FuncName, iBranch, TriBranch[Tri]);
06762          
06763           
06764       }
06765       
06766       if (LocalHead) fprintf (SUMA_STDERR, "%s: End of branch. Returning.\n", FuncName);
06767       return (YUP);
06768    }
06769    
06770    fprintf (SUMA_STDERR, "Error %s: Should not be here.\n", FuncName);
06771    return (NOPE);
06772 }
06773 
06774 
06775 
06776 
06777 
06778 
06779 
06780 
06781 
06782 
06783 
06784 
06785 
06786 
06787 int SUMA_Find_Edge_Nhost (SUMA_EDGE_LIST  *EL, int *IsInter, int N_IsInter, int *i, int Nhost)
06788 {
06789    static char FuncName[]={"SUMA_Find_Edge_Nhost"};
06790    
06791    SUMA_ENTRY;
06792 
06793    for (*i=0; *i < N_IsInter; ++(*i)) {
06794       if (EL->ELps[IsInter[*i]][2] == Nhost) SUMA_RETURN (IsInter[*i]);
06795    }
06796    
06797    SUMA_RETURN (-1);
06798 
06799 }
06800 
06801 
06802 
06803 
06804 
06805 
06806 
06807 
06808 
06809 
06810 
06811 
06812 
06813 
06814 
06815 
06816 
06817 
06818 
06819 
06820 
06821 
06822 
06823 
06824 
06825 
06826 
06827 
06828 
06829 
06830 
06831 
06832 
06833 
06834 
06835 #define LARGE_NUM 9e300
06836  
06837 int * SUMA_Dijkstra (SUMA_SurfaceObject *SO, int Nx, int Ny, SUMA_Boolean *isNodeInMesh, int *N_isNodeInMesh, int Method_Number, float *Lfinal, int *N_Path)
06838 {
06839    static char FuncName[] = {"SUMA_Dijkstra"};
06840    SUMA_Boolean LocalHead = NOPE;
06841    float *L = NULL, Lmin = -1.0, le = 0.0, DT_DIJKSTRA;
06842    int i, iw, iv, v, w, N_Neighb, *Path = NULL;
06843    struct  timeval  start_time;
06844    SUMA_DIJKSTRA_PATH_CHAIN *DC = NULL, *DCi, *DCp;
06845    SUMA_Boolean Found = NOPE;
06846    
06847    int N_Lmins, *vLmins, *vLocInLmins, iLmins, ReplacingNode, ReplacedNodeLocation;
06848    float *Lmins; 
06849    
06850    
06851    SUMA_ENTRY;
06852    
06853    *Lfinal = -1.0;
06854    *N_Path = 0;
06855    
06856    
06857    if (!isNodeInMesh[Nx]) {
06858       fprintf (SUMA_STDERR,"\aError %s: Node %d (Nx) is not in mesh.\n", FuncName, Nx);
06859       SUMA_RETURN (NULL);
06860    }  
06861    if (!isNodeInMesh[Ny]) {
06862       fprintf (SUMA_STDERR,"\aError %s: Node %d (Ny) is not in mesh.\n", FuncName, Ny);
06863       SUMA_RETURN (NULL);
06864    }
06865 
06866    if (!SO->FN) {
06867       fprintf (SUMA_STDERR, "Error %s: SO does not have FN structure.\n", FuncName);
06868       SUMA_RETURN (NULL);
06869    }
06870 
06871    if (LocalHead) {
06872       
06873       SUMA_etime(&start_time,0);      
06874    }
06875    
06876    
06877    DC = (SUMA_DIJKSTRA_PATH_CHAIN *) SUMA_malloc (sizeof(SUMA_DIJKSTRA_PATH_CHAIN) * SO->N_Node);
06878    if (!DC) {
06879       fprintf (SUMA_STDERR, "Error %s: Could not allocate. \n", FuncName);
06880       SUMA_RETURN (NULL);
06881    }
06882    
06883    switch (Method_Number) {
06884    
06885       case 0:  
06886          
06887          L = (float *) SUMA_calloc (SO->N_Node, sizeof (float));
06888          if (!L) {
06889             fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
06890             SUMA_free(DC);
06891             SUMA_RETURN (NULL);
06892          }
06893 
06894          
06895          for (i=0; i < SO->N_Node; ++i) {
06896             L[i] = LARGE_NUM;   
06897             DC[i].Previous = NULL;
06898          }
06899          
06900          L[Nx] = 0.0;
06901          Lmin = 0.0;
06902          v = Nx;
06903          *Lfinal = -1.0;
06904          
06905          DC[Nx].Previous = NULL;
06906          DC[Nx].node = Nx;
06907          DC[Nx].le = 0.0;
06908          DC[Nx].order = 0;
06909          *N_Path = 0;
06910          
06911          do {
06912             
06913             
06914 
06915             SUMA_MIN_LOC_VEC(L, SO->N_Node, Lmin, v);   
06916             if (!isNodeInMesh[v]) {
06917                fprintf (SUMA_STDERR, "\aERROR %s: Dijkstra derailed. v = %d, Lmin = %f\n. Try another point.", FuncName, v, Lmin);
06918                SUMA_free (L);
06919                SUMA_free(DC);
06920                SUMA_RETURN (NULL); 
06921             }
06922             if (v == Ny) {
06923                if (LocalHead) fprintf (SUMA_STDERR, "%s: Done.\n", FuncName);
06924                *Lfinal = L[v];
06925                Found = YUP;
06926             } else {
06927                N_Neighb = SO->FN->N_Neighb[v];
06928                for (i=0; i < N_Neighb; ++i) {
06929                   w = SO->FN->FirstNeighb[v][i];
06930                   if (isNodeInMesh[w]) {
06931                      iw = 3*w;
06932                      iv = 3*v;
06933                      le = sqrt ( (SO->NodeList[iw] - SO->NodeList[iv]) * (SO->NodeList[iw] - SO->NodeList[iv]) +
06934                                  (SO->NodeList[iw+1] - SO->NodeList[iv+1]) * (SO->NodeList[iw+1] - SO->NodeList[iv+1]) +
06935                                  (SO->NodeList[iw+2] - SO->NodeList[iv+2]) * (SO->NodeList[iw+2] - SO->NodeList[iv+2]) );
06936                      if (L[w] > L[v] + le ) {
06937                         L[w] = L[v] + le;  
06938                         
06939                         DCp = &(DC[v]); 
06940                         DC[w].Previous = (void *) DCp;
06941                         DC[w].le = le;
06942                         DC[w].node = w;
06943                         DC[w].order = DCp->order + 1;
06944                      } 
06945                   }
06946                }
06947 
06948                
06949 
06950                isNodeInMesh[v] = NOPE;
06951                *N_isNodeInMesh -= 1;
06952                L[v] = LARGE_NUM; 
06953                Found = NOPE;
06954             }
06955          } while (*N_isNodeInMesh > 0 && !Found);
06956 
06957          if (!Found) {
06958             fprintf (SUMA_STDERR, "Error %s: No more nodes in mesh, failed to reach target.\n", FuncName);
06959             SUMA_free (L);
06960             SUMA_free(DC);
06961             SUMA_RETURN (NULL);
06962          }else {
06963             if (LocalHead) fprintf (SUMA_STDERR, "%s: Path between Nodes %d and %d is %f.\n", FuncName, Nx, Ny, *Lfinal);
06964          }
06965 
06966 
06967          if (LocalHead) {
06968             
06969             DT_DIJKSTRA = SUMA_etime(&start_time,1);
06970             fprintf (SUMA_STDERR, "%s: Method 1- Elapsed time in function %f seconds.\n", FuncName, DT_DIJKSTRA);
06971          }
06972 
06973          SUMA_free(L);
06974          break;
06975 
06976       case 1:  
06977          if (LocalHead) {
06978             
06979             SUMA_etime(&start_time,0);      
06980          }
06981 
06982          
06983          L = (float *) SUMA_calloc (SO->N_Node, sizeof (float));        
06984          Lmins = (float *) SUMA_calloc (SO->N_Node, sizeof (float));    
06985          vLmins = (int *) SUMA_calloc (SO->N_Node, sizeof (int));       
06986          vLocInLmins = (int *) SUMA_calloc (SO->N_Node, sizeof (int));  
06987 
06988          if (!L || !Lmins || !vLmins || !vLocInLmins) {
06989             fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
06990             SUMA_RETURN (NULL);
06991          }
06992 
06993          
06994          for (i=0; i < SO->N_Node; ++i) {
06995             L[i] = LARGE_NUM;
06996             Lmins[i] = LARGE_NUM;   
06997             vLocInLmins[i] = -1;            
06998             DC[i].Previous = NULL;
06999          }
07000 
07001          
07002          L[Nx] = 0.0;
07003          *Lfinal = -1.0;
07004 
07005          
07006          Lmins[0] = 0.0;
07007          vLmins[0] = Nx;
07008          vLocInLmins[Nx] = 0;
07009          N_Lmins = 1;
07010 
07011          
07012          DC[Nx].Previous = NULL;
07013          DC[Nx].node = Nx;
07014          DC[Nx].le = 0.0;
07015          DC[Nx].order = 0;
07016          *N_Path = 0;
07017          
07018          
07019          if (LocalHead) fprintf (SUMA_STDERR, "%s: about to MIN_LOC ....N_isNodeInMesh = %d\n", FuncName, *N_isNodeInMesh);
07020          do {
07021             
07022             SUMA_MIN_LOC_VEC(Lmins, N_Lmins, Lmin, iLmins);   
07023             v = vLmins[iLmins];   
07024             if (!isNodeInMesh[v]) {
07025                fprintf (SUMA_STDERR, "\aERROR %s: Dijkstra derailed. v = %d, Lmin = %f\n. Try another point.", FuncName, v, Lmin);
07026                SUMA_free (L);
07027                SUMA_free (Lmins);
07028                SUMA_free(vLmins);
07029                SUMA_free(vLocInLmins);
07030                SUMA_free(DC);
07031                SUMA_RETURN (NULL);
07032             }
07033             #ifdef LOCALDEBUG
07034                fprintf (SUMA_STDERR, "%s: Node v = %d.\n", FuncName, v);
07035             #endif
07036             if (v == Ny) {
07037                if (LocalHead) fprintf (SUMA_STDERR, "%s: Done.\n", FuncName);
07038                *Lfinal = L[v];
07039                Found = YUP;
07040             } else {
07041                N_Neighb = SO->FN->N_Neighb[v];
07042                for (i=0; i < N_Neighb; ++i) {
07043                   w = SO->FN->FirstNeighb[v][i];
07044                   if (isNodeInMesh[w]) {
07045                      iw = 3*w;
07046                      iv = 3*v;
07047                      le = sqrt ( (SO->NodeList[iw] - SO->NodeList[iv]) * (SO->NodeList[iw] - SO->NodeList[iv]) +
07048                                  (SO->NodeList[iw+1] - SO->NodeList[iv+1]) * (SO->NodeList[iw+1] - SO->NodeList[iv+1]) +
07049                                  (SO->NodeList[iw+2] - SO->NodeList[iv+2]) * (SO->NodeList[iw+2] - SO->NodeList[iv+2]) );
07050                      if (L[w] > L[v] + le ) {
07051                         #ifdef LOCALDEBUG
07052                            fprintf (SUMA_STDERR, "%s: L[%d]=%f > L[%d] = %f + le = %f.\n", FuncName, w, L[w], v, L[v], le);
07053                         #endif
07054                         L[w] = L[v] + le; 
07055                         
07056                         DCp = &(DC[v]); 
07057                         DC[w].Previous = (void *) DCp;
07058                         DC[w].le = le;
07059                         DC[w].node = w;
07060                         DC[w].order = DCp->order + 1;
07061                         
07062                         if (vLocInLmins[w] < 0) { 
07063                            #ifdef LOCALDEBUG
07064                               fprintf (SUMA_STDERR, "%s: adding entry for w = %d - First Hit. \n", FuncName, w);
07065                            #endif
07066                            Lmins[N_Lmins] = L[w]; 
07067                            vLmins[N_Lmins] = w; 
07068                            vLocInLmins[w] = N_Lmins; 
07069                            ++N_Lmins;    
07070                         } else {
07071                            #ifdef LOCALDEBUG
07072                               fprintf (SUMA_STDERR, "%s: modifying entry for w = %d  Second Hit.\n", FuncName, w); */
07073                            #endif
07074                            Lmins[vLocInLmins[w]] = L[w]; 
07075                         }                        
07076                      }else {
07077                         #ifdef LOCALDEBUG
07078                            fprintf (SUMA_STDERR, "%s: L[%d]=%f < L[%d] = %f + le = %f.\n", FuncName, w, L[w], v, L[v], le); */
07079                         #endif
07080                      } 
07081                   }
07082                }
07083 
07084                
07085 
07086                isNodeInMesh[v] = NOPE;
07087                *N_isNodeInMesh -= 1;
07088                L[v] = LARGE_NUM; 
07089                Found = NOPE;
07090 
07091                
07092                #ifdef LOCALDEBUG
07093                   {
07094                      int kkk;
07095                      fprintf (SUMA_STDERR,"Lmins\tvLmins\tvLocInLmins\n");
07096                      for (kkk=0; kkk < N_Lmins; ++kkk) fprintf (SUMA_STDERR,"%f\t%d\t%d\n", Lmins[kkk], vLmins[kkk], vLocInLmins[vLmins[kkk]] );
07097                
07098                   }
07099                #endif
07100                
07101                if (vLocInLmins[v] >= 0) { 
07102                   #ifdef LOCALDEBUG
07103                      fprintf (SUMA_STDERR, "%s: removing node v = %d. N_Lmins = %d\n", FuncName,  v, N_Lmins);
07104                   #endif
07105                   --N_Lmins;
07106                   ReplacingNode = vLmins[N_Lmins];
07107                   ReplacedNodeLocation = vLocInLmins[v];
07108                   Lmins[vLocInLmins[v]] = Lmins[N_Lmins];
07109                   vLmins[vLocInLmins[v]] = vLmins[N_Lmins];
07110                   vLocInLmins[ReplacingNode] = ReplacedNodeLocation;
07111                   vLocInLmins[v] = -1;
07112                   Lmins[N_Lmins] = LARGE_NUM; 
07113                }
07114             }
07115          } while (*N_isNodeInMesh > 0 && !Found);
07116 
07117          if (!Found) {
07118             fprintf (SUMA_STDERR, "Error %s: No more nodes in mesh, failed to reach target %d. NLmins = %d\n", FuncName, Ny, N_Lmins);
07119             SUMA_free (L);
07120             SUMA_free (Lmins);
07121             SUMA_free(vLmins);
07122             SUMA_free(vLocInLmins);
07123             SUMA_free(DC);
07124             SUMA_RETURN (NULL);
07125          }else {
07126             if (LocalHead) fprintf (SUMA_STDERR, "%s: Path between Nodes %d and %d is %f.\n", FuncName, Nx, Ny, *Lfinal);
07127          }
07128 
07129 
07130          if (LocalHead) {
07131             
07132             DT_DIJKSTRA = SUMA_etime(&start_time,1);
07133             fprintf (SUMA_STDERR, "%s: Method 2- Elapsed time in function %f seconds.\n", FuncName, DT_DIJKSTRA);
07134          }
07135 
07136          SUMA_free(L);
07137          SUMA_free(Lmins);
07138          SUMA_free(vLmins);
07139          SUMA_free(vLocInLmins);
07140          break;   
07141       default: 
07142          fprintf (SUMA_STDERR, "Error %s: No such method (%d).\n", FuncName, Method_Number);
07143          if (DC) SUMA_free(DC);
07144          SUMA_RETURN (NULL);
07145          break;
07146    }
07147    
07148    
07149    *N_Path = DC[Ny].order+1;
07150    Path = (int *) SUMA_calloc (*N_Path, sizeof(int));
07151    if (!Path) {
07152       fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
07153       if (DC) SUMA_free(DC);
07154       SUMA_RETURN (NULL);
07155    }
07156    
07157    DCi = &(DC[Ny]);
07158    iv = *N_Path - 1;
07159    Path[iv] = Ny;
07160    if (iv > 0) {
07161       do {
07162          --iv;
07163          DCp = (SUMA_DIJKSTRA_PATH_CHAIN *) DCi->Previous;
07164          Path[iv] = DCp->node;
07165          DCi = DCp;
07166       } while (DCi->Previous);
07167    }
07168    
07169    if (iv != 0) {
07170       fprintf (SUMA_STDERR, "Error %s: iv = %d. This should not be.\n", FuncName, iv);
07171    }  
07172    
07173    SUMA_free(DC);
07174    SUMA_RETURN (Path);
07175 }
07176 
07177 
07178 
07179 
07180 
07181 
07182 
07183 
07184 
07185 
07186 
07187 
07188 
07189 
07190 
07191 
07192 
07193 
07194 
07195 int *SUMA_NodePath_to_EdgePath (SUMA_EDGE_LIST *EL, int *Path, int N_Path, int *N_Edge)
07196 {
07197    static char FuncName[]={"SUMA_NodePath_to_EdgePath"};
07198    int *ePath = NULL, i, i0;
07199    SUMA_Boolean LocalHead = NOPE;
07200    
07201    SUMA_ENTRY;
07202  
07203  
07204   *N_Edge = 0;
07205    ePath = (int *) SUMA_calloc(N_Path, sizeof(int));
07206    if (!ePath) {
07207       fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
07208       SUMA_RETURN (NULL);
07209    }
07210 
07211    for (i=1; i<N_Path; ++i) {
07212       i0 = Path[i-1];
07213       
07214       ePath[i-1] = SUMA_FindEdge (EL, i0, Path[i]); 
07215       if (ePath[i-1] < 0) { 
07216          fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_FindEdge.\n", FuncName);
07217          SUMA_free(ePath);
07218          *N_Edge = 0;
07219          SUMA_RETURN (NULL);   
07220       }else {
07221          ++(*N_Edge);
07222       }
07223    }
07224 
07225    SUMA_RETURN (ePath);   
07226 }   
07227 
07228 
07229 
07230 
07231 
07232 
07233 
07234 
07235 
07236 
07237 
07238 
07239 
07240 
07241 
07242 SUMA_Boolean SUMA_isSameEdge (SUMA_EDGE_LIST *EL, int E1, int E2) 
07243 {
07244    static char FuncName[]={"SUMA_isSameEdge"};
07245    
07246    SUMA_ENTRY;
07247 
07248    if (EL->EL[E1][0] == EL->EL[E2][0] && EL->EL[E1][1] == EL->EL[E2][1]) {
07249       SUMA_RETURN (YUP);
07250    } else {
07251       SUMA_RETURN (NOPE);
07252    }
07253    
07254 }
07255 
07256 
07257 
07258 
07259 
07260 
07261 
07262 
07263 
07264 
07265 
07266 
07267 
07268 
07269 
07270 
07271 
07272 
07273 
07274 
07275 
07276 
07277 
07278 
07279 
07280 
07281 
07282 
07283 
07284 int * SUMA_IntersectionStrip (SUMA_SurfaceObject *SO, SUMA_SURF_PLANE_INTERSECT *SPI, 
07285             int *nPath, int N_nPath, float *dinters, float dmax, int *N_tPath)
07286 {
07287    static char FuncName[]={"SUMA_IntersectionStrip"};
07288    int *tPath1 = NULL, *tPath2 = NULL, Incident[50], N_Incident, Nx = -1, 
07289       Ny = -1, Tri = -1, Tri1 = -1, istart, n2 = -1, n3 = -1, E1, E2, cnt, N_tPath1, N_tPath2;
07290    float d1, d2;
07291    SUMA_Boolean *Visited = NULL, Found, LocalHead = NOPE;
07292    
07293    SUMA_ENTRY;
07294    
07295    
07296    
07297    Tri1 = -1;
07298    if (LocalHead) {
07299       fprintf (SUMA_STDERR, "%s: Looking for a triangle containing nodes [%d %d].\n", FuncName, nPath[0], nPath[1]);
07300    }
07301    
07302    Found = SUMA_Get_Incident(nPath[0], nPath[1], SO->EL, Incident, &N_Incident, 1);
07303    if (!Found) {
07304       
07305       fprintf (SUMA_STDERR, "%s: No triangle contains nodes [%d %d].\n", FuncName, nPath[0], nPath[1]);
07306       if (nPath[0] == SO->N_Node - 1) {
07307          fprintf (SUMA_STDERR, "Warning %s: 1st node is last node of surface, traversing path backwards.\n", FuncName);
07308          Nx = nPath[N_nPath - 1];
07309          Ny = nPath[0];
07310       }else {
07311          Nx = nPath[0];
07312          Ny = nPath[N_nPath - 1];
07313       }
07314       istart = SO->EL->ELloc[Nx];
07315       
07316       Found = NOPE;
07317       while (SO->EL->EL[istart][0] == Nx && !Found) {
07318          Tri = SO->EL->ELps[istart][1];
07319          if (SPI->isTriHit[Tri]) {
07320             Found = YUP;
07321             Tri1 = Tri;
07322          }
07323          ++istart;
07324       } 
07325    }else {
07326       Nx = nPath[0];
07327       Ny = nPath[N_nPath - 1];
07328       
07329       
07330       if (LocalHead) {
07331          fprintf (SUMA_STDERR, "%s: Found %d triangles containing nodes [%d %d].\n", FuncName, N_Incident, nPath[0], nPath[1]);
07332          for (cnt = 0; cnt < N_Incident; ++cnt) fprintf (SUMA_STDERR, "%d isHit %d\n", Incident[cnt], SPI->isTriHit[Incident[cnt]]);
07333          fprintf (SUMA_STDERR, "\n"); 
07334       }
07335       Found = NOPE;
07336       cnt = 0;
07337       while (cnt < N_Incident && !Found) {
07338          if (SPI->isTriHit[Incident[cnt]]) {
07339             Found = YUP;
07340             Tri1 = Incident[cnt];
07341          }
07342          ++cnt;
07343       }
07344    }
07345    
07346    if (!Found) {
07347       fprintf (SUMA_STDERR, "Error %s: Starting Edge could not be found.\n", FuncName);
07348       SUMA_RETURN (NULL);
07349    }else if (LocalHead) {
07350       fprintf (SUMA_STDERR, "%s: Starting with triangle %d.\n", FuncName, Tri1);
07351    }
07352 
07353    
07354    if (SO->FaceSetList[3*Tri1] == Nx) {
07355       n2 = SO->FaceSetList[3*Tri1+1];
07356       n3 = SO->FaceSetList[3*Tri1+2];
07357    } else if (SO->FaceSetList[3*Tri1+1] == Nx) {
07358       n2 = SO->FaceSetList[3*Tri1];
07359       n3 = SO->FaceSetList[3*Tri1+2];
07360    } else if (SO->FaceSetList[3*Tri1+2] == Nx) {
07361       n2 = SO->FaceSetList[3*Tri1];
07362       n3 = SO->FaceSetList[3*Tri1+1];
07363    } else {
07364       fprintf (SUMA_STDERR, "Error %s: Triangle %d does not contain Nx %d.\n", FuncName, Tri1, Nx);
07365       SUMA_RETURN (NULL);
07366    }  
07367    
07368    
07369    
07370    E1 = SUMA_FindEdgeInTri (SO->EL, Nx, n2, Tri1);
07371    if (!SPI->isEdgeInters[E1]) {
07372       E1 = SUMA_FindEdgeInTri (SO->EL, Nx, n3, Tri1);
07373    }
07374    
07375    if (!SUMA_isSameEdge (SO->EL, SO->EL->Tri_limb[Tri1][0], E1) && SPI->isEdgeInters[SO->EL->Tri_limb[Tri1][0]]) {
07376       E2 = SO->EL->Tri_limb[Tri1][0];
07377    }else if (!SUMA_isSameEdge (SO->EL, SO->EL->Tri_limb[Tri1][1], E1) && SPI->isEdgeInters[SO->EL->Tri_limb[Tri1][1]]) {
07378       E2 = SO->EL->Tri_limb[Tri1][1];
07379    }else if (!SUMA_isSameEdge (SO->EL, SO->EL->Tri_limb[Tri1][2], E1) && SPI->isEdgeInters[SO->EL->Tri_limb[Tri1][2]]) {
07380       E2 = SO->EL->Tri_limb[Tri1][2];
07381    }else {
07382       fprintf (SUMA_STDERR,"Error %s: No E2 found.\n", FuncName);
07383       SUMA_RETURN (NULL);
07384    }
07385 
07386    Visited = (SUMA_Boolean *) SUMA_calloc (SO->N_FaceSet, sizeof(SUMA_Boolean));
07387    tPath1 = (int *) SUMA_calloc (SO->N_FaceSet, sizeof(int));
07388    if (!Visited || !tPath1) {
07389       fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
07390       if (Visited) SUMA_free(Visited);
07391       if (tPath2) SUMA_free(tPath1); 
07392       SUMA_RETURN (NULL);
07393    }
07394    
07395    N_tPath1 = 0;
07396    if (!SUMA_FromIntEdgeToIntEdge (Tri1, E1, E2, SO->EL, SPI, Ny, Visited, &d1, dmax, tPath1, &N_tPath1)) {
07397       fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_FromIntEdgeToIntEdge.\n", FuncName);
07398       if (Visited) SUMA_free(Visited);
07399       if (tPath2) SUMA_free(tPath1);      
07400       SUMA_RETURN (NULL);
07401    }
07402    
07403    if (LocalHead) {
07404       fprintf (SUMA_STDERR, "%s: Found a distance of %f.\n\n\n", FuncName, d1);
07405    }
07406    
07407    
07408    cnt = E2;
07409    E2 = E1;
07410    E1 = cnt;
07411    
07412    
07413    for (cnt=0; cnt < SO->N_FaceSet; ++cnt) if (Visited[cnt]) Visited[cnt] = NOPE;
07414    
07415    tPath2 = (int *) SUMA_calloc (SO->N_FaceSet, sizeof(int));
07416    if (!Visited || !tPath2) {
07417       fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
07418       if (Visited) SUMA_free(Visited);
07419       if (tPath1) SUMA_free(tPath1);
07420       if (tPath2) SUMA_free(tPath2);
07421       SUMA_RETURN (NULL);
07422    }
07423 
07424    N_tPath2 = 0;
07425    if (!SUMA_FromIntEdgeToIntEdge (Tri1, E1, E2, SO->EL, SPI, Ny, Visited, &d2, dmax, tPath2, &N_tPath2)) {
07426       fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_FromIntEdgeToIntEdge.\n", FuncName);
07427       if (Visited) SUMA_free(Visited);
07428       if (tPath1) SUMA_free(tPath1);
07429       if (tPath2) SUMA_free(tPath2);
07430       SUMA_RETURN (NULL);
07431    }
07432    
07433    if (Visited) SUMA_free(Visited);
07434    
07435    if (LocalHead) {
07436       fprintf (SUMA_STDERR, "%s: Found a distance of %f.\n", FuncName, d2);
07437    }
07438    
07439    if (d2 < d1) {
07440       *N_tPath = N_tPath2;
07441       *dinters = d2;
07442       if (tPath1) SUMA_free(tPath1);
07443       SUMA_RETURN (tPath2);
07444    } else {
07445       *dinters = d1;
07446       *N_tPath = N_tPath1;
07447       if (tPath2) SUMA_free(tPath2);
07448       SUMA_RETURN (tPath1);
07449    }
07450    
07451 }
07452 
07453 
07454 
07455 
07456 
07457 
07458 
07459 
07460 
07461 
07462 
07463 
07464 
07465 
07466 
07467 
07468 
07469 
07470 
07471 
07472 
07473 
07474 
07475 
07476 
07477 
07478 
07479 
07480 
07481 
07482 
07483 SUMA_Boolean SUMA_FromIntEdgeToIntEdge (int Tri, int E1, int E2, SUMA_EDGE_LIST *EL, SUMA_SURF_PLANE_INTERSECT *SPI, int Ny,
07484          SUMA_Boolean *Visited, float *d, float dmax, int *tPath, int *N_tPath)
07485 {  static char FuncName[]={"SUMA_FromIntEdgeToIntEdge"};
07486    int Tri2 = 0, cnt, Incident[5], N_Incident;
07487    float dx, dy, dz;
07488    SUMA_Boolean Found, LocalHead = NOPE;
07489    
07490    SUMA_ENTRY;
07491 
07492    if (Tri < 0 || E1 < 0 || E2 < 0) {
07493       fprintf (SUMA_STDERR, "Error %s: Tri (%d) or E1 (%d) or E2 (%d) is negative!\n", FuncName, Tri, E1, E2);
07494       SUMA_RETURN (NOPE);
07495    }
07496    
07497    
07498    dx = (SPI->IntersNodes[3*E2] - SPI->IntersNodes[3*E1]);
07499    dy = (SPI->IntersNodes[3*E2+1] - SPI->IntersNodes[3*E1+1]);
07500    dz = (SPI->IntersNodes[3*E2+2] - SPI->IntersNodes[3*E1+2]);
07501    if (LocalHead) {
07502       fprintf (SUMA_STDERR, "%s: Entered - Tri %d, E1 %d [%d %d], E2 %d [%d %d]\n\tdx = %f dy = %f dz = %f\n", 
07503          FuncName, Tri, E1, EL->EL[E1][0], EL->EL[E1][1], E2, EL->EL[E2][0], EL->EL[E2][1], dx, dy, dz);
07504    }
07505    *d += sqrt( dx * dx + dy * dy + dz * dz);
07506    
07507    if (*d > dmax) {
07508       
07509       fprintf (SUMA_STDERR, "%s: Path longer than dmax. Returning.\n", FuncName);
07510       SUMA_RETURN (YUP);
07511    }
07512    
07513    if (EL->EL[E2][0] == Ny || EL->EL[E2][1] == Ny) {
07514       fprintf (SUMA_STDERR, "%s: Found Ny, d = %f\n", FuncName, *d);
07515       if (!Visited[Tri]) {
07516          
07517          tPath[*N_tPath] = Tri;
07518          ++*N_tPath;
07519       }
07520       SUMA_RETURN (YUP);
07521    } else if (Visited[Tri]) {
07522       fprintf (SUMA_STDERR, "Error %s: Triangle %d already visited.\n",FuncName, Tri); 
07523       SUMA_RETURN (NOPE);
07524    }
07525      
07526    
07527    if (LocalHead) fprintf (SUMA_STDERR, "%s: Marking triangle %d and adding %dth element to tPath.\n", FuncName, Tri, *N_tPath);
07528    Visited[Tri] = YUP;
07529    
07530    
07531    tPath[*N_tPath] = Tri;
07532    ++*N_tPath;
07533    
07534    
07535    if (LocalHead) fprintf (SUMA_STDERR, "%s: Searching for triangles incident to E2 %d.\n", FuncName, E2);
07536    if (!SUMA_Get_Incident(EL->EL[E2][0], EL->EL[E2][1], EL, Incident, &N_Incident, 1)) {
07537       fprintf (SUMA_STDERR,"Error %s: Failed to get Incident triangles.\n", FuncName);
07538       SUMA_RETURN (NOPE);
07539    }
07540    
07541    
07542    cnt = 0;
07543    Found = NOPE;
07544    while (cnt < N_Incident && !Found) {
07545       if (SPI->isTriHit[Incident[cnt]] && Incident[cnt] != Tri && !Visited[Incident[cnt]]) {
07546          Found = YUP;
07547          Tri2 = Incident[cnt];
07548       }
07549       ++cnt;
07550    }
07551    
07552    if (!Found) {
07553       fprintf (SUMA_STDERR,"Error %s: Could not find next triangle.\n", FuncName);
07554       SUMA_RETURN (NOPE);
07555    }
07556    
07557    Tri = Tri2;
07558    E1 = E2;
07559    
07560    
07561    if (LocalHead) fprintf (SUMA_STDERR, "%s: Finding new E2.\n", FuncName);
07562    
07563    if (!SUMA_isSameEdge (EL, EL->Tri_limb[Tri][0], E1) && SPI->isEdgeInters[EL->Tri_limb[Tri][0]]) {
07564       E2 = EL->Tri_limb[Tri][0];
07565    }else if (!SUMA_isSameEdge (EL, EL->Tri_limb[Tri][1], E1) && SPI->isEdgeInters[EL->Tri_limb[Tri][1]]) {
07566       E2 = EL->Tri_limb[Tri][1];
07567    }else if (!SUMA_isSameEdge (EL, EL->Tri_limb[Tri][2], E1) && SPI->isEdgeInters[EL->Tri_limb[Tri][2]]) {
07568       E2 = EL->Tri_limb[Tri][2];
07569    }else {
07570       fprintf (SUMA_STDERR,"Error %s: No E2 found.\n", FuncName);
07571       SUMA_RETURN (NOPE);
07572    }
07573    
07574    
07575    if (!SUMA_FromIntEdgeToIntEdge (Tri, E1, E2, EL, SPI, Ny, Visited, d, dmax, tPath, N_tPath)) {
07576       fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_FromIntEdgeToIntEdge.\n", FuncName);
07577       SUMA_RETURN (NOPE);
07578    }
07579    
07580    SUMA_RETURN (YUP);
07581 }
07582 
07583 
07584 
07585 
07586 
07587 
07588 
07589 
07590 
07591 
07592 
07593 
07594 
07595 
07596 
07597 
07598 
07599 
07600 
07601 
07602 
07603 
07604 
07605 
07606 int *SUMA_NodePath_to_TriPath_Inters ( SUMA_SurfaceObject *SO, SUMA_SURF_PLANE_INTERSECT *SPI, int *nPath, int N_nPath, int *N_tPath)
07607 {
07608    static char FuncName[]={"SUMA_NodePath_to_TriPath_Inters"};
07609    int *tPath = NULL, e, i, N_nc, nc[3], N_HostTri, E, j, 
07610       HostTri, PrevTri, k, N1[2], N2[2], cnt, MissTri = 0, candidate;
07611    SUMA_Boolean Found, LocalHead = NOPE;
07612    
07613    SUMA_ENTRY;
07614    
07615    tPath = (int *) SUMA_calloc(2*N_nPath, sizeof(int));
07616    if (!tPath) {
07617       fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
07618       SUMA_RETURN (NULL);
07619    }
07620    
07621    *N_tPath = 0;
07622    for (i=0; i < N_nPath - 1; ++i) {
07623       
07624       E = SUMA_FindEdge (SO->EL, nPath[i], nPath[i+1]);
07625       if (E < 0) {
07626          fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_FindEdge.\n", FuncName);
07627          SUMA_free(tPath);
07628          SUMA_RETURN(NULL);
07629       }
07630       
07631       N_HostTri = SO->EL->ELps[E][2]; 
07632       if (N_HostTri > 2) {
07633          fprintf (SUMA_STDERR, "Warning %s: Surface is not a surface, Edge %d has more than %d hosting triangles.\n", FuncName, E, N_HostTri);
07634       }
07635       candidate = 0;
07636       
07637       for (j=0; j < N_HostTri; ++j) {
07638          HostTri = SO->EL->ELps[E+j][1];
07639          if (SPI->isTriHit[HostTri]) { 
07640             ++candidate;
07641             if (*N_tPath > 2*N_nPath) {
07642                fprintf (SUMA_STDERR, "Error %s: N_tPath = %d > %d allocated.\n", FuncName, *N_tPath, 2*N_nPath);
07643             }  
07644             #if 1
07645             
07646 
07647             if (*N_tPath == 0) { 
07648                tPath[*N_tPath] = HostTri; 
07649                ++ (*N_tPath);
07650             } else { 
07651                PrevTri = tPath[*N_tPath - 1];
07652                N_nc = SUMA_isTriLinked (&(SO->FaceSetList[3*PrevTri]), &(SO->FaceSetList[3*HostTri]), nc);
07653                if (!N_nc) {
07654                   fprintf (SUMA_STDERR, "Warning %s: Triangles %d and %d are not linked.\nAdding triangle %d anyway.\n", 
07655                      FuncName, PrevTri, HostTri, HostTri);
07656                   
07657                   tPath[*N_tPath] = HostTri; 
07658                   ++ (*N_tPath);
07659                }else if (N_nc == 1) {
07660                   
07661                   
07662                   e = 0;
07663                   for (k=0; k <3; ++k) {
07664                      if (SO->FaceSetList[3*PrevTri+k] != nc[0]) {
07665                         N1[e] = SO->FaceSetList[3*PrevTri+k]; ++e;
07666                      }
07667                   }
07668                   
07669                   e = 0;
07670                   for (k=0; k <3; ++k) {
07671                      if (SO->FaceSetList[3*HostTri+k] != nc[0]) {
07672                         N2[e] = SO->FaceSetList[3*HostTri+k]; ++e;
07673                      }
07674                   }
07675                   
07676 
07677                   Found = NOPE;
07678                   cnt = 0;
07679                   while (!Found && cnt < 4) {
07680                      switch (cnt) {
07681                         case 0:
07682                            MissTri = SUMA_whichTri (SO->EL, nc[0], N1[0], N2[0], 1);
07683                            if (LocalHead) fprintf (SUMA_STDERR, "%s: looking for triangle with nodes %d and %d... Tri = %d\n", 
07684                                  FuncName, N1[0], N2[0], MissTri);
07685                            break;
07686                         case 1:
07687                            MissTri = SUMA_whichTri (SO->EL, nc[0], N1[0], N2[1], 1);
07688                            if (LocalHead) fprintf (SUMA_STDERR, "%s: looking for triangle with nodes %d and %d... Tri = %d\n", 
07689                                  FuncName, N1[0], N2[1], MissTri);
07690                            break;
07691                         case 2:
07692                            MissTri = SUMA_whichTri (SO->EL, nc[0], N1[1], N2[0], 1);
07693                            if (LocalHead) fprintf (SUMA_STDERR, "%s: looking for triangle with nodes %d and %d... Tri = %d\n", 
07694                                  FuncName, N1[1], N2[0], MissTri);
07695                            break;
07696                         case 3:
07697                            MissTri = SUMA_whichTri (SO->EL, nc[0], N1[1], N2[1], 1);
07698                            if (LocalHead) fprintf (SUMA_STDERR, "%s: looking for triangle with nodes %d and %d... Tri = %d\n", 
07699                                  FuncName, N1[1], N2[1], MissTri);
07700                            break;
07701                      }
07702                      if (MissTri >= 0) {
07703                         Found = YUP;
07704                      }
07705                      ++cnt;
07706                   }
07707                   if (!Found) {
07708                      fprintf (SUMA_STDERR, "Warning %s: Failed to find missing triangle.\n", FuncName);
07709                      tPath[*N_tPath] = HostTri; 
07710                      ++ (*N_tPath);
07711                   }else {
07712                      
07713                      tPath[*N_tPath] = MissTri; 
07714                      ++ (*N_tPath);
07715                      tPath[*N_tPath] = HostTri; 
07716                      ++ (*N_tPath);
07717                   }
07718                }else if (N_nc == 2) {
07719                   
07720                   tPath[*N_tPath] = HostTri; 
07721                   ++ (*N_tPath);
07722                }else {
07723                   fprintf (SUMA_STDERR, "Error %s: Triangles %d and %d are identical.\n", FuncName, PrevTri, HostTri);
07724                   SUMA_free(tPath);
07725                   SUMA_RETURN(NULL);
07726                }
07727             }
07728             #else 
07729                tPath[*N_tPath] = HostTri; 
07730                ++ (*N_tPath);
07731             #endif   
07732          }
07733       }
07734       if (!candidate) {
07735          fprintf (SUMA_STDERR, "\aWarning %s: Nodes %d and %d of edge %d had no intersected hosting triangle.\n", FuncName, nPath[i], nPath[i+1], E);
07736          
07737       }
07738    }
07739    
07740    SUMA_RETURN (tPath);   
07741 }
07742 
07743 
07744 
07745 
07746 
07747 
07748 
07749 
07750 
07751 
07752 
07753 
07754 
07755 
07756 
07757 
07758 
07759 
07760 
07761 
07762 int *SUMA_NodePath_to_TriPath_Inters_OLD (SUMA_SurfaceObject *SO, SUMA_TRI_BRANCH *Bv, int *Path, int N_Path, int *N_Tri)
07763 {
07764    static char FuncName[]={"SUMA_NodePath_to_TriPath_Inters_OLD"};
07765    int *tPath = NULL, ilist, i0, Tri, eTri, EdgeBuf, Tri0, Tri1, Direction, i1, loc2f, iDirSet;
07766    SUMA_Boolean LocalHead = NOPE, Found = NOPE;
07767    
07768    SUMA_ENTRY;
07769  
07770  
07771   *N_Tri = 0;
07772    tPath = (int *) SUMA_calloc(Bv->N_list+1, sizeof(int));
07773    if (!tPath) {
07774       fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
07775       SUMA_RETURN (NULL);
07776    }
07777    
07778    
07779       i0 = Path[0];
07780       Tri0 = Bv->list[0];
07781       if (SO->FaceSetList[3*Tri0] != i0 && SO->FaceSetList[3*Tri0+1] != i0 && SO->FaceSetList[3*Tri0+2] != i0) {
07782          fprintf (SUMA_STDERR, "Error %s: Did not find node %d in first triangle in branch.\n", FuncName, i0);
07783          SUMA_free(tPath);
07784          *N_Tri = 0;
07785          SUMA_RETURN (NULL);  
07786       }
07787    
07788    
07789    
07790    tPath[0] = Tri0;
07791    *N_Tri = 1;
07792    Found = NOPE;
07793    ilist = 0;
07794 
07795    if (LocalHead)   fprintf(SUMA_STDERR, "%s: Going forward looking for third node\n", FuncName);
07796    if (N_Path > 2) {
07797       iDirSet = 2; 
07798    }else {
07799       iDirSet = 1; 
07800    }
07801    
07802    ilist = 1;
07803    while (!Found && ilist < Bv->N_list) {
07804       tPath[*N_Tri] = Bv->list[ilist];
07805       if (SO->FaceSetList[3*Bv->list[ilist]] == Path[iDirSet] || 
07806          SO->FaceSetList[3*Bv->list[ilist]+1] == Path[iDirSet] ||
07807          SO->FaceSetList[3*Bv->list[ilist]+2] == Path[iDirSet]) {
07808             Found = YUP;
07809       }
07810       ++(*N_Tri);
07811       ++ilist;      
07812    }
07813     
07814    if (!Found) {
07815       fprintf (SUMA_STDERR, "Error %s: Did not find next node %d in branch.\n", FuncName, Path[iDirSet]);
07816       SUMA_free(tPath);
07817       *N_Tri = 0;
07818       SUMA_RETURN (NULL); 
07819    }
07820   
07821    loc2f = *N_Tri; 
07822 
07823    
07824    tPath[0] = Tri0;
07825    *N_Tri = 1;
07826    Found = NOPE;
07827    ilist = 0;
07828    
07829    if (LocalHead) fprintf(SUMA_STDERR, "%s: Going backwards looking for third node\n", FuncName);
07830    ilist = Bv->N_list - 1;
07831    while (!Found && ilist >=  0) {
07832       tPath[*N_Tri] = Bv->list[ilist];
07833       if (LocalHead) fprintf(SUMA_STDERR, "%s: trying triangle %d for node %d.\n", FuncName, Bv->list[ilist], Path[N_Path-1]);
07834       if (SO->FaceSetList[3*Bv->list[ilist]] == Path[iDirSet] || 
07835          SO->FaceSetList[3*Bv->list[ilist]+1] == Path[iDirSet] ||
07836          SO->FaceSetList[3*Bv->list[ilist]+2] == Path[iDirSet]) {
07837             Found = YUP;
07838       }
07839       ++(*N_Tri);
07840       --ilist;      
07841    }
07842    
07843    if (*N_Tri < loc2f) { 
07844       
07845 
07846       Direction = -1;
07847    } else Direction = 1;
07848    
07849    
07850    
07851    tPath[0] = Tri0;
07852    *N_Tri = 1;
07853    Found = NOPE;
07854    ilist = 0;
07855    if (Direction == 1) { 
07856      if (LocalHead)   fprintf(SUMA_STDERR, "%s: Going forward, final pass \n", FuncName);
07857      ilist = 1;
07858       while (!Found && ilist < Bv->N_list) {
07859          tPath[*N_Tri] = Bv->list[ilist];
07860          if (SO->FaceSetList[3*Bv->list[ilist]] == Path[N_Path-1] || 
07861             SO->FaceSetList[3*Bv->list[ilist]+1] == Path[N_Path-1] ||
07862             SO->FaceSetList[3*Bv->list[ilist]+2] == Path[N_Path-1]) {
07863                Found = YUP;
07864          }
07865          ++(*N_Tri);
07866          ++ilist;      
07867       }
07868    } else { 
07869       if (LocalHead) fprintf(SUMA_STDERR, "%s: Going backwards, final pass \n", FuncName);
07870       ilist = Bv->N_list - 1;
07871       while (!Found && ilist >=  0) {
07872          tPath[*N_Tri] = Bv->list[ilist];
07873          if (LocalHead) fprintf(SUMA_STDERR, "%s: trying triangle %d for node %d.\n", FuncName, Bv->list[ilist], Path[N_Path-1]);
07874          if (SO->FaceSetList[3*Bv->list[ilist]] == Path[N_Path-1] || 
07875             SO->FaceSetList[3*Bv->list[ilist]+1] == Path[N_Path-1] ||
07876             SO->FaceSetList[3*Bv->list[ilist]+2] == Path[N_Path-1]) {
07877                Found = YUP;
07878          }
07879          ++(*N_Tri);
07880          --ilist;      
07881       }
07882       
07883    }   
07884 
07885    if (!Found) {
07886       fprintf (SUMA_STDERR, "Error %s: Path not completed.\n", FuncName);
07887       SUMA_free(tPath);
07888       *N_Tri = 0;
07889       SUMA_RETURN (NULL);
07890    }else {
07891       if (LocalHead) {
07892          fprintf (SUMA_STDERR,"%s: Path is %d triangles long:\n", FuncName, *N_Tri); 
07893          for (ilist=0; ilist< *N_Tri; ++ilist) {
07894             fprintf (SUMA_STDERR,"t%d\t", tPath[ilist]);
07895          }
07896          fprintf (SUMA_STDERR,"\n");
07897       }
07898    }
07899    SUMA_RETURN (tPath);
07900 }   
07901 
07902 
07903 
07904 #ifdef SUMA_SurfQual_STANDALONE
07905 #define SURFQUAL_MAX_SURF 10  
07906 
07907 void usage_SUMA_SurfQual ()
07908    {
07909       static char FuncName[]={"usage_SUMA_SurfQual"};
07910       char * s = NULL;
07911       s = SUMA_help_basics();
07912       printf ( "\nUsage: A program to check the quality of surfaces.\n"
07913                "  SurfQual <-spec SpecFile> <-surf_A insurf> <-surf_B insurf> ...\n"
07914                "             <-sphere> [-prefix OUTPREF]  \n"
07915                "\n"
07916                "  Mandatory parameters:\n"
07917                "     -spec SpecFile: Spec file containing input surfaces.\n"
07918                "     -surf_X: Name of input surface X where X is a character\n"
07919                "              from A to Z. If surfaces are specified using two\n"
07920                "              files, use the name of the node coordinate file.\n"
07921                "  Mesh winding consistency and 2-manifold checks are performed\n"
07922                "  on all surfaces.\n"
07923                "  Most other checks are specific to spherical surfaces (see option below).\n"
07924                "     -sphere: Indicates that surfaces read are spherical.\n"
07925                "              With this option you get the following output.\n"
07926                "              - Absolute deviation between the distance (d) of each\n"
07927                "                node from the surface's center and the estimated\n"
07928                "                radius(r). The distances, abs (d - r), are \n"
07929                "                and written to the file OUTPREF_Dist.1D.dset .\n"
07930                "                The first column represents node index and the \n"
07931                "                second is the absolute distance. A colorized \n"
07932                "                version of the distances is written to the file \n"
07933                "                OUTPREF_Dist.1D.col (node index followed \n"
07934                "                by r g b values). A list of the 10 largest absolute\n"
07935                "                distances is also output to the screen.\n"
07936                "              - Also computed is the cosine of the angle between \n"
07937                "                the normal at a node and the direction vector formed\n"
07938                "                formed by the center and that node. Since both vectors\n"
07939                "                are normalized, the cosine of the angle is the dot product.\n"
07940                "                On a sphere, the abs(dot product) should be 1 or pretty \n"
07941                "                close. Nodes where abs(dot product) < 0.9 are flagged as\n"
07942                "                bad and written out to the file OUTPREF_BadNodes.1D.dset .\n"
07943                "                The file OUTPREF_dotprod.1D.dset contains the dot product \n"
07944                "                values for all the nodes. The files with colorized results\n"
07945                "                are OUTPREF_BadNodes.1D.col and OUTPREF_dotprod.1D.col .\n"
07946                "                A list of the bad nodes is also output to the screen for\n"
07947                "                convenience. You can use the 'j' option in SUMA to have\n"
07948                "                the cross-hair go to a particular node. Use 'Alt+l' to\n"
07949                "                have the surface rotate and place the cross-hair at the\n"
07950                "                center of your screen.\n"
07951                "              NOTE: For detecting topological problems with spherical\n"
07952                "                surfaces, I find the dot product method to work best.\n"              
07953                "  Optional parameters:\n"
07954                "     -prefix OUTPREF: Prefix of output files. If more than one surface\n"
07955                "                      are entered, then the prefix will have _X added\n"
07956                "                      to it, where X is a character from A to Z.\n"
07957                "                      THIS PROGRAM WILL OVERWRITE EXISTING FILES.\n"
07958                "                      Default prefix is the surface's label.\n"
07959                "\n"
07960                "  Comments:\n"
07961                "     - The colorized (.col) files can be loaded into SUMA (with the 'c' \n"
07962                "     option. By focusing on the bright spots, you can find trouble spots\n"
07963                "     which would otherwise be very difficult to locate.\n"
07964                "     - You should also pay attention to the messages output when the \n"
07965                "     surfaces are being loaded, particularly to edges (segments that \n"
07966                "     join 2 nodes) are shared by more than 2 triangles. For a proper\n"
07967                "     closed surface, every segment should be shared by 2 triangles. \n"
07968                "     For cut surfaces, segments belonging to 1 triangle only form\n"
07969                "     the edge of that surface.\n"
07970                "     - There are no utilities within SUMA to correct these defects.\n"
07971                "     It is best to fix these problems with the surface creation\n"
07972                "     software you are using.\n"
07973                "     - Some warnings may be redundant. That should not hurt you.\n"
07974                "%s"
07975                "\n", s);
07976        SUMA_free(s); s = NULL;        
07977        s = SUMA_New_Additions(0, 1); printf("%s\n", s);SUMA_free(s); s = NULL;
07978        printf("       Ziad S. Saad SSCC/NIMH/NIH ziad@nih.gov     \n");
07979        exit (0);
07980    }
07981 
07982 typedef struct {
07983    SUMA_SO_File_Type iType;
07984    char *out_prefix;
07985    char *sv_name;
07986    char *surf_names[SURFQUAL_MAX_SURF];
07987    int N_surf;
07988    char *spec_file;
07989    char *surftype;
07990 } SUMA_SURFQUAL_OPTIONS;
07991 
07992 
07993 
07994 
07995 
07996 
07997 
07998 
07999 
08000 
08001 
08002 SUMA_SURFQUAL_OPTIONS *SUMA_SurfQual_ParseInput (char *argv[], int argc)
08003 {
08004    static char FuncName[]={"SUMA_SurfQual_ParseInput"}; 
08005    SUMA_SURFQUAL_OPTIONS *Opt=NULL;
08006    int kar, i, ind;
08007    char *outprefix;
08008    SUMA_Boolean brk = NOPE;
08009    SUMA_Boolean LocalHead = NOPE;
08010 
08011    SUMA_ENTRY;
08012    
08013    Opt = (SUMA_SURFQUAL_OPTIONS *)SUMA_malloc(sizeof(SUMA_SURFQUAL_OPTIONS));
08014 
08015    kar = 1;
08016    Opt->iType = SUMA_FT_NOT_SPECIFIED;
08017    Opt->out_prefix = NULL;
08018    Opt->sv_name = NULL;
08019    Opt->spec_file = NULL;
08020    Opt->N_surf = -1;
08021    Opt->surftype = NULL;
08022    for (i=0; i<SURFQUAL_MAX_SURF; ++i) { Opt->surf_names[i] = NULL; }
08023         brk = NOPE;
08024    
08025         while (kar < argc) { 
08026                 
08027                 if (strcmp(argv[kar], "-h") == 0 || strcmp(argv[kar], "-help") == 0) {
08028                          usage_SUMA_SurfQual();
08029           exit (0);
08030                 }
08031                 
08032       
08033                 SUMA_SKIP_COMMON_OPTIONS(brk, kar);
08034       
08035       if (!brk && (strcmp(argv[kar], "-sphere") == 0)) {
08036                         if (Opt->surftype) {
08037             SUMA_S_Err("Surface type already specified.\nOnly one type allowed.");
08038             exit(1);
08039          }
08040          Opt->surftype = argv[kar];
08041                         brk = YUP;
08042                 }
08043       
08044       if (!brk && (strcmp(argv[kar], "-spec") == 0)) {
08045          kar ++;
08046                         if (kar >= argc)  {
08047                                 fprintf (SUMA_STDERR, "need argument after -spec \n");
08048                                 exit (1);
08049                         }
08050                         Opt->spec_file = argv[kar];
08051                         brk = YUP;
08052                 }
08053             
08054       if (!brk && (strcmp(argv[kar], "-prefix") == 0)) {
08055          kar ++;
08056                         if (kar >= argc)  {
08057                                 fprintf (SUMA_STDERR, "need argument after -prefix \n");
08058                                 exit (1);
08059                         }
08060                         Opt->out_prefix = SUMA_copy_string(argv[kar]);
08061                         brk = YUP;
08062                 }
08063             
08064       if (!brk && (strncmp(argv[kar], "-surf_", 6) == 0)) {
08065                         if (kar + 1>= argc)  {
08066                                 fprintf (SUMA_STDERR, "need argument after -surf_X SURF_NAME \n");
08067                                 exit (1);
08068                         }
08069                         ind = argv[kar][6] - 'A';
08070          if (ind < 0 || ind >= SURFQUAL_MAX_SURF) {
08071             fprintf (SUMA_STDERR, "-surf_X SURF_NAME option is out of range.\n");
08072                                 exit (1);
08073          }
08074          kar ++;
08075          Opt->surf_names[ind] = argv[kar];
08076          Opt->N_surf = ind+1;
08077          brk = YUP;
08078                 }
08079       
08080       
08081       if (!brk) {
08082                         fprintf (SUMA_STDERR,"Error %s:\nOption %s not understood. Try -help for usage\n", FuncName, argv[kar]);
08083                         exit (1);
08084                 } else {        
08085                         brk = NOPE;
08086                         kar ++;
08087                 }
08088       
08089    }
08090    
08091    if (Opt->N_surf < 1) {
08092       SUMA_SL_Err("No surface specified.");
08093       exit(1);
08094    }
08095       
08096    SUMA_RETURN (Opt);
08097      
08098 }
08099 
08100 int main (int argc,char *argv[])
08101 {    
08102    static char FuncName[]={"SurfQual"};
08103    char *OutName = NULL, ext[5], *prefix = NULL, *shist=NULL;
08104    SUMA_SURFQUAL_OPTIONS *Opt; 
08105    int SO_read = -1;
08106    int i, cnt, trouble;
08107    SUMA_SurfaceObject *SO = NULL;
08108    SUMA_SurfSpecFile Spec;
08109    void *SO_name = NULL;
08110    SUMA_Boolean DoConv = NOPE, DoSphQ = NOPE;   
08111    SUMA_Boolean LocalHead = NOPE;
08112         
08113    SUMA_mainENTRY;
08114    
08115    SUMA_STANDALONE_INIT;
08116    
08117         
08118         SUMAg_DOv = SUMA_Alloc_DisplayObject_Struct (SUMA_MAX_DISPLAYABLE_OBJECTS);
08119    
08120    if (argc < 4)
08121        {
08122           usage_SUMA_SurfQual();
08123           exit (1);
08124        }
08125    
08126    Opt = SUMA_SurfQual_ParseInput (argv, argc);
08127    
08128    
08129    if (!SUMA_Read_SpecFile (Opt->spec_file, &Spec)) {
08130                 fprintf(SUMA_STDERR,"Error %s: Error in SUMA_Read_SpecFile\n", FuncName);
08131                 exit(1);
08132         }
08133    SO_read = SUMA_spec_select_surfs(&Spec, Opt->surf_names, SURFQUAL_MAX_SURF, 0);
08134    if ( SO_read != Opt->N_surf )
08135    {
08136            if (SO_read >=0 )
08137          fprintf(SUMA_STDERR,"Error %s:\nFound %d surfaces, expected %d.\n", FuncName,  SO_read, Opt->N_surf);
08138       exit(1);
08139    }
08140    
08141    if (!SUMA_LoadSpec_eng(&Spec, SUMAg_DOv, &SUMAg_N_DOv, Opt->sv_name, 0, SUMAg_CF->DsetList) ) {
08142            fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_LoadSpec_eng\n", FuncName);
08143       exit(1);
08144    }
08145   
08146    DoConv = NOPE;
08147    DoSphQ = NOPE;   
08148    if (Opt->surftype) {
08149       if (!strcmp(Opt->surftype, "-sphere")) { 
08150          DoSphQ = YUP;
08151       }else {
08152          
08153       }
08154    }
08155    
08156    for (i=0; i < Opt->N_surf; ++i) {
08157       
08158       SO = SUMA_find_named_SOp_inDOv(Opt->surf_names[i], SUMAg_DOv, SUMAg_N_DOv);
08159       if (!SO) {
08160          fprintf (SUMA_STDERR,"Error %s:\n"
08161                               "Failed to find surface %s\n"
08162                               "in spec file. Use full name.\n",
08163                               FuncName, Opt->surf_names[i]);
08164          exit(1);
08165       }
08166       
08167       if (!SO->EL) SUMA_SurfaceMetrics(SO, "EdgeList", NULL);
08168       if (!SO->MF) SUMA_SurfaceMetrics(SO, "MemberFace", NULL);
08169       if (!SO->Label) SUMA_SurfaceFileName(SO, NOPE);
08170       
08171       
08172       
08173       if (!Opt->out_prefix) prefix = SUMA_copy_string(SO->Label);
08174       else prefix = SUMA_copy_string (Opt->out_prefix);
08175       
08176       
08177       if (!SUMA_MakeConsistent (SO->FaceSetList, SO->N_FaceSet, SO->EL, 0, &trouble)) {
08178          SUMA_S_Warn("Failed to make sure surface's mesh is consistently wound.\n"
08179                      "You should fix the mesh.\n");
08180       }
08181       if (DoConv) {
08182          float *Cx = NULL;
08183          if (Opt->N_surf > 1) {
08184             sprintf(ext,"_%c", 65+i);
08185             OutName = SUMA_append_replace_string (prefix, "_Conv_detail.1D.dset", ext, 0);
08186          } else { 
08187             OutName = SUMA_append_string (prefix, "_Conv_detail.1D.dset");
08188          }
08189          Cx = SUMA_Convexity_Engine ( SO->NodeList, SO->N_Node, 
08190                                       SO->NodeNormList, SO->FN, OutName);
08191          if (Cx) SUMA_free(Cx); Cx = NULL;
08192          if (OutName) SUMA_free(OutName); OutName = NULL;
08193       } 
08194       if (DoSphQ) {
08195          if (Opt->N_surf > 1) {
08196             sprintf(ext,"_%c", 65+i);
08197             OutName = SUMA_append_string (prefix, ext);
08198          } else { 
08199             OutName = SUMA_copy_string (prefix);
08200          }
08201          shist = SUMA_HistString (NULL, argc, argv, NULL);
08202          SUMA_SphereQuality (SO, OutName, shist);   
08203          if (shist) SUMA_free(shist); shist = NULL;
08204          if (OutName) SUMA_free(OutName); OutName = NULL;
08205       }
08206       
08207       if (prefix) SUMA_free(prefix); prefix = NULL;
08208    }
08209    
08210   
08211    if (trouble) { 
08212       fprintf (SUMA_STDERR,"\n");
08213       SUMA_S_Warn("Mesh is not consistent, use ConvertSurface's -make_consistent \n"
08214                   "option to fix the problem before proceeding further.\n"
08215                   "Other results reported by this and other programs\n"
08216                   "may be incorrect if mesh is not consistently wound.\n" ); 
08217    } else {
08218       fprintf (SUMA_STDERR,"\n");
08219       fprintf (SUMA_STDERR,"Surface is consistently wound\n");
08220    }
08221    { 
08222       int eu;
08223       SUMA_EULER_SO(SO, eu);
08224       fprintf (SUMA_STDERR,"\n");
08225       fprintf(SUMA_STDERR,"Surface Euler number is: %d\n", eu);
08226    }
08227    if ((SO->EL->min_N_Hosts == 1 || SO->EL->max_N_Hosts == 1)) {
08228          fprintf (SUMA_STDERR,"\n");
08229          fprintf(SUMA_STDERR,"Warning %s:\n Min/Max number of edge hosting triangles: [%d/%d] \n", FuncName, SO->EL->min_N_Hosts, SO->EL->max_N_Hosts);
08230          fprintf(SUMA_STDERR," You have edges that form a border in the surface.\n");
08231    }
08232    if (SO->EL->min_N_Hosts == 2 && SO->EL->max_N_Hosts == 2) {
08233       fprintf (SUMA_STDERR,"\n");
08234       fprintf(SUMA_STDERR,"Surface is closed and is a 2-manifold.");
08235    }
08236    if (SO->EL->min_N_Hosts > 2 || SO->EL->max_N_Hosts > 2) {
08237       fprintf (SUMA_STDERR,"\n");
08238       fprintf(SUMA_STDERR, "Warning %s:\n"
08239                            "Min/Max number of edge hosting triangles: [%d/%d] \n", FuncName, SO->EL->min_N_Hosts, SO->EL->max_N_Hosts);
08240       fprintf(SUMA_STDERR, "Warning %s:\n"
08241                            " You have edges that belong to more than two triangles.\n"
08242                            " Bad for analysis assuming surface is a 2-manifold.\n", FuncName);
08243       if (1) {
08244          int iii=0;
08245          fprintf(SUMA_STDERR, " These edges are formed by the following nodes:\n");
08246          for (iii = 0; iii < SO->EL->N_EL; ++iii) { 
08247             if (SO->EL->ELps[iii][2] > 2) fprintf (SUMA_STDERR," %d: Edge [%d %d] shared by %d triangles.\n", 
08248                                              iii+1, SO->EL->EL[iii][0], SO->EL->EL[iii][1] , SO->EL->ELps[iii][2] );
08249          }
08250       }
08251    }
08252    
08253    fprintf (SUMA_STDERR,"\n");
08254    
08255    SUMA_LH("clean up");
08256    if (Opt->out_prefix) SUMA_free(Opt->out_prefix); Opt->out_prefix = NULL;
08257    if (Opt) SUMA_free(Opt);   
08258    if (!SUMA_Free_Displayable_Object_Vect (SUMAg_DOv, SUMAg_N_DOv)) {
08259       SUMA_SL_Err("DO Cleanup Failed!");
08260    }
08261    if (!SUMA_Free_CommonFields(SUMAg_CF)) SUMA_error_message(FuncName,"SUMAg_CF Cleanup Failed!",1);
08262    
08263    SUMA_RETURN(0);
08264 } 
08265 #endif
08266 
08267 
08268 
08269 #if 0
08270     
08271    
08272 
08273    
08274                   
08275 
08276 
08277 
08278 
08279 
08280 
08281 
08282 
08283 
08284 
08285 
08286 
08287 
08288 
08289 
08290 
08291 
08292 
08293 
08294 
08295 
08296 
08297 
08298 
08299 
08300 
08301 
08302 
08303 
08304 
08305 
08306 
08307 
08308 
08309 
08310 
08311 
08312 
08313 
08314 
08315                   SUMA_BRANCH * SUMA_FindBranch (int ** InterMat, int N_InterMat, float ** InterNodes, int ** NodeLoc_in_InterMat, int verbose,  int * WBsz)
08316                   {
08317                      int DBG , VeryFirstSeed, Seed, sz_Branch, kk;
08318                      int n_comp = 0, ntmpint, nunqrow , NodeIndex , curnode , BranchIndex;
08319                      int ntmpint2D_V2, N_vunq , brEnd1 , brEnd2 , i, k;
08320                      int tmpint2D_V2[1][2], *v, *vunq;
08321                      int *tmpint, *unqrow, iii, GotSeed;
08322                      static char FuncName[]={"SUMA_FindBranch"};
08323                      float Dprecision;
08324                      static SUMA_BRANCH * branch;
08325                      struct  timeval  start_time, tt_sub, start_time2;
08326                      float DT_WELDSUMA_BRANCH, DT_BUILDSUMA_BRANCH, DT_WELDSUMA_BRANCHONLY ,DT_FINDININTVECT, DT_VUNQ;
08327                      FILE *TimeOut;
08328                      SUMA_Boolean LocalHead = NOPE; 
08329 
08330                      SUMA_ENTRY;
08331 
08332                      if (LocalHead) SUMA_disp_dmat (NodeLoc_in_InterMat, 20, 4, 1); 
08333 
08334                      
08335                      TimeOut = fopen("FB.TimeOut","a");   
08336 
08337                      DBG = 1;
08338                      Dprecision = 0.001;
08339 
08340                      VeryFirstSeed = 0;
08341 
08342                      
08343 
08344                      Seed = VeryFirstSeed;   
08345 
08346                      
08347                      if (!branch)
08348                         {
08349                            branch = (SUMA_BRANCH *) SUMA_calloc(SUMA_BRANCHMAX, sizeof(SUMA_BRANCH));
08350                            if (!branch )
08351                               {
08352                                  fprintf (SUMA_STDERR, "Error %s: Could not allocate for branch", FuncName);
08353                                  SUMA_RETURN (NULL);
08354                               }
08355                         }
08356 
08357                      if (LocalHead) fprintf(SUMA_STDERR, "%s : Determining branches\n", FuncName);
08358 
08359                      
08360                      SUMA_etime(&start_time,0);
08361 
08362                      
08363                      BranchIndex = 0;
08364                      NodeIndex = 0;
08365                      branch[BranchIndex].start = Seed;
08366                      branch[BranchIndex].list[NodeIndex] = branch[BranchIndex].start;
08367                      curnode = branch[BranchIndex].start;
08368                      n_comp = N_InterMat;
08369                      ntmpint2D_V2 = 0;
08370                      while (n_comp)
08371                         {
08372                            
08373                            
08374                            if (NodeLoc_in_InterMat[curnode][2] > -1)
08375                               {
08376                                  tmpint2D_V2[0][0] = NodeLoc_in_InterMat[curnode][2];
08377                                  tmpint2D_V2[0][1] = NodeLoc_in_InterMat[curnode][3];
08378                                  NodeLoc_in_InterMat[curnode][2] = -1;
08379                                  ntmpint2D_V2 = 1;
08380                               }
08381                            else
08382                            if (NodeLoc_in_InterMat[curnode][0] > -1)
08383                               {
08384                                  tmpint2D_V2[0][0] = NodeLoc_in_InterMat[curnode][0];
08385                                  tmpint2D_V2[0][1] = NodeLoc_in_InterMat[curnode][1];
08386                                  NodeLoc_in_InterMat[curnode][0] = -1;
08387                                  ntmpint2D_V2 = 1;
08388                               }
08389                            else
08390                               ntmpint2D_V2 = 0;
08391 
08392                            if (!ntmpint2D_V2)  
08393                               {
08394                                  
08395                                  branch[BranchIndex].last = branch[BranchIndex].list[NodeIndex];
08396                                  branch[BranchIndex].listsz = NodeIndex + 1;
08397 
08398                                  
08399                                  
08400                                  iii = 0;
08401                                  GotSeed = 0;
08402                                  while (!GotSeed)
08403                                  {
08404                                     if (NodeLoc_in_InterMat[iii][2] > -1)
08405                                        {
08406 
08407                                           Seed = InterMat[NodeLoc_in_InterMat[iii][2]][NodeLoc_in_InterMat[iii][3]];
08408                                           GotSeed = 1;
08409                                        }
08410                                     else
08411                                     if (NodeLoc_in_InterMat[iii][0] > -1)
08412                                        {
08413                                           Seed = InterMat[NodeLoc_in_InterMat[iii][0]][NodeLoc_in_InterMat[iii][1]];
08414                                           GotSeed = 1;
08415                                        }
08416                                     else
08417                                        {
08418                                           ++iii;
08419                                           GotSeed = 0;
08420                                        }
08421                                  }
08422                                  ++BranchIndex;
08423                                  NodeIndex=0;
08424                                  branch[BranchIndex].start = Seed;
08425                                  branch[BranchIndex].list[NodeIndex] = branch[BranchIndex].start;
08426                                  curnode = branch[BranchIndex].start;
08427                               }
08428                            else 
08429                               {
08430                                  ++NodeIndex;
08431                                  if (tmpint2D_V2[0][1]) 
08432                                     branch[BranchIndex].list[NodeIndex] = 
08433                                        InterMat[tmpint2D_V2[0][0]][0];
08434                                     else 
08435                                     branch[BranchIndex].list[NodeIndex] = 
08436                                        InterMat[tmpint2D_V2[0][0]][1];
08437 
08438                                  
08439                                  curnode = branch[BranchIndex].list[NodeIndex];
08440 
08441                                  --n_comp;
08442                               }
08443 
08444                         }
08445 
08446                      
08447 
08448                      branch[BranchIndex].last = branch[BranchIndex].list[NodeIndex];
08449                      branch[BranchIndex].listsz = NodeIndex + 1;
08450 
08451                      sz_Branch = BranchIndex + 1;
08452 
08453                      
08454                      DT_BUILDSUMA_BRANCH = SUMA_etime(&start_time,1);
08455 
08456                      if (LocalHead) fprintf(SUMA_STDERR, "%s : Welding branches\n", FuncName);
08457 
08458                      
08459                      
08460                      SUMA_etime(&start_time,0);
08461 
08462                      
08463                      v = (int *)SUMA_calloc(2*sz_Branch,sizeof(int));
08464                      if (!v)
08465                         {
08466                            fprintf (SUMA_STDERR, "Error %s: Could not allocate", FuncName);
08467                            SUMA_RETURN (NULL);
08468                         }
08469                      for (i=0;i<sz_Branch;++i)
08470                         {
08471                            v[i] = branch[i].start;
08472                            v[i+sz_Branch] = branch[i].last;
08473                         }
08474 
08475 
08476                      vunq = SUMA_UniqueInt (v, 2*sz_Branch, &N_vunq, 0);
08477 
08478                      for (i=0;i<N_vunq;++i)
08479                         {
08480                            
08481 
08482                            tmpint = SUMA_Find_inIntVect (v, 2*sz_Branch, vunq[i], &ntmpint);
08483 
08484                            if (ntmpint == 2)
08485                               {
08486                                  
08487                                  if (tmpint[0] >= sz_Branch)
08488                                     {   
08489                                        tmpint[0] = tmpint[0] - sz_Branch;
08490                                        brEnd1 = 1;
08491                                     }
08492                                  else
08493                                     brEnd1 = 0;
08494                                  if (tmpint[1] >= sz_Branch)
08495                                     {   
08496                                        tmpint[1] = tmpint[1] - sz_Branch;
08497                                        brEnd2 = 1;
08498                                     }
08499                                  else
08500                                     brEnd2 = 0;
08501 
08502                                  if (tmpint[1] != tmpint[0])
08503                                     {   
08504 
08505                                        SUMA_WeldBranches (branch, &sz_Branch, tmpint[0] ,tmpint[1] , brEnd1, brEnd2);
08506 
08507                                        for (k=0;k<sz_Branch;++k)
08508                                           {
08509                                              v[k] = branch[k].start;
08510                                              v[k+sz_Branch] = branch[k].last;
08511                                           }
08512                                     }
08513                               }
08514                            SUMA_free(tmpint);
08515                         }
08516 
08517                      
08518                      for (i=0;i<sz_Branch; ++i)
08519                         {
08520                            if (branch[i].start == branch[i].last)
08521                               branch[i].closed = 1;
08522                            else
08523                               branch[i].closed = 0;
08524 
08525                         }
08526 
08527 
08528                      *WBsz = sz_Branch; 
08529 
08530                      
08531                      DT_WELDSUMA_BRANCH = SUMA_etime(&start_time,1);
08532 
08533                      if (LocalHead) fprintf(SUMA_STDERR, "%s : Freeing allocation\n", FuncName);
08534 
08535                      SUMA_free(vunq);
08536                      SUMA_free(v);
08537 
08538                      
08539                      if (LocalHead) {
08540                         printf ("\n\t\t%s, time fractions :\n",FuncName);
08541                         printf ("\t\t\tDT_WELDSUMA_BRANCH time: %f sec\n", DT_WELDSUMA_BRANCH);
08542                         printf ("\t\t\t DT_BUILDSUMA_BRANCH percent time : %f sec\n",  DT_BUILDSUMA_BRANCH);
08543                      }
08544                      fprintf(TimeOut, "%f\t%f\n", 
08545                         DT_BUILDSUMA_BRANCH, DT_WELDSUMA_BRANCH ); 
08546 
08547 
08548                      fclose(TimeOut);
08549                      SUMA_RETURN (branch);
08550 
08551                   }
08552 
08553                   
08554 
08555 
08556 
08557 
08558 
08559 
08560 
08561 
08562 
08563 
08564 
08565 
08566 
08567 
08568 
08569 
08570 
08571 
08572 
08573 
08574 
08575 
08576 
08577 
08578 
08579 
08580 
08581 
08582 
08583 
08584 
08585 
08586 
08587 
08588 
08589 
08590 
08591 
08592 
08593                   void SUMA_WeldBranches ( SUMA_BRANCH *branch, int *sz_Branch, int brIndx1, int brIndx2 , int brEnd1, int brEnd2 )
08594                   {
08595                      SUMA_BRANCH tmp;
08596                      int nlst1, nlst2, k, tmpreplace, tmpmove;
08597                      static char FuncName[]={"SUMA_WeldBranches"};
08598                      SUMA_Boolean LocalHead = NOPE;
08599 
08600                      SUMA_ENTRY;
08601 
08602                      nlst1 = branch[brIndx1].listsz;
08603                      nlst2 = branch[brIndx2].listsz;
08604                      tmp.listsz = nlst1 + nlst2 - 1;
08605 
08606                      if (!brEnd1  && !brEnd2)
08607                         {
08608                            tmp.last = branch[brIndx2].last;
08609                            tmp.start = branch[brIndx1].last;
08610                            for (k= nlst1; k>0; --k)
08611                               tmp.list[nlst1-k] =  branch[brIndx1].list[k-1];   
08612                            for (k=1;k<nlst2;++k) 
08613                               tmp.list[nlst1+k-1] = branch[brIndx2].list[k];
08614                         }
08615                      else if (brEnd1  && brEnd2)
08616                         {
08617                            tmp.last = branch[brIndx2].start;
08618                            tmp.start = branch[brIndx1].start;
08619                            for (k= 0; k <nlst1; ++k)
08620                               tmp.list[k] = branch[brIndx1].list[k];
08621                            for (k=nlst2; k >1 ; --k)
08622                               tmp.list[nlst1+nlst2-k] = branch[brIndx2].list[k-2];
08623                         }   
08624                      else if (!brEnd1 && brEnd2)
08625                         {
08626                            tmp.last = branch[brIndx2].start;
08627                            tmp.start = branch[brIndx1].last;
08628                            for (k=nlst1; k > 0; --k)
08629                               tmp.list[nlst1 - k] = branch[brIndx1].list[k-1];
08630                            for (k=nlst2; k > 1; --k)
08631                               tmp.list[nlst1+nlst2-k] = branch[brIndx2].list[k-2];
08632                         }
08633                      else if (brEnd1 && !brEnd2)
08634                         {
08635                            tmp.last = branch[brIndx2].last;
08636                            tmp.start = branch[brIndx1].start;
08637                            for (k=0;k<nlst1;++k)
08638                               tmp.list[k] = branch[brIndx1].list[k];
08639                            for (k=0;k<nlst2-1;++k)
08640                               tmp.list[nlst1+k] = branch[brIndx2].list[k+1];
08641                         }
08642 
08643                      
08644                      if (brIndx1 > brIndx2)
08645                         {
08646                            tmpreplace = brIndx2;
08647                            tmpmove = brIndx1;
08648                         }
08649                      else
08650                         {
08651                            tmpreplace = brIndx1;
08652                            tmpmove = brIndx2;
08653                         }
08654                      
08655                      branch[tmpreplace].start = tmp.start;
08656                      branch[tmpreplace].last = tmp.last;
08657                      branch[tmpreplace].listsz = tmp.listsz;
08658                      for(k=0;k<branch[tmpreplace].listsz;++k)
08659                         branch[tmpreplace].list[k] = tmp.list[k];
08660 
08661                      
08662                      
08663                      
08664                      
08665 
08666                      if (tmpmove < *sz_Branch-1)
08667                         {
08668                            branch[tmpmove].start = branch[*sz_Branch-1].start;
08669                            branch[tmpmove].last = branch[*sz_Branch-1].last;
08670                            branch[tmpmove].listsz = branch[*sz_Branch-1].listsz;
08671                            for(k=0;k<branch[tmpmove].listsz;++k)
08672                               branch[tmpmove].list[k] = branch[*sz_Branch-1].list[k];
08673                         }
08674 
08675                      
08676                      --*sz_Branch;
08677 
08678                      SUMA_RETURNe;
08679 
08680                   }
08681 
08682                       
08683 
08684 
08685 #endif