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