1 #include "SUMA_suma.h"
2 
3 extern SUMA_CommonFields *SUMAg_CF;
4 
5 #ifdef USE_SUMA_MALLOC
6    /* NO LONGER SUPPORTED Apr. 09 04 */
7    /* This group of functions will get replaced by Bob's mcw_malloc functions that are more efficient */
8 
9    /*!
10       ptr = SUMA_malloc_fn (const char *CF,  size );
11       \purpose a wrapper around malloc function that allows one to keep track of allocated memory.
12       For the tracking to occurr, you need to have SUMA_MEMTRACE_FLAG set to 1 (when compiling) and then turn the flag SUMAg_CF->MemTrace on.
13       ifdef SUMA_MEMTRACE_FLAG and SUMAg_CF->MemTrace then when size bytes are allocated to ptr the following happens:
14       SUMAg_CF->Mem->Pointers[SUMAg_CF->Mem->N_alloc] = ptr;
15       SUMAg_CF->Mem->Size[SUMAg_CF->Mem->N_alloc] = size;
16       ++SUMAg_CF->Mem->N_alloc;
17 
18       otherwise, only ptr = malloc (size) is executed.
19       \param CF (const char *) name of calling function
20       \param size (size_t)
21       \ret ptr (void *)
22    */
SUMA_malloc_fn(const char * CF,size_t size)23    void *SUMA_malloc_fn (const char *CF, size_t size)
24    {
25       void *ptr;
26       static char FuncName[]={"SUMA_malloc_fn"};
27 
28       #if SUMA_MEMTRACE_FLAG
29          SUMA_ENTRY;
30       #endif
31       /* The allocation */
32       ptr = malloc (size);
33 
34       #if SUMA_MEMTRACE_FLAG
35          if (SUMAg_CF->MemTrace) {
36             ++SUMAg_CF->Mem->N_alloc;
37             if (SUMAg_CF->Mem->N_MaxPointers <= SUMAg_CF->Mem->N_alloc) {
38                /* must reallocate */
39                SUMAg_CF->Mem->N_MaxPointers += SUMA_MEMTRACE_BLOCK;
40                SUMAg_CF->Mem->Pointers = (void **)realloc (SUMAg_CF->Mem->Pointers, sizeof(void*) * SUMAg_CF->Mem->N_MaxPointers);
41                SUMAg_CF->Mem->Size  = (int *)realloc (SUMAg_CF->Mem->Size, sizeof(int) * SUMAg_CF->Mem->N_MaxPointers);
42               if (!SUMAg_CF->Mem->Pointers || !SUMAg_CF->Mem->Pointers) {
43                   fprintf (SUMA_STDERR, "Error %s: Failed to reallocate.\nTurning off memory tracing.\n", \
44                            FuncName);
45                   /* free up allocated space, clean up pointers, turn off memory tracing */
46                   if (SUMAg_CF->Mem->Pointers) free(SUMAg_CF->Mem->Pointers);
47                   if (SUMAg_CF->Mem->Size) free(SUMAg_CF->Mem->Size);
48                   SUMAg_CF->MemTrace = 0;
49                   SUMAg_CF->Mem->N_alloc = 0;
50                   SUMAg_CF->Mem->N_MaxPointers = 0;
51                   SUMA_RETURN(ptr);
52                }
53             }
54             SUMAg_CF->Mem->Pointers[SUMAg_CF->Mem->N_alloc-1] = ptr;
55             SUMAg_CF->Mem->Size[SUMAg_CF->Mem->N_alloc-1] = size;
56          }
57          SUMA_RETURN(ptr);
58       #else
59          return(ptr);
60       #endif
61    }
62 
SUMA_realloc_fn(const char * CF,void * ptr,size_t size)63    void *SUMA_realloc_fn (const char *CF, void *ptr, size_t size)
64    {
65       void *ptr2;
66       int i;
67       static char FuncName[]={"SUMA_realloc_fn"};
68 
69       #if SUMA_MEMTRACE_FLAG
70          SUMA_ENTRY;
71       #endif
72 
73       /* The allocation */
74       ptr2 = realloc(ptr, size);
75 
76       #if SUMA_MEMTRACE_FLAG
77          if (SUMAg_CF->MemTrace) {
78             SUMA_Boolean Found = NOPE;
79             /* find the pointer that's being changed*/
80             for (i=0; i < SUMAg_CF->Mem->N_alloc && !Found; ++i) {
81                if (SUMAg_CF->Mem->Pointers[i] == ptr) {
82                  /* cleanup that one and replace with new*/
83                   SUMAg_CF->Mem->Pointers[i] = ptr2;
84                   SUMAg_CF->Mem->Size[i] = size;
85                   Found = YUP;
86                }
87             }
88 
89             if (!Found) {
90               fprintf (SUMA_STDERR, "Error %s: Pointer %p not found in Mem struct. \n", FuncName,ptr);
91             }
92          }
93 
94          SUMA_RETURN(ptr2);
95       #else
96          return(ptr2);
97       #endif
98 
99    }
100    /*!
101       This function is very similar to SUMA_malloc_fn except that it uses calloc instead of malloc and
102       SUMAg_CF->Mem->Size[SUMAg_CF->Mem->N_alloc] = nmemb*size;
103       \param CF (const char *) name of calling function
104       \param nmemb (size_t) number of elements
105       \param size (size_t) size of an element
106       \ret ptr (void *) pointer to nmemb*size allocated space
107 
108       \sa SUMA_malloc_fn
109    */
SUMA_calloc_fn(const char * CF,size_t nmemb,size_t size)110    void *SUMA_calloc_fn (const char *CF, size_t nmemb, size_t size) {
111       void *ptr;
112       static char FuncName[]={"SUMA_calloc_fn"};
113 
114       #if SUMA_MEMTRACE_FLAG
115          SUMA_ENTRY;
116       #endif
117 
118       /* The allocation */
119       ptr = calloc (nmemb, size);
120 
121       /* the block below is also used in SUMA_allocate2D */
122       #if SUMA_MEMTRACE_FLAG
123          if (SUMAg_CF->MemTrace) {
124             ++SUMAg_CF->Mem->N_alloc;
125             if (SUMAg_CF->Mem->N_MaxPointers <= SUMAg_CF->Mem->N_alloc) {
126                /* must reallocate */
127                /* SUMA_ShowMemTrace (SUMAg_CF->Mem, NULL);*/
128                SUMAg_CF->Mem->N_MaxPointers += SUMA_MEMTRACE_BLOCK;
129 
130                SUMAg_CF->Mem->Pointers =
131                   (void **)realloc (SUMAg_CF->Mem->Pointers, sizeof(void*) *
132                                     SUMAg_CF->Mem->N_MaxPointers);
133                SUMAg_CF->Mem->Size  =
134                   (int *)realloc((void *)SUMAg_CF->Mem->Size, sizeof(int) *
135                                          SUMAg_CF->Mem->N_MaxPointers);
136                if (!SUMAg_CF->Mem->Pointers || !SUMAg_CF->Mem->Pointers) {
137                   fprintf (SUMA_STDERR,
138                         "Error %s: Failed to reallocate.\n"
139                         "Turning off memory tracing.\n",
140                      FuncName);
141                   /* free up allocated space, clean up pointers, turn off memory
142                      tracing DO NOT USE SUMA_free here*/
143                   if (SUMAg_CF->Mem->Pointers) free(SUMAg_CF->Mem->Pointers);
144                   SUMAg_CF->Mem->Pointers = NULL;
145                   if (SUMAg_CF->Mem->Size) free(SUMAg_CF->Mem->Size);
146                   SUMAg_CF->Mem->Size = NULL;
147                   SUMAg_CF->MemTrace = 0;
148                   SUMAg_CF->Mem->N_alloc = 0;
149                   SUMAg_CF->Mem->N_MaxPointers =0;
150                   SUMA_RETURN(ptr);
151                }
152             }
153             SUMAg_CF->Mem->Pointers[SUMAg_CF->Mem->N_alloc-1] = ptr;
154             SUMAg_CF->Mem->Size[SUMAg_CF->Mem->N_alloc-1] = nmemb * size;
155          }
156          SUMA_RETURN(ptr);
157       #else
158          return(ptr);
159       #endif
160 
161    }
162 
163    /*!
164       ptr = SUMA_free(const char *CF, ptr);
165 
166       \param CF (const char *) name of calling function
167       \param ptr (void *)
168       \return NULL
169 
170       This function is the complement of SUMA_malloc_fn and SUMA_calloc_fn, it keeps track of freed memory.
171       Its usage is slightly different from that of C's free function in that the function always returns
172       a NULL so that one could with one function call free a pointer and set it to NULL.
173 
174       Even if you are not tracking memory usage, this function checks that ptr is !NULL before freeing it.
175       If you are doing massive amounts of freeing you may not want to use this function.
176 
177    */
SUMA_free_fn(const char * CF,void * ptr)178    void* SUMA_free_fn(const char *CF, void *ptr)
179    {
180       static char FuncName[]={"SUMA_free_fn"};
181       int i;
182 
183       #if SUMA_MEMTRACE_FLAG
184          SUMA_ENTRY;
185       #endif
186 
187 
188       /* This block is also used in SUMA_free2D */
189       #if SUMA_MEMTRACE_FLAG
190 
191          if (SUMAg_CF->MemTrace && ptr) {
192             SUMA_Boolean Found = NOPE;
193             for (i=0; i < SUMAg_CF->Mem->N_alloc && !Found; ++i) {
194                if (SUMAg_CF->Mem->Pointers[i] == ptr) {
195                   SUMAg_CF->Mem->Pointers[i] = SUMAg_CF->Mem->Pointers[SUMAg_CF->Mem->N_alloc-1];
196                   SUMAg_CF->Mem->Size[i] = SUMAg_CF->Mem->Size[SUMAg_CF->Mem->N_alloc-1];
197                   SUMAg_CF->Mem->Pointers[SUMAg_CF->Mem->N_alloc-1] = NULL;
198                   SUMAg_CF->Mem->Size[SUMAg_CF->Mem->N_alloc-1] = 0;
199                   --SUMAg_CF->Mem->N_alloc;
200                   Found = YUP;
201                }
202             }
203             if (!Found) {
204               fprintf (SUMA_STDERR, "Error %s: Pointer %p not found in Mem struct. \n\tOffending Calling Function is %s\n", FuncName,ptr, CF);
205             }
206          }
207 
208          if (ptr) free (ptr);
209          SUMA_RETURN(NULL);
210       #else
211          if (ptr) free (ptr);
212          return (NULL);
213       #endif
214    }
215 #else
216    /* classic vanilla */
SUMA_malloc_fn(const char * CF,size_t size)217    void *SUMA_malloc_fn (const char *CF, size_t size)
218    {
219       return (malloc(size));
220    }
SUMA_free_fn(const char * CF,void * ptr)221    void* SUMA_free_fn(const char *CF, void *ptr)
222    {
223       free(ptr);
224       return (NULL);
225    }
SUMA_calloc_fn(const char * CF,size_t nmemb,size_t size)226    void *SUMA_calloc_fn (const char *CF, size_t nmemb, size_t size)
227    {
228       return (calloc(nmemb, size));
229    }
SUMA_realloc_fn(const char * CF,void * ptr,size_t size)230    void *SUMA_realloc_fn (const char *CF, void *ptr, size_t size)
231    {
232       return (realloc(ptr, size));
233    }
234 #endif
235 
SUMA_Create_MemTrace(void)236 SUMA_MEMTRACE_STRUCT * SUMA_Create_MemTrace (void) {
237    static char FuncName[]={"SUMA_Create_MemTrace"};
238    SUMA_MEMTRACE_STRUCT *Mem;
239 
240    #ifdef USE_SUMA_MALLOC
241    SUMA_SL_Err("NO LONGER SUPPORTED");
242    return(NULL);
243    /* you cannot use SUMAg_CF here because the function that allocates for SUMAg_CF calls that one */
244 
245    /* DO NOT USE SUMA_malloc function here ! */
246    Mem = malloc (sizeof(SUMA_MEMTRACE_STRUCT));
247    /* allocate for the Pointers and Size vectors */
248    Mem->Pointers = (void **)calloc(SUMA_MEMTRACE_BLOCK, sizeof(void *));
249 
250    Mem->Size = (int *)calloc(SUMA_MEMTRACE_BLOCK, sizeof(int));
251    Mem->N_MaxPointers = SUMA_MEMTRACE_BLOCK;
252    Mem->N_alloc = 0;
253 
254    if (!Mem->Pointers || !Mem->Size) {
255       fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
256       return (NULL);
257    }
258    return(Mem);
259    #else
260    return(NULL);
261    #endif
262 }
263 
264 /*!
265    \brief Calculate factorial
266 */
SUMA_factorial(int n)267 double SUMA_factorial (int n)
268 {
269    static char FuncName[]={"SUMA_factorial"};
270    double f;
271    int c;
272 
273    SUMA_ENTRY;
274 
275    if (n<0) { SUMA_S_Errv("Factorial of negative number (%d)!\n", n); SUMA_RETURN(0); }
276    if (n==0) SUMA_RETURN(1);
277    f = 1;
278    c = 1;
279    do {
280       f *= c;
281       ++c;
282    } while (c<=n);
283 
284    SUMA_RETURN(f);
285 }
286 
287 /*!
288    \brief Calculate factorials from [0 to n]
289    results are retuned in a long long vector (n+1) elements long long
290 */
SUMA_factorial_array(int n)291 double *SUMA_factorial_array (int n)
292 {
293    static char FuncName[]={"SUMA_factorial_array"};
294    double *f;
295    int c;
296    SUMA_ENTRY;
297    if (n<0) { SUMA_S_Errv("Factorial of negative number (%d)!\n", n); SUMA_RETURN(NULL); }
298    f = (double *)SUMA_calloc(n+1, sizeof(double));
299    if (!f) {
300       SUMA_S_Crit("Failed to allocate");
301       SUMA_RETURN(NULL);
302    }
303    f[0] = 1;
304    c = 1;
305    while (c<=n) {
306       f[c] = c*f[c-1];
307       ++c;
308    }
309 
310    SUMA_RETURN(f);
311 }
312 
313 /*!
314    \brief Kronecker product
315 */
SUMA_KronProd(SUMA_MX_VEC * A,SUMA_MX_VEC * B)316 SUMA_MX_VEC *SUMA_KronProd(SUMA_MX_VEC *A, SUMA_MX_VEC *B)
317 {
318    static char FuncName[]={"SUMA_KronProd"};
319    SUMA_MX_VEC *P = NULL;
320    int pdims[2], a0, a1, b0, b1, p0, p1;
321 
322    SUMA_ENTRY;
323 
324    if (!A || !B) {
325       SUMA_S_Err("NULL input");
326       SUMA_RETURN(NULL);
327    }
328    if (A->N_dims != B->N_dims || A->N_dims != 2) {
329       SUMA_S_Err("Bad input matrix ndims");
330       SUMA_RETURN(NULL);
331    }
332    if (A->tp != SUMA_double || A->tp != B->tp) {
333       SUMA_S_Err("Only for SUMA_double matrices for the moment.");
334       SUMA_RETURN(NULL);
335    }
336    pdims[0] = A->dims[0] * B->dims[0];
337    pdims[1] = A->dims[1] * B->dims[1];
338 
339 
340    if (!(P = SUMA_NewMxVec(A->tp, 2, pdims, 1))) {
341       SUMA_S_Err("Failed to create output matrix.");
342       SUMA_RETURN(NULL);
343    }
344 
345    if (P->tp == SUMA_double) {
346       double Aij, Bij;
347       for (a0=0; a0<A->dims[0]; ++a0) {
348          for (a1=0; a1<A->dims[1]; ++a1) {
349             Aij = mxvd2(A, a0, a1);
350             for (b0=0; b0<B->dims[0]; ++b0) {
351                for (b1=0; b1<B->dims[1]; ++b1) {
352                   Bij = mxvd2(B, b0, b1);
353                   p0 = B->dims[0]*a0+b0;
354                   p1 = B->dims[1]*a1+b1;
355                   mxvd2(P, p0, p1) = Aij*Bij;
356                }
357             }
358          }
359       }
360    }
361 
362    SUMA_RETURN(P);
363 }
364 
365 /*!
366    \brief turn a SUMA_MX_VEC into an equivalent matrix
367 
368 */
SUMA_MxVecBuildMat(SUMA_MX_VEC * mxv)369 int SUMA_MxVecBuildMat(SUMA_MX_VEC *mxv)
370 {
371    static char FuncName[]={"SUMA_MxVecBuildMat"};
372    int i = 0, j=0;
373 
374    SUMA_ENTRY;
375 
376    if (!mxv) {
377       SUMA_S_Err("NULL mxv");
378       SUMA_RETURN(0);
379    }
380    if (mxv->tp != SUMA_double) {
381       SUMA_S_Err("This function is only for double types");
382    }
383 
384    if (!mxv->fdf) {
385       SUMA_S_Err("Will not work if fdf != 1");
386       SUMA_RETURN(0);
387    }
388    if (!mxv->N_dims || mxv->N_dims > 2) {
389       SUMA_S_Err("MxVec not in matriceable form!");
390       SUMA_RETURN(0);
391    }
392 
393    if (mxv->m) {
394       SUMA_S_Err("m is not null here");
395       SUMA_RETURN(0);
396    }
397 
398    mxv->m = (matrix *)SUMA_malloc(sizeof(matrix));
399    matrix_initialize(mxv->m);
400 
401    /* create matrix using trickery to avoid duplicating data(reflects matrix_create)*/
402    mxv->m->rows = mxv->dims[0];
403    if (mxv->N_dims == 2) mxv->m->cols = mxv->dims[1];
404    else mxv->m->cols = 1;
405 
406    mxv->m->elts = (double **) malloc (sizeof(double *) * mxv->m->rows);
407    if (mxv->m->elts == NULL) {
408       SUMA_S_Err("Failed to allocate for elts");
409       SUMA_RETURN(0);
410    }
411 
412    for (i = 0;  i < mxv->m->rows;  i++) {
413       mxv->m->elts[i] = (double *)malloc(sizeof(double)*mxv->m->cols);
414       if (mxv->m->elts[i] == NULL) {
415          SUMA_S_Err("Failed to allocate for elts[i]");
416          SUMA_RETURN(0);
417       }
418    }
419 
420    /* fill it up , explicit copy! MxVec does not store matrices row by row*/
421    for (i = 0;  i < mxv->m->rows;  i++) {
422       for (j = 0;  j < mxv->m->cols;  j++) {
423          mxv->m->elts[i][j] = mxvd2(mxv, i,j);
424       }
425    }
426 
427    SUMA_RETURN(1);
428 }
429 
430 /*!
431    Note: contents of input matrix c are destroyed here
432    ONLY works for double matrices
433 */
SUMA_matrix2MxVec(matrix c)434 SUMA_MX_VEC *SUMA_matrix2MxVec(matrix c)
435 {
436    static char FuncName[]={"SUMA_matrix2MxVec"};
437    SUMA_MX_VEC *mxv;
438    int N_dims=2, dims[2], i, j;
439    SUMA_Boolean LocalHead = NOPE;
440 
441    SUMA_ENTRY;
442 
443    dims[0] = c.rows; dims[1] = c.cols;
444    mxv = SUMA_NewMxNullVec(SUMA_double, N_dims,  dims,  1);
445    /* have to create a new vector, MxVec does not store row by row*/
446    mxv->dv = (double *)SUMA_malloc(c.cols*c.rows*sizeof(double));
447    mxv->v = (void*)mxv->dv;
448    if (!mxv->dv) {
449          SUMA_S_Crit("Failed to allocate");
450          SUMA_RETURN(NULL);
451    }
452 
453    SUMA_LHv("Filling %d rows, %d cols", c.rows, c.cols);
454    for (i=0; i<c.rows; ++i) {
455       for (j=0; j<c.cols; ++j) {
456          mxvd2(mxv,i,j) = c.elts[i][j];
457       }
458    }
459 
460    matrix_destroy(&c);
461 
462    SUMA_RETURN(mxv);
463 }
464 
SUMA_CoerceMxVec(SUMA_MX_VEC * va,SUMA_VARTYPE tp,int abs,SUMA_MX_VEC * recycle)465 SUMA_MX_VEC *SUMA_CoerceMxVec(SUMA_MX_VEC *va, SUMA_VARTYPE tp,
466                               int abs, SUMA_MX_VEC *recycle)
467 {
468    static char FuncName[]={"SUMA_CoerceMxVec"};
469    SUMA_MX_VEC *vt=NULL;
470    int i;
471 
472    SUMA_ENTRY;
473 
474    if (  (va->tp != SUMA_double && va->tp != SUMA_complex) ||
475          (tp != SUMA_double && tp != SUMA_complex) ) {
476       SUMA_S_Err("Only complex and double types allowed.");
477       SUMA_RETURN(NULL);
478    }
479 
480    if (recycle) {
481       if (!SUMA_MxVecSameDims(va, recycle)) {
482          SUMA_S_Err("Bad recycle");
483          SUMA_RETURN(NULL);
484       }
485       if (recycle->tp != tp) {
486          SUMA_S_Errv("Mismatch between recycle->tp=%d and tp=%d\n",
487                      recycle->tp , tp);
488          SUMA_RETURN(NULL);
489       }
490       vt = recycle;
491    } else {
492       if (!(vt = SUMA_NewMxVec(tp, va->N_dims, va->dims, 1))) {
493          SUMA_S_Err("Failed to allocate");
494          SUMA_RETURN(NULL);
495       }
496    }
497 
498    if (va->tp == SUMA_complex  && tp == SUMA_double) {
499        if (abs) {
500          for (i=0; i<va->N_vals; ++i) {
501             mxvd1(vt, i) = (double)SUMA_COMPLEX_ABS(mxvc1(va,i));
502          }
503        } else {
504          for (i=0; i<va->N_vals; ++i) {
505             mxvd1(vt, i) = (double)mxvc1(va,i).r;
506          }
507        }
508    } else if (va->tp == SUMA_double  && tp == SUMA_complex) {
509       if (abs) {
510          for (i=0; i<va->N_vals; ++i) {
511             mxvc1(vt, i).r = (float)SUMA_ABS(mxvd1(va,i));
512             mxvc1(vt, i).i = 0.0;
513          }
514       } else {
515          for (i=0; i<va->N_vals; ++i) {
516             mxvc1(vt, i).r = (float)(mxvd1(va,i));
517             mxvc1(vt, i).i = 0.0;
518          }
519       }
520    } else {
521       SUMA_S_Err("Type combo not supported, should not be here");
522       vt = SUMA_FreeMxVec(vt);
523    }
524 
525    SUMA_RETURN(vt);
526 }
527 
SUMA_MxVecAdd(SUMA_MX_VEC * va,SUMA_MX_VEC * vb,int sign,SUMA_MX_VEC * recycle)528 SUMA_MX_VEC *SUMA_MxVecAdd(SUMA_MX_VEC *va, SUMA_MX_VEC *vb, int sign, SUMA_MX_VEC *recycle)
529 {
530    static char FuncName[]={"SUMA_MxVecAdd"};
531    SUMA_MX_VEC *vt=NULL;
532    int i, j;
533    SUMA_VARTYPE tp;
534    int dims[SUMA_MX_VEC_MAX_DIMS];
535 
536    SUMA_Boolean LocalHead = NOPE;
537 
538    SUMA_ENTRY;
539 
540    if (va->N_dims != vb->N_dims) {
541       SUMA_S_Err("Mismatch in N_dims");
542       SUMA_RETURN(vt);
543    }
544    if (va->N_vals != vb->N_vals) {
545       SUMA_S_Err("Mismatch in N_vals");
546       SUMA_RETURN(vt);
547    }
548    for (i=0; i<va->N_dims; ++i) {
549       dims[i] = va->dims[i];
550       if (va->dims[i] != vb->dims[i]) {
551          SUMA_S_Err("Mismatch in dims of va and vb\n");
552          SUMA_RETURN(vt);
553       }
554    }
555    if (  (va->tp != SUMA_complex && va->tp != SUMA_double) ||
556          (vb->tp != SUMA_complex && vb->tp != SUMA_double)  ) {
557       SUMA_S_Err("Only complex and double allowed.");
558       SUMA_RETURN(vt);
559    }
560    if (va->tp == SUMA_complex || vb->tp == SUMA_complex) tp = SUMA_complex;
561    else tp = SUMA_double;
562 
563    if (recycle ) {
564       if (recycle->tp != tp) {
565          SUMA_S_Errv("Recycled vector of type %d, type %d needed.\n", recycle->tp, va->tp);
566          SUMA_RETURN(vt);
567       }
568       if (recycle->N_vals != va->N_vals) {
569          SUMA_S_Errv("Recycled vector of N_vals %d, N_vals %d needed.\n", recycle->N_vals, va->N_vals);
570          SUMA_RETURN(vt);
571       }
572       if (recycle->N_dims != va->N_dims) {
573          SUMA_S_Errv("Recycled vector of N_dims %d, N_dims of %d needed.\n", recycle->N_dims, va->N_dims);
574          SUMA_RETURN(vt);
575       }
576       for (i=0; i<va->N_dims; ++i) {
577          if (recycle->dims[i] != dims[i]) {
578             SUMA_S_Errv("Recycled vector dims[%d]=%d, dims[%d]=%d needed.\n", i, recycle->dims[i], i, dims[i]);
579             SUMA_RETURN(vt);
580          }
581       }
582       vt = recycle;
583    } else {
584       vt = SUMA_NewMxVec(tp, va->N_dims, dims, 1);
585    }
586 
587    /* here goes */
588    if (va->tp == SUMA_complex && vb->tp == SUMA_complex) {
589       if (sign > 0){ for (i=0; i<va->N_vals; ++i) {
590                         mxvc1(vt, i).r = mxvc1(va, i).r + mxvc1(vb, i).r;
591                         mxvc1(vt, i).i = mxvc1(va, i).i + mxvc1(vb, i).i;
592                      }
593       } else  {      for (i=0; i<va->N_vals; ++i) {
594                         mxvc1(vt, i).r = mxvc1(va, i).r - mxvc1(vb, i).r;
595                         mxvc1(vt, i).i = mxvc1(va, i).i - mxvc1(vb, i).i;
596                      }
597       }
598    } else if (va->tp == SUMA_complex && vb->tp == SUMA_double) {
599       if (sign > 0){ for (i=0; i<va->N_vals; ++i) {
600                         mxvc1(vt, i).r = mxvc1(va, i).r + mxvd1(vb, i);
601                         mxvc1(vt, i).i = mxvc1(va, i).i ;
602                      }
603       } else  {      for (i=0; i<va->N_vals; ++i) {
604                         mxvc1(vt, i).r = mxvc1(va, i).r - mxvd1(vb, i);
605                         mxvc1(vt, i).i = mxvc1(va, i).i ;
606                      }
607       }
608    } else if (va->tp == SUMA_double && vb->tp == SUMA_complex) {
609       if (sign > 0){ for (i=0; i<va->N_vals; ++i) {
610                         mxvc1(vt, i).r = mxvd1(va, i)   + mxvc1(vb, i).r;
611                         mxvc1(vt, i).i =                  mxvc1(vb, i).i;
612                      }
613       } else  {      for (i=0; i<va->N_vals; ++i) {
614                         mxvc1(vt, i).r = mxvd1(va, i)   - mxvc1(vb, i).r;
615                         mxvc1(vt, i).i =                - mxvc1(vb, i).i;
616                      }
617       }
618    } else if (va->tp == SUMA_double && vb->tp == SUMA_double) {
619       if (sign > 0){ for (i=0; i<va->N_vals; ++i) {
620                         mxvd1(vt, i)   = mxvd1(va, i)   + mxvd1(vb, i)  ;
621                      }
622       } else  {      for (i=0; i<va->N_vals; ++i) {
623                         mxvd1(vt, i)   = mxvd1(va, i)   - mxvd1(vb, i)  ;
624                      }
625       }
626    } else {
627       SUMA_S_Err("Bad combo");
628       vt = SUMA_FreeMxVec(vt);
629    }
630 
631    SUMA_RETURN(vt);
632 }
633 
634 /*!
635    \brief Return the transpose of MxVec
636 */
SUMA_MxVecTranspose(SUMA_MX_VEC * va,SUMA_MX_VEC * recycle)637 SUMA_MX_VEC * SUMA_MxVecTranspose(SUMA_MX_VEC *va, SUMA_MX_VEC *recycle)
638 {
639    static char FuncName[]={"SUMA_MxVecTranspose"};
640    SUMA_MX_VEC *vt=NULL;
641    int i, j;
642    int dims[2];
643 
644    SUMA_Boolean LocalHead = NOPE;
645    SUMA_ENTRY;
646 
647    if (va->N_dims > 2 || va->N_dims < 0) {
648       SUMA_S_Errv("Bad N_dims (%d)\n", va->N_dims);
649    }
650    if (va->N_dims == 1) va->dims[1] = 1;
651    dims[0] = va->dims[1];
652    dims[1] = va->dims[0];
653    if (recycle ) {
654       if (recycle->tp != va->tp) {
655          SUMA_S_Errv("Recycled vector of type %d, type %d needed.\n", recycle->tp, va->tp);
656          SUMA_RETURN(vt);
657       }
658       if (recycle->dims[0] != dims[0]) {
659          SUMA_S_Errv("Recycled vector dims[0]=%d, dims[0]=%d needed.\n", recycle->dims[0], dims[0]);
660          SUMA_RETURN(vt);
661       }
662       if (recycle->dims[1] != dims[1]) {
663          SUMA_S_Errv("Recycled vector dims[1]=%d, dims[1]=%d needed.\n", recycle->dims[1], dims[1]);
664          SUMA_RETURN(vt);
665       }
666       vt = recycle;
667    } else {
668       vt = SUMA_NewMxVec(va->tp, 2, dims, 1);
669    }
670    switch (va->tp) {
671       case SUMA_double:
672          if (va->dims[0] > va->dims[1]){  /* an optimization that is significant for stretched matrices */
673             for (i=0;i<va->dims[0];++i) {
674                for (j=0; j<va->dims[1]; ++j) {
675                   mxvd2(vt,j,i) = mxvd2(va,i,j);
676                }
677             }
678          } else {
679             for (j=0; j<va->dims[1]; ++j) {
680                for (i=0;i<va->dims[0];++i) {
681                   mxvd2(vt,j,i) = mxvd2(va,i,j);
682                }
683             }
684          }
685          break;
686       case SUMA_complex:
687          if (va->dims[0] > va->dims[1]){  /* an optimization that is significant for stretched matrices */
688             for (i=0;i<va->dims[0];++i) {
689                for (j=0; j<va->dims[1]; ++j) {
690                   mxvc2(vt,j,i).r = mxvc2(va,i,j).r;
691                   mxvc2(vt,j,i).i = -mxvc2(va,i,j).i;
692                }
693             }
694          } else {
695             for (j=0; j<va->dims[1]; ++j) {
696                for (i=0;i<va->dims[0];++i) {
697                   mxvc2(vt,j,i).r = mxvc2(va,i,j).r;
698                   mxvc2(vt,j,i).i = -mxvc2(va,i,j).i;
699                }
700             }
701          }
702          break;
703       default:
704          SUMA_S_Err("Lazy did not implement this one.\n");
705          SUMA_RETURN(NULL);
706          break;
707    }
708    SUMA_RETURN(vt);
709 }
710 
SUMA_MxVecSetIdentity(SUMA_MX_VEC * thisone)711 SUMA_MX_VEC * SUMA_MxVecSetIdentity(SUMA_MX_VEC *thisone)
712 {
713    static char FuncName[]={"SUMA_MxVecSetIdentity"};
714    SUMA_ENTRY;
715    SUMA_RETURN(SUMA_MxVecIdentity(thisone->tp, thisone->N_dims, thisone->dims, thisone));
716 }
717 
SUMA_MxVecIdentity(SUMA_VARTYPE tp,int n,int dims[],SUMA_MX_VEC * thisone)718 SUMA_MX_VEC * SUMA_MxVecIdentity(SUMA_VARTYPE tp, int n, int dims[], SUMA_MX_VEC *thisone)
719 {
720    static char FuncName[]={"SUMA_MxVecIdentity"};
721    SUMA_MX_VEC *vi=NULL;
722    int i,j;
723    SUMA_Boolean LocalHead = NOPE;
724 
725    SUMA_ENTRY;
726 
727    if (n != 2) {
728       SUMA_S_Err("Function only for matrices");
729       SUMA_RETURN(vi);
730    }
731    if (tp != SUMA_double && tp != SUMA_complex) {
732       SUMA_S_Err("Function only for double or complex matrices");
733       SUMA_RETURN(vi);
734    }
735 
736    if (thisone) {
737       if (thisone->tp != tp) {
738          SUMA_S_Err("Incompatible type for recycled vector");
739          SUMA_RETURN(vi);
740       }
741       if (thisone->N_dims != n) {
742          SUMA_S_Err("Incompatible number of dimensions for recycled vector");
743          SUMA_RETURN(vi);
744       }
745       if (thisone->dims[0] != dims[0]) {
746          SUMA_S_Err("Incompatible 0th dimensions for recycled vector");
747          SUMA_RETURN(vi);
748       }
749       if (thisone->dims[1] != dims[1]) {
750          SUMA_S_Err("Incompatible 1st dimensions for recycled vector");
751          SUMA_RETURN(vi);
752       }
753       vi = thisone;
754    } else {
755       vi = SUMA_NewMxVec(tp, n, dims, 1);
756    }
757    switch (tp) {
758       case SUMA_double:
759          for (i=0; i<dims[0]; ++i) {
760             for (j=0; j<dims[0]; ++j) {
761                if (i==j) mxvd2(vi, i, j) = 1.0;
762                else mxvd2(vi, i, j) = 0.0;
763             }
764          }
765          break;
766       case SUMA_complex:
767          for (i=0; i<dims[0]; ++i) {
768             for (j=0; j<dims[0]; ++j) {
769                if (i==j) mxvc2(vi, i, j).r = 1.0;
770                else mxvc2(vi, i, j).r = 0.0;
771                mxvc2(vi, i, j).i = 0.0;
772             }
773          }
774          break;
775       default:
776          SUMA_S_Err("Bad type Raul");
777          break;
778    }
779 
780    SUMA_RETURN(vi);
781 }
782 
SUMA_MxVecSameDims(SUMA_MX_VEC * va,SUMA_MX_VEC * vb)783 int SUMA_MxVecSameDims(SUMA_MX_VEC *va,SUMA_MX_VEC *vb)
784 {
785    static char FuncName[]={"SUMA_MxVecSameDims"};
786    int i;
787    SUMA_ENTRY;
788    if (va->N_dims != vb->N_dims) SUMA_RETURN(0);
789    for (i=0;i<va->N_dims; ++i) if (va->dims[i]!=vb->dims[i]) SUMA_RETURN(0);
790    SUMA_RETURN(1);
791 }
SUMA_MxVecSameDims2(int N_dims,int * dims,SUMA_MX_VEC * va)792 int SUMA_MxVecSameDims2(int N_dims, int *dims, SUMA_MX_VEC *va)
793 {
794    static char FuncName[]={"SUMA_MxVecSameDims2"};
795    int i;
796    SUMA_ENTRY;
797    if (va->N_dims != N_dims) SUMA_RETURN(0);
798    for (i=0;i<va->N_dims; ++i) if (va->dims[i]!=dims[i]) SUMA_RETURN(0);
799    SUMA_RETURN(1);
800 }
801 
SUMA_MxVecCopy(SUMA_MX_VEC * va,SUMA_MX_VEC * recycle)802 SUMA_MX_VEC * SUMA_MxVecCopy(SUMA_MX_VEC *va, SUMA_MX_VEC *recycle)
803 {
804    static char FuncName[]={"SUMA_MxVecCopy"};
805    SUMA_MX_VEC *vi=NULL;
806    SUMA_Boolean LocalHead = NOPE;
807 
808    SUMA_ENTRY;
809 
810    if (recycle) {
811       if (recycle->tp != va->tp || !SUMA_MxVecSameDims(va,recycle)) {
812          SUMA_S_Err("Bad recycled MxVec");
813          SUMA_RETURN(NULL);
814       }
815       vi = recycle;
816    } else {
817       vi = SUMA_NewMxVec(va->tp, va->N_dims, va->dims, 1);
818    }
819    memcpy(vi->v, va->v, va->N_vals*SUMA_SizeOf(va->tp));
820 
821    SUMA_RETURN(vi);
822 }
823 
SUMA_MxVecRand(SUMA_VARTYPE tp,int N_dims,int * dims,SUMA_MX_VEC * recycle)824 SUMA_MX_VEC * SUMA_MxVecRand(SUMA_VARTYPE tp, int N_dims, int *dims, SUMA_MX_VEC *recycle)
825 {
826    static char FuncName[]={"SUMA_MxVecRand"};
827    SUMA_MX_VEC *vi=NULL;
828    int i;
829    SUMA_Boolean LocalHead = NOPE;
830 
831    SUMA_ENTRY;
832 
833    if (recycle) {
834       if (recycle->tp != tp || !SUMA_MxVecSameDims2(N_dims, dims,recycle)) {
835          SUMA_S_Err("Bad recycled MxVec");
836          SUMA_RETURN(NULL);
837       }
838       vi = recycle;
839    } else {
840       vi = SUMA_NewMxVec(tp, N_dims, dims, 1);
841    }
842 
843    switch (tp){
844       case SUMA_complex:
845          for (i=0; i<vi->N_vals; ++i) { mxvc1(vi, i).r = (float)rand()/(float)RAND_MAX; mxvc1(vi, i).i = (float)rand()/(float)RAND_MAX; }
846          break;
847       case SUMA_double:
848          for (i=0; i<vi->N_vals; ++i) mxvd1(vi, i) = (double)rand()/(double)RAND_MAX;
849          break;
850       default:
851          SUMA_S_Err("MxVec Type not supported");
852          vi = SUMA_FreeMxVec(vi);
853          break;
854    }
855    SUMA_RETURN(vi);
856 }
857 
858 /*!
859    \brief swap two rows in a matrix (not very efficient because matrix is stored column_major (fdf = 1)
860 */
SUMA_MxVecSwapRows(SUMA_MX_VEC * va,int r1,int r2)861 int SUMA_MxVecSwapRows(SUMA_MX_VEC *va, int r1, int r2)
862 {
863    static char FuncName[]={"SUMA_MxVecSwapRows"};
864    int j;
865    double d;
866    complex c;
867 
868    SUMA_ENTRY;
869 
870    if (r1 >= va->dims[0] || r2 >= va->dims[0]) {
871       SUMA_S_Err("Rows exceed matrix dimension");
872       SUMA_RETURN(0);
873    }
874 
875    if (va->tp != SUMA_double && va->tp != SUMA_complex) {
876       SUMA_S_Err("No type support");
877       SUMA_RETURN(0);
878    }
879 
880 
881    switch(va->tp) {
882       case SUMA_double:
883          for (j=0;j<va->dims[1];++j) {
884             d = mxvd2(va, r1, j);
885             mxvd2(va, r1, j) = mxvd2(va, r2, j);
886             mxvd2(va, r2, j) = d;
887          }
888          break;
889       case SUMA_complex:
890          for (j=0;j<va->dims[1];++j) {
891             c.r = mxvc2(va, r1, j).r;
892             c.i = mxvc2(va, r1, j).i;
893             mxvc2(va, r1, j).r = mxvc2(va, r2, j).r;
894             mxvc2(va, r1, j).i = mxvc2(va, r2, j).i;
895             mxvc2(va, r2, j).r = c.r;
896             mxvc2(va, r2, j).i = c.i;
897          }
898          break;
899       default:
900          SUMA_S_Err("Should not be here");
901          SUMA_RETURN(0);
902          break;
903    }
904 
905    SUMA_RETURN(1);
906 }
907 
908 /*!
909    \brief Return the inverse of MxVec
910 */
SUMA_MxVecInverse(SUMA_MX_VEC * va,SUMA_MX_VEC * recycle)911 SUMA_MX_VEC * SUMA_MxVecInverse(SUMA_MX_VEC *va, SUMA_MX_VEC *recycle)
912 {
913    static char FuncName[]={"SUMA_MxVecInverse"};
914    SUMA_MX_VEC *ainv=NULL, *tmp=NULL;
915    matrix a, c;
916    int i, j=0, ii, n;
917    double fmax, fval;
918    const double epsilon = 1.0e-10;
919    complex cval, cmult;
920    SUMA_Boolean LocalHead = NOPE;
921 
922    SUMA_ENTRY;
923 
924    if (LocalHead) SUMA_etime2(FuncName, NULL, NULL);
925 
926    if (va->dims[0] != va->dims[1]) {
927       SUMA_S_Err("Cannot invert non square matrix");
928       SUMA_RETURN(ainv);
929    }
930 
931    #if 0    /* not much faster using matrix functions...*/
932    if (recycle) {
933       SUMA_S_Err("No recycling in this case");
934       SUMA_RETURN(ainv);
935    }
936    if (va->tp == SUMA_double) {
937       if (!va->m) {
938          SUMA_MxVecBuildMat(va);
939          if (LocalHead) SUMA_ShowMxVec(va,va->N_vals, NULL, "\ndbg va\n");
940       }
941       if (LocalHead) SUMA_etime2(FuncName, "Matrix build time",FuncName);
942       if (!va->m) {
943          SUMA_S_Err("Failed to create matrix");
944          SUMA_RETURN(ainv);
945       }
946       a = *(va->m);
947       matrix_initialize (&c);
948       if (!matrix_inverse (a,&c)) {
949          SUMA_S_Err("Failed in inverse");
950          SUMA_RETURN(ainv);
951       }
952       if (LocalHead) SUMA_etime2(FuncName, "Matrix inverse time",FuncName);
953       SUMA_LH("Going from matrix to vector");
954       ainv = SUMA_matrix2MxVec(c); /* c is destroyed inside SUMA_matrix2MxVec */
955       if (LocalHead) SUMA_etime2(FuncName, "Matrix copy time",FuncName);
956       SUMA_S_Note("va now contains duplicate of vector data in m");
957    } else {
958       SUMA_S_Err("Not ready yet ");
959    }
960    SUMA_RETURN(ainv);
961    #else
962    /* do it in house (after matrix_inverse)*/
963    n = va->dims[0];
964    if (recycle) {
965       SUMA_LH("Reusing vector");
966       if (recycle->tp != va->tp) {
967          SUMA_S_Errv("Recycled vector of type %d, type %d needed.\n", recycle->tp, va->tp);
968          SUMA_RETURN(ainv);
969       }
970       if (recycle->dims[0] != va->dims[0]) {
971          SUMA_S_Errv("Recycled vector dims[0]=%d, dims[0]=%d needed.\n", recycle->dims[0], va->dims[0]);
972          SUMA_RETURN(ainv);
973       }
974       if (recycle->dims[1] != va->dims[1]) {
975          SUMA_S_Errv("Recycled vector dims[1]=%d, dims[1]=%d needed.\n", recycle->dims[1], va->dims[1]);
976          SUMA_RETURN(ainv);
977       }
978       ainv = recycle;
979       if (!(ainv = SUMA_MxVecSetIdentity(ainv))) {
980          SUMA_S_Err("Failed to set identity");
981          SUMA_RETURN(ainv);
982       }
983    } else {
984       ainv = SUMA_MxVecIdentity(va->tp, 2, va->dims, NULL);
985    }
986    tmp = SUMA_MxVecCopy(va, NULL);
987 
988    switch (va->tp) {
989       case SUMA_double:
990          for (i = 0;  i < n;  i++) {
991             fmax = fabs(mxvd2(tmp,i,i));
992             for (j = i+1;  j < n;  j++) {
993                if (fabs(mxvd2(tmp,j,i)) > fmax) {
994                   fmax = fabs(mxvd2(tmp,j,i));
995                   SUMA_MxVecSwapRows(tmp, i, j);
996                   SUMA_MxVecSwapRows(ainv, i, j);
997                }
998             }
999             if (fmax < epsilon) {
1000                SUMA_S_Err("Near singular or badly scaled");
1001                ainv = SUMA_FreeMxVec(ainv);
1002                SUMA_RETURN(ainv);
1003             }
1004             fval = 1.0 / mxvd2(tmp,i,i);   /* RWCox: change division by this to */
1005             for (j = 0;  j < n;  j++)  {   /*        multiplication by 1.0/this */
1006 	            mxvd2(tmp,i,j) *= fval;
1007 	            mxvd2(ainv,i,j) *= fval;
1008 	         }
1009             for (ii = 0;  ii < n;  ii++) {
1010 	            if (ii != i) {
1011 	               fval = mxvd2(tmp,ii,i);
1012 	               for (j = 0;  j < n;  j++) {
1013 		               mxvd2(tmp,ii,j) -= fval*mxvd2(tmp,i,j);
1014 		               mxvd2(ainv,ii,j) -= fval*mxvd2(ainv,i,j);
1015 	               }
1016 	            }
1017             }
1018          }
1019          break;
1020       case SUMA_complex:
1021          for (i = 0;  i < n;  i++) {
1022             fmax = SUMA_COMPLEX_ABS(mxvc2(tmp,i,i));
1023             for (j = i+1;  j < n;  j++) {
1024                if (SUMA_COMPLEX_ABS(mxvc2(tmp,j,i)) > fmax) {
1025                   fmax = SUMA_COMPLEX_ABS(mxvc2(tmp,j,i));
1026                   SUMA_MxVecSwapRows(tmp, i, j);
1027                   SUMA_MxVecSwapRows(ainv, i, j);
1028                }
1029             }
1030             if (fmax < epsilon) {
1031                SUMA_S_Err("Near singular or badly scaled");
1032                ainv = SUMA_FreeMxVec(ainv);
1033                SUMA_RETURN(ainv);
1034             }
1035             SUMA_COMPLEX_INV(mxvc2(tmp,i,i), cval);
1036             for (j = 0;  j < n;  j++)  {
1037 	            cmult.r = mxvc2(tmp,i,j).r;
1038                cmult.i = mxvc2(tmp,i,j).i;
1039                SUMA_COMPLEX_MULT(cmult, cval, mxvc2(tmp,i,j));
1040 	            cmult.r = mxvc2(ainv,i,j).r;
1041                cmult.i = mxvc2(ainv,i,j).i;
1042                SUMA_COMPLEX_MULT(cmult, cval, mxvc2(ainv,i,j));
1043 	         }
1044             for (ii = 0;  ii < n;  ii++) {
1045 	            if (ii != i) {
1046 	               cval = mxvc2(tmp,ii,i);
1047 	               for (j = 0;  j < n;  j++) {
1048 		               SUMA_COMPLEX_MULT(cval, mxvc2(tmp,i,j), cmult);
1049                      mxvc2(tmp,ii,j).r = mxvc2(tmp,ii,j).r - cmult.r;
1050                      mxvc2(tmp,ii,j).i = mxvc2(tmp,ii,j).i - cmult.i;
1051 		               SUMA_COMPLEX_MULT(cval, mxvc2(ainv,i,j), cmult);
1052                      mxvc2(ainv,ii,j).r = mxvc2(ainv,ii,j).r - cmult.r;
1053                      mxvc2(ainv,ii,j).i = mxvc2(ainv,ii,j).i - cmult.i;
1054 	               }
1055 	            }
1056             }
1057          }
1058          break;
1059       default:
1060          SUMA_S_Err("Unsupported type");
1061          SUMA_RETURN(SUMA_FreeMxVec(ainv));
1062          break;
1063    }
1064    tmp = SUMA_FreeMxVec(tmp);
1065    if (LocalHead) SUMA_etime2(FuncName, "Matrix inverse time", FuncName);
1066    SUMA_RETURN(ainv);
1067    #endif
1068 }
1069 
1070 /*!
1071    \brief Multiply two MX_VEC matrices where one dimension is much larger than the other
1072    Main difference with SUMA_MxVecMult is that here, the sum is
1073    mxvd2(vp, i,j) += mxvd2(vt,k,i) * mxvd2(vb, k,j);
1074    instead of
1075    mxvd2(vp, i,j) += mxvd2(va,i,k) * mxvd2(vb, k,j);
1076 
1077 */
SUMA_MxVecMultRect(SUMA_MX_VEC * va,SUMA_MX_VEC * vb,SUMA_MX_VEC * recycle,int InfoMask)1078 SUMA_MX_VEC *SUMA_MxVecMultRect(SUMA_MX_VEC *va, SUMA_MX_VEC *vb, SUMA_MX_VEC *recycle, int InfoMask)
1079 {
1080    static char FuncName[]={"SUMA_MxVecMultRect"};
1081    SUMA_ENTRY;
1082    SUMA_RETURN(SUMA_MxVecMultRect_Engine(va, vb, recycle, NULL, NULL, InfoMask));
1083 }
1084 /*! Passing transpose of va (if you need it elsewhere) would save on waisted computations. vbt is useless */
SUMA_MxVecMultRect_Engine(SUMA_MX_VEC * va,SUMA_MX_VEC * vb,SUMA_MX_VEC * recycle,SUMA_MX_VEC * vat,SUMA_MX_VEC * vbt,int InfoMask)1085 SUMA_MX_VEC *SUMA_MxVecMultRect_Engine(SUMA_MX_VEC *va, SUMA_MX_VEC *vb, SUMA_MX_VEC *recycle, SUMA_MX_VEC *vat, SUMA_MX_VEC *vbt, int InfoMask)
1086 {
1087    static char FuncName[]={"SUMA_MxVecMultRect_Engine"};
1088    SUMA_MX_VEC *vp=NULL, *vt=NULL;
1089    SUMA_VARTYPE tp=SUMA_notypeset;
1090    int dims[2], N_dims, i, j, k;
1091    complex ctmp;
1092    struct timeval tt;
1093    int symm = 0;
1094    matrix a, b, c;
1095    SUMA_Boolean LocalHead = NOPE;
1096 
1097    SUMA_ENTRY;
1098 
1099    if (!va || va->N_dims != 2 || !vb || vb->N_dims != 2) {
1100       SUMA_S_Err("inappropriate");
1101       SUMA_RETURN(NULL);
1102    }
1103 
1104    SUMA_LHv("Fast rectangular matrix multiplication mode. va is %d x %d\n", va->dims[0], va->dims[1]);
1105 
1106    SUMA_etime2(FuncName, NULL, NULL);
1107 
1108    if (!vat && InfoMask & MATRIX_B_IS_AT) vat = vb;
1109 
1110    if (!vat) vt = SUMA_MxVecTranspose(va, NULL);
1111    else vt = vat;
1112 
1113    if (InfoMask & MATRIX_B_IS_AT || InfoMask & MATRIX_OUT_SYMMETRIC) {
1114       symm = 1;
1115    } else {
1116       symm = 0;
1117    }
1118 
1119    if (  va->N_dims > 2 || va->N_dims < 1 ||
1120          vb->N_dims > 2 || vb->N_dims < 1 ) {
1121       SUMA_S_Err("Bad N_dims");
1122       if (vt != vat) vt = SUMA_FreeMxVec(vt);
1123       SUMA_RETURN(vp);
1124    }
1125    if (va->fdf != 1 || vb->fdf != 1) {
1126       SUMA_S_Err("Only first dimension first");
1127       if (vt != vat) vt = SUMA_FreeMxVec(vt);
1128       SUMA_RETURN(vp);
1129    }
1130    if (va->N_dims == 1) va->dims[1] = 1;
1131    if (vb->N_dims == 1) vb->dims[1] = 1;
1132    if (va->dims[1] != vb->dims[0]) {
1133       SUMA_S_Err("Incompatible dimensions for matrix multiplications");
1134       if (vt != vat) vt = SUMA_FreeMxVec(vt);
1135       SUMA_RETURN(vp);
1136    }
1137    if (  (vb->tp != SUMA_complex && vb->tp != SUMA_double) ||
1138          (va->tp != SUMA_complex && va->tp != SUMA_double) ) {
1139       SUMA_S_Err("vectors must either be complex or double");
1140       if (vt != vat) vt = SUMA_FreeMxVec(vt);
1141       SUMA_RETURN(vp);
1142    }
1143 
1144    dims[0] = va->dims[0]; dims[1] = vb->dims[1];
1145    if (va->tp == SUMA_complex || vb->tp == SUMA_complex) {
1146       tp = SUMA_complex;
1147    } else if (va->tp == SUMA_double && vb->tp == SUMA_double) {
1148       tp = SUMA_double;
1149    } else {
1150       SUMA_S_Err("vectors must either be complex or double");
1151       if (vt != vat) vt = SUMA_FreeMxVec(vt);
1152       SUMA_RETURN(vp);
1153    }
1154    SUMA_LHv("tp=%d, dims[0]=%d, dims[1]=%d\n", tp, dims[0], dims[1]);
1155    if (recycle) {
1156       SUMA_LH("Reusing vector");
1157       if (recycle->tp != tp) {
1158          SUMA_S_Errv("Recycled vector of type %d, type %d needed.\n", recycle->tp, tp);
1159          if (vt != vat) vt = SUMA_FreeMxVec(vt);
1160          SUMA_RETURN(vp);
1161       }
1162       if (recycle->dims[0] != dims[0]) {
1163          SUMA_S_Errv("Recycled vector dims[0]=%d, dims[0]=%d needed.\n", recycle->dims[0], dims[0]);
1164          if (vt != vat) vt = SUMA_FreeMxVec(vt);
1165          SUMA_RETURN(vp);
1166       }
1167       if (recycle->dims[1] != dims[1]) {
1168          SUMA_S_Errv("Recycled vector dims[1]=%d, dims[1]=%d needed.\n", recycle->dims[1], dims[1]);
1169          if (vt != vat) vt = SUMA_FreeMxVec(vt);
1170          SUMA_RETURN(vp);
1171       }
1172       vp = recycle;
1173    } else {
1174       vp = SUMA_NewMxVec(tp, 2, dims, 1);
1175    }
1176    if (!vp) {
1177       SUMA_S_Err("Failed to create output vector");
1178       if (vt != vat) vt = SUMA_FreeMxVec(vt);
1179       SUMA_RETURN(vp);
1180    }
1181    switch(tp) {
1182       case SUMA_complex:
1183          if (vb->tp == va->tp) { /* both are complex */
1184             SUMA_LH("Both complex");
1185             if (symm) {
1186                for (i = 0;  i < vp->dims[0];  i++) {
1187                   for (j = 0;  j < vp->dims[1];  j++) {
1188                      if (j<i) {
1189                         mxvc2(vp, i,j).r = mxvc2(vp, j,i).r ;
1190                         mxvc2(vp, i,j).i = mxvc2(vp, j,i).i ;
1191                      } else {
1192                         mxvc2(vp, i,j).r = 0.0 ;
1193                         mxvc2(vp, i,j).i = 0.0 ;
1194 	                     for (k = 0;  k < va->dims[1];  k++) {
1195 	                        SUMA_COMPLEX_MULT(mxvc2(vt,k,i), mxvc2(vb, k,j), ctmp);
1196                            mxvc2(vp, i,j).r += ctmp.r;
1197                            mxvc2(vp, i,j).i += ctmp.i;
1198                         }
1199                      }
1200                   }
1201                }
1202             } else {
1203                for (i = 0;  i < vp->dims[0];  i++) {
1204                   for (j = 0;  j < vp->dims[1];  j++) {
1205                      mxvc2(vp, i,j).r = 0.0 ;
1206                      mxvc2(vp, i,j).i = 0.0 ;
1207 	                  for (k = 0;  k < va->dims[1];  k++) {
1208 	                     SUMA_COMPLEX_MULT(mxvc2(vt,k,i), mxvc2(vb, k,j), ctmp);
1209                         mxvc2(vp, i,j).r += ctmp.r;
1210                         mxvc2(vp, i,j).i += ctmp.i;
1211                      }
1212                   }
1213                }
1214             }
1215          } else { /* only one is complex */
1216             if (va->tp == SUMA_complex) {
1217                SUMA_LH("va complex");
1218                if (symm) {
1219                   for (i = 0;  i < vp->dims[0];  i++) {
1220                      for (j = 0;  j < vp->dims[1];  j++) {
1221                         if (j<i) {
1222                            mxvc2(vp, i,j).r = mxvc2(vp, j,i).r ;
1223                            mxvc2(vp, i,j).i = mxvc2(vp, j,i).i ;
1224                         } else {
1225                            mxvc2(vp, i,j).r = 0.0 ;
1226                            mxvc2(vp, i,j).i = 0.0 ;
1227 	                        for (k = 0;  k < va->dims[1];  k++) {
1228 	                           SUMA_COMPLEX_SCALE(mxvc2(vt,k,i), mxvd2(vb, k,j), ctmp);
1229                               mxvc2(vp, i,j).r += ctmp.r;
1230                               mxvc2(vp, i,j).i += ctmp.i;
1231                            }
1232                         }
1233                      }
1234                   }
1235                } else {
1236                   for (i = 0;  i < vp->dims[0];  i++) {
1237                      for (j = 0;  j < vp->dims[1];  j++) {
1238                         mxvc2(vp, i,j).r = 0.0 ;
1239                         mxvc2(vp, i,j).i = 0.0 ;
1240 	                     for (k = 0;  k < va->dims[1];  k++) {
1241 	                        SUMA_COMPLEX_SCALE(mxvc2(vt,k,i), mxvd2(vb, k,j), ctmp);
1242                            mxvc2(vp, i,j).r += ctmp.r;
1243                            mxvc2(vp, i,j).i += ctmp.i;
1244                         }
1245                      }
1246                   }
1247                }
1248             } else {
1249                SUMA_LH("vb complex");
1250                if (symm) {
1251                   for (i = 0;  i < vp->dims[0];  i++) {
1252                      for (j = 0;  j < vp->dims[1];  j++) {
1253                         if (j<i) {
1254                            mxvc2(vp, i,j).r =  mxvc2(vp, j,i).r;
1255                            mxvc2(vp, i,j).i =  mxvc2(vp, j,i).i;
1256                         } else {
1257                            mxvc2(vp, i,j).r = 0.0 ;
1258                            mxvc2(vp, i,j).i = 0.0 ;
1259 	                        for (k = 0;  k < va->dims[1];  k++) {
1260 	                           SUMA_COMPLEX_SCALE(mxvc2(vb, k,j), mxvd2(vt,k,i), ctmp);
1261                               mxvc2(vp, i,j).r += ctmp.r;
1262                               mxvc2(vp, i,j).i += ctmp.i;
1263                            }
1264                         }
1265                      }
1266                   }
1267                } else {
1268                   for (i = 0;  i < vp->dims[0];  i++) {
1269                      for (j = 0;  j < vp->dims[1];  j++) {
1270                         mxvc2(vp, i,j).r = 0.0 ;
1271                         mxvc2(vp, i,j).i = 0.0 ;
1272 	                     for (k = 0;  k < va->dims[1];  k++) {
1273 	                        SUMA_COMPLEX_SCALE(mxvc2(vb, k,j), mxvd2(vt,k,i), ctmp);
1274                            mxvc2(vp, i,j).r += ctmp.r;
1275                            mxvc2(vp, i,j).i += ctmp.i;
1276                         }
1277                      }
1278                   }
1279                }
1280             }
1281          }
1282          break;
1283       case SUMA_double:
1284          {
1285             {
1286                   if (LocalHead) SUMA_etime2(FuncName, "Fast Matrix transpose time", FuncName);
1287                   if (symm) {
1288                      for (i = 0;  i < vp->dims[0];  i++) {
1289                         for (j = 0;  j < vp->dims[1];  j++) {
1290                            if(j<i) {
1291                               mxvd2(vp, i,j) = mxvd2(vp, j,i);
1292                            } else {
1293                               mxvd2(vp, i,j) = 0.0 ;
1294 	                           for (k = 0;  k < va->dims[1];  k++) {
1295                                  mxvd2(vp, i,j) += mxvd2(vt,k,i) * mxvd2(vb, k,j);
1296                               }
1297                            }
1298                         }
1299                      }
1300                   } else {
1301                      for (i = 0;  i < vp->dims[0];  i++) {
1302                         for (j = 0;  j < vp->dims[1];  j++) {
1303                            mxvd2(vp, i,j) = 0.0 ;
1304 	                        for (k = 0;  k < va->dims[1];  k++) {
1305                               mxvd2(vp, i,j) += mxvd2(vt,k,i) * mxvd2(vb, k,j);
1306                            }
1307                         }
1308                      }
1309                   }
1310 
1311                   if (LocalHead) SUMA_etime2(FuncName, "Fast Matrix Mult. time", FuncName);
1312             }
1313          }
1314 
1315          break;
1316       default:
1317          SUMA_S_Err("Bad types");
1318          SUMA_RETURN(NULL);
1319    }
1320 
1321    if (vt != vat) vt = SUMA_FreeMxVec(vt);
1322 
1323    SUMA_RETURN(vp);
1324 }
1325 
1326 /*!
1327    \brief Multiply two MX_VEC matrices
1328 */
SUMA_MxVecMult(SUMA_MX_VEC * va,SUMA_MX_VEC * vb,SUMA_MX_VEC * recycle,int InfoMask)1329 SUMA_MX_VEC *SUMA_MxVecMult(SUMA_MX_VEC *va, SUMA_MX_VEC *vb, SUMA_MX_VEC *recycle, int InfoMask)
1330 {
1331    static char FuncName[]={"SUMA_MxVecMult"};
1332    SUMA_ENTRY;
1333    SUMA_RETURN(SUMA_MxVecMult_Engine(va, vb, recycle, NULL, NULL, InfoMask));
1334 }
1335 /*!
1336    if va->dims[0] << va->dims[1], passing vat also would speed things up . vbt is useless
1337 */
SUMA_MxVecMult_Engine(SUMA_MX_VEC * va,SUMA_MX_VEC * vb,SUMA_MX_VEC * recycle,SUMA_MX_VEC * vat,SUMA_MX_VEC * vbt,int InfoMask)1338 SUMA_MX_VEC *SUMA_MxVecMult_Engine(SUMA_MX_VEC *va, SUMA_MX_VEC *vb, SUMA_MX_VEC *recycle, SUMA_MX_VEC *vat, SUMA_MX_VEC *vbt, int InfoMask)
1339 {
1340    static char FuncName[]={"SUMA_MxVecMult_Engine"};
1341    SUMA_MX_VEC *vp=NULL;
1342    SUMA_VARTYPE tp=SUMA_notypeset;
1343    int dims[2], symm, N_dims, i, j, k, ij, ik, kj;
1344    complex ctmp;
1345    struct timeval tt;
1346    matrix a, b, c;
1347    SUMA_Boolean LocalHead = NOPE;
1348 
1349    SUMA_ENTRY;
1350 
1351    if ( va->N_dims == 2 && ((float)va->dims[1]/(float)va->dims[0] > 100 && va->dims[1] > 1000)) {
1352       SUMA_LH("The fast mode");
1353       SUMA_RETURN(SUMA_MxVecMultRect_Engine(va, vb,recycle, vat, vbt, InfoMask));
1354       SUMA_LH("***************OUT");
1355    }
1356 
1357    if (InfoMask & MATRIX_B_IS_AT || InfoMask & MATRIX_OUT_SYMMETRIC) {
1358       symm = 1;
1359       SUMA_S_Note("No optimization for symmetric output yet!");
1360    } else {
1361       symm = 0;
1362    }
1363    if (!vb) {
1364       SUMA_S_Err("NULL input");
1365       SUMA_RETURN(NULL);
1366    }
1367    if (LocalHead) SUMA_etime2(FuncName, NULL, NULL);
1368 
1369    if (  va->N_dims > 2 || va->N_dims < 1 ||
1370          vb->N_dims > 2 || vb->N_dims < 1 ) {
1371       SUMA_S_Err("Bad N_dims");
1372       SUMA_RETURN(vp);
1373    }
1374    if (va->fdf != 1 || vb->fdf != 1) {
1375       SUMA_S_Err("Only first dimension first");
1376       SUMA_RETURN(vp);
1377    }
1378    if (va->N_dims == 1) va->dims[1] = 1;
1379    if (vb->N_dims == 1) vb->dims[1] = 1;
1380    if (va->dims[1] != vb->dims[0]) {
1381       SUMA_S_Err("Incompatible dimensions for matrix multiplications");
1382       SUMA_RETURN(vp);
1383    }
1384    if (  (vb->tp != SUMA_complex && vb->tp != SUMA_double) ||
1385          (va->tp != SUMA_complex && va->tp != SUMA_double) ) {
1386       SUMA_S_Err("vectors must either be complex or double");
1387       SUMA_RETURN(vp);
1388    }
1389 
1390    dims[0] = va->dims[0]; dims[1] = vb->dims[1];
1391    if (va->tp == SUMA_complex || vb->tp == SUMA_complex) {
1392       tp = SUMA_complex;
1393    } else if (va->tp == SUMA_double && vb->tp == SUMA_double) {
1394       tp = SUMA_double;
1395    } else {
1396       SUMA_S_Err("vectors must either be complex or double");
1397       SUMA_RETURN(vp);
1398    }
1399    SUMA_LHv("tp=%d, dims[0]=%d, dims[1]=%d\n", tp, dims[0], dims[1]);
1400    if (recycle) {
1401       SUMA_LH("Reusing vector");
1402       if (recycle->tp != tp) {
1403          SUMA_S_Errv("Recycled vector of type %d, type %d needed.\n", recycle->tp, tp);
1404          SUMA_RETURN(vp);
1405       }
1406       if (recycle->dims[0] != dims[0]) {
1407          SUMA_S_Errv("Recycled vector dims[0]=%d, dims[0]=%d needed.\n", recycle->dims[0], dims[0]);
1408          SUMA_RETURN(vp);
1409       }
1410       if (recycle->dims[1] != dims[1]) {
1411          SUMA_S_Errv("Recycled vector dims[1]=%d, dims[1]=%d needed.\n", recycle->dims[1], dims[1]);
1412          SUMA_RETURN(vp);
1413       }
1414       vp = recycle;
1415    } else {
1416       vp = SUMA_NewMxVec(tp, 2, dims, 1);
1417    }
1418    if (!vp) {
1419       SUMA_S_Err("Failed to create output vector");
1420       SUMA_RETURN(vp);
1421    }
1422    switch(tp) {
1423       case SUMA_complex:
1424          if (vb->tp == va->tp) { /* both are complex */
1425             SUMA_LH("Both complex");
1426             for (j = 0;  j < vp->dims[1];  j++) {
1427                for (i = 0;  i < vp->dims[0];  i++) {
1428                   mxvc2(vp, i,j).r = 0.0 ;
1429                   mxvc2(vp, i,j).i = 0.0 ;
1430 	               for (k = 0;  k < va->dims[1];  k++) {
1431 	                  SUMA_COMPLEX_MULT(mxvc2(va,i,k), mxvc2(vb, k,j), ctmp);
1432                      mxvc2(vp, i,j).r += ctmp.r;
1433                      mxvc2(vp, i,j).i += ctmp.i;
1434                   }
1435                }
1436             }
1437          } else { /* only one is complex */
1438             if (va->tp == SUMA_complex) {
1439                SUMA_LH("va complex");
1440                for (j = 0;  j < vp->dims[1];  j++) {
1441                   for (i = 0;  i < vp->dims[0];  i++) {
1442                      mxvc2(vp, i,j).r = 0.0 ;
1443                      mxvc2(vp, i,j).i = 0.0 ;
1444 	                  for (k = 0;  k < va->dims[1];  k++) {
1445 	                     SUMA_COMPLEX_SCALE(mxvc2(va,i,k), mxvd2(vb, k,j), ctmp);
1446                         mxvc2(vp, i,j).r += ctmp.r;
1447                         mxvc2(vp, i,j).i += ctmp.i;
1448                      }
1449                   }
1450                }
1451             } else {
1452                SUMA_LH("vb complex");
1453                for (j = 0;  j < vp->dims[1];  j++) {
1454                   for (i = 0;  i < vp->dims[0];  i++) {
1455                      mxvc2(vp, i,j).r = 0.0 ;
1456                      mxvc2(vp, i,j).i = 0.0 ;
1457 	                  for (k = 0;  k < va->dims[1];  k++) {
1458 	                     SUMA_COMPLEX_SCALE(mxvc2(vb, k,j), mxvd2(va,i,k), ctmp);
1459                         mxvc2(vp, i,j).r += ctmp.r;
1460                         mxvc2(vp, i,j).i += ctmp.i;
1461                      }
1462                   }
1463                }
1464             }
1465          }
1466          break;
1467       case SUMA_double:
1468          #if 0 /* using matrix functions, not much faster */
1469          if (recycle) {
1470             /* kill the recycled puppy BAD BAD BAD */
1471             SUMA_S_Warn("Carefull, with that one! Caller may not know this happened");
1472             vp = SUMA_FreeMxVec(vp);
1473          }
1474          if (!va->m) {
1475             SUMA_MxVecBuildMat(va);
1476             if (LocalHead) SUMA_ShowMxVec(va,va->N_vals, NULL, "\ndbg va\n");
1477          }
1478          if (!vb->m) {
1479             SUMA_MxVecBuildMat(vb);
1480             if (LocalHead) SUMA_ShowMxVec(vb,vb->N_vals, NULL, "\ndbg vb\n");
1481          }
1482          if (LocalHead) SUMA_etime2(FuncName, "Matrix build time",FuncName);
1483          if (!vb->m || !va->m) {
1484             SUMA_S_Err("Failed to create matrix");
1485             SUMA_RETURN(NULL);
1486          }
1487          a = *(va->m); b = *(vb->m);
1488          matrix_initialize(&c);
1489          matrix_multiply (a,b, &c);
1490          if (LocalHead) SUMA_etime2(FuncName, "Matrix multiply time",FuncName);
1491          SUMA_LH("Going from matrix to vector");
1492          vp = SUMA_matrix2MxVec(c); /* c is destroyed inside SUMA_matrix2MxVec */
1493          if (LocalHead) SUMA_etime2(FuncName, "Matrix copy time",FuncName);
1494          SUMA_S_Note("va and vb now contain duplicates of vector data in m");
1495          #else
1496          {
1497             for (j = 0;  j < vp->dims[1];  j++) {     /* j, then i is faster on mac OS X G5, at least for spharm computations */
1498                for (i = 0;  i < vp->dims[0];  i++) {
1499                   mxvd2(vp, i,j) = 0.0 ;
1500                   ij = i+vp->dims[0]*j;
1501 	               for (k = 0;  k < va->dims[1];  k++) {
1502                      ik = i+va->dims[0]*k;
1503                      kj = k+vb->dims[0]*j;
1504                      vp->dv[ij] += va->dv[ik] * vb->dv[kj];
1505                   }
1506                }
1507             }
1508          }
1509          #endif
1510          break;
1511       default:
1512          SUMA_S_Err("Bad types");
1513          SUMA_RETURN(NULL);
1514    }
1515 
1516    SUMA_RETURN(vp);
1517 }
1518 
1519 /*
1520    a function to test matrix operations using MxVec structures
1521 */
SUMA_TestMxVecMatOps(void)1522 void SUMA_TestMxVecMatOps(void)
1523 {
1524    static char FuncName[]={"SUMA_TestMxVecMatOps"};
1525    SUMA_MX_VEC *da, *db, *dc, *dat, *dbt, *dct;
1526    int dd[2]={2,3}, N_dims, dims[50];
1527    struct timeval tt;
1528    int i, j;
1529    char stmp[100];
1530    matrix a, b, c;
1531 
1532    SUMA_ENTRY;
1533    SUMA_S_Note("Testing matrix speed");
1534 
1535 
1536    matrix_initialize(&a);
1537    matrix_create(60, 40962, &a);
1538    matrix_initialize(&b);
1539    matrix_create(40962, 60, &b);
1540    srand(123);
1541    for (i=0; i<40962; ++i) {
1542       for (j=0; j<60;++j) {
1543          a.elts[j][i] = (double)rand()/(double)RAND_MAX;
1544          b.elts[i][j] = a.elts[j][i];
1545       }
1546    }
1547    da = SUMA_matrix2MxVec(a);
1548    db = SUMA_matrix2MxVec(b);
1549    SUMA_ShowMxVec(da, 1, NULL, "\nInitial da\n");
1550    SUMA_etime2(FuncName, NULL, NULL);
1551    dat = SUMA_MxVecTranspose(da, NULL);
1552    da = SUMA_FreeMxVec(da);
1553    SUMA_etime2(FuncName, "Vector Transpose 1(60*40962)", FuncName);
1554    da = SUMA_MxVecTranspose(dat, NULL);
1555    dat = SUMA_FreeMxVec(dat);
1556    SUMA_etime2(FuncName, "Vector Transpose 2(40962*60)", FuncName);
1557    SUMA_ShowMxVec(da, 1, NULL, "\n(da')'\n");
1558    SUMA_etime2(FuncName, "Next is multiplication.", FuncName);
1559    dc = SUMA_MxVecMult(da, db, NULL, MATRIX_B_IS_AT);
1560    SUMA_etime2(FuncName, "Vector multiplication test (60*40962 X 40962 * 60)", FuncName);
1561    SUMA_ShowMxVec(dc, 1, NULL, "\nMult via MxVec\n");
1562    dc = SUMA_FreeMxVec(dc);
1563    dc = SUMA_MxVecMult(da, db, NULL, MATRIX_OUT_SYMMETRIC);   /* try the a ainv trick */
1564    SUMA_etime2(FuncName, "Vector multiplication test (60*40962 X 40962 * 60)", FuncName);
1565    SUMA_ShowMxVec(dc, 1, NULL, "\nMult via MxVec, mode 2\n");
1566 
1567    matrix_initialize(&c);
1568    SUMA_S_Note("Testing matrix speed with 'matrix' calls");
1569    if (!da->m) SUMA_MxVecBuildMat(da);
1570    if (!db->m) SUMA_MxVecBuildMat(db);
1571    a = *(da->m); b = *(db->m);
1572    matrix_multiply(a, b, &c);
1573    SUMA_etime2(FuncName, "Vector multiplication test 2 (60*40962 X 40962 * 60)", FuncName);
1574    SUMA_S_Notev("c is (%d x %d)\n", c.rows, c.cols);
1575    da = SUMA_FreeMxVec(da);
1576    db = SUMA_FreeMxVec(db);
1577    dc = SUMA_FreeMxVec(dc);
1578    dc = SUMA_matrix2MxVec(c);
1579    SUMA_ShowMxVec(dc, 1, NULL, "\nMult via 'matrix'\n");
1580    dc = SUMA_FreeMxVec(dc);
1581 
1582    matrix_initialize(&a);
1583    matrix_create(129, 129, &a);
1584    matrix_initialize(&b);
1585    matrix_create(129, 40962, &b);
1586    srand(123);
1587    for (i=0; i<129; ++i) {
1588       for (j=0; j<129;++j) {
1589          a.elts[i][j] = (double)rand()/(double)RAND_MAX;
1590       }
1591    }
1592    for (i=0; i<40962; ++i) {
1593       for (j=0; j<129;++j) {
1594          b.elts[j][i] = (double)rand()/(double)RAND_MAX;
1595       }
1596    }
1597    da = SUMA_matrix2MxVec(a);
1598    db = SUMA_matrix2MxVec(b);
1599    SUMA_etime2(FuncName, NULL, NULL);
1600    dc = SUMA_MxVecMult(da, db, NULL, 0);
1601    SUMA_etime2(FuncName, "Vector multiplication test 3 (129*129 X 129 * 40962 )", FuncName);
1602    SUMA_ShowMxVec(dc, 1, NULL, "\nMult via MxVec\n");
1603    dc = SUMA_FreeMxVec(dc);
1604    dbt = SUMA_MxVecTranspose(db, NULL);
1605    dat = SUMA_MxVecTranspose(da, NULL);
1606    SUMA_etime2(FuncName, "Vector multiplication test 4 (built transposes)(129*129 X 129 * 40962 )", FuncName);
1607    dct = SUMA_MxVecMult(dbt, dat, NULL, 0);
1608    dc = SUMA_MxVecTranspose(dct, NULL);
1609    SUMA_etime2(FuncName, "Vector multiplication test 4 (129*129 X 129 * 40962 )", FuncName);
1610    SUMA_ShowMxVec(dc, 1, NULL, "\nMult via tranposed MxVec\n");
1611    da = SUMA_FreeMxVec(da);
1612    db = SUMA_FreeMxVec(db);
1613    dc = SUMA_FreeMxVec(dc);
1614    dat = SUMA_FreeMxVec(dat);
1615    dbt = SUMA_FreeMxVec(dbt);
1616    dct = SUMA_FreeMxVec(dct);
1617 
1618 
1619    SUMA_RETURNe;
1620 
1621    SUMA_S_Note("Testing transpose");
1622    da = SUMA_NewMxVec(SUMA_double, 2, dd, 1);
1623    mxvd2(da,0,0) = 1.0;
1624    mxvd2(da,0,1) = 2.0;
1625    mxvd2(da,0,2) = 3.0;
1626    mxvd2(da,1,0) = -1.0;
1627    mxvd2(da,1,1) = -4.0;
1628    mxvd2(da,1,2) = -3.0;
1629    db = SUMA_MxVecTranspose(da, NULL);
1630    SUMA_ShowMxVec(da, da->N_vals, NULL, "\nda\n");
1631    SUMA_ShowMxVec(db, db->N_vals, NULL, "\ntransp(da)\n");
1632 
1633    SUMA_S_Note("Testing multiplication");
1634    mxvd2(db,0,0) = 1.5;
1635    mxvd2(db,0,1) = 2.3;
1636    mxvd2(db,1,0) = 3.1;
1637    mxvd2(db,1,1) = -1.3;
1638    mxvd2(db,2,0) = -2.8;
1639    mxvd2(db,2,1) = -3.1;
1640    SUMA_ShowMxVec(da, da->N_vals, NULL, "\nda\n");
1641    SUMA_ShowMxVec(db, db->N_vals, NULL, "\ndb\n");
1642    dc = SUMA_MxVecMult(da, db, NULL, 0);
1643    SUMA_ShowMxVec(dc, dc->N_vals, NULL, "\nda*db\n");
1644 
1645    SUMA_S_Note("Testing Real Inversion\n");
1646    db = SUMA_FreeMxVec(db);
1647    db = SUMA_MxVecInverse(dc, NULL);
1648    SUMA_ShowMxVec(dc, dc->N_vals, NULL, "\ndc\n");
1649    SUMA_ShowMxVec(db, db->N_vals, NULL, "\ninv(dc)\n");
1650 
1651    SUMA_S_Note("Testing complex multiplication, b complex");
1652    db = SUMA_FreeMxVec(db);
1653    dc = SUMA_FreeMxVec(dc);
1654    dd[0]= 3; dd[1] = 2;
1655    db = SUMA_NewMxVec(SUMA_complex, 2, dd, 1);
1656    mxvc2(db,0,0).r = 1.5;
1657    mxvc2(db,0,1).r = 2.3;
1658    mxvc2(db,1,0).r = 3.1;
1659    mxvc2(db,1,1).r = -1.3;
1660    mxvc2(db,2,0).r = -2.8;
1661    mxvc2(db,2,1).r = -3.1;
1662    mxvc2(db,0,0).i = 3.5;
1663    mxvc2(db,0,1).i = 6.3;
1664    mxvc2(db,1,0).i = 9.1;
1665    mxvc2(db,1,1).i = 3.3;
1666    mxvc2(db,2,0).i = 2.8;
1667    mxvc2(db,2,1).i = -6.1;
1668    SUMA_ShowMxVec(da, da->N_vals, NULL, "\nda\n");
1669    SUMA_ShowMxVec(db, db->N_vals, NULL, "\ndb\n");
1670    dc = SUMA_MxVecMult(da, db, NULL,0);
1671    SUMA_ShowMxVec(dc, dc->N_vals, NULL, "\nda*db\n");
1672 
1673    SUMA_S_Note("Testing complex multiplication, a,b complex");
1674    da = SUMA_FreeMxVec(da);
1675    dc = SUMA_FreeMxVec(dc);
1676    dd[0]= 2; dd[1] = 3;
1677    da = SUMA_NewMxVec(SUMA_complex, 2, dd, 1);
1678    mxvc2(da,0,0).r = 1.0;
1679    mxvc2(da,0,1).r = 2.0;
1680    mxvc2(da,0,2).r = 3.0;
1681    mxvc2(da,1,0).r = -1.0;
1682    mxvc2(da,1,1).r = -2.0;
1683    mxvc2(da,1,2).r = -3.0;
1684    mxvc2(da,0,0).i = 3.0;
1685    mxvc2(da,0,1).i = -2.0;
1686    mxvc2(da,0,2).i = 6.0;
1687    mxvc2(da,1,0).i = -0.20;
1688    mxvc2(da,1,1).i = 3.0;
1689    mxvc2(da,1,2).i = 9.0;
1690    SUMA_ShowMxVec(da, da->N_vals, NULL, "\nda\n");
1691    SUMA_ShowMxVec(db, db->N_vals, NULL, "\ndb\n");
1692    dc = SUMA_MxVecMult(da, db, NULL, 0);
1693    SUMA_ShowMxVec(dc, dc->N_vals, NULL, "\nda*db\n");
1694 
1695    SUMA_S_Note("Testing Complex Inversion\n");
1696    db = SUMA_FreeMxVec(db);
1697    db = SUMA_MxVecInverse(dc, NULL);
1698    SUMA_ShowMxVec(dc, dc->N_vals, NULL, "\ndc\n");
1699    SUMA_ShowMxVec(db, db->N_vals, NULL, "\ninv(dc)\n");
1700 
1701    SUMA_S_Note("Testing complex multiplication, a complex");
1702    db = SUMA_FreeMxVec(db);
1703    dc = SUMA_FreeMxVec(dc);
1704    dd[0]= 3; dd[1] = 2;
1705    db = SUMA_NewMxVec(SUMA_double, 2, dd, 1);
1706    mxvd2(db,0,0) = 4.0;
1707    mxvd2(db,0,1) = 2.0;
1708    mxvd2(db,1,0) = 6.0;
1709    mxvd2(db,1,1) = -9.0;
1710    mxvd2(db,2,0) = -1.0;
1711    mxvd2(db,2,1) = -2.0;
1712    SUMA_ShowMxVec(da, da->N_vals, NULL, "\nda\n");
1713    SUMA_ShowMxVec(db, db->N_vals, NULL, "\ndb\n");
1714    dc = SUMA_MxVecMult(da, db, NULL, 0);
1715    SUMA_ShowMxVec(dc, dc->N_vals, NULL, "\nda*db\n");
1716 
1717    SUMA_S_Note("Testing complex transpose\n");
1718    dc = SUMA_FreeMxVec(dc);
1719    dc = SUMA_MxVecTranspose(da, NULL);
1720    SUMA_ShowMxVec(da, da->N_vals, NULL, "\nda\n");
1721    SUMA_ShowMxVec(dc, dc->N_vals, NULL, "\nTranspose(da)\n");
1722 
1723 
1724    da = SUMA_FreeMxVec(da);
1725    db = SUMA_FreeMxVec(db);
1726    dc = SUMA_FreeMxVec(dc);
1727    SUMA_RETURNe;
1728 }
1729 
1730 /*!
1731    \brief Function to change a bunch of spherical coordinates to
1732     cartesian ones
1733    \param sph (float *) Nval*3 [rho, theta(azimuth), phi(elevation)] spherical  coords
1734    \param Nval (int) number of coord triplets
1735    \param center (float *) 3x1 XYZ of center (CARTESIAN). If NULL center is 0 0 0
1736                            center is ADDED to each coord triplet
1737                            after xformation to cartesian
1738    \return coord (float *) Nval*3 XYZ coords
1739 
1740    \sa SUMA_SPH_2_CART
1741 */
SUMA_Sph2Cart(double * sph,int Nval,float * center)1742 float * SUMA_Sph2Cart (double *sph, int Nval, float *center )
1743 {
1744    static char FuncName[]={"SUMA_Sph2Cart"};
1745    double v[3], *f;
1746    int i, i3;
1747    float *coord=NULL;
1748 
1749    SUMA_ENTRY;
1750 
1751    if (Nval <= 0) {
1752       SUMA_RETURN(NULL);
1753    }
1754 
1755    coord = (float *)SUMA_malloc(Nval*sizeof(float)*3);
1756    if (!coord) {
1757       SUMA_SL_Crit("Failed to allocate");
1758       SUMA_RETURN(NULL);
1759    }
1760 
1761    for (i=0; i<Nval; ++i) {
1762       i3 = 3*i;
1763       f = &(sph[i3]);
1764       SUMA_SPH_2_CART(f, v);
1765 
1766       if (center) {
1767          coord[i3+0] = v[0] + center[0];
1768          coord[i3+1] = v[1] + center[1];
1769          coord[i3+2] = v[2] + center[2];
1770       } else {
1771          coord[i3+0] = v[0];
1772          coord[i3+1] = v[1];
1773          coord[i3+2] = v[2];
1774       }
1775 
1776    }
1777 
1778    SUMA_RETURN(coord);
1779 }
1780 
1781 
1782 /*!
1783    \brief Function to change a bunch of cartesian coordinates to
1784    spherical ones
1785    \param coord (float *) Nval*3 XYZ coords
1786    \param Nval (int) number of coord triplets
1787    \param center (float *) 3x1 XYZ of center (CARTESIAN). If NULL center is 0 0 0
1788                            center is subtracted from each coord triplet
1789                            before xformation
1790    \return sph (float *) Nval*3 [rho, theta(azimuth), phi(elevation)] spherical  coords
1791 
1792    \sa SUMA_CART_2_SPH
1793 */
SUMA_Cart2Sph(float * coord,int Nval,float * center)1794 double * SUMA_Cart2Sph (float *coord, int Nval, float *center )
1795 {
1796    static char FuncName[]={"SUMA_Cart2Sph"};
1797    double v[3], *f;
1798    int i, i3;
1799    double *sph=NULL;
1800 
1801    SUMA_ENTRY;
1802 
1803    if (Nval <= 0) {
1804       SUMA_RETURN(NULL);
1805    }
1806 
1807    sph = (double *)SUMA_malloc(Nval*sizeof(double)*3);
1808    if (!sph) {
1809       SUMA_SL_Crit("Failed to allocate");
1810       SUMA_RETURN(NULL);
1811    }
1812 
1813    for (i=0; i<Nval; ++i) {
1814       i3 = 3*i;
1815       if (center) {
1816          v[0] = coord[i3+0] - center[0];
1817          v[1] = coord[i3+1] - center[1];
1818          v[2] = coord[i3+2] - center[2];
1819       } else {
1820          v[0] = coord[i3+0];
1821          v[1] = coord[i3+1];
1822          v[2] = coord[i3+2];
1823       }
1824       f = &(sph[i3]);
1825       SUMA_CART_2_SPH(v,f);
1826    }
1827 
1828    SUMA_RETURN(sph);
1829 }
1830 
SUMA_ShowMemTrace(SUMA_MEMTRACE_STRUCT * Mem,FILE * Out)1831 void SUMA_ShowMemTrace (SUMA_MEMTRACE_STRUCT *Mem, FILE *Out)
1832 {
1833    static char FuncName[]={"SUMA_ShowMemTrace"};
1834    int i, *isort = NULL, *mem_sz_sort = NULL, Tot;
1835 
1836    SUMA_ENTRY;
1837 
1838    SUMA_S_Err("No longer in use, use mcw_malloc_dump_sort() instead");
1839 
1840    if (!Out) Out = SUMA_STDERR;
1841 
1842    #ifdef USE_SUMA_MALLOC
1843    SUMA_SL_Err("NO LONGER SUPPORTED");
1844    SUMA_RETURNe;
1845    if (!Out) Out = SUMA_STDERR;
1846    if (!Mem) {
1847       fprintf (Out,"\nNull struct. Nothing to show.\n");
1848       SUMA_RETURNe;
1849    }
1850 
1851    fprintf (Out,"\nShowing SUMA_MEMTRACE_STRUCT: %p\n", Mem);
1852    fprintf (Out,"->N_alloc: %d allocated elements.\n", Mem->N_alloc);
1853    fprintf (Out,"->N_MaxPointers: %d\n", Mem->N_MaxPointers);
1854 
1855    /* sort the pointers by their sizes */
1856    /* make a copy of Mem->Size to keep it from getting modified then sort it.
1857    Do not use SUMA_calloc here because that'll increment N_alloc after space is allocated! */
1858    mem_sz_sort = (int *)calloc(Mem->N_alloc, sizeof(int));
1859    if (!mem_sz_sort) {
1860       fprintf (SUMA_STDERR, "Error %s: Could not allocate for mem_sz_sort.\n", FuncName);
1861       SUMA_RETURNe;
1862    }
1863 
1864    #if 1
1865    for (i=0; i < Mem->N_alloc; ++i) mem_sz_sort[i] = Mem->Size[i];
1866    isort = SUMA_z_dqsort_nsc (mem_sz_sort, Mem->N_alloc); /* this version of
1867          SUMA_z_dqsort does not use SUMA_calloc for allocation thus
1868          keeping the memory trace unchanged */
1869 
1870    Tot = 0;
1871    for (i=0; i < Mem->N_alloc; ++i) {
1872       fprintf (Out,"->[%d]\tPointer %p\t %d bytes.\n",
1873                i, Mem->Pointers[isort[i]], Mem->Size[isort[i]]);
1874       Tot += Mem->Size[isort[i]];
1875    }
1876    #else
1877 
1878    Tot = 0;
1879    for (i=0; i < Mem->N_alloc; ++i) {
1880       fprintf (Out,"->[%d]\tPointer %p\t %d bytes.\n",
1881                i, Mem->Pointers[i], Mem->Size[i]);
1882       Tot += Mem->Size[i];
1883    }
1884    #endif
1885 
1886    fprintf (Out,"Total Memory Allocated %f Mbytes.\n", (float)Tot/1000000.0);
1887    if (mem_sz_sort) free(mem_sz_sort); /* mem_sz_sort should not be freed with SUMA_free */
1888    if (isort) free(isort); /* isort should not be freed with SUMA_free */
1889 
1890    #endif
1891 
1892    SUMA_RETURNe;
1893 
1894 }
1895 
SUMA_Free_MemTrace(SUMA_MEMTRACE_STRUCT * Mem)1896 SUMA_Boolean SUMA_Free_MemTrace (SUMA_MEMTRACE_STRUCT * Mem) {
1897    static char FuncName[]={"SUMA_Free_MemTrace"};
1898 
1899    #ifdef USE_SUMA_MALLOC
1900    SUMA_SL_Err("NO LONGER SUPPORTED");
1901    return(NOPE);
1902    /* DO NOT USE SUMA_free function here ! */
1903    if (Mem->Pointers) free (Mem->Pointers);
1904    if (Mem->Size) free(Mem->Size);
1905    if (Mem) free (Mem);
1906    #endif
1907    return(YUP);
1908 }
1909 
1910 /*!
1911 
1912 File : Read_file.c
1913 Author : Ziad Saad
1914 Date : 19 Dec. 1994
1915 
1916 Purpose :
1917          Reads a file sequence of int numbers, one value per line .
1918 
1919 Usage :
1920 
1921    int SUMA_Read_dfile (int *x,char *f_name,int n_points);
1922 or int SUMA_Read_file (float *x,char *f_name,int n_points);
1923 
1924 Input Parameters:
1925       x, (int*) or (float *) array where the values will be stored.
1926       f_name, (char)* string holding file name.
1927       n_points, (int) number of points to be read from file. if  set to 0,
1928           then all the file will be read .
1929 
1930 Output parameters :
1931             Number of points read.
1932 
1933 Side effects :
1934          function does not check for array overflow while reading file.
1935 
1936 */
SUMA_Read_dfile(int * x,char * f_name,int n_points)1937 int SUMA_Read_dfile (int *x,char *f_name,int n_points)
1938 
1939 { /* pass a 0 to n_points if you want to read till EOF */
1940    int cnt=0,ex,dec;
1941    static char FuncName[]={"SUMA_Read_dfile"};
1942    FILE*internal_file;
1943 
1944    SUMA_ENTRY;
1945 
1946    internal_file = fopen (f_name,"r");
1947    if (internal_file == NULL) {
1948                           fprintf(SUMA_STDERR, "\aCould not open %s \n",f_name);
1949                           fprintf(SUMA_STDERR, "Exiting @ SUMA_Read_file function\n");
1950                           exit (0);
1951                           }
1952    ex = fscanf (internal_file,"%d",&x[cnt]);
1953    while (ex != EOF)
1954    {
1955      ++cnt;
1956      /* NOT WORKING, RETURNS SIZEOF (FLOAT) .....
1957      if (sizeof(x) < cnt)
1958       {
1959         fprintf(SUMA_STDERR, "%d = sizeof(x)\n",sizeof(x));
1960         fprintf(SUMA_STDERR, "\nNot Enough Memory Allocated \n\a");
1961         fprintf(SUMA_STDERR, "Exiting @SUMA_Read_file function\n");
1962         exit (0);
1963       }
1964      ............................................ */
1965      ex = fscanf (internal_file,"%d",&x[cnt]);
1966 
1967      if ((n_points != 0) && (cnt == n_points)) ex = EOF;
1968    }
1969 
1970    if (cnt < n_points)
1971       {
1972        fprintf(SUMA_STDERR, "\a\nAttempt to read %d points failed,\n",n_points);
1973        fprintf(SUMA_STDERR, " file contains %d points only.\n",cnt);
1974        do {
1975 
1976        fprintf(SUMA_STDERR, "End Execution (Yes (1) No (0) ? : ");
1977        ex=scanf ("%d",&dec);
1978        } while (ex != 1 || (dec != 1 && dec !=0));
1979        if (dec)
1980         {
1981           fprintf(SUMA_STDERR, "Exiting @ SUMA_Read_file function\n");
1982       exit (0);
1983       }
1984       else fprintf(SUMA_STDERR, "\nContinuing execution with %d points\n",cnt);
1985 
1986       }
1987 
1988    fclose (internal_file);
1989    SUMA_RETURN (cnt);
1990 }
SUMA_Read_file(float * x,char * f_name,int n_points)1991 int SUMA_Read_file (float *x,char *f_name,int n_points)
1992 
1993 { /* pass a 0 to n_points if you want to read till EOF */
1994    int cnt=0,ex,dec;
1995    FILE*internal_file;
1996    static char FuncName[]={"SUMA_Read_file"};
1997 
1998    SUMA_ENTRY;
1999 
2000    internal_file = fopen (f_name,"r");
2001    if (internal_file == NULL) {
2002                           fprintf(SUMA_STDERR, "\aCould not open %s \n",f_name);
2003                           fprintf(SUMA_STDERR, "Exiting @ SUMA_Read_file function\n");
2004                           exit (0);
2005                           }
2006    ex = fscanf (internal_file,"%f",&x[cnt]);
2007    while (ex != EOF)
2008    {
2009      ++cnt;
2010 
2011      ex = fscanf (internal_file,"%f",&x[cnt]);
2012 
2013      if ((n_points != 0) && (cnt == n_points)) ex = EOF;
2014    }
2015 
2016    if (cnt < n_points)
2017       {
2018        fprintf(SUMA_STDERR, "\a\nAttempt to read %d points failed,\n",n_points);
2019        fprintf(SUMA_STDERR, " file contains %d points only.\n",cnt);
2020        do {
2021 
2022        fprintf(SUMA_STDERR, "End Execution (Yes (1) No (0) ? : ");
2023        ex=scanf ("%d",&dec);
2024        } while (ex != 1 || (dec != 1 && dec !=0));
2025        if (dec)
2026         {
2027           fprintf(SUMA_STDERR, "Exiting @ SUMA_Read_file function\n");
2028               exit (0);
2029       }
2030       else fprintf(SUMA_STDERR, "\nContinuing execution with %d points\n",cnt);
2031 
2032       }
2033 
2034    fclose (internal_file);
2035    return (cnt);
2036 }
2037 
2038 /*!**
2039 
2040 File : Read_2Dfile.c
2041 Author : Ziad Saad
2042 Date : Sat Nov 14 18:52:31 CST 1998/remix Wed Feb  6 17:22:32 EST 2002
2043 
2044 
2045 Purpose :
2046    Reads a file of float numbers, with n_cols values per line
2047 
2048 
2049 Usage :
2050    n_rows_read = SUMA_Read_2Dfile ( char *f_name, float **x, int n_cols, int n_rows)
2051 
2052 
2053 Input paramters :
2054       f_name, (char)* string holding file name.
2055       x, (float)** array where the values will be stored.
2056       n_cols, (int) number of columns per line.
2057       n_rows, (int) number of rows .
2058 
2059 
2060 Returns :
2061    n_rows_read, (int) number of rows read from file.
2062         -1 if critcial operations fail.
2063         if EOF is reached before n_rows, n_rows_read reflects the
2064         number of rows read.
2065 
2066 
2067 Support :
2068 
2069 
2070 
2071 Side effects :
2072 
2073 
2074 ***/
2075 
2076 
SUMA_Read_2Dfile(char * f_name,float ** x,int n_cols,int n_rows)2077 int SUMA_Read_2Dfile (char *f_name, float **x,  int n_cols, int n_rows)
2078 {/*SUMA_Read_2Dfile*/
2079    int ir=0, ic=0, ex;
2080    FILE*internal_file;
2081    static char FuncName[]={"SUMA_Read_2Dfile"};
2082 
2083    SUMA_ENTRY;
2084 
2085    internal_file = fopen (f_name,"r");
2086    if (internal_file == NULL) {
2087                           fprintf (SUMA_STDERR,"%s: \aCould not open %s \n",FuncName, f_name);
2088                           SUMA_RETURN (-1);
2089                           }
2090    ir = 0;
2091    while (ir < n_rows)
2092    {
2093        ic = 0;
2094       while (ic < n_cols)
2095          {
2096             ex = fscanf (internal_file,"%f",&x[ir][ic]);
2097             if (ex == EOF)
2098                {
2099                   fprintf(stderr,"Error SUMA_Read_2Dfile: Premature EOF\n");
2100                   fclose (internal_file);
2101                   SUMA_RETURN (n_rows);
2102                }
2103             ++ic;
2104          }
2105       ++ir;
2106    }
2107 
2108    fclose (internal_file);
2109    SUMA_RETURN (ir);
2110 
2111 }/*SUMA_Read_2Dfile*/
2112 
2113 /*!
2114    \brief Allocate for irgb structure containing n_el elements in each vector
2115 
2116    \sa SUMA_Free_IRGB
2117 */
SUMA_Create_IRGB(int n_el)2118 SUMA_IRGB *SUMA_Create_IRGB(int n_el)
2119 {
2120    SUMA_IRGB *irgb=NULL;
2121    static char FuncName[]={"SUMA_Create_IRGB"};
2122 
2123    SUMA_ENTRY;
2124 
2125    irgb = (SUMA_IRGB *)SUMA_malloc(sizeof(SUMA_IRGB));
2126 
2127 
2128    irgb->i = (int *)SUMA_calloc(n_el, sizeof(int));
2129    irgb->r = (float*)SUMA_calloc(n_el, sizeof(float));
2130    irgb->g = (float*)SUMA_calloc(n_el, sizeof(float));
2131    irgb->b = (float*)SUMA_calloc(n_el, sizeof(float));
2132    irgb->N = n_el;
2133    if (!irgb->i || !irgb->r || !irgb->g || !irgb->b) {
2134       SUMA_S_Crit ("Failed to allocate for i, r, g and/or b.");
2135       if (irgb) SUMA_free(irgb);
2136       SUMA_RETURN (NULL);
2137    }
2138 
2139    SUMA_RETURN(irgb);
2140 }
2141 
2142 /*!
2143    \brief function to free SUMA_IRGB *
2144 
2145    \return NULL
2146    \sa SUMA_Create_IRGB
2147    - This function frees all vectors in structure and the structure itself
2148 */
SUMA_Free_IRGB(SUMA_IRGB * irgb)2149 SUMA_IRGB *SUMA_Free_IRGB(SUMA_IRGB *irgb)
2150 {
2151    static char FuncName[]={"SUMA_Free_IRGB"};
2152 
2153    SUMA_ENTRY;
2154 
2155    if (irgb) {
2156       if (irgb->i) SUMA_free(irgb->i);
2157       if (irgb->r) SUMA_free(irgb->r);
2158       if (irgb->g) SUMA_free(irgb->g);
2159       if (irgb->b) SUMA_free(irgb->b);
2160       SUMA_free(irgb);
2161    }
2162 
2163    SUMA_RETURN(NULL);
2164 }
2165 /*!
2166    \brief Function to read a node color file formatted as:
2167    i r g b (int float float float)
2168 
2169    \param f_name (char *) filename
2170    \return irgb (SUMA_IRGB *) structure containing irgb data
2171 
2172    \sa SUMA_Create_IRGB
2173    \sa SUMA_Free_IRGB
2174 */
SUMA_Read_IRGB_file(char * f_name)2175 SUMA_IRGB *SUMA_Read_IRGB_file (char *f_name)
2176 {
2177    int i=0, ncol = 0, nrow = 0;
2178    MRI_IMAGE *im = NULL;
2179    float *far=NULL;
2180    SUMA_IRGB *irgb=NULL;
2181    static char FuncName[]={"SUMA_Read_IRGB_file"};
2182 
2183    SUMA_ENTRY;
2184 
2185    im = mri_read_1D (f_name);
2186 
2187    if (!im) {
2188       SUMA_SLP_Err("Failed to read 1D file");
2189       SUMA_RETURN(NULL);
2190    }
2191 
2192    far = MRI_FLOAT_PTR(im);
2193    ncol = im->nx;
2194    nrow = im->ny;
2195 
2196    if (!ncol) {
2197       SUMA_SL_Err("Empty file");
2198       SUMA_RETURN(NULL);
2199    }
2200    if (nrow !=  4 ) {
2201       SUMA_SL_Err("File must have\n"
2202                   "4 columns.");
2203       mri_free(im); im = NULL;   /* done with that baby */
2204       SUMA_RETURN(NULL);
2205    }
2206 
2207    if (!(irgb = SUMA_Create_IRGB(ncol))) {
2208       fprintf (SUMA_STDERR,"%s: Failed to create irgb.\n",FuncName);
2209       SUMA_RETURN (NULL);
2210    }
2211 
2212    for (i=0; i < ncol; ++i) {
2213       irgb->i[i] = (int)far[i];
2214       irgb->r[i] = far[i+ncol];
2215       irgb->g[i] = far[i+2*ncol];
2216       irgb->b[i] = far[i+3*ncol];
2217    }
2218 
2219    mri_free(im); im = NULL;
2220 
2221    SUMA_RETURN (irgb);
2222 
2223 }
2224 
2225 /*!
2226 
2227 Purpose :
2228    Reads a file of integer numbers, with n_cols values per line
2229 
2230 Usage :
2231    ans = SUMA_Read_2Ddfile (char *f_name, int **x,int n_rows, int n_cols)
2232 
2233 
2234 Input paramters :
2235    \param   x, (int)** array where the values will be stored.
2236    \param   f_name, (char)* string holding file name.
2237    \param   n_rows, (int) number of rows to be read from file.
2238    \param   n_cols, (int) number of columns per line.
2239 
2240    \ret Number of rows read (maybe incomplete rows)
2241 */
SUMA_Read_2Ddfile(char * f_name,int ** x,int n_rows,int n_cols)2242 int SUMA_Read_2Ddfile (char *f_name, int **x, int n_rows, int n_cols)
2243 {/*SUMA_Read_2Ddfile*/
2244    int ir, ic, ex;
2245    FILE*internal_file;
2246    static char FuncName[]={"SUMA_Read_2Ddfile"};
2247 
2248    SUMA_ENTRY;
2249 
2250    internal_file = fopen (f_name,"r");
2251    if (internal_file == NULL) {
2252       fprintf (SUMA_STDERR,"%s: \aCould not open %s \n",FuncName, f_name);
2253       SUMA_RETURN (-1);
2254    }
2255 
2256 
2257 
2258    ir = 0;
2259    while (ir < n_rows)
2260    {
2261        ic = 0;
2262       while (ic < n_cols)
2263          {
2264             ex = fscanf (internal_file,"%d",&x[ir][ic]);
2265             if (ex == EOF)
2266                {
2267                   fprintf(stderr,"Error SUMA_Read_2Ddfile: Premature EOF\n");
2268                   fclose (internal_file);
2269                   SUMA_RETURN(ir);
2270                }
2271             ++ic;
2272          }
2273       ++ir;
2274    }
2275 
2276    fclose (internal_file);
2277    SUMA_RETURN (ir);
2278 
2279 }/*SUMA_Read_2Ddfile*/
2280 
2281 
2282 /*!
2283 count the number of float values in a file
2284 -1 if the file could not be open
2285 1D reading based.
2286 */
SUMA_float_file_size_1D(char * f_name)2287 int SUMA_float_file_size_1D(char *f_name)
2288 {
2289    static char FuncName[]={"SUMA_float_file_size_1D"};
2290    int i=0, ncol = 0, nrow = 0;
2291    MRI_IMAGE *im = NULL;
2292    float *far=NULL;
2293 
2294    SUMA_ENTRY;
2295 
2296    im = mri_read_1D (f_name);
2297 
2298    if (!im) {
2299       SUMA_SLP_Err("Failed to read 1D file");
2300       SUMA_RETURN(-1);
2301    }
2302 
2303    far = MRI_FLOAT_PTR(im);
2304    ncol = im->nx;
2305    nrow = im->ny;
2306 
2307    mri_free(im); im = NULL;   /* done with that baby */
2308 
2309    SUMA_RETURN(ncol);
2310 }
2311 
2312 /* dumber version of SUMA_float_file_size_1D */
SUMA_float_file_size(char * f_name)2313 int SUMA_float_file_size (char *f_name)
2314 {
2315    int cnt=0,ex;
2316    float buf;
2317    static char FuncName[]={"SUMA_float_file_size"};
2318    FILE*internal_file;
2319 
2320    SUMA_ENTRY;
2321 
2322    internal_file = fopen (f_name,"r");
2323    if (internal_file == NULL) {
2324                           printf ("\aCould not open %s \n",f_name);
2325                           SUMA_RETURN (-1);
2326                           }
2327    ex = fscanf (internal_file,"%f",&buf);
2328    while (ex != EOF)
2329    {
2330      ++cnt;
2331      ex = fscanf (internal_file,"%f",&buf);
2332    }
2333 
2334 
2335    fclose (internal_file);
2336    SUMA_RETURN (cnt);
2337 }
2338 
2339 
2340 /*! Taken from SUMA_alloc_problem */
SUMA_alloc_problem(char * s1)2341 void SUMA_alloc_problem (char *s1)
2342 
2343 {
2344    static char FuncName[]={"SUMA_alloc_problem"};
2345    SUMA_ENTRY;
2346 
2347    printf ("\n\n\aError in memory allocation\n");
2348    printf ("Error origin : %s\n\n",s1);
2349    printf ("Exiting Program ..\n\n");
2350    exit (0);
2351 }
2352 
2353 /*!
2354 
2355 Taken from allocate2D.c - Make matrix of given size (rows x cols) and type
2356 
2357 The type is given by element_size (2 = ints, 4 = floats, 8 = doubles).
2358 Exits if the matrix could not be allocated.
2359 
2360     char **allocate2D(int rows,int cols,int element_size)
2361 SIZE might vary depending on platform used !!!
2362 
2363 This function was adapted from DSP_in_C functions in
2364 C Language Algorithms for Digital Signal Processing
2365 by
2366 Bruce Kimball, Paul Embree and Bruce Kimble
2367 1991, Prentice Hall
2368 
2369             Ziad Saad                  Oct_21_96
2370 
2371 This function should not use SUMA_calloc because it can slow things down
2372 for Nxm arrays where N is very large.
2373 
2374 *************************************************************************/
2375 
SUMA_allocate2D(int rows,int cols,int element_size)2376 char **SUMA_allocate2D (int rows,int cols,int element_size)
2377 
2378 {
2379    int i;
2380    char **A;
2381    static char FuncName[]={"SUMA_allocate2D"};
2382    SUMA_Boolean LocalHead = NOPE;
2383 
2384    SUMA_ENTRY;
2385 
2386    if (rows <= 0 || cols < 0) {
2387       SUMA_S_Errv("Allocate2D with rows = %d and cols = %d!\n", rows, cols);
2388       SUMA_RETURN(NULL);
2389    }
2390    SUMA_LHv("nrows = %d, ncols = %d\n", rows, cols);
2391    #ifdef USE_SUMA_MALLOC
2392       SUMA_SL_Err("NO LONGER SUPPORTED");
2393       SUMA_RETURN(NULL);
2394    #else
2395       pause_mcw_malloc();
2396    #endif
2397 
2398    /* try to allocate the request */
2399    switch(element_size) {
2400      case sizeof(short): {    /* short matrix */
2401          short **int_matrix;
2402          int_matrix = (short **)calloc(rows,sizeof(short *));
2403          if(!int_matrix) {
2404              printf("\nError making pointers in %dx%d short matrix\n"
2405                          ,rows,cols);
2406              SUMA_RETURN(NULL);
2407          }
2408          for(i = 0 ; i < rows ; i++) {
2409              int_matrix[i] = (short *)calloc(cols,sizeof(short));
2410              if(!int_matrix[i]) {
2411                  printf("\nError making row %d in %dx%d short matrix\n"
2412                          ,i,rows,cols);
2413                  SUMA_RETURN(NULL);
2414              }
2415          }
2416          A = (char **)int_matrix;
2417          break;
2418      }
2419      case sizeof(char): {    /* char matrix */
2420          char **char_matrix;
2421          char_matrix = (char **)calloc(rows,sizeof(char *));
2422          if(!char_matrix) {
2423              printf("\nError making pointers in %dx%d char matrix\n"
2424                          ,rows,cols);
2425              SUMA_RETURN(NULL);
2426          }
2427          for(i = 0 ; i < rows ; i++) {
2428              char_matrix[i] = (char *)calloc(cols,sizeof(char));
2429              if(!char_matrix[i]) {
2430                  printf("\nError making row %d in %dx%d char matrix\n"
2431                          ,i,rows,cols);
2432                  SUMA_RETURN(NULL);
2433              }
2434          }
2435          A = (char **)char_matrix;
2436          break;
2437      }
2438      case sizeof(float): {    /* float, int,  matrix */
2439          float **float_matrix;
2440          float_matrix = (float **)calloc(rows,sizeof(float *));
2441          if(!float_matrix) {
2442              printf("\nError making pointers in %dx%d float matrix\n"
2443                          ,rows,cols);
2444              SUMA_RETURN(NULL);
2445          }
2446          for(i = 0 ; i < rows ; i++) {
2447              float_matrix[i] = (float *)calloc(cols,sizeof(float));
2448              if(!float_matrix[i]) {
2449                  printf("\nError making row %d in %dx%d float matrix\n"
2450                          ,i,rows,cols);
2451                  SUMA_RETURN(NULL);
2452              }
2453          }
2454          A = (char **)float_matrix;
2455          break;
2456      }
2457      case sizeof(double): {   /* double matrix */
2458          double **double_matrix;
2459          double_matrix = (double **)calloc(rows,sizeof(double *));
2460          if(!double_matrix) {
2461              printf("\nError making pointers in %dx%d double matrix\n"
2462                          ,rows,cols);
2463              SUMA_RETURN(NULL);
2464          }
2465          for(i = 0 ; i < rows ; i++) {
2466              double_matrix[i] = (double *)calloc(cols,sizeof(double));
2467              if(!double_matrix[i]) {
2468                  printf("\nError making row %d in %dx%d double matrix\n"
2469                          ,i,rows,cols);
2470                  SUMA_RETURN(NULL);
2471              }
2472          }
2473          A = (char **)double_matrix;
2474          break;
2475      }
2476 
2477      default:
2478          printf("\nERROR in matrix_allocate: unsupported type\n");
2479          SUMA_RETURN(NULL);
2480    }
2481 
2482    #ifdef USE_SUMA_MALLOC
2483    SUMA_SL_Err("NO LONGER SUPPORTED");
2484    SUMA_RETURN(NULL);
2485 
2486    #if SUMA_MEMTRACE_FLAG
2487    if (SUMAg_CF->MemTrace) {
2488       ++SUMAg_CF->Mem->N_alloc;
2489       if (SUMAg_CF->Mem->N_MaxPointers <= SUMAg_CF->Mem->N_alloc) {
2490          /* must reallocate */
2491          /* SUMA_ShowMemTrace (SUMAg_CF->Mem, NULL);*/
2492          SUMAg_CF->Mem->N_MaxPointers += SUMA_MEMTRACE_BLOCK;
2493 
2494          SUMAg_CF->Mem->Pointers = (void **)realloc(SUMAg_CF->Mem->Pointers,
2495                                  sizeof(void*) * SUMAg_CF->Mem->N_MaxPointers);
2496          SUMAg_CF->Mem->Size  = (int *)realloc((void *)SUMAg_CF->Mem->Size,
2497                                  sizeof(int) * SUMAg_CF->Mem->N_MaxPointers);
2498          if (!SUMAg_CF->Mem->Pointers || !SUMAg_CF->Mem->Pointers) {
2499             fprintf (SUMA_STDERR,
2500                "Error %s: Failed to reallocate.\nTurning off memory tracing.\n",
2501                FuncName);
2502             /* free up allocated space, clean up pointers, turn off memory
2503                tracing DO NOT USE SUMA_free here*/
2504             if (SUMAg_CF->Mem->Pointers) free(SUMAg_CF->Mem->Pointers);
2505             SUMAg_CF->Mem->Pointers = NULL;
2506             if (SUMAg_CF->Mem->Size) free(SUMAg_CF->Mem->Size);
2507             SUMAg_CF->Mem->Size = NULL;
2508             SUMAg_CF->MemTrace = 0;
2509             SUMAg_CF->Mem->N_alloc = 0;
2510             SUMAg_CF->Mem->N_MaxPointers =0;
2511          }
2512       }
2513       SUMAg_CF->Mem->Pointers[SUMAg_CF->Mem->N_alloc-1] = A;
2514       SUMAg_CF->Mem->Size[SUMAg_CF->Mem->N_alloc-1] = rows * cols * element_size;
2515    }
2516    #endif
2517 
2518    #else
2519       resume_mcw_malloc();
2520    #endif
2521 
2522    SUMA_RETURN(A);
2523 }
2524 
2525 /*!
2526 
2527 Taken from free2D.c - Free all elements of matrix
2528 
2529 Frees the 2D array (rows and cols) allocated using allocate2D
2530 
2531 Error message and exit if improper structure is
2532 passed to it (null pointers or zero size matrix).
2533 
2534     void free2D(char **a, int rows);
2535 
2536 This function was adapted from DSP_in_C functions in
2537 C Language Algorithms for Digital Signal Processing
2538 by
2539 Bruce Kimball, Paul Embree and Bruce Kimble
2540 1991, Prentice Hall
2541 
2542 
2543             Ziad Saad                  Oct_22_96
2544 
2545 This function should not use SUMA_free for freeing the pointers making up the matrix.
2546 Doing so would result in very slow execution times.
2547 
2548 *************************************************************************/
SUMA_free2D(char ** a,int rows)2549 void SUMA_free2D(char **a,int rows)
2550 {
2551    int i;
2552    static char FuncName[]={"SUMA_free2D"};
2553 
2554    SUMA_ENTRY;
2555 
2556    if (!a) SUMA_RETURNe;
2557 
2558       #ifdef USE_SUMA_MALLOC
2559          SUMA_SL_Err("NO LONGER SUPPORTED");
2560          SUMA_RETURNe;
2561 
2562       #if SUMA_MEMTRACE_FLAG
2563          if (SUMAg_CF->MemTrace && a) {
2564             SUMA_Boolean Found = NOPE;
2565             for (i=0; i < SUMAg_CF->Mem->N_alloc && !Found; ++i) {
2566                if (SUMAg_CF->Mem->Pointers[i] == a) {
2567                   SUMAg_CF->Mem->Pointers[i] = SUMAg_CF->Mem->Pointers[SUMAg_CF->Mem->N_alloc-1];
2568                   SUMAg_CF->Mem->Size[i] = SUMAg_CF->Mem->Size[SUMAg_CF->Mem->N_alloc-1];
2569                   SUMAg_CF->Mem->Pointers[SUMAg_CF->Mem->N_alloc-1] = NULL;
2570                   SUMAg_CF->Mem->Size[SUMAg_CF->Mem->N_alloc-1] = 0;
2571                   --SUMAg_CF->Mem->N_alloc;
2572                   Found = YUP;
2573                }
2574             }
2575             if (!Found) {
2576               fprintf (SUMA_STDERR, "Error %s: Pointer %p not found in Mem struct. \n", FuncName,a);
2577             }
2578          }
2579       #endif
2580       #else
2581          pause_mcw_malloc();
2582       #endif
2583 
2584    /* free each row of data */
2585    for(i = 0 ; i < rows ; i++) if (a[i]) free(a[i]);
2586 
2587    /* free each row pointer */
2588    free((char *)a);
2589    a = NULL;           /* set to null for error */
2590 
2591    #ifdef USE_SUMA_MALLOC
2592       /* don't use ifndef, keep it parallel with stuff above */
2593       SUMA_SL_Err("NO LONGER SUPPORTED");
2594       SUMA_RETURNe;
2595 
2596    #else
2597       resume_mcw_malloc();
2598    #endif
2599 
2600    SUMA_RETURNe;
2601 }
2602 
2603 /*!
2604 
2605 Taken from error_message.c
2606 Author : Ziad Saad
2607 Date : 26 Jan 95
2608 
2609 Purpose :
2610          displays error message, and exits the program if ext = 1;
2611 
2612 Usage :
2613       void error_message (s1,s2,ext);
2614 
2615 Input Parameters:
2616       s1, (char*) pointer to string to be printed for error location.
2617       s2, (char*) pointer to string holding error message.
2618       ext (int) if ext = 1 the program is aborted
2619 
2620 
2621 Header Files    */
2622 
SUMA_error_message(char * s1,char * s2,int ext)2623 void SUMA_error_message (char *s1,char *s2,int ext)
2624 
2625  {
2626     static char FuncName[]={"SUMA_error_message"};
2627 
2628    SUMA_ENTRY;
2629 
2630    printf ("\n\n\aError: %s\n",s2);
2631    printf ("Error origin: %s\n\n",s1);
2632    if (ext == 1)
2633       {
2634         printf ("Exiting Program ..\n\n");
2635          exit (0);
2636       }
2637       else SUMA_RETURNe;
2638 
2639   }
2640 
2641 /*!
2642    Return a string that is a catenation
2643    of the characters that differ between s1 and s2
2644    s1 and s2 are switched in the function so that
2645    s1 is always the longest of the two
2646 */
SUMA_StringDiff(char * s1,char * s2)2647 char *SUMA_StringDiff(char *s1, char *s2)
2648 {
2649    static char FuncName[]={"SUMA_StringDiff"};
2650    char *sd=NULL;
2651    int ns1=0, ns2=0, ns=0, i;
2652    SUMA_Boolean LocalHead = NOPE;
2653 
2654    SUMA_ENTRY;
2655 
2656    SUMA_LHv("Will diff on %p and %p\n", s1, s2);
2657    if (!s1 && !s2) {
2658       SUMA_RETURN(sd);
2659    }
2660    if (!s1 && s2) {
2661       SUMA_RETURN(SUMA_copy_string(s2));
2662    }
2663    if (s1 && !s2) {
2664       SUMA_RETURN(SUMA_copy_string(s1));
2665    }
2666    ns1 = strlen(s1);
2667    ns2 = strlen(s2);
2668    if (ns1 < ns2) {
2669       sd = s1; ns = ns1;
2670       s1 = s2;
2671       s2 = sd; sd = NULL;
2672       ns1 = ns2;
2673       ns2 = ns; ns = 0;
2674    }
2675 
2676    /* OK, have s1, and s2, and s1 is the longest */
2677    sd = (char *)calloc(ns1+1, sizeof(char));
2678    ns = 0;
2679    for (i=0; i < ns2; ++i) {
2680       if (s1[i] != s2[i]) {
2681          sd[ns]=s1[i];++ns;
2682       }
2683    }
2684    for (i=ns2; i < ns1; ++i) {
2685       sd[ns]=s1[i];++ns;
2686    }
2687    sd[ns]='\0';
2688 
2689    SUMA_LHv("Diff of %s and %s is\n%s\n",
2690                s1, s2, sd);
2691    RETURN(sd);
2692 }
2693 
2694 /*!
2695    Return a string that contains matching
2696    characters between s1 and s2
2697    s1 and s2 are switched in the function so that
2698    s1 is always the longest of the two
2699    firstdiff: if 1, then stop at the firt difference
2700    filler : if filler != '\0' then fill differing spots with 'filler'
2701             Otherwise differing characters are dropped from the output.
2702 */
SUMA_StringMatch(char * s1,char * s2,int firstdiff,char filler)2703 char *SUMA_StringMatch(char *s1, char *s2, int firstdiff, char filler)
2704 {
2705    static char FuncName[]={"SUMA_StringMatch"};
2706    char *sm=NULL;
2707    int ns1=0, ns2=0, ns=0, i;
2708    SUMA_Boolean LocalHead = NOPE;
2709 
2710    SUMA_ENTRY;
2711 
2712    SUMA_LHv("Will match on %p and %p\n", s1, s2);
2713    if (!s1 && !s2) {
2714       SUMA_RETURN(sm);
2715    }
2716    if (!s1 && s2) {
2717       SUMA_RETURN(sm);
2718    }
2719    if (s1 && !s2) {
2720       SUMA_RETURN(sm);
2721    }
2722    ns1 = strlen(s1);
2723    ns2 = strlen(s2);
2724    if (ns1 < ns2) {
2725       sm = s1; ns = ns1;
2726       s1 = s2;
2727       s2 = sm; sm = NULL;
2728       ns1 = ns2;
2729       ns2 = ns; ns = 0;
2730    }
2731 
2732    /* OK, have s1, and s2, and s1 is the longest */
2733    sm = (char *)calloc(ns1+1, sizeof(char));
2734    ns = 0;
2735    for (i=0; i < ns2; ++i) {
2736       if (s1[i] != s2[i]) {
2737          if (firstdiff) {
2738             sm[ns] = '\0';
2739             RETURN(sm);
2740          } else {
2741             if (filler != '\0') {
2742                sm[ns] = filler; ++ns;
2743             }
2744          }
2745       } else {
2746          sm[ns]=s1[i];++ns;
2747       }
2748    }
2749    if (filler != '\0') {
2750       for (i=ns2; i < ns1; ++i) {
2751          sm[ns]=filler;++ns;
2752       }
2753    }
2754    sm[ns]='\0';
2755 
2756    SUMA_LHv("Match of %s and %s (firstdiff=%d, filler=%c) is\n%s\n",
2757                s1, s2, firstdiff, filler, sm);
2758    RETURN(sm);
2759 }
2760 
2761 
2762 /*!
2763    \brief case insensitive version of SUMA_iswordin
2764 */
SUMA_iswordin_ci(const char * sbig,const char * ssub)2765 int SUMA_iswordin_ci ( const char *sbig, const char *ssub)
2766 {
2767    static char FuncName[]={"SUMA_iswordin_ci"};
2768    char *sbigc, *ssubc;
2769    int ans;
2770 
2771    SUMA_ENTRY;
2772    sbigc = SUMA_copy_string((char *)sbig);
2773    ssubc = SUMA_copy_string((char *)ssub);
2774 
2775    SUMA_TO_LOWER(sbigc);
2776    SUMA_TO_LOWER(ssubc);
2777 
2778    ans = SUMA_iswordin (sbigc, ssubc);
2779    if (sbigc) SUMA_free(sbigc); sbigc = NULL;
2780    if (ssubc) SUMA_free(ssubc); ssubc = NULL;
2781 
2782    SUMA_RETURN(ans);
2783 
2784 }
2785 
SUMA_wordswap_ci(const char * sbig,const char * ssub,const char * sswap,char * sout)2786 int SUMA_wordswap_ci ( const char *sbig, const char *ssub,
2787                        const char *sswap, char *sout)
2788 {
2789    static char FuncName[]={"SUMA_wordswap_ci"};
2790    char *sbigc, *ssubc, *sswapc, *sfn=NULL;
2791    int ans, i, n, k;
2792 
2793    SUMA_ENTRY;
2794    sbigc = SUMA_copy_string((char *)sbig);
2795    ssubc = SUMA_copy_string((char *)ssub);
2796    sswapc = SUMA_copy_string((char *)sswap);
2797 
2798    SUMA_TO_LOWER(sbigc);
2799    SUMA_TO_LOWER(ssubc);
2800    SUMA_TO_LOWER(sswapc);
2801 
2802    ans = SUMA_iswordin (sbigc, ssubc);
2803    k = 0;
2804    if (ans) {
2805       sfn = strstr(sbigc, ssubc);
2806       i = 0;
2807       while (i < (int)(sfn-sbigc)) { sout[k++] = sbigc[i++]; }/* Copy to swap */
2808       if (sswapc) {
2809          n = 0;
2810          while (n < strlen(sswapc)) { sout[k++] = sswapc[n++]; }
2811       }
2812       i += strlen(ssub);
2813       while (i < strlen(sbigc)) { sout[k++] = sbigc[i++]; } /* Copy left over */
2814       sout[k] = '\0';
2815    }
2816 
2817    if (sbigc) SUMA_free(sbigc); sbigc = NULL;
2818    if (sswapc) SUMA_free(sswapc); sswapc = NULL;
2819    if (ssubc) SUMA_free(ssubc); ssubc = NULL;
2820 
2821    SUMA_RETURN(ans);
2822 
2823 }
2824 
2825 /*!
2826    \brief case insensitive version of SUMA_iswordsame
2827 */
SUMA_iswordsame_ci(const char * sbig,const char * ssub)2828 int SUMA_iswordsame_ci ( const char *sbig, const char *ssub)
2829 {
2830    static char FuncName[]={"SUMA_iswordsame_ci"};
2831    int ans;
2832 
2833    SUMA_ENTRY;
2834    if ( (ans = SUMA_iswordin_ci(sbig, ssub)) == 1 &&
2835         strlen(sbig) != strlen(ssub) ) ans = 0;
2836 
2837    SUMA_RETURN(ans);
2838 }
2839 
SUMA_iswordsame(const char * sbig,const char * ssub)2840 int SUMA_iswordsame ( const char *sbig, const char *ssub)
2841 {
2842    static char FuncName[]={"SUMA_iswordsame"};
2843    int ans;
2844 
2845    SUMA_ENTRY;
2846    if ( (ans = SUMA_iswordin(sbig, ssub)) == 1 &&
2847         strlen(sbig) != strlen(ssub) ) ans = 0;
2848 
2849    SUMA_RETURN(ans);
2850 }
2851 
2852 /*!
2853 
2854 File : Taken from iswordin.c
2855 Author : Ziad Saad
2856 Date : Mon Sep 22 18:52:28 CDT 1997
2857 
2858 Purpose :
2859     To find out if an array of characters is an element of another array
2860     of characters
2861 
2862 
2863 Input paramters :
2864 
2865        S (char *) : Mother String (character array)
2866        Ssub (char *) : Subset array
2867 
2868 
2869 Usage :
2870       int SUMA_iswordin (const char *S, const char *Ssub );
2871 
2872  (you could use space characters in the two strings like:
2873     SUMA_iswordin ("Hello The Gump","The Gu"); would return a 1
2874     SUMA_iswordin ("Hello The Gump",""); would return a 1
2875     SUMA_iswordin ("Hello The Gump","Tha"); would return a 0
2876     SUMA_iswordin ("Hello The Gump"," "); would return a 1
2877     SUMA_iswordin ("Hel","Hello sdsd"); would return a 0
2878 
2879 Returns :
2880           returns 1 if Ssub is part of S
2881           returns 0 if Ssub is not part of S
2882           returns -1 if either Ssub or S is NULL
2883           returns -2 if both Ssub and S are NULL
2884 
2885 \sa  SUMA_iswordin_ci
2886 ***/
2887 #define IS_TRACE 0
SUMA_iswordin(const char * sbig,const char * ssub)2888 int SUMA_iswordin (const char *sbig, const char *ssub)
2889 {/*SUMA_iswordin*/
2890    int i=0,j=0;
2891    static char FuncName[]={"SUMA_iswordin"};
2892 
2893    #if IS_TRACE
2894    SUMA_ENTRY;
2895    #endif
2896 
2897    if (sbig == NULL && ssub == NULL) {
2898       #if IS_TRACE
2899          SUMA_RETURN (-2);
2900       #else
2901          return(-2);
2902       #endif
2903    }
2904    if (sbig == NULL || ssub == NULL) {
2905       #if IS_TRACE
2906          SUMA_RETURN (-1);
2907       #else
2908          return(-1);
2909       #endif
2910    }
2911    if (strlen(sbig) < strlen(ssub)) {
2912       #if IS_TRACE
2913          SUMA_RETURN (0);
2914       #else
2915          return(0);
2916       #endif
2917    }
2918 
2919    j=0;
2920    while (sbig[i] != '\0' && ssub[j] != '\0')
2921    {
2922        if (sbig[i] == ssub[j])
2923           {
2924              ++j;
2925              /*printf ("j=%d ",j);*/
2926           }
2927        else j=0;
2928    ++i;
2929    }
2930 
2931    if (j == strlen (ssub)) {
2932       #if IS_TRACE
2933          SUMA_RETURN (1);
2934       #else
2935          return(1);
2936       #endif
2937    }
2938    else {
2939       #if IS_TRACE
2940          SUMA_RETURN (0);
2941       #else
2942          return(0);
2943       #endif
2944    }
2945 
2946 }/*SUMA_iswordin*/
2947 
2948 /*!
2949 
2950 File : Taken from disp_dmat.c
2951 Author : Ziad Saad
2952 Date : Tue Nov 17 13:19:26 CST 1998
2953 
2954 Purpose :
2955    Displays on the terminal the 2D matrix of integers
2956 
2957 
2958 Usage :
2959        SUMA_disp_dmat (int **v,int nr, int nc, int SpcOpt  )
2960 
2961 
2962 Input paramters :
2963     v (int **) the 2D matrix to display
2964    nr (int) the number of rows in v
2965    nc (int) the number of columns
2966    SpcOpt (int) : spacing option (0 for space, 1 for tab and 2 for comma)
2967 
2968 
2969 
2970 Returns :
2971 
2972 
2973 
2974 Support :
2975 
2976 
2977 
2978 Side effects :
2979 
2980 
2981 
2982 ***/
2983 
SUMA_disp_dmat(int ** v,int nr,int nc,int SpcOpt)2984 void SUMA_disp_dmat (int **v,int nr, int nc , int SpcOpt)
2985 {/*SUMA_disp_dmat*/
2986    char spc [40];
2987    int i,j;
2988    static char FuncName[]={"SUMA_disp_dmat"};
2989 
2990    SUMA_ENTRY;
2991 
2992    if (!SpcOpt)
2993       sprintf(spc," ");
2994    else if (SpcOpt == 1)
2995       sprintf(spc,"\t");
2996    else
2997       sprintf(spc," , ");
2998 
2999    fprintf (SUMA_STDOUT,"\n");
3000    for (i=0; i < nr; ++i)
3001       {
3002          for (j=0; j < nc; ++j)
3003                fprintf (SUMA_STDOUT,"%d%s",v[i][j],spc);
3004          fprintf (SUMA_STDOUT,"\n");
3005       }
3006    SUMA_RETURNe;
3007 }/*SUMA_disp_dmat*/
3008 
3009 /*!**
3010 
3011 File : SUMA_MiscFunc.c
3012 Author : Ziad Saad
3013 Date : Tue Nov 17 13:19:26 CST 1998
3014 
3015 Purpose :
3016    Displays on the terminal the 2D float matrix
3017 
3018 
3019 Usage :
3020        SUMA_disp_mat (float **v,int nr, int nc, int SpcOpt )
3021 
3022 
3023 Input paramters :
3024     v (float **) the 2D matrix to display
3025    nr (int) the number of rows in v
3026    nc (int) the number of columns
3027    SpcOpt (int) : spacing option (0 for space, 1 for tab and 2 for comma)
3028 
3029 
3030 
3031 */
SUMA_disp_mat(float ** v,int nr,int nc,int SpcOpt)3032 void SUMA_disp_mat (float **v,int nr, int nc , int SpcOpt)
3033 {/*SUMA_disp_mat*/
3034    char spc [40];
3035     int i,j;
3036    static char FuncName[]={"SUMA_disp_mat"};
3037 
3038    SUMA_ENTRY;
3039 
3040    if (!SpcOpt)
3041       sprintf(spc," ");
3042    else if (SpcOpt == 1)
3043       sprintf(spc,"\t");
3044    else
3045       sprintf(spc," , ");
3046 
3047    fprintf (SUMA_STDOUT,"\n");
3048    for (i=0; i < nr; ++i)
3049       {
3050          for (j=0; j < nc; ++j)
3051                fprintf (SUMA_STDOUT, "%4.2f%s",v[i][j],spc);
3052          fprintf (SUMA_STDOUT,"\n");
3053       }
3054    SUMA_RETURNe;
3055 }/*SUMA_disp_mat*/
3056 
3057 /*!**
3058 Purpose :
3059    Displays on the terminal a 2D double matrix stored in a vector
3060 
3061 
3062 Usage :
3063        SUMA_disp_vecdoubmat (double *v,int nr, int nc, int SpcOpt, d_order, Out )
3064 
3065 
3066 Input paramters :
3067     v (double *) (nr x nc) vector containing the 2D matrix to display
3068    nr (int) the number of rows in v
3069    nc (int) the number of columns
3070    SpcOpt (int) : spacing option (0 for space, 1 for tab and 2 for comma)
3071    d_order (SUMA_INDEXING_ORDER): Indicates how multiple values per node are stored in fin
3072                         SUMA_ROW_MAJOR: The data in fin is stored in *** Row Major *** order.
3073                         The ith value (start at 0) for node n is at index fin[vpn*n+i]
3074                         SUMA_COLUMN_MAJOR: The data in fin is stored in *** Column Major *** order.
3075                         The ith (start at 0) value for node n is at index fin[n+SO->N_Node*i];
3076                         etc...
3077    AddRowInd (SUMA_Boolean) YUP  = add the row index in the first column
3078    Out (FILE *) pointer to output file. If NULL then output is to stdout.
3079 
3080 
3081 */
SUMA_disp_vecdoubmat(double * v,int nr,int nc,int SpcOpt,SUMA_INDEXING_ORDER d_order,FILE * fout,SUMA_Boolean AddRowInd)3082 void SUMA_disp_vecdoubmat (double *v,int nr, int nc , int SpcOpt,
3083                         SUMA_INDEXING_ORDER d_order, FILE *fout, SUMA_Boolean AddRowInd)
3084 {/*SUMA_disp_vecdoubmat*/
3085    char spc [40];
3086    int i,j;
3087    FILE *foutp;
3088    static char FuncName[]={"SUMA_disp_vecdoubmat"};
3089    SUMA_Boolean LocalHead = NOPE;
3090 
3091    SUMA_ENTRY;
3092 
3093    if (!fout) foutp = stdout;
3094    else foutp = fout;
3095 
3096    if (LocalHead) fprintf(SUMA_STDERR,"%s:\nExpecting to write %d rows/%d columns\n", FuncName, nr, nc);
3097 
3098    if (!SpcOpt)
3099       sprintf(spc," ");
3100    else if (SpcOpt == 1)
3101       sprintf(spc,"\t");
3102    else
3103       sprintf(spc," , ");
3104 
3105    if (!fout) fprintf (SUMA_STDOUT,"\n"); /* a blank 1st line when writing to screen */
3106    switch (d_order) {
3107       case SUMA_ROW_MAJOR:
3108          for (i=0; i < nr; ++i) {
3109             if (AddRowInd) fprintf (foutp, "%d%s", i, spc);
3110             for (j=0; j < nc; ++j) fprintf (foutp, "%lf%s",v[i*nc+j],spc);
3111             fprintf (foutp,"\n");
3112          }
3113          break;
3114       case SUMA_COLUMN_MAJOR:
3115          for (i=0; i < nr; ++i) {
3116             if (AddRowInd) fprintf (foutp, "%d%s", i, spc);
3117             for (j=0; j < nc; ++j) fprintf (foutp, "%lf%s",v[i+j*nr],spc);
3118             fprintf (foutp,"\n");
3119          }
3120          break;
3121       default:
3122          SUMA_SL_Err("Bad order.\n");
3123          SUMA_RETURNe;
3124          break;
3125    }
3126 
3127    SUMA_RETURNe;
3128 }/*SUMA_disp_vecdoubmat*/
3129 
3130 /*!**
3131 
3132 File : SUMA_MiscFunc.c
3133 Author : Ziad Saad
3134 Date : Tue Nov 17 13:19:26 CST 1998, modified Tue Aug 20 11:11:29 EDT 2002
3135 
3136 Purpose :
3137    Displays on the terminal a 2D byte matrix stored in a vector
3138 
3139 
3140 Usage :
3141        SUMA_disp_vecbytemat (byte *v,int nr, int nc, int SpcOpt, d_order, Out )
3142 
3143 
3144 Input paramters :
3145     v (byte *) (nr x nc) vector containing the 2D matrix to display
3146    nr (int) the number of rows in v
3147    nc (int) the number of columns
3148    SpcOpt (int) : spacing option (0 for space, 1 for tab and 2 for comma)
3149    d_order (SUMA_INDEXING_ORDER): Indicates how multiple values per node are stored in fin
3150                         SUMA_ROW_MAJOR: The data in fin is stored in *** Row Major *** order.
3151                         The ith value (start at 0) for node n is at index fin[vpn*n+i]
3152                         SUMA_COLUMN_MAJOR: The data in fin is stored in *** Column Major *** order.
3153                         The ith (start at 0) value for node n is at index fin[n+SO->N_Node*i];
3154                         etc...
3155    AddRowInd (SUMA_Boolean) YUP  = add the row index in the first column
3156    Out (FILE *) pointer to output file. If NULL then output is to stdout.
3157 
3158 
3159 */
SUMA_disp_vecbytemat(byte * v,int nr,int nc,int SpcOpt,SUMA_INDEXING_ORDER d_order,FILE * fout,SUMA_Boolean AddRowInd)3160 void SUMA_disp_vecbytemat (byte *v,int nr, int nc , int SpcOpt,
3161                         SUMA_INDEXING_ORDER d_order, FILE *fout, SUMA_Boolean AddRowInd)
3162 {/*SUMA_disp_vecbytemat*/
3163    char spc [40];
3164    int i,j;
3165    FILE *foutp;
3166    static char FuncName[]={"SUMA_disp_vecbytemat"};
3167    SUMA_Boolean LocalHead = NOPE;
3168 
3169    SUMA_ENTRY;
3170 
3171    if (!fout) foutp = stdout;
3172    else foutp = fout;
3173 
3174    if (LocalHead) fprintf(SUMA_STDERR,"%s:\nExpecting to write %d rows/%d columns\n", FuncName, nr, nc);
3175 
3176    if (!SpcOpt)
3177       sprintf(spc," ");
3178    else if (SpcOpt == 1)
3179       sprintf(spc,"\t");
3180    else
3181       sprintf(spc," , ");
3182 
3183    if (!fout) fprintf (SUMA_STDOUT,"\n"); /* a blank 1st line when writing to screen */
3184    switch (d_order) {
3185       case SUMA_ROW_MAJOR:
3186          for (i=0; i < nr; ++i) {
3187             if (AddRowInd) fprintf (foutp, "%d%s", i, spc);
3188             for (j=0; j < nc; ++j) fprintf (foutp, "%d%s",v[i*nc+j],spc);
3189             fprintf (foutp,"\n");
3190          }
3191          break;
3192       case SUMA_COLUMN_MAJOR:
3193          for (i=0; i < nr; ++i) {
3194             if (AddRowInd) fprintf (foutp, "%d%s", i, spc);
3195             for (j=0; j < nc; ++j) fprintf (foutp, "%d%s",v[i+j*nr],spc);
3196             fprintf (foutp,"\n");
3197          }
3198          break;
3199       default:
3200          SUMA_SL_Err("Bad order.\n");
3201          SUMA_RETURNe;
3202          break;
3203    }
3204 
3205    SUMA_RETURNe;
3206 }/*SUMA_disp_vecbytemat*/
3207 
3208 /*!**
3209 
3210 File : SUMA_MiscFunc.c
3211 Author : Ziad Saad
3212 Date : Tue Nov 17 13:19:26 CST 1998, modified Tue Aug 20 11:11:29 EDT 2002
3213 
3214 Purpose :
3215    Displays on the terminal a 2D short matrix stored in a vector
3216 
3217 
3218 Usage :
3219        SUMA_disp_vecshortmat (short *v,int nr, int nc, int SpcOpt, d_order, Out )
3220 
3221 
3222 Input paramters :
3223     v (short *) (nr x nc) vector containing the 2D matrix to display
3224    nr (int) the number of rows in v
3225    nc (int) the number of columns
3226    SpcOpt (int) : spacing option (0 for space, 1 for tab and 2 for comma)
3227    d_order (SUMA_INDEXING_ORDER): Indicates how multiple values per node are stored in fin
3228                         SUMA_ROW_MAJOR: The data in fin is stored in *** Row Major *** order.
3229                         The ith value (start at 0) for node n is at index fin[vpn*n+i]
3230                         SUMA_COLUMN_MAJOR: The data in fin is stored in *** Column Major *** order.
3231                         The ith (start at 0) value for node n is at index fin[n+SO->N_Node*i];
3232                         etc...
3233    AddRowInd (SUMA_Boolean) YUP  = add the row index in the first column
3234    Out (FILE *) pointer to output file. If NULL then output is to stdout.
3235 
3236 
3237 */
SUMA_disp_vecshortmat(short * v,int nr,int nc,int SpcOpt,SUMA_INDEXING_ORDER d_order,FILE * fout,SUMA_Boolean AddRowInd)3238 void SUMA_disp_vecshortmat (short *v,int nr, int nc , int SpcOpt,
3239                         SUMA_INDEXING_ORDER d_order, FILE *fout, SUMA_Boolean AddRowInd)
3240 {/*SUMA_disp_vecshortmat*/
3241    char spc [40];
3242    int i,j;
3243    FILE *foutp;
3244    static char FuncName[]={"SUMA_disp_vecshortmat"};
3245    SUMA_Boolean LocalHead = NOPE;
3246 
3247    SUMA_ENTRY;
3248 
3249    if (!fout) foutp = stdout;
3250    else foutp = fout;
3251 
3252    if (LocalHead) fprintf(SUMA_STDERR,"%s:\nExpecting to write %d rows/%d columns\n", FuncName, nr, nc);
3253 
3254    if (!SpcOpt)
3255       sprintf(spc," ");
3256    else if (SpcOpt == 1)
3257       sprintf(spc,"\t");
3258    else
3259       sprintf(spc," , ");
3260 
3261    if (!fout) fprintf (SUMA_STDOUT,"\n"); /* a blank 1st line when writing to screen */
3262    switch (d_order) {
3263       case SUMA_ROW_MAJOR:
3264          for (i=0; i < nr; ++i) {
3265             if (AddRowInd) fprintf (foutp, "%d%s", i, spc);
3266             for (j=0; j < nc; ++j) fprintf (foutp, "%d%s",v[i*nc+j],spc);
3267             fprintf (foutp,"\n");
3268          }
3269          break;
3270       case SUMA_COLUMN_MAJOR:
3271          for (i=0; i < nr; ++i) {
3272             if (AddRowInd) fprintf (foutp, "%d%s", i, spc);
3273             for (j=0; j < nc; ++j) fprintf (foutp, "%d%s",v[i+j*nr],spc);
3274             fprintf (foutp,"\n");
3275          }
3276          break;
3277       default:
3278          SUMA_SL_Err("Bad order.\n");
3279          SUMA_RETURNe;
3280          break;
3281    }
3282 
3283    SUMA_RETURNe;
3284 }/*SUMA_disp_vecshortmat*/
3285 /*!**
3286 
3287 File : SUMA_MiscFunc.c
3288 Author : Ziad Saad
3289 Date : Tue Nov 17 13:19:26 CST 1998, modified Tue Aug 20 11:11:29 EDT 2002
3290 
3291 Purpose :
3292    Displays on the terminal a 2D complex matrix stored in a vector
3293 
3294 
3295 Usage :
3296        SUMA_disp_veccompmat (complex *v,int nr, int nc, int SpcOpt, d_order, Out )
3297 
3298 
3299 Input paramters :
3300     v (complex *) (nr x nc) vector containing the 2D matrix to display
3301    nr (int) the number of rows in v
3302    nc (int) the number of columns
3303    SpcOpt (int) : spacing option (0 for space, 1 for tab and 2 for comma)
3304    d_order (SUMA_INDEXING_ORDER): Indicates how multiple values per node are stored in fin
3305                         SUMA_ROW_MAJOR: The data in fin is stored in *** Row Major *** order.
3306                         The ith value (start at 0) for node n is at index fin[vpn*n+i]
3307                         SUMA_COLUMN_MAJOR: The data in fin is stored in *** Column Major *** order.
3308                         The ith (start at 0) value for node n is at index fin[n+SO->N_Node*i];
3309                         etc...
3310    AddRowInd (SUMA_Boolean) YUP  = add the row index in the first column
3311    Out (FILE *) pointer to output file. If NULL then output is to stdout.
3312 
3313 
3314 */
SUMA_disp_veccompmat(complex * v,int nr,int nc,int SpcOpt,SUMA_INDEXING_ORDER d_order,FILE * fout,SUMA_Boolean AddRowInd)3315 void SUMA_disp_veccompmat (complex *v,int nr, int nc , int SpcOpt,
3316                         SUMA_INDEXING_ORDER d_order, FILE *fout, SUMA_Boolean AddRowInd)
3317 {/*SUMA_disp_veccompmat*/
3318    char spc [40];
3319    int i,j;
3320    FILE *foutp;
3321    static char FuncName[]={"SUMA_disp_veccompmat"};
3322    SUMA_Boolean LocalHead = NOPE;
3323 
3324    SUMA_ENTRY;
3325 
3326    if (!fout) foutp = stdout;
3327    else foutp = fout;
3328 
3329    if (LocalHead) fprintf(SUMA_STDERR,"%s:\nExpecting to write %d rows/%d columns\n", FuncName, nr, nc);
3330 
3331    if (!SpcOpt)
3332       sprintf(spc," ");
3333    else if (SpcOpt == 1)
3334       sprintf(spc,"\t");
3335    else
3336       sprintf(spc," , ");
3337 
3338    if (!fout) fprintf (SUMA_STDOUT,"\n"); /* a blank 1st line when writing to screen */
3339    switch (d_order) {
3340       case SUMA_ROW_MAJOR:
3341          for (i=0; i < nr; ++i) {
3342             if (AddRowInd) fprintf (foutp, "%d%s", i, spc);
3343             for (j=0; j < nc; ++j) fprintf (foutp, "%f %+fi%s",v[i*nc+j].r, v[i*nc+j].i,spc);
3344             fprintf (foutp,"\n");
3345          }
3346          break;
3347       case SUMA_COLUMN_MAJOR:
3348          for (i=0; i < nr; ++i) {
3349             if (AddRowInd) fprintf (foutp, "%d%s", i, spc);
3350             for (j=0; j < nc; ++j) fprintf (foutp, "%f %+fi%s",v[i+j*nr].r, v[i+j*nr].i,spc);
3351             fprintf (foutp,"\n");
3352          }
3353          break;
3354       default:
3355          SUMA_SL_Err("Bad order.\n");
3356          SUMA_RETURNe;
3357          break;
3358    }
3359 
3360    SUMA_RETURNe;
3361 }/*SUMA_disp_veccompmat*/
3362 
3363 /*!**
3364 
3365 File : SUMA_MiscFunc.c
3366 Author : Ziad Saad
3367 Date : Tue Nov 17 13:19:26 CST 1998, modified Tue Aug 20 11:11:29 EDT 2002
3368 
3369 Purpose :
3370    Displays on the terminal a 2D float matrix stored in a vector
3371 
3372 
3373 Usage :
3374        SUMA_disp_vecmat (float *v,int nr, int nc, int SpcOpt, d_order, Out )
3375 
3376 
3377 Input paramters :
3378     v (float *) (nr x nc) vector containing the 2D matrix to display
3379    nr (int) the number of rows in v
3380    nc (int) the number of columns
3381    SpcOpt (int) : spacing option (0 for space, 1 for tab and 2 for comma)
3382    d_order (SUMA_INDEXING_ORDER): Indicates how multiple values per node are stored in fin
3383                         SUMA_ROW_MAJOR: The data in fin is stored in *** Row Major *** order.
3384                         The ith value (start at 0) for node n is at index fin[vpn*n+i]
3385                         SUMA_COLUMN_MAJOR: The data in fin is stored in *** Column Major *** order.
3386                         The ith (start at 0) value for node n is at index fin[n+SO->N_Node*i];
3387                         etc...
3388    AddRowInd (SUMA_Boolean) YUP  = add the row index in the first column
3389    Out (FILE *) pointer to output file. If NULL then output is to stdout.
3390 
3391 
3392 */
SUMA_disp_vecmat(float * v,int nr,int nc,int SpcOpt,SUMA_INDEXING_ORDER d_order,FILE * fout,SUMA_Boolean AddRowInd)3393 void SUMA_disp_vecmat (float *v,int nr, int nc , int SpcOpt,
3394                         SUMA_INDEXING_ORDER d_order, FILE *fout, SUMA_Boolean AddRowInd)
3395 {/*SUMA_disp_vecmat*/
3396    char spc [40];
3397    int i,j;
3398    FILE *foutp;
3399    static char FuncName[]={"SUMA_disp_vecmat"};
3400    SUMA_Boolean LocalHead = NOPE;
3401 
3402    SUMA_ENTRY;
3403 
3404    if (!fout) foutp = stdout;
3405    else foutp = fout;
3406 
3407    if (LocalHead) fprintf(SUMA_STDERR,"%s:\nExpecting to write %d rows/%d columns\n", FuncName, nr, nc);
3408 
3409    if (!SpcOpt)
3410       sprintf(spc," ");
3411    else if (SpcOpt == 1)
3412       sprintf(spc,"\t");
3413    else
3414       sprintf(spc," , ");
3415 
3416    if (!fout) fprintf (SUMA_STDOUT,"\n"); /* a blank 1st line when writing to screen */
3417    switch (d_order) {
3418       case SUMA_ROW_MAJOR:
3419          for (i=0; i < nr; ++i) {
3420             if (AddRowInd) fprintf (foutp, "%d%s", i, spc);
3421             for (j=0; j < nc; ++j) fprintf (foutp, "%f%s",v[i*nc+j],spc);
3422             fprintf (foutp,"\n");
3423          }
3424          break;
3425       case SUMA_COLUMN_MAJOR:
3426          for (i=0; i < nr; ++i) {
3427             if (AddRowInd) fprintf (foutp, "%d%s", i, spc);
3428             for (j=0; j < nc; ++j) fprintf (foutp, "%f%s",v[i+j*nr],spc);
3429             fprintf (foutp,"\n");
3430          }
3431          break;
3432       default:
3433          SUMA_SL_Err("Bad order.\n");
3434          SUMA_RETURNe;
3435          break;
3436    }
3437 
3438    SUMA_RETURNe;
3439 }/*SUMA_disp_vecmat*/
3440 /*!**
3441 
3442 File : SUMA_MiscFunc.c
3443 Author : Ziad Saad
3444 Date : Tue Nov 17 13:19:26 CST 1998, modified Tue Aug 20 11:11:29 EDT 2002
3445 
3446 Purpose :
3447    Displays on the terminal a 2D int matrix stored in a 1D vector
3448 
3449 
3450 Usage :
3451        SUMA_disp_vecdmat (float *v,int nr, int nc, int SpcOpt, d_order, Out,  AddRowInd)
3452 
3453 
3454 Input paramters :
3455     v (int *) (nr x nc) vector containing the 2D matrix to display
3456    nr (int) the number of rows in v
3457    nc (int) the number of columns
3458    SpcOpt (int) : spacing option (0 for space, 1 for tab and 2 for comma)
3459    d_order (SUMA_INDEXING_ORDER): Indicates how multiple values per node are stored in fin
3460                         SUMA_ROW_MAJOR: The data in fin is stored in *** Row Major *** order.
3461                         The ith value (start at 0) for node n is at index fin[vpn*n+i]
3462                         SUMA_COLUMN_MAJOR: The data in fin is stored in *** Column Major *** order.
3463                         The ith (start at 0) value for node n is at index fin[n+SO->N_Node*i];
3464                         etc...
3465    Out (FILE *) pointer to output file. If NULL then output is to stdout.
3466    AddRowInd (SUMA_Boolean) YUP  = add the row index in the first column
3467 
3468 
3469    \sa SUMA_disp_vecucmat
3470 */
SUMA_disp_vecdmat(int * v,int nr,int nc,int SpcOpt,SUMA_INDEXING_ORDER d_order,FILE * fout,SUMA_Boolean AddRowInd)3471 void SUMA_disp_vecdmat (int *v,int nr, int nc , int SpcOpt,
3472                         SUMA_INDEXING_ORDER d_order, FILE *fout, SUMA_Boolean AddRowInd)
3473 {/*SUMA_disp_vecdmat*/
3474    char spc [40];
3475    int i,j;
3476    FILE *foutp;
3477    static char FuncName[]={"SUMA_disp_vecdmat"};
3478 
3479    SUMA_ENTRY;
3480 
3481    if (!fout) foutp = stdout;
3482    else foutp = fout;
3483 
3484    if (!SpcOpt)
3485       sprintf(spc," ");
3486    else if (SpcOpt == 1)
3487       sprintf(spc,"\t");
3488    else
3489       sprintf(spc," , ");
3490 
3491    if (!fout) fprintf (SUMA_STDOUT,"\n"); /* a blank 1st line when writing to screen */
3492    switch (d_order) {
3493       case SUMA_ROW_MAJOR:
3494          for (i=0; i < nr; ++i) {
3495             if (AddRowInd) fprintf (foutp, "%d%s", i, spc);
3496             for (j=0; j < nc; ++j) fprintf (foutp, "%d%s",v[i*nc+j],spc);
3497             fprintf (foutp,"\n");
3498          }
3499          break;
3500       case SUMA_COLUMN_MAJOR:
3501          for (i=0; i < nr; ++i) {
3502             if (AddRowInd) fprintf (foutp, "%d%s", i, spc);
3503             for (j=0; j < nc; ++j) fprintf (foutp, "%d%s",v[i+j*nr],spc);
3504             fprintf (foutp,"\n");
3505          }
3506          break;
3507       default:
3508          SUMA_SL_Err("Bad order.\n");
3509          SUMA_RETURNe;
3510          break;
3511    }
3512    SUMA_RETURNe;
3513 }/*SUMA_disp_vecdmat*/
3514 
3515 /*!
3516    \brief same as SUMA_disp_vecdmat, except with unsigned char * instead of int *
3517 */
SUMA_disp_vecucmat(unsigned char * v,int nr,int nc,int SpcOpt,SUMA_INDEXING_ORDER d_order,FILE * fout,SUMA_Boolean AddRowInd)3518 void SUMA_disp_vecucmat (unsigned char *v,int nr, int nc , int SpcOpt,
3519                         SUMA_INDEXING_ORDER d_order, FILE *fout, SUMA_Boolean AddRowInd)
3520 {/*SUMA_disp_vecucmat*/
3521    char spc [40];
3522    int i,j;
3523    FILE *foutp;
3524    static char FuncName[]={"SUMA_disp_vecucmat"};
3525 
3526    SUMA_ENTRY;
3527 
3528    if (!fout) foutp = stdout;
3529    else foutp = fout;
3530 
3531    if (!SpcOpt)
3532       sprintf(spc," ");
3533    else if (SpcOpt == 1)
3534       sprintf(spc,"\t");
3535    else
3536       sprintf(spc," , ");
3537 
3538    if (!fout) fprintf (SUMA_STDOUT,"\n"); /* a blank 1st line when writing to screen */
3539    switch (d_order) {
3540       case SUMA_ROW_MAJOR:
3541          for (i=0; i < nr; ++i) {
3542             if (AddRowInd) fprintf (foutp, "%d%s", i, spc);
3543             for (j=0; j < nc; ++j) fprintf (foutp, "%d%s",v[i*nc+j],spc);
3544             fprintf (foutp,"\n");
3545          }
3546          break;
3547       case SUMA_COLUMN_MAJOR:
3548          for (i=0; i < nr; ++i) {
3549             if (AddRowInd) fprintf (foutp, "%d%s", i, spc);
3550             for (j=0; j < nc; ++j) fprintf (foutp, "%d%s",v[i+j*nr],spc);
3551             fprintf (foutp,"\n");
3552          }
3553          break;
3554       default:
3555          SUMA_SL_Err("Bad order.\n");
3556          SUMA_RETURNe;
3557          break;
3558    }
3559    SUMA_RETURNe;
3560 }/*SUMA_disp_vecucmat*/
SUMA_disp_veccmat(char * v,int nr,int nc,int SpcOpt,SUMA_INDEXING_ORDER d_order,FILE * fout,SUMA_Boolean AddRowInd)3561 void SUMA_disp_veccmat (char *v,int nr, int nc , int SpcOpt,
3562                         SUMA_INDEXING_ORDER d_order, FILE *fout,
3563                         SUMA_Boolean AddRowInd)
3564 {/*SUMA_disp_veccmat*/
3565    char spc [40];
3566    int i,j;
3567    FILE *foutp;
3568    static char FuncName[]={"SUMA_disp_veccmat"};
3569 
3570    SUMA_ENTRY;
3571 
3572    if (!fout) foutp = stdout;
3573    else foutp = fout;
3574 
3575    if (!SpcOpt)
3576       sprintf(spc," ");
3577    else if (SpcOpt == 1)
3578       sprintf(spc,"\t");
3579    else
3580       sprintf(spc," , ");
3581 
3582    if (!fout) fprintf (SUMA_STDOUT,"\n"); /* a blank 1st line when writing to screen */
3583    switch (d_order) {
3584       case SUMA_ROW_MAJOR:
3585          for (i=0; i < nr; ++i) {
3586             if (AddRowInd) fprintf (foutp, "%d%s", i, spc);
3587             for (j=0; j < nc; ++j) fprintf (foutp, "%d%s",v[i*nc+j],spc);
3588             fprintf (foutp,"\n");
3589          }
3590          break;
3591       case SUMA_COLUMN_MAJOR:
3592          for (i=0; i < nr; ++i) {
3593             if (AddRowInd) fprintf (foutp, "%d%s", i, spc);
3594             for (j=0; j < nc; ++j) fprintf (foutp, "%d%s",v[i+j*nr],spc);
3595             fprintf (foutp,"\n");
3596          }
3597          break;
3598       default:
3599          SUMA_SL_Err("Bad order.\n");
3600          SUMA_RETURNe;
3601          break;
3602    }
3603    SUMA_RETURNe;
3604 }/*SUMA_disp_vecucmat*/
3605 
3606 /*!
3607    Set *N_dims to -1 if you don't have dims setup and are willing to take whatever is in Name
3608 */
SUMA_Read1DMxVec(SUMA_VARTYPE tp,char * Name,int * dims,int * N_dims)3609 SUMA_MX_VEC *SUMA_Read1DMxVec(SUMA_VARTYPE tp, char *Name, int *dims, int *N_dims)
3610 {
3611    static char FuncName[]={"SUMA_Read1DMxVec"};
3612    SUMA_MX_VEC *v=NULL;
3613    float *fv=NULL;
3614    double *dv = NULL;
3615    int ncol, nrow, i, nvals;
3616    complex *cv = NULL;
3617    SUMA_Boolean LocalHead   = NOPE;
3618 
3619    SUMA_ENTRY;
3620 
3621    if (*N_dims > 0) {
3622       /* user has format in mind */
3623       nvals = dims[0];
3624       for (i=1;i<*N_dims;++i) nvals = nvals * dims[i];
3625    } else {
3626       nvals = -1;
3627    }
3628    switch (tp) {
3629       case SUMA_complex:
3630          cv = SUMA_LoadComplex1D_eng (Name, &ncol, &nrow, 0, 0);
3631          if (!cv) {
3632             SUMA_S_Errv("Failed to load %s\n", Name);
3633             SUMA_RETURN(v);
3634          }
3635          if (nvals >= 0) {
3636             if (ncol*nrow != nvals) {
3637                SUMA_S_Errv("User wants a total of %d values, %d found in file.\n", nvals, ncol*nrow);
3638                SUMA_RETURN(v);
3639             }
3640          } else {
3641             nvals = ncol*nrow;
3642             dims[0] = nrow; dims[1] = ncol;
3643             *N_dims = 2;
3644          }
3645          SUMA_LHv("nvals = %d, dims=[%d,%d], ncol=%d, *Ndims=%d\n", nvals, dims[0], dims[1], ncol, *N_dims);
3646 
3647          v = SUMA_VecToMxVec(SUMA_complex, *N_dims, dims, 1, (void *)cv); cv = NULL; /* cv should be nulled, pointer copied into output*/
3648          break;
3649 
3650       #if 0
3651       case SUMA_double:
3652          fv = SUMA_Load1D_eng (Name, &ncol, &nrow, 0, 0);
3653          if (!fv) {
3654             SUMA_S_Errv("Failed to load %s\n", Name);
3655             SUMA_RETURN(v);
3656          }
3657          if (nvals >= 0) {
3658             if (ncol*nrow != nvals) {
3659                SUMA_S_Errv("User wants a total of %d values, %d (%dx%d) found in file.\n", nvals, ncol*nrow, ncol, nrow);
3660                SUMA_RETURN(v);
3661             }
3662          } else {
3663             nvals = ncol*nrow;
3664             dims[0] = nrow; dims[1] = ncol;
3665             *N_dims = 2;
3666          }
3667          v = SUMA_NewMxVec(tp, *N_dims,  dims,  1);
3668          for (i=0; i<nvals; ++i) {
3669             mxvd1(v,i) = (double)fv[i];
3670          }
3671          SUMA_free(fv); fv = NULL;
3672          break;
3673       #else
3674       case SUMA_double:
3675          dv = SUMA_LoadDouble1D_eng(Name, &ncol, &nrow, 0, 0);
3676          if (!dv) {
3677             SUMA_S_Errv("Failed to load %s\n", Name);
3678             SUMA_RETURN(v);
3679          }
3680          if (nvals >= 0) {
3681             if (ncol*nrow != nvals) {
3682                SUMA_S_Errv("User wants a total of %d values, %d found in file.\n", nvals, ncol*nrow);
3683                SUMA_RETURN(v);
3684             }
3685          } else {
3686             nvals = ncol*nrow;
3687             dims[0] = nrow; dims[1] = ncol;
3688             *N_dims = 2;
3689          }
3690          SUMA_LHv("nvals = %d, dims=[%d,%d], ncol=%d, *Ndims=%d\n", nvals, dims[0], dims[1], ncol, *N_dims);
3691 
3692          v = SUMA_VecToMxVec(SUMA_double, *N_dims, dims, 1, (void *)dv); dv = NULL; /* dv should be nulled, pointer copied into output*/
3693          break;
3694       #endif
3695       default:
3696          SUMA_S_Err("Not ready for this type");
3697          break;
3698    }
3699 
3700    SUMA_RETURN(v);
3701 }
3702 
3703 /*!
3704    \brief a function to write MxVec to a file, mostly
3705    for debugging. No overwrite protection provided
3706    If Name is NULL then output is to stdout
3707 */
SUMA_WriteMxVec(SUMA_MX_VEC * mxv,char * Name,char * title)3708 int SUMA_WriteMxVec(SUMA_MX_VEC *mxv, char *Name, char *title)
3709 {
3710    static char FuncName[]={"SUMA_WriteMxVec"};
3711    FILE *out = NULL;
3712    int i, d0, d1;
3713 
3714    SUMA_ENTRY;
3715 
3716    if (!Name) out = stdout;
3717    else {
3718       out = fopen(Name,"w");
3719       if (!out) {
3720          SUMA_S_Err("Could not open file for output");
3721          SUMA_RETURN(0);
3722       }
3723    }
3724    if (title) {
3725       if (title[0] != '#') fprintf(out,"#");
3726       fprintf(out,"%s", title);
3727       if (title[strlen(title)] != '\n'); fprintf(out,"\n");
3728    }
3729 
3730    if (mxv->N_dims > 2) {
3731       fprintf(out,"#MxVec is %d dimensional, writing results in column major (first dimension first) array form.\n", mxv->N_dims);
3732       d0 = mxv->N_vals;
3733       d1 = 1;
3734    } else if (mxv->N_dims == 1) {
3735       d0 = mxv->N_vals;
3736       d1 = 1;
3737    } else {
3738       d0 = mxv->dims[0];
3739       d1 = mxv->dims[1];
3740    }
3741 
3742    if (mxv->fdf != 1) {
3743       SUMA_S_Err("Not ready for vectors that are not first dimension first");
3744       SUMA_RETURN(0);
3745    }
3746 
3747    fprintf(out,"#Dimensions are: [");
3748    for (i=0;i<mxv->N_dims;++i) fprintf(out,"%d, ", mxv->dims[i]);
3749    fprintf(out,"]\n");
3750 
3751    switch (mxv->tp) {
3752       case SUMA_byte:
3753          SUMA_disp_vecbytemat((byte *)mxv->v, d0, d1, 1,
3754                               SUMA_COLUMN_MAJOR, out, 0);
3755          break;
3756       case SUMA_short:
3757          SUMA_disp_vecshortmat((short *)mxv->v, d0, d1, 1,
3758                                  SUMA_COLUMN_MAJOR, out, 0);
3759          break;
3760       case SUMA_int:
3761          SUMA_disp_vecdmat((int *)mxv->v, d0, d1, 1,
3762                            SUMA_COLUMN_MAJOR, out, 0);
3763          break;
3764       case SUMA_float:
3765          SUMA_disp_vecmat((float *)mxv->v, d0, d1, 1,
3766                            SUMA_COLUMN_MAJOR, out, 0);
3767          break;
3768       case SUMA_double:
3769          SUMA_disp_vecdoubmat((double *)mxv->v, d0, d1, 1,
3770                               SUMA_COLUMN_MAJOR, out, 0);
3771          break;
3772       case SUMA_complex:
3773          SUMA_disp_veccompmat((complex *)mxv->v, d0, d1, 1,
3774                               SUMA_COLUMN_MAJOR, out, 0);
3775          break;
3776       default:
3777          SUMA_SL_Err("Type not supported");
3778          SUMA_RETURN(0);
3779    }
3780 
3781    if (Name) fclose(out); out = NULL;
3782    SUMA_RETURN(1);
3783 }
3784 
3785 
3786 /*!
3787 File : SUMA_MiscFunc.c from disp_vect.c
3788 Author : Ziad Saad
3789 Date : 23 Oct 1996
3790 
3791 Purpose :
3792          displays a variable or vector of type float
3793 
3794 Usage :
3795        void SUMA_disp_vect (float *v,int l);
3796 
3797 
3798 
3799 Input Parameters:
3800                 v, (float *) pointer to input  vector or variable
3801                 ln, (int) lenght of complex vector, set equal to 1 if vector is a variable
3802 
3803 */
SUMA_disp_vect(float * v,int l)3804 void SUMA_disp_vect (float *v,int l)
3805 { int i;
3806    static char FuncName[]={"SUMA_disp_vect"};
3807 
3808    SUMA_ENTRY;
3809 
3810    fprintf (SUMA_STDOUT,"\n");
3811    if ((l-1) == 0)
3812       fprintf (SUMA_STDOUT,"%f\n",*v);
3813    else
3814    {
3815    for (i=0;i<l;++i)
3816                  fprintf (SUMA_STDOUT,"%f\t",v[i]);
3817    fprintf (SUMA_STDOUT,"\n");
3818    }
3819    SUMA_RETURNe;
3820 }
SUMA_disp_doubvect(double * v,int l)3821 void SUMA_disp_doubvect (double *v,int l)
3822 { int i;
3823    static char FuncName[]={"SUMA_disp_doubvect"};
3824 
3825    SUMA_ENTRY;
3826 
3827    fprintf (SUMA_STDOUT,"\n");
3828    if ((l-1) == 0)
3829       fprintf (SUMA_STDOUT,"%g\n",*v);
3830    else
3831    {
3832    for (i=0;i<l;++i)
3833                  fprintf (SUMA_STDOUT,"%g\t",v[i]);
3834    fprintf (SUMA_STDOUT,"\n");
3835    }
3836    SUMA_RETURNe;
3837 }
3838 
3839 /*
3840 File : SUMA_MiscFunc.c,  from disp_dvect.c
3841 Author : Ziad Saad
3842 Date : 23 Oct 1996
3843 
3844 Purpose :
3845          displays a variable or vector of type int
3846 
3847 Usage :
3848        void SUMA_disp_dvect (int *v,int l);
3849 
3850 
3851 
3852 Input Parameters:
3853                 v, (int *) pointer to input vector or variable
3854                 ln, (int) lenght of complex vector, set equal to 1 if vector is a variable
3855 
3856 */
SUMA_disp_dvect(int * v,int l)3857 void SUMA_disp_dvect (int *v,int l)
3858 {   int i;
3859    static char FuncName[]={"SUMA_disp_dvect"};
3860 
3861    SUMA_ENTRY;
3862 
3863    fprintf (SUMA_STDOUT,"\n");
3864    if ((l-1) == 0)
3865       fprintf (SUMA_STDOUT, "%d\n",*v);
3866    else
3867    {
3868    for (i=0;i<l;++i)
3869       fprintf (SUMA_STDOUT,"%d\t",v[i]);
3870 
3871    fprintf (SUMA_STDOUT,"\n");
3872    }
3873    SUMA_RETURNe;
3874 }
3875 
3876 /*!
3877    SUMA_etime2(char *name, char *str, char *strloc)
3878    SUMA_etime2(name, NULL, NULL) initialize time stamp
3879    SUMA_etime2(name, str, strloc) show elapsed time from last call,
3880                            use strings str and strloc in report.
3881                            str must be non null.
3882 */
SUMA_etime2(char * name,char * str,char * strloc)3883 int SUMA_etime2(char *name, char *str, char *strloc)
3884 {
3885    static char FuncName[]={"SUMA_etime2"};
3886    int i;
3887    double dt;
3888    SUMA_Boolean LocalHead = NOPE;
3889 
3890    SUMA_ENTRY;
3891 
3892    if (!name) {
3893       SUMA_LH("Resetting all timers");
3894       /* reset all */
3895       for (i=0; i<SUMA_MAX_N_TIMER; ++i) {
3896          SUMAg_CF->Timer[i].name[0]='\0';
3897          SUMAg_CF->Timer[i].lastcall = -1.0;
3898       }
3899       SUMAg_CF->N_Timer = 0;
3900       SUMA_RETURN(-1);
3901    }else {
3902       /* find the time */
3903       SUMA_LHv("Locating timer %s\n", name);
3904       i = 0;
3905       while (i < SUMAg_CF->N_Timer && strcmp(SUMAg_CF->Timer[i].name, name)) {
3906          ++i;
3907       }
3908       if (i+1 >= SUMA_MAX_N_TIMER) {
3909          SUMA_S_Errv("Cannot add a new timer %s\n", name);
3910          SUMA_RETURN(-1);
3911       } else if (i == SUMAg_CF->N_Timer) { /* add the new timer */
3912          SUMA_LHv("Adding new timer %s at i=%d\n", name, i);
3913          sprintf(SUMAg_CF->Timer[i].name, "%s", name);
3914          SUMAg_CF->Timer[i].lastcall = -1.0;
3915          ++SUMAg_CF->N_Timer;
3916       } else {
3917          SUMA_LHv("Timer %s found at i = %d\n", SUMAg_CF->Timer[i].name, i);
3918       }
3919       SUMA_LHv("Timer is %s at %d\n", SUMAg_CF->Timer[i].name, i);
3920       if (str) { /* have something to say, not first call */
3921          if (SUMAg_CF->Timer[i].lastcall < 0) {
3922             dt = 0.0;
3923          } else {
3924             dt = SUMA_etime(&(SUMAg_CF->Timer[i].tt),1) - SUMAg_CF->Timer[i].lastcall ;
3925          }
3926          SUMAg_CF->Timer[i].lastcall = SUMA_etime(&(SUMAg_CF->Timer[i].tt),1);
3927          if (strloc) fprintf (SUMA_STDERR,"Timer %s, in %s: %s\n"
3928                                           "      Time from last stamp %fs (%.2fmin)\n"
3929                                           "      Total time from init. %fs (%.2fmin)\n",
3930                                                 SUMAg_CF->Timer[i].name,
3931                                                 strloc, str, dt, dt/60.0,
3932                                                 SUMAg_CF->Timer[i].lastcall,
3933                                                 SUMAg_CF->Timer[i].lastcall/60.0);
3934          else        fprintf (SUMA_STDERR,"Timer %s, %s\n"
3935                                           "      Time from last stamp %fs (%.2fmin)\n"
3936                                           "      Total time from init. %fs (%.2fmin)\n",
3937                                                  SUMAg_CF->Timer[i].name,
3938                                                  str, dt, dt/60.0,
3939                                                  SUMAg_CF->Timer[i].lastcall,
3940                                                  SUMAg_CF->Timer[i].lastcall/60.0);
3941 
3942          SUMA_RETURN(i);
3943       } else { /* Reset timer */
3944          SUMA_etime(&(SUMAg_CF->Timer[i].tt), 0);
3945          SUMAg_CF->Timer[i].lastcall = -1.0;
3946          SUMA_RETURN(i);
3947       }
3948    }
3949    SUMA_LH("Going home");
3950    SUMA_RETURN(-1);
3951 }
3952 
3953 
3954 /*!
3955 
3956 File : SUMA_MiscFunc.c from ~Zlib/code/etime.c
3957 Author : Ziad Saad
3958 Date : Mon Dec 28 13:06:36 CST 1998
3959 
3960 Purpose :
3961    computes the time elapsed between different operations, for example:
3962 
3963    float delta_t;
3964    struct  timeval tt;
3965 
3966    SUMA_etime (&tt, 0);  :the zero tells the function to start a new counter
3967 
3968     :operations are here ......
3969 
3970    delta_t = SUMA_etime (&tt, 1);  :computes the time between tt the time stamp (set in the previous call)
3971                               :delta_t is the elapsed time in seconds
3972 
3973 Usage :
3974    delta_t = SUMA_etime (tt, Report );
3975 
3976 
3977 Input paramters :
3978    tt (struct  timeval *) : a pointer that holds the time stamp structure
3979    Report (int ) : a (0/1) flag to signal time reporting or the start of a new timer
3980 
3981 
3982 
3983 Returns :
3984    delta_t (float) : the time elapsed between the time stamp and the call to etime
3985 
3986 
3987 Support :
3988    #include <sys/time.h>
3989 
3990 
3991 
3992 Side effects :
3993 
3994 
3995 
3996 ***/
SUMA_etime(struct timeval * t,int Report)3997 float SUMA_etime (struct  timeval  *t, int Report  )
3998 {/*SUMA_etime*/
3999    static char FuncName[]={"SUMA_etime"};
4000    struct  timeval  tn;
4001    float Time_Fact = 1000000.0;
4002    float delta_t;
4003 
4004    SUMA_ENTRY;
4005 
4006    /* get time */
4007    gettimeofday(&tn, NULL);
4008 
4009    if (Report)
4010       {
4011          /* fprintf(stderr,"%s: Reporting from %d sec to %d sec\n",
4012                         FuncName, t->tv_sec, tn.tv_sec);  */
4013          delta_t = (((float)(tn.tv_sec - t->tv_sec)*Time_Fact) +
4014                      (float)(tn.tv_usec - t->tv_usec)) /Time_Fact;
4015       }
4016    else
4017       {
4018          t->tv_sec = tn.tv_sec;
4019          t->tv_usec = tn.tv_usec;
4020          /*fprintf(stderr,"%s: Initialized to %f sec \n",
4021                            FuncName, (float)tn.tv_sec); */
4022          delta_t = 0.0;
4023       }
4024 
4025    SUMA_RETURN (delta_t);
4026 
4027 }/*SUMA_etime*/
4028 
4029 /*
4030    Return time stamp in a string.
4031    yymmdd_hhmmss.MMM
4032    with MMM being a 3 digit msec stamp that
4033    is useless except for minimizing the chance of similar stamps
4034    in repeated calls. You can't rely on the msec part to be accurate.
4035 
4036    Do not free returned string.
4037    \sa SUMA_time
4038 */
SUMA_time_stamp(void)4039 char *SUMA_time_stamp(void )
4040 {
4041    struct  timeval  tn;
4042    time_t tnow = time(NULL) ;
4043    static char res[64], ttt[31];
4044 
4045    gettimeofday(&tn, NULL);
4046    strftime(ttt,31*sizeof(char),"%y%m%d_%H%M%S", localtime(&tnow));
4047    snprintf(res,63*sizeof(char),"%s.%03d", ttt, (int)(tn.tv_usec/1000));
4048    return(res);
4049 }
4050 
SUMA_time(void)4051 char *SUMA_time(void)
4052 {
4053    static char dt[32]={"??:??:??"}, *tm;
4054    time_t tnow = time(NULL) ;
4055 
4056    strftime(dt,31*sizeof(char),"%H:%M:%S", localtime(&tnow));
4057 
4058    return(dt);
4059 }
4060 
4061 /*!
4062 
4063 File : SUMA_MiscFunc.c, from ~Zlib/code/isinsphere.c
4064 Author : Ziad Saad
4065 Date : Fri Nov 20 22:56:31 CST 1998
4066 
4067 Purpose :
4068    determines which nodes lie inside a sphere
4069 
4070 
4071 Usage :
4072       Ret =  SUMA_isinsphere (NodeList, nr, S_cent , S_rad , BoundIn)
4073 
4074 Input paramters :
4075    NodeList (float * ) : Nx3 vector containing the NodeList of the nodes
4076                         to consider
4077    nr  (int )   : that's N, the number of nodes
4078    S_cent (float *) : a 3x1 vector containing the
4079                       coordinates of the center of the sphere
4080    S_rad  (float ) : the radius of the sphere
4081    BoundIn (int) : 0/1 set to 0 for exclusive boundary
4082 
4083 
4084 Returns :
4085    a structure of the type SUMA_ISINSPHERE with the following fields
4086 
4087    .IsIn    (int *) : a pointer to an [nIsIn x 1] vector will contain
4088                      the indices into the rows of NodeList that
4089                      locates the nodes inside the sphere.
4090    .nIsIn   (int) : the number of nodes in the sphere
4091    .d (float *) : a pointer to an [nIsIn x 1]  vector containing
4092                   the distance of those nodes inside the sphere to the center.
4093 
4094 Support :
4095 
4096 Side effects :
4097 
4098 ***/
SUMA_isinsphere(float * NodeList,int nr,float * S_cent,float S_rad,int BoundIn)4099 SUMA_ISINSPHERE SUMA_isinsphere (float * NodeList, int nr, float *S_cent ,
4100                                  float S_rad , int BoundIn )
4101 {/*SUMA_isinsphere*/
4102    static char FuncName[]={"SUMA_isinsphere"};
4103    float *t, t0, t1, t2, ta;
4104    int k, *IsIn, id, ND;
4105    SUMA_ISINSPHERE IsIn_strct;
4106 
4107    SUMA_ENTRY;
4108 
4109    ND = 3;
4110    IsIn_strct.nIsIn = 0;
4111    IsIn_strct.dXYZ = NULL;
4112    IsIn_strct.IsIn = NULL;
4113    IsIn_strct.d = NULL;
4114 
4115    t = (float *) SUMA_calloc (nr, sizeof(float));
4116    IsIn = (int *) SUMA_calloc (nr, sizeof(int));
4117 
4118    if (!t || !IsIn)
4119       {
4120          SUMA_alloc_problem (FuncName);
4121          SUMA_RETURN (IsIn_strct);
4122       }
4123 
4124 
4125    if (BoundIn) /* split into two to avoid checking for this
4126                   condition all the time */
4127       {
4128          for (k=0; k < nr; ++k)
4129             {
4130                id = ND * k;
4131                /* Net distance to center */
4132                t0 = NodeList[id] - S_cent[0];
4133                t1 = NodeList[id+1] - S_cent[1];
4134                t2 = NodeList[id+2] - S_cent[2];
4135 
4136                ta = sqrt (t0 * t0 + t1 * t1 + t2 * t2);
4137 
4138                if (ta <= S_rad)
4139                   {
4140                      IsIn[IsIn_strct.nIsIn] = k;
4141                      t[IsIn_strct.nIsIn] = ta;
4142                      ++(IsIn_strct.nIsIn);
4143                   }
4144             }
4145       }
4146    else
4147       {
4148          for (k=0; k < nr; ++k)
4149             {
4150                id = ND * k;
4151                /* Net distance to center */
4152                t0 = NodeList[id] - S_cent[0];
4153                t1 = NodeList[id+1] - S_cent[1];
4154                t2 = NodeList[id+2] - S_cent[2];
4155 
4156                ta = sqrt (t0 * t0 + t1 * t1 + t2 * t2);
4157 
4158                if (ta < S_rad)
4159                   {
4160                      IsIn[IsIn_strct.nIsIn] = k;
4161                      t[IsIn_strct.nIsIn] = ta;
4162                      ++(IsIn_strct.nIsIn);
4163                   }
4164             }
4165       }
4166 
4167    /* get ridd of extra allocation space*/
4168    IsIn_strct.d = (float *) SUMA_calloc (IsIn_strct.nIsIn, sizeof(float));
4169    IsIn_strct.IsIn = (int *) SUMA_calloc (IsIn_strct.nIsIn, sizeof(int));
4170 
4171    if (!IsIn_strct.d || !IsIn_strct.IsIn )
4172       {
4173          IsIn_strct.nIsIn = 0;
4174          SUMA_alloc_problem(FuncName);
4175          SUMA_RETURN (IsIn_strct);
4176       }
4177 
4178    SUMA_COPY_VEC (t, IsIn_strct.d, IsIn_strct.nIsIn, float , float);
4179    SUMA_COPY_VEC (IsIn, IsIn_strct.IsIn , IsIn_strct.nIsIn, int , int);
4180 
4181    SUMA_free(t);
4182    SUMA_free(IsIn);
4183 
4184    SUMA_RETURN (IsIn_strct);
4185 
4186 }/*SUMA_isinsphere*/
4187 
4188 /* Same as SUMA_isinsphere but return a byte mask */
SUMA_isinsphere_bm(float * NodeList,int nr,float * S_cent,float S_rad,int BoundIn)4189 byte *SUMA_isinsphere_bm (float * NodeList, int nr, float *S_cent ,
4190                                  float S_rad , int BoundIn )
4191 {/*SUMA_isinsphere_bm*/
4192    static char FuncName[]={"SUMA_isinsphere_bm"};
4193    int k;
4194    SUMA_ISINSPHERE IsIn_strct;
4195    byte *bm = NULL;
4196 
4197    SUMA_ENTRY;
4198 
4199    if (!NodeList || !nr) SUMA_RETURN(bm);
4200    IsIn_strct = SUMA_isinsphere(NodeList, nr, S_cent, S_rad, BoundIn);
4201    bm = (byte *)calloc(nr, sizeof(byte));
4202    for (k=0; k<IsIn_strct.nIsIn;++k) bm[IsIn_strct.IsIn[k]]=1;
4203    SUMA_Free_IsInSphere(&IsIn_strct);
4204 
4205    SUMA_RETURN(bm);
4206 }
4207 
4208 /*!
4209 free SUMA_ISINSPHERE structure contents.
4210 Structure pointer is not freed
4211 */
SUMA_Free_IsInSphere(SUMA_ISINSPHERE * IB)4212 SUMA_Boolean SUMA_Free_IsInSphere (SUMA_ISINSPHERE *IB)
4213 {
4214    static char FuncName[]={"SUMA_Free_IsInSphere"};
4215 
4216    SUMA_ENTRY;
4217 
4218    if (IB == NULL) {
4219       fprintf (SUMA_STDERR,
4220                "Error SUMA_Free_IsInSphere: pointer to null cannot be freed\n");
4221       SUMA_RETURN (NOPE);
4222    }
4223    if (IB->IsIn != NULL) SUMA_free(IB->IsIn);
4224    if (IB->d != NULL) SUMA_free(IB->d);
4225    IB->nIsIn = 0;
4226    SUMA_RETURN (YUP);
4227 }
4228 
4229 /*!**
4230 
4231 File : SUMA_MiscFunc from ~Zlib/code/ isinbox.c
4232 Author : Ziad Saad
4233 Date : Fri Nov 20 23:52:52 CST 1998
4234 
4235 Purpose :
4236       determines which nodes lie inside a box
4237 
4238 
4239 
4240 Usage :
4241    Ret = SUMA_isinbox (float * XYZ, int nr, S_cent , S_dim ,  BoundIn)
4242 
4243 
4244 Input paramters :
4245     XYZ (float * ) : Nx3 vector containing the XYZ of the nodes to consider
4246    nr  (int )   : that's N, the number of nodes
4247    S_cent (float *) : a 3x1 vector containing the XYZ coordinates of the center of the box
4248    S_dim  (float *) : a 3x1 containing the size of the box from side
4249                     to side along the three dimentions
4250    BoundIn (int) : 0/1 set to 0 if you want to have exclusive boundary conditions
4251 
4252 
4253 Returns :
4254    a structure of the type SUMA_ISINBOX with the following fields
4255 
4256    IsIn    (int *) : a pointer to an [nIsIn x 1] vector that will contain indices into the rows of XYZ that
4257                      locates the nodes inside the box.
4258    d   (float *): The distance between each of the nodes and the center of the box
4259    nIsIn   (int) : the number of nodes in the box
4260 
4261 
4262 Support :
4263 
4264 
4265 
4266 Side effects :
4267 
4268 
4269 
4270 ***/
SUMA_isinbox(float * XYZ,int nr,float * S_cent,float * S_dim,int BoundIn)4271 SUMA_ISINBOX SUMA_isinbox (float * XYZ, int nr,
4272                            float *S_cent , float *S_dim , int BoundIn )
4273 {/*SUMA_isinbox*/
4274 
4275    static char FuncName[]={"SUMA_isinbox"};
4276    float t0, t1, t2, hdim0, hdim1, hdim2, *d;
4277    int k , *IsIn, id, ND;
4278    SUMA_ISINBOX IsIn_strct;
4279 
4280    SUMA_ENTRY;
4281 
4282    ND = 3;
4283    /*
4284    fprintf(SUMA_STDOUT,"%f %f %f, %f %f %f, %d, %f, %f, %f\n",
4285       S_cent[0], S_cent[1], S_cent[2], S_dim[0], S_dim[1], S_dim[2],
4286       nr, XYZ[0], XYZ[1], XYZ[2]);
4287    */
4288 
4289    IsIn_strct.nIsIn = 0;
4290    IsIn_strct.dXYZ = NULL;
4291    IsIn_strct.d = NULL;
4292    IsIn_strct.IsIn = NULL;
4293 
4294    hdim0 = S_dim[0]/2;
4295    hdim1 = S_dim[1]/2;
4296    hdim2 = S_dim[2]/2;
4297 
4298    IsIn = (int *) SUMA_calloc (nr, sizeof(int));
4299    d = (float *)SUMA_calloc(nr, sizeof(float));
4300 
4301    if (!IsIn || !d)
4302       {
4303          SUMA_alloc_problem (FuncName);
4304          SUMA_RETURN (IsIn_strct);
4305       }
4306 
4307    if (BoundIn) {/* split to avoid checking for this condition all the time */
4308       /*fprintf(SUMA_STDERR,"%s: inbound\n", FuncName);*/
4309       for (k=0; k < nr; ++k)
4310          {
4311          /*fprintf(SUMA_STDERR,"%s: inbound %d\n", FuncName, k);*/
4312          /* relative distance to center */
4313             id = ND * k;
4314             t0 = hdim0 - fabs(XYZ[id] - S_cent[0]);
4315 
4316             if (t0 >= 0) {
4317                t1 = hdim1 - fabs(XYZ[id+1] - S_cent[1]);
4318                if (t1 >= 0) {
4319                   t2 = hdim2 - fabs(XYZ[id+2] - S_cent[2]);
4320                   if (t2 >= 0)
4321                      {
4322                         IsIn[IsIn_strct.nIsIn] = k;
4323                         d[IsIn_strct.nIsIn] = sqrt(t0*t0+t1*t1+t2*t2);
4324                         ++(IsIn_strct.nIsIn);
4325                      }
4326                }
4327             }
4328          }
4329          /*fprintf(SUMA_STDERR,"%s: outbound\n", FuncName);*/
4330    } else {
4331       for (k=0; k < nr; ++k)
4332          {
4333             /* relative distance to center */
4334             id = ND * k;
4335             t0 = hdim0 - fabs(XYZ[id] - S_cent[0]);
4336 
4337             if (t0 > 0) {
4338                t1 = hdim1 - fabs(XYZ[id+1] - S_cent[1]);
4339                if (t1 > 0) {
4340                   t2 = hdim2 - fabs(XYZ[id+2] - S_cent[2]);
4341                   if (t2 > 0)
4342                      {
4343                         IsIn[IsIn_strct.nIsIn] = k;
4344                         d[IsIn_strct.nIsIn] = sqrt(t0*t0+t1*t1+t2*t2);
4345                         ++(IsIn_strct.nIsIn);
4346                      }
4347                }
4348             }
4349          }
4350    }
4351 
4352    if (IsIn_strct.nIsIn) {
4353       /*fprintf(SUMA_STDERR,"%s: SUMA_realloc\n", FuncName);*/
4354 
4355       /* get ridd of extra allocation space*/
4356       IsIn_strct.IsIn = (int *) SUMA_calloc (IsIn_strct.nIsIn, sizeof(int));
4357       IsIn_strct.d = (float *)SUMA_calloc(IsIn_strct.nIsIn, sizeof(float));
4358 
4359       if (!IsIn_strct.IsIn || !IsIn_strct.d)
4360          {
4361             IsIn_strct.nIsIn = 0;
4362             SUMA_alloc_problem(FuncName);
4363             SUMA_RETURN (IsIn_strct);
4364          }
4365 
4366       SUMA_COPY_VEC (IsIn, IsIn_strct.IsIn , IsIn_strct.nIsIn, int , int);
4367       SUMA_COPY_VEC (d, IsIn_strct.d, IsIn_strct.nIsIn, float, float);
4368    } else {
4369       /*fprintf(SUMA_STDERR,"%s: NADA\n", FuncName);*/
4370       IsIn_strct.IsIn = NULL;
4371       IsIn_strct.d = NULL;
4372    }
4373 
4374    /*fprintf(SUMA_STDERR,"%s: freeing\n", FuncName);*/
4375    SUMA_free(IsIn);
4376    SUMA_free(d);
4377    /*fprintf(SUMA_STDERR,"%s: freed\n", FuncName);*/
4378 
4379    SUMA_RETURN (IsIn_strct) ;
4380 
4381 }/*SUMA_isinbox*/
4382 
4383 /*! much faster than isinbox, send NULL for dinsq if you don't care for it
4384    n = SUMA_nodesinbox2(xyz, nr, s_cent, s_dim, nodein, dinsq);
4385    \param xyz (float *) xyz triplets
4386    \param nr (int) number of triplets
4387    \param s_cent (float *) xyz for boxes' center
4388    \param s_dim (float *) side to side dimensions of the box
4389    \param nodesin (int *) to contain indices of nodes in box.
4390                            if nodesin[i]=nnn when i < Nin, then
4391                            node nnn is inside the box.
4392    \param dinsq (float *) to contain the squared distance from a node
4393                           to the center of the box. Send NULL if you do not
4394                           care for it.
4395    \return Nin (int) number of nodes inside box.
4396          You must pre-allocate nr values for each of nodesin and dinsq .
4397          But on Nin values are meaningful
4398 */
SUMA_nodesinbox2(float * XYZ,int nr,float * S_cent,float * S_dim,int * nodesin,float * dinsq)4399 int SUMA_nodesinbox2 (float *XYZ, int nr,
4400                       float *S_cent , float *S_dim ,
4401                       int *nodesin, float *dinsq)
4402 {
4403    static char FuncName[]={"SUMA_nodesinbox2"};
4404    int nin = -1;
4405    float hdim0, hdim1, hdim2, t0, t1, t2;
4406    int k, id;
4407    SUMA_ENTRY;
4408 
4409    hdim0 = S_dim[0]/2.0;
4410    hdim1 = S_dim[1]/2.0;
4411    hdim2 = S_dim[2]/2.0;
4412 
4413    /* Inclusive boundary mode */
4414 
4415          nin = 0;
4416          /*fprintf(SUMA_STDERR,"%s: inbound\n", FuncName);*/
4417          for (k=0; k < nr; ++k)
4418             {
4419             /*fprintf(SUMA_STDERR,"%s: inbound %d\n", FuncName, k);*/
4420             /* relative distance to center */
4421                id = 3 * k;
4422                t0 = hdim0 - SUMA_ABS(XYZ[id] - S_cent[0]);
4423 
4424                if (t0 >= 0) {
4425                   t1 = hdim1 - SUMA_ABS(XYZ[id+1] - S_cent[1]);
4426                   if (t1 >= 0) {
4427                      t2 = hdim2 - SUMA_ABS(XYZ[id+2] - S_cent[2]);
4428                      if (t2 >= 0)
4429                         {
4430                            nodesin[nin] = k;
4431                            if (dinsq) dinsq[nin] = (t0*t0+t1*t1+t2*t2);
4432                            ++nin;
4433                         }
4434                   }
4435                }
4436             }
4437             /*fprintf(SUMA_STDERR,"%s: outbound\n", FuncName);*/
4438 
4439    SUMA_RETURN(nin);
4440 }
4441 /* Same as SUMA_nodesinbox2 but return a byte mask */
SUMA_nodesinbox2_bm(float * NodeList,int nr,float * S_cent,float * S_edge,byte * bmu)4442 byte *SUMA_nodesinbox2_bm (float *NodeList, int nr,
4443                         float *S_cent , float *S_edge,
4444                         byte *bmu)
4445 {/*SUMA_nodesinbox2_bm*/
4446    static char FuncName[]={"SUMA_nodesinbox2_bm"};
4447    int k, nin;
4448    int *nodesin=NULL;
4449    byte *bm = NULL;
4450 
4451    SUMA_ENTRY;
4452 
4453    if (!NodeList || !nr) SUMA_RETURN(bm);
4454    nodesin = (int *)SUMA_calloc(nr, sizeof(int));
4455    nin = SUMA_nodesinbox2(NodeList, nr, S_cent, S_edge, nodesin, NULL);
4456    if (!bmu) bm = (byte *)calloc(nr, sizeof(byte));
4457    else bm = bmu;
4458    for (k=0; k<nin;++k) bm[nodesin[k]]=1;
4459    SUMA_free(nodesin); nodesin = NULL;
4460 
4461    SUMA_RETURN(bm);
4462 }
4463 
4464 
4465 
4466 /* same as nodesinbox2 only sdim is one float, specifying the RADIUS,
4467 see SUMA_NODESINSPHERE2 for slimmed, slightly faster version*/
SUMA_nodesinsphere2(float * XYZ,int nr,float * S_cent,float S_dim,int * nodesin,float * dinsq)4468 int SUMA_nodesinsphere2 (float *XYZ, int nr, float *S_cent , float S_dim ,
4469                          int *nodesin, float *dinsq)
4470 {
4471    static char FuncName[]={"SUMA_nodesinsphere2"};
4472    int k;
4473    int nin = -1, id;
4474    float t0, t1, t2, d2, r2;
4475 
4476    SUMA_ENTRY;
4477 
4478    r2 = S_dim*S_dim;
4479    nin = 0;
4480          /*fprintf(SUMA_STDERR,"%s: inbound\n", FuncName);*/
4481          for (k=0; k < nr; ++k)
4482             {
4483             /*fprintf(SUMA_STDERR,"%s: inbound %d\n", FuncName, k);*/
4484             /* relative distance to center */
4485                id = 3 * k;
4486                t0 = SUMA_ABS(XYZ[id] - S_cent[0]);
4487 
4488                if (t0 <= S_dim) {
4489                   t1 = SUMA_ABS(XYZ[id+1] - S_cent[1]);
4490                   if (t1 <= S_dim) {
4491                      t2 = SUMA_ABS(XYZ[id+2] - S_cent[2]);
4492                      if (t2 <= S_dim)
4493                         {
4494                            /* in box, is it in sphere? */
4495                            d2 = (t0*t0+t1*t1+t2*t2);
4496                            if (d2 <=r2) {
4497                               nodesin[nin] = k;
4498                               if (dinsq) dinsq[nin] = d2;
4499                               ++nin;
4500                            }
4501                         }
4502                   }
4503                }
4504             }
4505             /*fprintf(SUMA_STDERR,"%s: outbound\n", FuncName);*/
4506 
4507    SUMA_RETURN(nin);
4508 }
4509 /* Same as SUMA_nodesinsphere2 but return a byte mask */
SUMA_nodesinsphere2_bm(float * NodeList,int nr,float * S_cent,float S_rad,byte * bmu)4510 byte *SUMA_nodesinsphere2_bm (float * NodeList, int nr,
4511                            float *S_cent , float S_rad,
4512                            byte *bmu)
4513 {/*SUMA_nodesinsphere2_bm*/
4514    static char FuncName[]={"SUMA_nodesinsphere2_bm"};
4515    int k, nin;
4516    int *nodesin=NULL;
4517    byte *bm = NULL;
4518 
4519    SUMA_ENTRY;
4520 
4521    if (!NodeList || !nr) SUMA_RETURN(bm);
4522    nodesin = (int *)SUMA_calloc(nr, sizeof(int));
4523    nin = SUMA_nodesinsphere2(NodeList, nr, S_cent, S_rad, nodesin, NULL);
4524    if (!bmu) bm = (byte *)calloc(nr, sizeof(byte));
4525    else bm = bmu;
4526    for (k=0; k<nin;++k) bm[nodesin[k]]=1;
4527    SUMA_free(nodesin); nodesin = NULL;
4528 
4529    SUMA_RETURN(bm);
4530 }
4531 
4532 
4533 
4534 /*!
4535 free SUMA_ISINBOX structure contents.
4536 Structure pointer is not freed
4537 */
SUMA_Free_IsInBox(SUMA_ISINBOX * IB)4538 SUMA_Boolean SUMA_Free_IsInBox (SUMA_ISINBOX *IB)
4539 {
4540    static char FuncName[]={"SUMA_Free_IsInBox"};
4541 
4542    SUMA_ENTRY;
4543 
4544    if (IB == NULL) {
4545       fprintf (SUMA_STDERR,"Error SUMA_Free_IsInBox: pointer to null cannot be freed\n");
4546       SUMA_RETURN (NOPE);
4547    }
4548    if (IB->IsIn != NULL) SUMA_free(IB->IsIn);
4549    if (IB->d != NULL) SUMA_free(IB->d);
4550    IB->nIsIn = 0;
4551    SUMA_RETURN (YUP);
4552 }
4553 
4554 /*!
4555    \brief Determines is a point in 2D is inside a polygon with no holes.
4556    The function's parameters are abit strange because of the intended use.
4557 
4558    \param P (float *) 3x1 vector containing XYZ of the point to test
4559    \param NodeList (float *) the proverbial nodelist xyz xyz xyz etc.
4560    \param FaceSetList (int *) the proverbial FaceSetList defining polygons
4561    \param N_FaceSet (int) number of polygons in each list
4562    \param FaceSetDim (int) number of points forming polygon
4563    \param dims (int) 2x1 vector indicating which dimensions to consider.
4564                      Recall this a 2D inclusion function! For example,
4565                      if dims = [ 0 1] then the z coordinate (2) is not considered
4566                      if dims = [ 0 2] then the y coordinate (1) is not considered
4567                      if dims = [ 2 1] then the x coordinate (0) is not considered
4568    \params N_in (int *) to contain the number of polygons that contain p
4569    \param usethis (byte *) use this vector to store results (see return param)
4570    \return isin (byte *) if isin[iv] the point P is in polygon iv
4571 
4572 
4573    core based on code by Paul Bourke, see copyright notice in suma -sources
4574    Does not work for polys with holes
4575 */
SUMA_isinpoly(float * P,float * NodeList,int * FaceSetList,int N_FaceSet,int FaceSetDim,int * dims,int * N_in,byte * usethis,byte * culled)4576 byte * SUMA_isinpoly(float *P, float *NodeList,
4577                      int *FaceSetList, int N_FaceSet,
4578                      int FaceSetDim, int *dims, int *N_in,
4579                      byte *usethis, byte *culled)
4580 {
4581    static char FuncName[]={"SUMA_isinpoly"};
4582    byte *isin=NULL;
4583    int iv, i, ip, counter, ni;
4584    double xinters;
4585    float p1[2], p2[2], p[2], poly[300];
4586    SUMA_Boolean LocalHead = NOPE;
4587 
4588    SUMA_ENTRY;
4589 
4590    *N_in = 0;
4591    if (!usethis) {
4592       isin = (byte *)SUMA_malloc(sizeof(byte)*N_FaceSet);
4593       if (!isin) {
4594          SUMA_SL_Crit("Failed to allocate!");
4595          SUMA_RETURN(NOPE);
4596       }
4597    } else isin = usethis;
4598    if (FaceSetDim > 99) {
4599       SUMA_SL_Err("max FaceSetDim = 99");
4600       SUMA_RETURN(NULL);
4601    }
4602    if (dims[0] < 0 || dims[0] > 2 || dims[1] < 0 || dims[1] > 2) {
4603       SUMA_SL_Err("dims is a 2x1 vector with allowed values of 0 1 or 2 only.");
4604       SUMA_RETURN(NULL);
4605    }
4606 
4607    p[0] = P[dims[0]]; p[1] = P[dims[1]]; /* the point of interest */
4608    for (iv = 0; iv < N_FaceSet; ++iv) {
4609       counter = 0;
4610       for (i=0; i<FaceSetDim; ++i) { /* form the polygon coordinate vector */
4611          ni = FaceSetList[FaceSetDim*iv+i];
4612          poly[3*i] = NodeList[3*ni];
4613          poly[3*i+1] = NodeList[3*ni+1]; poly[3*i+2] = NodeList[3*ni+2];
4614       }
4615       if (culled) if (culled[iv]) continue;
4616 
4617       p1[0] = poly[dims[0]]; p1[1] = poly[dims[1]]; /* the very first point */
4618       for (i=1; i <=FaceSetDim; ++i) {
4619          ip = i % FaceSetDim;
4620          p2[0] = poly[3*ip+dims[0]]; p2[1] = poly[3*ip+dims[1]];
4621          if (p[1] > SUMA_MIN_PAIR(p1[1], p2[1])) {
4622             if (p[1] <= SUMA_MAX_PAIR(p1[1], p2[1])) {
4623                if (p[0] <= SUMA_MAX_PAIR(p1[0], p2[0])) {
4624                   if (p1[1] != p2[1]) {
4625                      xinters = (p[1]-p1[1])*(p2[0]-p1[0])/(p2[1]-p1[1])+p1[0];
4626                      if (p1[0] == p2[0] || p[0] <= xinters) {
4627                         counter++;
4628                      }
4629                   }
4630                }
4631             }
4632          }
4633          p1[0] = p2[0]; p1[1] = p2[1];
4634       }
4635 
4636       if (counter % 2 == 0) {
4637          isin[iv] = 0;
4638       } else {
4639          isin[iv] = 1; ++(*N_in); /* p is inside polygon iv */
4640          #if 0
4641          if (LocalHead)
4642          {
4643             int kk;
4644             fprintf(SUMA_STDERR,"\n%%hit!\nPoly = [");
4645             for (kk=0; kk < FaceSetDim; ++kk) {
4646                fprintf(SUMA_STDERR,"%.2f %.2f; ", poly[3*kk+dims[0]] , poly[3*kk+dims[1]]);
4647             } fprintf(SUMA_STDERR,"%.2f %.2f] \np = [%.3f %.3f];", poly[dims[0]], poly[dims[1]], p[0], p[1]);
4648          }
4649          #endif
4650       }
4651    }
4652 
4653    SUMA_RETURN(isin);
4654 }
4655 
4656 /*!
4657           mandatory input
4658    P (float *)3 coords of point P in center of wedge
4659    C (float *)3 coords of center of 2 spheres of radii r1 and r2
4660    rr1 (float) squared radius of inner sphere
4661    rr2 (float) squared radius of outer sphere
4662    coshalpha (float) cosine of half angle of wedge
4663    Q (float *)3 coords of point in question
4664          Optional
4665    uCP(float *) if not NULL, then this is the unit vector CP
4666          Pass it to speed up computations
4667 
4668           returned
4669    rrQ (float*) square of distance from Q to C
4670                 -1.0 when nothing is computed
4671    cosaQ (float *) cosine of angle PCQ (using -2.0 for flag of no
4672                    angle computed. Happens when point is outside)
4673 
4674    return value: 1 for in, 0 for out
4675 */
is_in_wedge(float * P,float * C,float rr1,float rr2,float coshalpha,float * Q,float * uCP,float * rrQ,float * cosaQ)4676 int is_in_wedge(float *P, float *C, float rr1, float rr2, float coshalpha,
4677                 float *Q, float *uCP, float *rrQ, float *cosaQ)
4678 {
4679    float dp, dot, rr, rrP;
4680    float CP[3], CQ[3];
4681 
4682    if (!P || !C || rr2<=0.0) {
4683       if (cosaQ) *cosaQ=-2.0;
4684       if (rrQ) *rrQ=-1.0;
4685       return(0);
4686    }
4687 
4688    /* Distance check */
4689    CQ[0] = Q[0]-C[0];
4690    CQ[1] = Q[1]-C[1];
4691    CQ[2] = Q[2]-C[2];
4692    rr = CQ[0]*CQ[0]+CQ[1]*CQ[1]+CQ[2]*CQ[2];
4693    if (rrQ) *rrQ=rr;
4694 
4695    if (rr<rr1 || rr>rr2 || rr == 0.0) {
4696       if (cosaQ) *cosaQ=-2.0;
4697       return(0);
4698    }
4699    /* angle check */
4700    rr = sqrtf(rr);
4701    CQ[0] /= rr;  CQ[1] /= rr; CQ[2] /= rr;/* Normalize CQ */
4702 
4703    if (!uCP) {
4704       CP[0] = P[0]-C[0];
4705       CP[1] = P[1]-C[1];
4706       CP[2] = P[2]-C[2];
4707       rrP = sqrtf(CP[0]*CP[0]+CP[1]*CP[1]+CP[2]*CP[2]);
4708       CQ[0] /= rrP;  CQ[1] /= rrP; CQ[2] /= rrP;/* Normalize CP */
4709       dot = SUMA_MT_DOT(CP,CQ);
4710    } else {
4711       dot = SUMA_MT_DOT(uCP,CQ);
4712    }
4713    if (dot >= coshalpha) {
4714       if (cosaQ) *cosaQ=dot;
4715       return(1);
4716    } else {
4717       if (cosaQ) *cosaQ=2.0;
4718    }
4719    return(0);
4720 }
4721 
4722 /*!**
4723 Function: SUMA_Point_At_Distance
4724 Usage :
4725 P2 = SUMA_Point_At_Distance (U, P1, d)
4726 
4727 Returns the two points that are at a distance d from P1 along the direction of U
4728 
4729 Input paramters :
4730 \param U (float *) 3x1 vector specifying directions  along x, y, z axis
4731 \param P1 (float *) 3x1 vector containing the XYZ of P1
4732 \param d (float) distance from P1
4733 
4734 
4735 Returns :
4736 \return  P2 (float **) 2x3 matrix containg XYZ of 2 points equidistant from P1
4737                along U (first row) and -U (second row)
4738          NULL if there are problems in the land of chocolate
4739 
4740 Support :
4741 \sa   Point_At_Distance.m
4742 \sa  To free P2, use: SUMA_free2D((char **)P2, 2);
4743 
4744 \sa SUMA_POINT_AT_DISTANCE and SUMA_POINT_AT_DISTANCE_NORM macro
4745 
4746 ***/
SUMA_Point_At_Distance(float * U,float * P1,float d)4747 float **SUMA_Point_At_Distance(float *U, float *P1, float d)
4748 {/*SUMA_Point_At_Distance*/
4749    static char FuncName[]={"SUMA_Point_At_Distance"};
4750    float bf, **P2, P1orig[3], Uorig[3];
4751    float m, n, p, q, D, A, B, C, epsi = 0.0001;
4752    int flip, i;
4753    SUMA_Boolean LocalHead = NOPE;
4754 
4755    SUMA_ENTRY;
4756 
4757    SUMA_SL_Warn ("useless piece of junk, use SUMA_POINT_AT_DISTANCE instead!");
4758 
4759    if (d == 0) {
4760       fprintf(SUMA_STDERR,"Error %s: d is 0. Not good, Not good at all.\n", FuncName);
4761       SUMA_RETURN (NULL);
4762    }
4763 
4764    if (LocalHead) {
4765       fprintf (SUMA_STDOUT,"%s: U %f, %f, %f, P1 %f %f %f, d %f\n", FuncName,\
4766          U[0], U[1], U[2], P1[0], P1[1], P1[2], d);
4767    }
4768 
4769    /* store initial values */
4770    P1orig[0] = P1[0];
4771    P1orig[1] = P1[1];
4772    P1orig[2] = P1[2];
4773 
4774    Uorig[0] = U[0];
4775    Uorig[1] = U[1];
4776    Uorig[2] = U[2];
4777 
4778    /* normalize U such that U(0) = 1 */
4779    flip = 0;
4780    if (fabs(U[0]) < epsi) { /* must flip X with some other coordinate */
4781       if (fabs(U[1]) > epsi) {/*U[1] != 0; */
4782          U[0] = U[1]; U[1] = 0;
4783          bf = P1[0]; P1[0] = P1[1]; P1[1] = bf;
4784          flip = 1;
4785       } else {   /*U[1] = 0; */
4786          if (fabs(U[2]) > epsi) { /* U[2] != 0 */
4787             U[0] = U[2]; U[2] = 0;
4788             bf = P1[0]; P1[0] = P1[2]; P1[2] = bf;
4789             flip = 2;
4790          } else { /* U[2] = 0 */
4791             fprintf(SUMA_STDERR, "Error %s: 0 direction vector.\n", FuncName);
4792             SUMA_RETURN (NULL);
4793          }
4794       }/*U[1] = 0; */
4795    }/*U[0] = 0; */
4796 
4797    if (LocalHead) fprintf (SUMA_STDERR, "%s: flip = %d\n", FuncName, flip);
4798 
4799    if (LocalHead) fprintf (SUMA_STDERR, "%s: U original: %f, %f, %f\n", FuncName, U[0], U[1], U[2]);
4800    U[1] /= U[0];
4801    U[2] /= U[0];
4802    U[0] = 1.0;
4803    if (LocalHead) fprintf (SUMA_STDERR, "%s: U normalized: %f, %f, %f\n", FuncName, U[0], U[1], U[2]);
4804 
4805    /* Now U is clean, calculate P2 */
4806    m = U[1];
4807    n = U[2];
4808 
4809    q = P1[1] - m*P1[0];
4810    p = P1[2] - n*P1[0];
4811 
4812    if (LocalHead) fprintf (SUMA_STDERR, "%s: m=%f n=%f, p=%f, q=%f\n", FuncName, m, n, p, q);
4813 
4814    /* Now find P2 */
4815    A = (1 + n*n + m*m);
4816    B = -2 * P1[0] + 2 * m * (q - P1[1]) + 2 * n * (p - P1[2]);
4817    C = P1[0]*P1[0] + (q - P1[1])*(q - P1[1]) + (p - P1[2])*(p - P1[2]) - d*d;
4818 
4819    D = B*B - 4*A*C;
4820 
4821    if (LocalHead) fprintf (SUMA_STDERR, "%s: A=%f B=%f, C=%f, D=%f\n", FuncName, A, B, C, D);
4822 
4823    if (D < 0) {
4824       fprintf(SUMA_STDERR, "Error %s: Negative Delta: %f.\n"
4825                            "Input values were: \n"
4826                            "U :[%f %f %f]\n"
4827                            "P1:[%f %f %f]\n"
4828                            "d :[%f]\n"
4829                            , FuncName, D, Uorig[0], Uorig[1], Uorig[2],
4830                            P1orig[0], P1orig[1], P1orig[2], d);
4831       SUMA_RETURN(NULL);
4832    }
4833 
4834    P2 = (float **)SUMA_allocate2D(2,3, sizeof(float));
4835    if (P2 == NULL) {
4836       fprintf(SUMA_STDERR, "Error %s: Could not allocate for 6 floats! What is this? What is the matter with you?!\n", FuncName);
4837       SUMA_RETURN (NULL);
4838    }
4839 
4840    P2[0][0] = (-B + sqrt(D)) / (2 *A);
4841    P2[1][0] = (-B - sqrt(D)) / (2 *A);
4842 
4843    P2[0][1] = m * P2[0][0] + q;
4844    P2[1][1] = m * P2[1][0] + q;
4845 
4846    P2[0][2] = n * P2[0][0] + p;
4847    P2[1][2] = n * P2[1][0] + p;
4848 
4849 
4850    /* if flipping was performed, undo it */
4851    if (flip == 1) {
4852     for (i=0; i < 2; ++i) {
4853        bf = P2[i][1];
4854        P2[i][1] = P2[i][0];
4855        P2[i][0] = bf;
4856       }
4857    } else if (flip == 2){
4858     for (i=0; i < 2; ++i) {
4859        bf = P2[i][2];
4860        P2[i][2] = P2[i][0];
4861        P2[i][0] = bf;
4862       }
4863    }
4864 
4865    for (i=0; i < 3; ++i) {
4866       P1[i] = P1orig[i];
4867       U[i] = Uorig[i];
4868    }
4869 
4870    if (LocalHead) {
4871       fprintf(SUMA_STDOUT,"%s: P1 = %f, %f, %f\n  ", \
4872        FuncName, P1[0], P1[1], P1[2]);
4873       fprintf(SUMA_STDOUT,"%s: P2 = %f, %f, %f\n    %f, %f, %f\n", \
4874        FuncName, P2[0][0], P2[0][1], P2[0][2], P2[1][0], P2[1][1], P2[1][2]);
4875       fprintf(SUMA_STDOUT,"%s: U = %f, %f, %f\n  ", \
4876        FuncName, U[0], U[1], U[2]);
4877    }
4878 
4879 
4880    /* make sure 1st point is along the same direction */
4881    Uorig[0] = P2[0][0] - P1[0]; /* use Uorig, not needed anymore */
4882    Uorig[1] = P2[0][1] - P1[1];
4883    Uorig[2] = P2[0][2] - P1[2];
4884 
4885    SUMA_DOTP_VEC(Uorig, U, bf, 3, float, float)
4886    if (LocalHead) fprintf(SUMA_STDOUT,"%s: Dot product = %f\n", FuncName, bf);
4887    if (bf < 0) {
4888       if (LocalHead) fprintf(SUMA_STDOUT,"%s: Flipping at end...\n", FuncName);
4889       for (i=0; i< 3; ++i) {
4890          bf = P2[0][i];
4891          P2[0][i] = P2[1][i]; P2[1][i] = bf;
4892       }
4893    }
4894 
4895    if (LocalHead) {
4896       fprintf(SUMA_STDOUT,"%s: P2 = %f, %f, %f\n    %f, %f, %f\n", \
4897        FuncName, P2[0][0], P2[0][1], P2[0][2], P2[1][0], P2[1][1], P2[1][2]);
4898    }
4899 SUMA_RETURN (P2);
4900 
4901 }/*SUMA_Point_At_Distance*/
SUMA_dPoint_At_Distance(double * U,double * P1,double d)4902 double **SUMA_dPoint_At_Distance(double *U, double *P1, double d)
4903 {/*SUMA_dPoint_At_Distance*/
4904    static char FuncName[]={"SUMA_dPoint_At_Distance"};
4905    double bf, **P2, P1orig[3], Uorig[3];
4906    double m, n, p, q, D, A, B, C, epsi = 0.000001;
4907    int flip, i;
4908    SUMA_Boolean LocalHead = NOPE;
4909 
4910    SUMA_ENTRY;
4911 
4912    SUMA_SL_Warn ("useless piece of junk, use SUMA_POINT_AT_DISTANCE instead!");
4913 
4914    if (d == 0) {
4915       fprintf(SUMA_STDERR,"Error %s: d is 0. Not good, Not good at all.\n", FuncName);
4916       SUMA_RETURN (NULL);
4917    }
4918 
4919    if (LocalHead) {
4920       fprintf (SUMA_STDOUT,"%s: U %f, %f, %f, P1 %f %f %f, d %f\n", FuncName,\
4921          U[0], U[1], U[2], P1[0], P1[1], P1[2], d);
4922    }
4923 
4924    /* store initial values */
4925    P1orig[0] = P1[0];
4926    P1orig[1] = P1[1];
4927    P1orig[2] = P1[2];
4928 
4929    Uorig[0] = U[0];
4930    Uorig[1] = U[1];
4931    Uorig[2] = U[2];
4932 
4933    /* normalize U such that U(0) = 1 */
4934    flip = 0;
4935    if (fabs(U[0]) < epsi) { /* must flip X with some other coordinate */
4936       if (fabs(U[1]) > epsi) {/*U[1] != 0; */
4937          U[0] = U[1]; U[1] = 0;
4938          bf = P1[0]; P1[0] = P1[1]; P1[1] = bf;
4939          flip = 1;
4940       } else {   /*U[1] = 0; */
4941          if (fabs(U[2]) > epsi) { /* U[2] != 0 */
4942             U[0] = U[2]; U[2] = 0;
4943             bf = P1[0]; P1[0] = P1[2]; P1[2] = bf;
4944             flip = 2;
4945          } else { /* U[2] = 0 */
4946             fprintf(SUMA_STDERR, "Error %s: 0 direction vector.\n", FuncName);
4947             SUMA_RETURN (NULL);
4948          }
4949       }/*U[1] = 0; */
4950    }/*U[0] = 0; */
4951 
4952    if (LocalHead) fprintf (SUMA_STDERR, "%s: flip = %d\n", FuncName, flip);
4953 
4954    if (LocalHead) fprintf (SUMA_STDERR, "%s: U original: %f, %f, %f\n", FuncName, U[0], U[1], U[2]);
4955    U[1] /= U[0];
4956    U[2] /= U[0];
4957    U[0] = 1.0;
4958    if (LocalHead) fprintf (SUMA_STDERR, "%s: U normalized: %f, %f, %f\n", FuncName, U[0], U[1], U[2]);
4959 
4960    /* Now U is clean, calculate P2 */
4961    m = U[1];
4962    n = U[2];
4963 
4964    q = P1[1] - m*P1[0];
4965    p = P1[2] - n*P1[0];
4966 
4967    if (LocalHead) fprintf (SUMA_STDERR, "%s: m=%f n=%f, p=%f, q=%f\n", FuncName, m, n, p, q);
4968 
4969    /* Now find P2 */
4970    A = (1 + n*n + m*m);
4971    B = -2 * P1[0] + 2 * m * (q - P1[1]) + 2 * n * (p - P1[2]);
4972    C = P1[0]*P1[0] + (q - P1[1])*(q - P1[1]) + (p - P1[2])*(p - P1[2]) - d*d;
4973 
4974    D = B*B - 4*A*C;
4975 
4976    if (LocalHead) fprintf (SUMA_STDERR, "%s: A=%f B=%f, C=%f, D=%f\n", FuncName, A, B, C, D);
4977 
4978    if (D < 0) {
4979       fprintf(SUMA_STDERR, "Error %s: Negative Delta: %f.\n"
4980                            "Input values were: \n"
4981                            "U :[%f %f %f]\n"
4982                            "P1:[%f %f %f]\n"
4983                            "d :[%f]\n"
4984                            , FuncName, D, Uorig[0], Uorig[1], Uorig[2],
4985                            P1orig[0], P1orig[1], P1orig[2], d);
4986       SUMA_RETURN(NULL);
4987    }
4988 
4989    P2 = (double **)SUMA_allocate2D(2,3, sizeof(double));
4990    if (P2 == NULL) {
4991       fprintf(SUMA_STDERR, "Error %s: Could not allocate for 6 floats! What is this? What is the matter with you?!\n", FuncName);
4992       SUMA_RETURN (NULL);
4993    }
4994 
4995    P2[0][0] = (-B + sqrt(D)) / (2 *A);
4996    P2[1][0] = (-B - sqrt(D)) / (2 *A);
4997 
4998    P2[0][1] = m * P2[0][0] + q;
4999    P2[1][1] = m * P2[1][0] + q;
5000 
5001    P2[0][2] = n * P2[0][0] + p;
5002    P2[1][2] = n * P2[1][0] + p;
5003 
5004 
5005    /* if flipping was performed, undo it */
5006    if (flip == 1) {
5007     for (i=0; i < 2; ++i) {
5008        bf = P2[i][1];
5009        P2[i][1] = P2[i][0];
5010        P2[i][0] = bf;
5011       }
5012    } else if (flip == 2){
5013     for (i=0; i < 2; ++i) {
5014        bf = P2[i][2];
5015        P2[i][2] = P2[i][0];
5016        P2[i][0] = bf;
5017       }
5018    }
5019 
5020    for (i=0; i < 3; ++i) {
5021       P1[i] = P1orig[i];
5022       U[i] = Uorig[i];
5023    }
5024 
5025    if (LocalHead) {
5026       fprintf(SUMA_STDOUT,"%s: P1 = %f, %f, %f\n  ", \
5027        FuncName, P1[0], P1[1], P1[2]);
5028       fprintf(SUMA_STDOUT,"%s: P2 = %f, %f, %f\n    %f, %f, %f\n", \
5029        FuncName, P2[0][0], P2[0][1], P2[0][2], P2[1][0], P2[1][1], P2[1][2]);
5030       fprintf(SUMA_STDOUT,"%s: U = %f, %f, %f\n  ", \
5031        FuncName, U[0], U[1], U[2]);
5032    }
5033 
5034 
5035    /* make sure 1st point is along the same direction */
5036    Uorig[0] = P2[0][0] - P1[0]; /* use Uorig, not needed anymore */
5037    Uorig[1] = P2[0][1] - P1[1];
5038    Uorig[2] = P2[0][2] - P1[2];
5039 
5040    SUMA_DOTP_VEC(Uorig, U, bf, 3, double, double)
5041    if (LocalHead) fprintf(SUMA_STDOUT,"%s: Dot product = %f\n", FuncName, bf);
5042    if (bf < 0) {
5043       if (LocalHead) fprintf(SUMA_STDOUT,"%s: Flipping at end...\n", FuncName);
5044       for (i=0; i< 3; ++i) {
5045          bf = P2[0][i];
5046          P2[0][i] = P2[1][i]; P2[1][i] = bf;
5047       }
5048    }
5049 
5050    if (LocalHead) {
5051       fprintf(SUMA_STDOUT,"%s: P2 = %f, %f, %f\n    %f, %f, %f\n", \
5052        FuncName, P2[0][0], P2[0][1], P2[0][2], P2[1][0], P2[1][1], P2[1][2]);
5053    }
5054 SUMA_RETURN (P2);
5055 
5056 }/*SUMA_dPoint_At_Distance*/
5057 
5058 /*!
5059 
5060 Function: SUMA_Point_To_Line_Distance
5061 Usage :
5062 Ret = SUMA_Point_To_Line_Distance (float *NodeList, int N_nodes, float *P1, float *P2, float *d2, float *d2min, int *i2min)
5063 
5064 Calculates the squared distance between the points in NodeList and the line formed by P1-P2
5065 
5066 Input paramters :
5067 \param NodeList (float *) N_nodes x 3 vector containing XYZ of N_nodes nodes
5068 \param N_nodes (int) Number of nodes in NodeList
5069 \param P1 (float *) 3x1 vector containing the XYZ of P1
5070 \param P2 (float *) 3x1 vector containing the XYZ of P2
5071 \param d2 (float *) N_nodes x 1 vector containing the squared distance of each node in NodeList to the line P1-P2
5072        d2 must be pointing to a pre-allocated space
5073 \param d2min (float *) pointer to the smallest squared distance
5074 \param i2min (int *) pointer to the index (into NodeList) of the node with the shortest distance
5075 
5076 The squared distance is returned to save on a square root operation which may not be necessary to compute for all nodes
5077 
5078 Returns :
5079 \return  Ret (SUMA_Boolean) YUP/NOPE for success/failure
5080 
5081 \sa labbook NIH-2, p 37
5082 
5083 */
SUMA_Point_To_Line_Distance(float * NodeList,int N_points,float * P1,float * P2,float * d2,float * d2min,int * i2min)5084 SUMA_Boolean SUMA_Point_To_Line_Distance (float *NodeList, int N_points, float *P1, float *P2, float *d2, float *d2min, int *i2min)
5085 {
5086    static char FuncName[]={"SUMA_Point_To_Line_Distance"};
5087    float U[3], Un, xn, yn, zn, dx, dy, dz;
5088    int i, id, ND;
5089 
5090    SUMA_ENTRY;
5091 
5092    ND = 3;
5093    if (N_points < 1) {
5094       fprintf(SUMA_STDERR,"Error %s: N_points is 0.\n",FuncName);
5095       SUMA_RETURN (NOPE);
5096    }
5097 
5098    SUMA_UNIT_VEC(P1, P2, U, Un);
5099    if (Un == 0) {
5100       fprintf(SUMA_STDERR,"Error %s: P1 and P2 are identical.\n",FuncName);
5101       SUMA_RETURN (NOPE);
5102    }
5103 
5104 
5105 
5106    /* calculate the distances and keep track of the minimum distance while you're at it */
5107 
5108    /*bad practice, only returned pointers are allocated for in functions */
5109    /*
5110    d2 = (float *)SUMA_calloc(N_points, sizeof(float)); */
5111 
5112    if (d2 == NULL) {
5113       fprintf(SUMA_STDERR,"Error %s: d2 not allocated for.\n",FuncName);
5114       SUMA_RETURN (NOPE);
5115    }
5116 
5117 
5118    /* do the first point to initialize d2min without an extra if statement */
5119     i = 0;
5120     xn = NodeList[0] - P1[0];
5121     yn = NodeList[1] - P1[1];
5122     zn = NodeList[2] - P1[2];
5123 
5124     dx = (U[1]*zn - yn*U[2]);
5125     dy = (U[0]*zn - xn*U[2]);
5126     dz = (U[0]*yn - xn*U[1]);
5127 
5128     d2[i] = dx*dx+dy*dy +dz*dz; /* save the sqrt for speed */
5129     *d2min = d2[i];
5130     *i2min = i;
5131     /* Now do the rest */
5132    for (i=1; i < N_points; ++i) {
5133       id = ND * i;
5134       xn = NodeList[id] - P1[0];
5135       yn = NodeList[id+1] - P1[1];
5136       zn = NodeList[id+2] - P1[2];
5137 
5138       dx = (U[1]*zn - yn*U[2]);
5139       dy = (U[0]*zn - xn*U[2]);
5140       dz = (U[0]*yn - xn*U[1]);
5141 
5142       d2[i] = dx*dx+dy*dy +dz*dz; /* save the sqrt for speed */
5143       if (d2[i] < *d2min) {
5144          *d2min = d2[i];
5145          *i2min = i;
5146       }
5147    }
5148    SUMA_RETURN (YUP);
5149 }
5150 
5151 /*!
5152 
5153 Function: SUMA_Point_To_Point_Distance
5154 Usage :
5155 Ret = SUMA_Point_To_Point_Distance (float *NodeList, int N_nodes, float *P1, float *d2, float *d2min, int *i2min)
5156 
5157 Calculates the squared distance between the points in NodeList and  P1-P2
5158 
5159 Input paramters :
5160 \param NodeList (float *) N_nodes x 3 vector containing XYZ of N_nodes nodes
5161 \param N_nodes (int) Number of nodes in NodeList
5162 \param P1 (float *) 3x1 vector containing the XYZ of P1
5163 \param d2 (float *) N_nodes x 1 vector containing the squared distance of each node in NodeList to P1
5164        d2 must be pointing to a pre-allocated space
5165 \param d2min (float *) pointer to the smallest squared distance
5166 \param i2min (int *) pointer to the index (into NodeList) of the node with the shortest distance
5167 
5168 The squared distance is returned to save on a square root operation which may not be necessary to compute for all nodes
5169 
5170 Returns :
5171 \return  Ret (SUMA_Boolean) YUP/NOPE for success/failure
5172 
5173 */
SUMA_Point_To_Point_Distance(float * NodeList,int N_points,float * P1,float * d2,float * d2min,int * i2min)5174 SUMA_Boolean SUMA_Point_To_Point_Distance (float *NodeList, int N_points, float *P1, float *d2, float *d2min, int *i2min)
5175 {
5176    static char FuncName[]={"SUMA_Point_To_Point_Distance"};
5177    float xn, yn, zn;
5178    int i, id, ND;
5179 
5180    SUMA_ENTRY;
5181 
5182    ND = 3;
5183    if (N_points < 1) {
5184       fprintf(SUMA_STDERR,"Error %s: N_points is 0.\n",FuncName);
5185       SUMA_RETURN (NOPE);
5186    }
5187 
5188 
5189    /* calculate the distances and keep track of the minimum distance while you're at it */
5190 
5191    if (d2 == NULL) {
5192       fprintf(SUMA_STDERR,"Error %s: d2 not allocated for.\n",FuncName);
5193       SUMA_RETURN (NOPE);
5194    }
5195 
5196 
5197    /* do the first point to initialize d2min without an extra if statement */
5198     i = 0;
5199     xn = NodeList[0] - P1[0];
5200     yn = NodeList[1] - P1[1];
5201     zn = NodeList[2] - P1[2];
5202 
5203     d2[i] = xn*xn + yn*yn + zn*zn; /* save the sqrt for speed */
5204     *d2min = d2[i];
5205     *i2min = i;
5206     /* Now do the rest */
5207    for (i=1; i < N_points; ++i) {
5208       id = ND * i;
5209       xn = NodeList[id] - P1[0];
5210       yn = NodeList[id+1] - P1[1];
5211       zn = NodeList[id+2] - P1[2];
5212 
5213 
5214        d2[i] = xn*xn + yn*yn + zn*zn; /* save the sqrt for speed */
5215       if (d2[i] < *d2min) {
5216          *d2min = d2[i];
5217          *i2min = i;
5218       }
5219    }
5220    SUMA_RETURN (YUP);
5221 }
5222 
5223 #define SUMA_DOT3(a,b) (a[0]*b[0]+a[1]*b[1]+a[2]*b[2])
5224 /*!
5225    Find the shortest distance from each point in 3D space to
5226    a triangle.
5227    Based on algorithm by David Eberly per document:
5228    http://www.geometrictools.com/Documentation/DistancePoint3Triangle3.pdf
5229 
5230    \param Points (float *) N_points x 3 vector of coordinates
5231    \param N_points (int) number of points in Points
5232    \param P0, P1, P2 (float *) XYZ coords of each vertex in the triangle
5233    \param itri (int) an integer representing the triangle's ID
5234    \param distp (float **) pointer to array which will contain the (squared if city==0)
5235                            distance from each point to the triangle <P0, P1, P2>
5236                 if (*distp == NULL) it is allocated for and initialized and
5237                                     *distp[i] contains SD, the shortest distance
5238                                     of point i to the triangle itri.
5239                else *distp[i] = SD if (SD < *distp[i])
5240                                     otherwise leave distp[i] alone
5241    \param closestp (int **) pointer to array wich will contain for each point i
5242                                     the index of the triangle itri which
5243                                     resulted in the value of *distp[i]
5244    \param city (byte) 1 == City block distance, 0 == Euclidian distance squared
5245    \return NOPE on FAILURE, YUP on SUCCESS.
5246    This function is meant to be called repeatedly for each new triangle.
5247    See SUMA_Shortest_Point_To_Triangles_Distance()
5248 */
SUMA_Point_To_Triangle_Distance(float * Points,int N_points,float * P0,float * P1,float * P2,int itri,float * tnorm,float ** distp,int ** closestp,byte ** sgnp,byte city)5249 int SUMA_Point_To_Triangle_Distance (float *Points, int N_points,
5250                                      float *P0, float *P1, float *P2, int itri,
5251                                      float *tnorm,
5252                                      float **distp, int **closestp, byte **sgnp,
5253                                      byte city)
5254 {
5255    static char FuncName[]={"SUMA_Point_To_Triangle_Distance"};
5256    float *dist=NULL, *P=NULL;
5257    double E0[3], E1[3], a, b, c, d, e, f, B[3], BmP[3], nd,
5258          s, t, det, idet, numer, denom, I[3], sd, tmp0, tmp1;
5259    int in=0, reg, in3, *closest=NULL;
5260    byte *sgn=NULL;
5261    static int icall;
5262    SUMA_Boolean LocalHead = NOPE;
5263 
5264    SUMA_ENTRY;
5265 
5266    if (*distp == NULL) {
5267       dist = (float *)SUMA_calloc(N_points, sizeof(float));
5268       *distp = dist;
5269       for (in=0; in<N_points; ++in) dist[in]=-1.0;
5270       SUMA_LHv("icall %d, init done, itri=%d, %d points, dist=%p\n",
5271                      icall, itri, N_points, dist);
5272    } else {
5273       dist = *distp;
5274       if (icall < 3) SUMA_LHv("icall %d, reusing, itri=%d, dist=%p\n",
5275                               icall, itri, dist);
5276    }
5277    if (closestp) {
5278       if (*closestp == NULL) {
5279          closest = (int *)SUMA_calloc(N_points, sizeof(int));
5280          *closestp = closest;
5281          for (in=0; in<N_points; ++in) closest[in]=-1;
5282          SUMA_LHv("icall %d, init closest done\n", icall);
5283       } else {
5284          if (icall < 3) SUMA_LHv("icall %d, reusing closest\n", icall);
5285          closest = *closestp;
5286       }
5287    }
5288    if (sgnp) {
5289       if (*sgnp == NULL) {
5290          sgn = (byte *)SUMA_calloc(N_points, sizeof(byte));
5291          *sgnp = sgn;
5292       } else {
5293          sgn = *sgnp;
5294       }
5295    }
5296 
5297    E0[0] = P1[0]-P0[0]; E0[1] = P1[1]-P0[1]; E0[2] = P1[2]-P0[2];
5298    E1[0] = P2[0]-P0[0]; E1[1] = P2[1]-P0[1]; E1[2] = P2[2]-P0[2];
5299    B[0] = P0[0]; B[1] = P0[1]; B[2] = P0[2];
5300 
5301    a = SUMA_DOT3(E0, E0); b = SUMA_DOT3(E0, E1); c = SUMA_DOT3(E1, E1);
5302    for (in=0; in < N_points; ++in) {
5303       in3 = 3*in; P = Points+in3;
5304       BmP[0] = B[0]-P[0]; BmP[1] = B[1]-P[1]; BmP[2] = B[2]-P[2];
5305       d = SUMA_DOT3(E0, BmP);
5306       e = SUMA_DOT3(E1, BmP);
5307       f = SUMA_DOT3(BmP, BmP);
5308       det = a*c-b*b; s = b*e-c*d; t=b*d-a*e;
5309       reg = -1;
5310       if (s+t <= det) {
5311          if (s < 0) {
5312             if (t < 0) reg = 4; else reg = 3;
5313          } else if (t < 0) {
5314             reg = 5;
5315          } else {
5316             reg = 0;
5317          }
5318       } else {
5319          if (s < 0) reg = 2;
5320          else if (t < 0) reg = 6;
5321          else reg = 1;
5322       }
5323       switch (reg) {
5324          case 0:
5325             idet = 1.0/det;
5326             s *= idet;
5327             t *= idet;
5328             break;
5329          case 1:
5330             numer = c+e-b-d;
5331             if (numer <= 0) {
5332                s = 0;
5333             } else {
5334                denom = a-2*b+c;
5335                s = ( numer > denom ? 1 : numer/denom);
5336             }
5337             t = 1-s;
5338             break;
5339          case 3:
5340          case 5:
5341             s = 0;
5342             t = ( e >= 0 ? 0 : ( -e >= c ? 1: -e/c ) );
5343             break;
5344          case 2:
5345          case 4:
5346          case 6:
5347             tmp0 = b+d;
5348             tmp1 = c+e;
5349             if (tmp1 > tmp0) {
5350                numer = tmp1 - tmp0;
5351                denom = a- 2*b + c;
5352                s = (numer >= denom ? 1:numer/denom);
5353                t = 1-s;
5354             } else {
5355                s = 0;
5356                t = (tmp1 <= 0 ? 1 : ( e >= 0 ? 0 : -e/c));
5357             }
5358             break;
5359          default:
5360             SUMA_S_Errv("Reg %d not good\n", reg);
5361             RETURN(NOPE);
5362       }
5363       SUMA_FROM_BARYCENTRIC(s, t, P0, P1, P2, I);
5364       I[0] = I[0]-P[0]; I[1] = I[1]-P[1]; I[2] = I[2]-P[2];
5365       if (city) {
5366          sd = SUMA_ABS(I[0])+SUMA_ABS(I[1])+SUMA_ABS(I[2]);
5367       } else {
5368          sd = I[0]*I[0]+I[1]*I[1]+I[2]*I[2];
5369       }
5370       if (dist[in] < 0) {
5371          dist[in] = (float)sd;
5372          if (closest) closest[in] = itri;
5373          if (tnorm && sgn) {
5374             nd = SUMA_DOT3(I,tnorm);
5375             if (SUMA_SIGN(nd) <0) sgn[in] = 1;
5376             else sgn[in] = 2;
5377          }
5378       } else if (dist[in] > (float)sd) {
5379          dist[in] = (float)sd;
5380          if (closest) closest[in] = itri;
5381          if (tnorm && sgn) {
5382             nd = SUMA_DOT3(I,tnorm);
5383             if (SUMA_SIGN(nd) <0) sgn[in] = 1;
5384             else sgn[in] = 2;
5385          }
5386       }
5387       SUMA_LHv("reg = %d, s=%f, t=%f, P=[%f %f %f], "
5388                "I=[%f %f %f] dist2[%d]=%f, sign=%d\n",
5389                reg, s, t, P[0], P[1], P[2],
5390                I[0], I[1], I[2], in, dist[in],
5391                (sgn && sgn[in]==1) ? -1:1);
5392    } /* for each point */
5393    ++icall;
5394    SUMA_RETURN(YUP);
5395 }
5396 
Bad_Optimizer_Bad_Bad()5397 void Bad_Optimizer_Bad_Bad() {
5398    static int icall=0;/* Need to do something stupid, else I get crash on OSX*/
5399    if (!icall) {
5400       fprintf(stderr,"\n");
5401       ++icall;
5402    }
5403    return;
5404 }
5405 
5406 /* Square of distance is computed, if city == 0 */
SUMA_Shortest_Point_To_Triangles_Distance(float * Points,int N_points,float * NodeList,int * FaceSetList,int N_FaceSet,float * FaceNormList,float ** distp,int ** closestp,byte ** sgnp,byte city)5407 SUMA_Boolean SUMA_Shortest_Point_To_Triangles_Distance(
5408          float *Points, int N_points,
5409          float *NodeList, int *FaceSetList, int N_FaceSet,
5410          float *FaceNormList,
5411          float **distp, int **closestp, byte **sgnp,
5412          byte city ) {
5413    static char FuncName[]={"SUMA_Shortest_Point_To_Triangles_Distance"};
5414    float  *P0, *P1, *P2;
5415    int i=0;
5416    SUMA_Boolean LocalHead = NOPE;
5417 
5418    SUMA_ENTRY;
5419 
5420    for (i=0; i<N_FaceSet; ++i) {
5421       P0 = NodeList + 3*FaceSetList[3*i  ];
5422       P1 = NodeList + 3*FaceSetList[3*i+1];
5423       P2 = NodeList + 3*FaceSetList[3*i+2];
5424       Bad_Optimizer_Bad_Bad();
5425       SUMA_LHv("Tri %d\n"
5426                "[%f %f %f]\n"
5427                "[%f %f %f]\n"
5428                "[%f %f %f]\n"
5429                , i,
5430                P0[0], P0[1], P0[2],
5431                P1[0], P1[1], P1[2],
5432                P2[0], P2[1], P2[2]);
5433       if (!SUMA_Point_To_Triangle_Distance(Points, N_points,
5434                                            P0, P1, P2, i,
5435                                            FaceNormList+3*i,
5436                                            distp, closestp, sgnp,
5437                                            city)) {
5438          SUMA_S_Errv("Failed at triangle %d\n", i);
5439          SUMA_RETURN(NOPE);
5440       }
5441    }
5442    SUMA_RETURN(YUP);
5443 }
5444 
5445 
5446 /*! Sorting Functions */
5447 #define SUMA_Z_QSORT_structs
5448 
5449 /* DO not add debugging in the sorting functions since that might slow them down */
5450 
5451    typedef struct {
5452       float x;
5453       int Index;
5454    } SUMA_Z_QSORT_FLOAT;
5455 
5456    typedef struct {
5457       double x;
5458       int Index;
5459    } SUMA_Z_QSORT_DOUBLE;
5460 
5461    typedef struct {
5462       int x;
5463       int Index;
5464    } SUMA_Z_QSORT_INT;
5465 
compare_SUMA_Z_QSORT_FLOAT(SUMA_Z_QSORT_FLOAT * a,SUMA_Z_QSORT_FLOAT * b)5466 int compare_SUMA_Z_QSORT_FLOAT (SUMA_Z_QSORT_FLOAT *a, SUMA_Z_QSORT_FLOAT *b )
5467    {
5468       if (a->x < b->x)
5469          return (-1);
5470       else if (a->x == b->x)
5471          return (0);
5472       else if (a->x > b->x)
5473          return (1);
5474       /* this will never be reached but it will shut the compiler up */
5475       return (0);
5476    }
5477 
compare_SUMA_Z_QSORT_DOUBLE(SUMA_Z_QSORT_DOUBLE * a,SUMA_Z_QSORT_DOUBLE * b)5478 int compare_SUMA_Z_QSORT_DOUBLE (SUMA_Z_QSORT_DOUBLE *a, SUMA_Z_QSORT_DOUBLE *b )
5479    {
5480       if (a->x < b->x)
5481          return (-1);
5482       else if (a->x == b->x)
5483          return (0);
5484       else if (a->x > b->x)
5485          return (1);
5486       /* this will never be reached but it will shut the compiler up */
5487       return (0);
5488    }
5489 
5490 
compare_SUMA_Z_QSORT_INT(SUMA_Z_QSORT_INT * a,SUMA_Z_QSORT_INT * b)5491 int compare_SUMA_Z_QSORT_INT (SUMA_Z_QSORT_INT *a, SUMA_Z_QSORT_INT *b )
5492    {
5493       if (a->x < b->x)
5494          return (-1);
5495       else if (a->x == b->x)
5496          return (0);
5497       else if (a->x > b->x)
5498          return (1);
5499       /* this will never be reached but it will shut the compiler up */
5500       return (0);
5501    }
5502 
5503 
SUMA_compare_int(int * a,int * b)5504 int SUMA_compare_int (int *a, int *b )
5505 {/*SUMA_compare_int*/
5506     if (*a < *b)
5507       return (-1);
5508    else if (*a == *b)
5509       return (0);
5510    else
5511       return (1);
5512 
5513 }/*SUMA_compare_int*/
5514 
SUMA_compare_float(float * a,float * b)5515 int SUMA_compare_float (float *a, float *b )
5516 {/*SUMA_compare_float*/
5517     if (*a < *b)
5518       return (-1);
5519    else if (*a == *b)
5520       return (0);
5521    else
5522       return (1);
5523 
5524 }/*SUMA_compare_float*/
5525 
SUMA_compare_double(double * a,double * b)5526 int SUMA_compare_double (double *a, double *b )
5527 {/*SUMA_compare_double*/
5528     if (*a < *b)
5529       return (-1);
5530    else if (*a == *b)
5531       return (0);
5532    else
5533       return (1);
5534 
5535 }
5536 /*!**
5537 
5538 File : from ~/Programs/C/Z/Zlib/code/SUMA_z_qsort.c
5539 Author : Ziad Saad
5540 Date : Fri Nov 20 15:30:55 CST 1998
5541 
5542 Purpose :
5543    A sorting function that uses C library's qsort and returns an index table
5544    with it. So, if you're sorting vector x, you'll get y (y is STORED IN x, make a copy of x
5545    before calling the function if you want to preserve the unsorted version of x), a sorted version of
5546    x, and I such that x(I) = y;
5547 
5548 
5549 Usage :
5550    I = SUMA_z_qsort ( x , nx  );
5551    I = SUMA_z_dqsort ( x , nx );
5552 
5553 Input paramters :
5554    x (*float) vector of  floats, sorted array is returned in x
5555    nx (int) number of elements in x
5556 
5557    If you are sorting integers, use SUMA_z_dqsort where x is an (int *)
5558 
5559 
5560 Returns :
5561    I (int *) [nx x 1] vector containing the index table
5562    x, of course, is sorted
5563 
5564 
5565 Support :
5566 
5567 
5568 
5569 Side effects :
5570 
5571 
5572 
5573 ***/
SUMA_z_qsort(float * x,int nx)5574 int *SUMA_z_qsort (float *x , int nx )
5575 {/*SUMA_z_qsort*/
5576    static char FuncName[]={"SUMA_z_qsort"};
5577    int *I, k;
5578    SUMA_Z_QSORT_FLOAT *Z_Q_fStrct;
5579 
5580    SUMA_ENTRY;
5581 
5582    /* allocate for the structure */
5583    Z_Q_fStrct = (SUMA_Z_QSORT_FLOAT *)
5584                SUMA_calloc(nx, sizeof (SUMA_Z_QSORT_FLOAT));
5585    I = (int *) SUMA_calloc (nx, sizeof(int));
5586 
5587    if (!Z_Q_fStrct || !I)
5588       {
5589          fprintf(SUMA_STDERR,"Error %s: Allocation problem.\n",FuncName);
5590          SUMA_RETURN (NULL);
5591       }
5592 
5593    for (k=0; k < nx; ++k) /* copy the data into a structure */
5594       {
5595          Z_Q_fStrct[k].x = x[k];
5596          Z_Q_fStrct[k].Index = k;
5597       }
5598 
5599    /* sort the structure by it's field value */
5600    qsort(Z_Q_fStrct, nx, sizeof(SUMA_Z_QSORT_FLOAT),
5601          (int(*) (const void *, const void *)) compare_SUMA_Z_QSORT_FLOAT);
5602 
5603    /* recover the index table */
5604    for (k=0; k < nx; ++k) /* copy the data into a structure */
5605       {
5606          x[k] = Z_Q_fStrct[k].x;
5607          I[k] = Z_Q_fStrct[k].Index;
5608       }
5609 
5610    /* free the structure */
5611    SUMA_free(Z_Q_fStrct);
5612 
5613    /* return */
5614    SUMA_RETURN (I);
5615 
5616 
5617 }/*SUMA_z_qsort*/
5618 
SUMA_z_doubqsort(double * x,int nx)5619 int *SUMA_z_doubqsort (double *x , int nx )
5620 {/*SUMA_z_qsort*/
5621    static char FuncName[]={"SUMA_z_doubqsort"};
5622    int *I, k;
5623    SUMA_Z_QSORT_DOUBLE *Z_Q_doubStrct;
5624 
5625    SUMA_ENTRY;
5626 
5627    /* allocate for the structure */
5628    Z_Q_doubStrct = (SUMA_Z_QSORT_DOUBLE *) SUMA_calloc(nx, sizeof (SUMA_Z_QSORT_DOUBLE));
5629    I = (int *) SUMA_calloc (nx, sizeof(int));
5630 
5631    if (!Z_Q_doubStrct || !I)
5632       {
5633          fprintf(SUMA_STDERR,"Error %s: Allocation problem.\n",FuncName);
5634          SUMA_RETURN (NULL);
5635       }
5636 
5637    for (k=0; k < nx; ++k) /* copy the data into a structure */
5638       {
5639          Z_Q_doubStrct[k].x = x[k];
5640          Z_Q_doubStrct[k].Index = k;
5641       }
5642 
5643    /* sort the structure by it's field value */
5644    qsort(Z_Q_doubStrct, nx, sizeof(SUMA_Z_QSORT_DOUBLE), (int(*) (const void *, const void *)) compare_SUMA_Z_QSORT_DOUBLE);
5645 
5646    /* recover the index table */
5647    for (k=0; k < nx; ++k) /* copy the data into a structure */
5648       {
5649          x[k] = Z_Q_doubStrct[k].x;
5650          I[k] = Z_Q_doubStrct[k].Index;
5651       }
5652 
5653    /* free the structure */
5654    SUMA_free(Z_Q_doubStrct);
5655 
5656    /* return */
5657    SUMA_RETURN (I);
5658 
5659 
5660 }/*SUMA_z_doubqsort*/
5661 
SUMA_z_dqsort(int * x,int nx)5662 int *SUMA_z_dqsort (int *x , int nx )
5663 {/*SUMA_z_dqsort*/
5664    static char FuncName[]={"SUMA_z_dqsort"};
5665    int *I, k;
5666    SUMA_Z_QSORT_INT *Z_Q_iStrct;
5667 
5668    SUMA_ENTRY;
5669 
5670    /* allocate for the structure
5671  */
5672    Z_Q_iStrct = (SUMA_Z_QSORT_INT *) SUMA_calloc(nx, sizeof (SUMA_Z_QSORT_INT));
5673    I = (int *) SUMA_calloc (nx,sizeof(int));
5674 
5675    if (!Z_Q_iStrct || !I)
5676       {
5677          fprintf(SUMA_STDERR,"Error %s: Allocation problem.\n",FuncName);
5678          SUMA_RETURN (NULL);
5679       }
5680 
5681    for (k=0; k < nx; ++k) /* copy the data into a structure */
5682       {
5683          Z_Q_iStrct[k].x = x[k];
5684          Z_Q_iStrct[k].Index = k;
5685       }
5686 
5687    /* sort the structure by it's field value */
5688    qsort(Z_Q_iStrct, nx, sizeof(SUMA_Z_QSORT_INT), (int(*) (const void *, const void *)) compare_SUMA_Z_QSORT_INT);
5689 
5690    /* recover the index table */
5691    for (k=0; k < nx; ++k) /* copy the data into a structure */
5692       {
5693          x[k] = Z_Q_iStrct[k].x;
5694          I[k] = Z_Q_iStrct[k].Index;
5695       }
5696 
5697    /* free the structure */
5698    SUMA_free(Z_Q_iStrct);
5699 
5700    /* return */
5701    SUMA_RETURN (I);
5702 
5703 
5704 }/*SUMA_z_dqsort*/
5705 
5706 /*!
5707    same as SUMA_z_dqsort but does not use SUMA_calloc or SUMA_free functions.
5708 */
SUMA_z_dqsort_nsc(int * x,int nx)5709 int *SUMA_z_dqsort_nsc (int *x , int nx )
5710 {/*SUMA_z_dqsort_nsc*/
5711    static char FuncName[]={"SUMA_z_dqsort_nsc"};
5712    int *I, k;
5713    SUMA_Z_QSORT_INT *Z_Q_iStrct;
5714 
5715    SUMA_ENTRY;
5716 
5717    /* allocate for the structure
5718  */
5719    Z_Q_iStrct = (SUMA_Z_QSORT_INT *) calloc(nx, sizeof (SUMA_Z_QSORT_INT));
5720    I = (int *) calloc (nx,sizeof(int));
5721 
5722    if (!Z_Q_iStrct || !I)
5723       {
5724          fprintf(SUMA_STDERR,"Error %s: Allocation problem.\n",FuncName);
5725          SUMA_RETURN (NULL);
5726       }
5727 
5728    for (k=0; k < nx; ++k) /* copy the data into a structure */
5729       {
5730          Z_Q_iStrct[k].x = x[k];
5731          Z_Q_iStrct[k].Index = k;
5732       }
5733 
5734    /* sort the structure by it's field value */
5735    qsort(Z_Q_iStrct, nx, sizeof(SUMA_Z_QSORT_INT), (int(*) (const void *, const void *)) compare_SUMA_Z_QSORT_INT);
5736 
5737    /* recover the index table */
5738    for (k=0; k < nx; ++k) /* copy the data into a structure */
5739       {
5740          x[k] = Z_Q_iStrct[k].x;
5741          I[k] = Z_Q_iStrct[k].Index;
5742       }
5743 
5744    /* free the structure */
5745    free(Z_Q_iStrct);
5746 
5747    /* return */
5748    SUMA_RETURN (I);
5749 
5750 
5751 }/*SUMA_z_dqsort_nsc*/
5752 
5753 
5754 /*--------------------- Matrix Sorting functions Begin ------------------------*/
5755 
5756 typedef struct {
5757       float *x;
5758       int ncol;
5759       int Index;
5760    } SUMA_QSORTROW_FLOAT;
5761 
5762 /* DO not add debugging in the sorting functions since that might slow them down */
5763 
compare_SUMA_QSORTROW_FLOAT(SUMA_QSORTROW_FLOAT * a,SUMA_QSORTROW_FLOAT * b)5764 int compare_SUMA_QSORTROW_FLOAT (SUMA_QSORTROW_FLOAT *a, SUMA_QSORTROW_FLOAT *b)
5765    {
5766       int k;
5767 
5768       for (k=0; k < a->ncol ; ++k)
5769          {
5770             if (a->x[k] < b->x[k])
5771                return (-1);
5772             else if (a->x[k] > b->x[k])
5773                return (1);
5774          }
5775       return (0); /* They're similar */
5776    }
5777 
5778 
5779 /*!
5780 
5781 Purpose :
5782    Sort a matrix of floats by rows
5783    Imagine that each row is a word, the function sorts the rows as if in a dictionary list
5784 
5785 
5786 Usage :
5787       int * SUMA_fqsortrow (float **X , int nr, int nc )
5788 
5789    \param X (float ** ) matrix to sort by rows (if you need to preserve the original version of X you need to make a copy of it before calling the function )
5790    \param nr (int)  number of rows
5791    \param nc (int)  number of columns
5792 
5793    \ret ndx (int *) index table, such that Xsorted = X(ndx,:);
5794 
5795 
5796 
5797    \sa  SUMA_dqsortrow
5798 */
SUMA_fqsortrow(float ** X,int nr,int nc)5799 int * SUMA_fqsortrow (float **X , int nr, int nc  )
5800 {/*SUMA_fqsortrow*/
5801    static char FuncName[]={"SUMA_fqsortrow"};
5802    int k, *I;
5803    SUMA_QSORTROW_FLOAT *Z_Q_fStrct;
5804 
5805 
5806    SUMA_ENTRY;
5807 
5808    /* allocate for the structure */
5809    Z_Q_fStrct = (SUMA_QSORTROW_FLOAT *)
5810                   SUMA_calloc(nr, sizeof (SUMA_QSORTROW_FLOAT));
5811    I = (int *) SUMA_calloc (nr,sizeof(int));
5812 
5813    if (!Z_Q_fStrct || !I)
5814       {
5815       fprintf(SUMA_STDERR,
5816               "Error %s: Failed to allocate for Z_Q_fStrct || I\n", FuncName);
5817       SUMA_RETURN (NULL);
5818       }
5819 
5820    for (k=0; k < nr; ++k) /* copy the data into a structure */
5821       {
5822          Z_Q_fStrct[k].x = X[k];
5823          Z_Q_fStrct[k].ncol = nc;
5824          Z_Q_fStrct[k].Index = k;
5825       }
5826 
5827    /* sort the structure by comparing the rows in X */
5828    qsort(Z_Q_fStrct, nr, sizeof(SUMA_QSORTROW_FLOAT),
5829          (int(*) (const void *, const void *)) compare_SUMA_QSORTROW_FLOAT);
5830 
5831    /* recover the index table */
5832    for (k=0; k < nr; ++k)
5833       {
5834          X[k] = Z_Q_fStrct[k].x;
5835          I[k] = Z_Q_fStrct[k].Index;
5836       }
5837 
5838    /* free the structure */
5839    SUMA_free(Z_Q_fStrct);
5840 
5841    /* return */
5842    SUMA_RETURN (I);
5843 
5844 
5845 }/*SUMA_fqsortrow*/
5846 
5847    typedef struct {
5848       int *x;
5849       int ncol;
5850       int Index;
5851    } SUMA_QSORTROW_INT;
5852 
5853 /* CODE */
5854 
compare_SUMA_QSORTROW_INT(SUMA_QSORTROW_INT * a,SUMA_QSORTROW_INT * b)5855 int compare_SUMA_QSORTROW_INT (SUMA_QSORTROW_INT *a, SUMA_QSORTROW_INT *b)
5856    {
5857       int k;
5858 
5859       for (k=0; k < a->ncol ; ++k)
5860          {
5861             if (a->x[k] < b->x[k])
5862                return (-1);
5863             else if (a->x[k] > b->x[k])
5864                return (1);
5865          }
5866       return (0); /* They're similar */
5867    }
5868 
5869 
5870 /*!
5871 
5872 Purpose :
5873    Sort a matrix of ints by rows
5874    Imagine that each row is a word, the function sorts the rows as if in a dictionary list
5875 
5876 
5877 Usage :
5878     int * SUMA_dqsortrow (int **X, int nr, int nc)
5879 
5880    \param X (int ** ) matrix to sort by rows (if you need to preserve the original version of X you need to make a copy of it before calling the function )
5881    \param nr (int)  number of rows
5882    \param nc (int)  number of columns
5883 
5884    \ret ndx (int *) index table, such that Xsorted = X(ndx,:);
5885 
5886 
5887 
5888    \sa  SUMA_fqsortrow
5889 */
5890 
SUMA_dqsortrow(int ** X,int nr,int nc)5891 int * SUMA_dqsortrow (int **X , int nr, int nc  )
5892 {/*SUMA_dqsortrow*/
5893    static char FuncName[]={"SUMA_dqsortrow"};
5894    int k,  *I;
5895    SUMA_QSORTROW_INT *Z_Q_dStrct;
5896 
5897    SUMA_ENTRY;
5898 
5899    /* allocate for the structure */
5900    Z_Q_dStrct = (SUMA_QSORTROW_INT *) SUMA_calloc(nr, sizeof (SUMA_QSORTROW_INT));
5901    I = (int *) SUMA_calloc (nr,sizeof(int));
5902 
5903    if (!Z_Q_dStrct || !I)
5904       {
5905       fprintf(SUMA_STDERR,"Error %s: Failed to allocate for Z_Q_dStrct || I\n", FuncName);
5906       SUMA_RETURN (NULL);
5907       }
5908 
5909    for (k=0; k < nr; ++k) /* copy the data into a structure */
5910       {
5911          Z_Q_dStrct[k].x = X[k];
5912          Z_Q_dStrct[k].ncol = nc;
5913          Z_Q_dStrct[k].Index = k;
5914       }
5915 
5916    /* sort the structure by comparing the rows in X */
5917    qsort(Z_Q_dStrct, nr, sizeof(SUMA_QSORTROW_INT), (int(*) (const void *, const void *)) compare_SUMA_QSORTROW_INT);
5918 
5919    /* recover the index table */
5920    for (k=0; k < nr; ++k)
5921       {
5922          X[k] = Z_Q_dStrct[k].x;
5923          I[k] = Z_Q_dStrct[k].Index;
5924       }
5925 
5926    /* free the structure */
5927    SUMA_free(Z_Q_dStrct);
5928 
5929    /* return */
5930    SUMA_RETURN (I);
5931 
5932 
5933 }/*SUMA_dqsortrow*/
5934 
5935 
5936 /*--------------------- Matrix Sorting functions END ------------------------*/
5937 static int VoxIntersDbg = 0;
SUMA_Set_VoxIntersDbg(int v)5938 void SUMA_Set_VoxIntersDbg(int v)
5939 {
5940    VoxIntersDbg = v;
5941    return;
5942 }
5943 
5944 /*!
5945    \brief Returns the coordinates of a voxel corner
5946    \param center (float *): center of voxel
5947    \param dxyz (float *): dimensions of voxel
5948    \param en (int): corner of voxel (0 -- 7)
5949    \param P0 (float *): corner coords (set by macro)
5950    See labbook NIH-6 pp 201 for a recent diagram of edge and corner numbers
5951 */
5952 #define SUMA_CORNER_OF_VOXEL(center, dxyz, cn, P){\
5953    switch(cn) {   \
5954       case 0:  \
5955          P[0] =  dxyz[0]; P[1] = -dxyz[1]; P[2] =   dxyz[2];   \
5956          break;   \
5957       case 1:  \
5958          P[0] =  dxyz[0]; P[1] = -dxyz[1]; P[2] =  -dxyz[2];   \
5959          break;   \
5960       case 2:  \
5961          P[0] =  dxyz[0]; P[1] =  dxyz[1]; P[2] =  -dxyz[2];   \
5962          break;  \
5963       case 3:  \
5964          P[0] =  dxyz[0]; P[1] =  dxyz[1]; P[2] =   dxyz[2];   \
5965          break;   \
5966       case 4:  \
5967          P[0] = -dxyz[0]; P[1] = -dxyz[1]; P[2] =   dxyz[2];   \
5968          break;   \
5969       case 5:  \
5970          P[0] = -dxyz[0]; P[1] = -dxyz[1]; P[2] =  -dxyz[2];   \
5971          break;   \
5972       case 6:  \
5973          P[0] = -dxyz[0]; P[1] =  dxyz[1]; P[2] =  -dxyz[2];   \
5974          break;  \
5975       case 7:  \
5976          P[0] = -dxyz[0]; P[1] =  dxyz[1]; P[2] =   dxyz[2];   \
5977          break;  \
5978       default: \
5979          P[0] = 0; P[1] = 0; P[2] = 0; \
5980          SUMA_SL_Err("Bad corner index. Returning Center of voxel.");\
5981    }  \
5982    /* add center coord */  \
5983    P[0] = center[0] + 0.5 * P[0];   \
5984    P[1] = center[1] + 0.5 * P[1];   \
5985    P[2] = center[2] + 0.5 * P[2];   \
5986 }
5987 /*!
5988    \brief Returns the coordinates of the two points that form an edge of a voxel
5989    \param center (float *): center of voxel
5990    \param dxyz (float *): dimensions of voxel
5991    \param en (int): edge of voxel (0 -- 11)
5992    \param P0 (float *): first point forming edge (set by macro)
5993    \param P1 (float *): second point forming edge (set by macro)
5994    See labbook NIH-6 pp 201 for a recent diagram of edge and corner numbers
5995 */
5996 #define SUMA_EDGE_OF_VOXEL(center, dxyz, en, P0, P1){ \
5997    switch(en) {   \
5998       case 0:  \
5999          SUMA_CORNER_OF_VOXEL(center, dxyz, 0, P0);   \
6000          SUMA_CORNER_OF_VOXEL(center, dxyz, 1, P1);   \
6001          break;   \
6002       case 1:  \
6003          SUMA_CORNER_OF_VOXEL(center, dxyz, 0, P0);   \
6004          SUMA_CORNER_OF_VOXEL(center, dxyz, 3, P1);   \
6005          break;   \
6006       case 2:  \
6007          SUMA_CORNER_OF_VOXEL(center, dxyz, 0, P0);   \
6008          SUMA_CORNER_OF_VOXEL(center, dxyz, 4, P1);   \
6009          break;   \
6010       case 3:  \
6011          SUMA_CORNER_OF_VOXEL(center, dxyz, 1, P0);   \
6012          SUMA_CORNER_OF_VOXEL(center, dxyz, 5, P1);   \
6013          break;   \
6014       case 4:  \
6015          SUMA_CORNER_OF_VOXEL(center, dxyz, 1, P0);   \
6016          SUMA_CORNER_OF_VOXEL(center, dxyz, 2, P1);   \
6017          break;   \
6018       case 5:  \
6019          SUMA_CORNER_OF_VOXEL(center, dxyz, 2, P0);   \
6020          SUMA_CORNER_OF_VOXEL(center, dxyz, 6, P1);   \
6021          break;   \
6022       case 6:  \
6023          SUMA_CORNER_OF_VOXEL(center, dxyz, 2, P0);   \
6024          SUMA_CORNER_OF_VOXEL(center, dxyz, 3, P1);   \
6025          break;   \
6026       case 7:  \
6027          SUMA_CORNER_OF_VOXEL(center, dxyz, 3, P0);   \
6028          SUMA_CORNER_OF_VOXEL(center, dxyz, 7, P1);   \
6029          break;   \
6030       case 8:  \
6031          SUMA_CORNER_OF_VOXEL(center, dxyz, 4, P0);   \
6032          SUMA_CORNER_OF_VOXEL(center, dxyz, 7, P1);   \
6033          break;   \
6034       case 9:  \
6035          SUMA_CORNER_OF_VOXEL(center, dxyz, 4, P0);   \
6036          SUMA_CORNER_OF_VOXEL(center, dxyz, 5, P1);   \
6037          break;   \
6038       case 10:  \
6039          SUMA_CORNER_OF_VOXEL(center, dxyz, 5, P0);   \
6040          SUMA_CORNER_OF_VOXEL(center, dxyz, 6, P1);   \
6041          break;   \
6042       case 11:  \
6043          SUMA_CORNER_OF_VOXEL(center, dxyz, 6, P0);   \
6044          SUMA_CORNER_OF_VOXEL(center, dxyz, 7, P1);   \
6045          break;   \
6046       default: \
6047          P0[0] = center[0]; P0[1] = center[1]; P0[2] = center[2]; \
6048          P1[0] = center[0]; P1[1] = center[1]; P1[2] = center[2]; \
6049          SUMA_SL_Err("Bad edge index. Returning Centers of voxel.");\
6050    }  \
6051 }
6052 
6053 /*!
6054    \brief does a voxel intersect a triangle ? (i.e. one of the edges intersects a triangle)
6055    \param center (float *) center of voxel
6056    \param dxyz (float *) dimensions of voxel
6057    \param vert0 (float *) xyz first vertex of triangle
6058    \param vert1 (float *) xyz of second vertex of triangle
6059    \param vert2 (float *) xyz of third vertex of triangle
6060    \return YUP == intersects
6061 */
SUMA_isVoxelIntersect_Triangle(float * center,float * dxyz,float * vert0,float * vert1,float * vert2)6062 SUMA_Boolean SUMA_isVoxelIntersect_Triangle
6063       (float *center, float *dxyz,
6064        float *vert0, float *vert1, float *vert2)
6065 {
6066    static char FuncName[]={"SUMA_isVoxelIntersect_Triangle"};
6067    int i = 0;
6068    float P0[3], P1[3], iP[3];
6069 
6070    SUMA_ENTRY;
6071 
6072    /* loop accross all 12 edges and find out which pierces the triangle */
6073    for (i=0; i<12; ++i) {
6074       SUMA_EDGE_OF_VOXEL(center, dxyz, i, P0, P1);
6075       if (SUMA_MT_isIntersect_Triangle (P0, P1, vert0, vert1, vert2,
6076                                         iP, NULL, NULL)) {
6077          #if 0
6078             if (VoxIntersDbg)
6079                fprintf(SUMA_STDERR,
6080                        "%s: intersection detected (dxyz [%f %f %f], edge %d\n",
6081                            FuncName, dxyz[0], dxyz[1], dxyz[2], i);
6082          #endif
6083          /* intersects, make sure intersection is between P0 and P1 */
6084          if (SUMA_IS_POINT_IN_SEGMENT(iP, P0, P1)) {
6085             #if 0
6086             if (VoxIntersDbg) fprintf(SUMA_STDERR, "%s:\n"
6087                                                 "Triangle %.3f, %.3f, %.3f\n"
6088                                                 "         %.3f, %.3f, %.3f\n"
6089                                                 "         %.3f, %.3f, %.3f\n"
6090                                                 "Intersects voxel at:\n"
6091                                                 "         %.3f, %.3f, %.3f\n",
6092                                                 FuncName,
6093                                                 vert0[0], vert0[1], vert0[2],
6094                                                 vert1[0], vert1[1], vert1[2],
6095                                                 vert2[0], vert2[1], vert2[2],
6096                                                 center[0], center[1], center[2]);
6097             #endif
6098             SUMA_RETURN(YUP);
6099          }
6100       }
6101    }
6102    SUMA_RETURN(NOPE);
6103 }
6104 
6105 /*
6106 \brief This function is a stripped down version of SUMA_MT_intersect_triangle.
6107        It is meant to work faster when few triangles are to be tested.
6108 
6109 ans = SUMA_MT_isIntersect_Triangle (P0, P1, vert0, vert1, vert2, iP, d, closest_vert);
6110 
6111 \param   P0 (float *) 3x1 containing XYZ of point 0
6112 \param   P1 (float *) 3x1 containing XYZ of point 1
6113 \param   vert0 (float *) 3x1 containing XYZ of first node in triangle.
6114 \param   vert1 (float *) 3x1 containing XYZ of second node in triangle.
6115 \param   vert2 (float *) 3x1 containing XYZ of third node in triangle.
6116 \param   iP (float *) 3x1 vector containing XYZ of point of itnersection of P0-P1 with the triangle
6117 \param   d (float *) 3x1 vector containing distance from iP to each of the vertices forming the triangle.
6118 \param   closest_vert (int *) index of node (0, 1 or 2) closest to iP
6119          d[*closest_vert] is the smallest of d[0], d[1] and d[2]
6120 \return  ans (SUMA_Boolean) YUP (intersects)/NOPE (does not intersect)
6121 
6122          NOTE: iP, d and closest_vert are not touched by this function if P0-P1 does not
6123          intersect the triangle.
6124          NOTE: If you do not care for iP, d and closest_vert, pass NULL, NULL, NULL as their pointers
6125 
6126 
6127    \sa SUMA_MT_intersect_triangle
6128 */
6129 
SUMA_MT_isIntersect_Triangle(float * P0,float * P1,float * vert0,float * vert1,float * vert2,float * iP,float * d,int * closest_vert)6130 SUMA_Boolean SUMA_MT_isIntersect_Triangle (float *P0, float *P1, float *vert0, float *vert1, float *vert2, float *iP, float *d, int *closest_vert)
6131 {
6132    static char FuncName[]={"SUMA_MT_isIntersect_Triangle"};
6133    double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
6134    double det,inv_det, u, v, t;
6135    double dir[3], dirn, orig[3];
6136    SUMA_Boolean hit = NOPE;
6137 
6138    SUMA_ENTRY;
6139 
6140    /* direction from two points */
6141    orig[0] = (double)P0[0];
6142    orig[1] = (double)P0[1];
6143    orig[2] = (double)P0[2];
6144 
6145    dir[0] = (double)P1[0] - orig[0];
6146    dir[1] = (double)P1[1] - orig[1];
6147    dir[2] = (double)P1[2] - orig[2];
6148    dirn = sqrt(dir[0]*dir[0]+dir[1]*dir[1]+dir[2]*dir[2]);
6149    dir[0] /= dirn;
6150    dir[1] /= dirn;
6151    dir[2] /= dirn;
6152 
6153    /* find vectors for two edges sharing vert0 */
6154    SUMA_MT_SUB(edge1, vert1, vert0);
6155    SUMA_MT_SUB(edge2, vert2, vert0);
6156 
6157    /* begin calculating determinant - also used to calculate U parameter */
6158    SUMA_MT_CROSS(pvec, dir, edge2);
6159 
6160    /* if determinant is near zero, ray lies in plane of triangle */
6161    det = SUMA_MT_DOT(edge1, pvec);
6162 
6163    hit = NOPE;
6164 
6165       if (det > -SUMA_EPSILON && det < SUMA_EPSILON) {
6166          /* no hit, will return below */
6167          hit = NOPE;
6168       } else {
6169          inv_det = 1.0 / det;
6170 
6171          /* calculate distance from vert0 to ray origin */
6172          SUMA_MT_SUB(tvec, orig, vert0);
6173 
6174          /* calculate U parameter and test bounds */
6175          u = SUMA_MT_DOT(tvec, pvec) * inv_det;
6176          if (u < 0.0 || u > 1.0) {
6177             /* no hit, will return below */
6178             hit = NOPE;
6179          } else {
6180             /* prepare to test V parameter */
6181             SUMA_MT_CROSS(qvec, tvec, edge1);
6182 
6183             /* calculate V parameter and test bounds */
6184             v = SUMA_MT_DOT(dir, qvec) * inv_det;
6185             if (v < 0.0 || u + v > 1.0) {
6186                 /* no hit, will return below */
6187                 hit = NOPE;
6188             } else {
6189                hit = YUP;
6190 
6191                if (iP) {
6192                   /* calculate t, ray intersects triangle */
6193                   t = SUMA_MT_DOT(edge2, qvec) * inv_det;
6194 
6195                   /* calculate the location of the intersection (iP) in XYZ coords */
6196                   iP[0] = vert0[0] + u * (vert1[0] - vert0[0] ) + v * (vert2[0] - vert0[0] );
6197                   iP[1] = vert0[1] + u * (vert1[1] - vert0[1] ) + v * (vert2[1] - vert0[1] );
6198                   iP[2] = vert0[2] + u * (vert1[2] - vert0[2] ) + v * (vert2[2] - vert0[2] );
6199 
6200                   if (d) {
6201                      /* find out which node is closest to P */
6202                      d[0] = (vert0[0] - iP[0])*(vert0[0] - iP[0]) + (vert0[1] - iP[1])*(vert0[1] - iP[1]) + (vert0[2] - iP[2])*(vert0[2] - iP[2]);
6203                      *closest_vert = 0;
6204                      d[1] = (vert1[0] - iP[0])*(vert1[0] - iP[0]) + (vert1[1] - iP[1])*(vert1[1] - iP[1]) + (vert1[2] - iP[2])*(vert1[2] - iP[2]);
6205                      if (d[1] < d[*closest_vert]) {
6206                         *closest_vert = 1;
6207                      }
6208                      d[2] = (vert2[0] - iP[0])*(vert2[0] - iP[0]) + (vert2[1] - iP[1])*(vert2[1] - iP[1]) + (vert2[2] - iP[2])*(vert2[2] - iP[2]);
6209                      if (d[2] < d[*closest_vert]) {
6210                         *closest_vert = 2;
6211                      }
6212                      d[0] = (float)sqrt((double)d[0]);
6213                      d[1] = (float)sqrt((double)d[1]);
6214                      d[2] = (float)sqrt((double)d[2]);
6215                   }
6216                }
6217 
6218             }
6219          }
6220       }
6221 
6222    SUMA_RETURN (hit);
6223 }
6224 
6225 /*!
6226 
6227 SUMA_MT_INTERSECT_TRIANGLE *
6228 SUMA_MT_intersect_triangle(float *P0, float *P1,
6229                            float *NodeList, int N_Node,
6230                            int *FaceSetList, int N_FaceSet,
6231                            SUMA_MT_INTERSECT_TRIANGLE *prevMTI,
6232                            int posonly)
6233 
6234 \param   P0 (float *) 3x1 containing XYZ of point 0
6235 \param   P1 (float *) 3x1 containing XYZ of point 1
6236 \param   NodeList (float *) N_Node x 3 vector containing the XYZ of nodes
6237          making up FaceSetList
6238 \param   N_Node (int) number of nodes in NodeList
6239 \param   FaceSetList (int *) N_FaceSet x 3 with each triplet representing
6240          a triangle. Triangles are defined by their indices into NodeList
6241 \param   N_FaceSet (int) number of triangles in FaceSetList
6242 \param   PrevMTI (SUMA_MT_INTERSECT_TRIANGLE *) To keep the function from
6243                reallocating for MTI each time you call it, you can pass
6244                the previous MTI structure to the next call.
6245                If the number of facesets is the same as in the previous
6246                call and PrevMTI is not NULL then MTI is not reallocated for.
6247 
6248                If PrevMTI is not null and the last N_FaceSet was different
6249                from the current, PrevMTI is freed and a new one is returned.
6250                This change appears to save about 18% of the function's
6251                execution time. Be careful not to free PrevMTI without setting
6252                it to NULL and then send it to SUMA_MT_intersect_triangle.
6253 \param   posonly if 1 then search only in the positive direction. P0 --> P1
6254                  if 0 then abs min
6255                  if -1 then only in neg direction
6256                  Note that MTI->N_poshits is only properly set with
6257                  posonly == 0 or posonly == 1
6258 \ret   MTI (SUMA_MT_INTERSECT_TRIANGLE *) pointer to structure containing
6259                isHit (SUMA_Boolean *) N_FaceSet x 1 vector.
6260                isHit[i] = YUP --> FaceSet i is pierced by ray P0-->P1
6261       t (float *) signed distance to the plane in which the triangle lies
6262       u & v(float *) location withing the triangle of the intersection point
6263 
6264 \sa Algorithm from:Moller & Trumbore 97
6265    Tomas M�ller and Ben Trumbore. Fast, minimum storage ray-triangle intersection.
6266    Journal of graphics tools, 2(1):21-28, 1997
6267 
6268 NOTE:
6269 Tue Jan  7 15:07:05 EST 2003 Shruti noted that problems occured when a ray intersected a node.
6270 She is correct, if a ray intersects a node, it may or may not be detected and the results are undetermined.
6271 This is only expected to happen with synthesized data and checking for such situations will slow the function down.
6272 If you must use such data, I recommend you add a tiny bit of noise to the vertex coordinates
6273 or to your normals.
6274 
6275 */
6276 
6277 SUMA_MT_INTERSECT_TRIANGLE *
SUMA_MT_intersect_triangle(float * P0,float * P1,float * NodeList,int N_Node,int * FaceSetList,int N_FaceSet,SUMA_MT_INTERSECT_TRIANGLE * PrevMTI,int posonly)6278 SUMA_MT_intersect_triangle(float *P0, float *P1,
6279                            float *NodeList, int N_Node,
6280                            int *FaceSetList, int N_FaceSet,
6281                            SUMA_MT_INTERSECT_TRIANGLE *PrevMTI,
6282                            int posonly)
6283 {
6284    static char FuncName[]={"SUMA_MT_intersect_triangle"};
6285    double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
6286    double det,inv_det;
6287    int iface, ND, id, NP, ip;
6288    double vert0[3],vert1[3], vert2[3], dir[3], dirn, orig[3];
6289    float tmin, tmax, dii, disttest;
6290    static SUMA_MT_INTERSECT_TRIANGLE *MTI = NULL;
6291    static int N_FaceSet_Previous = 0, entry = 0;
6292    SUMA_Boolean LocalHead = NOPE;
6293 
6294    SUMA_ENTRY;
6295 
6296    tmin = 10000000.0;
6297    tmax = 0.0;
6298 
6299    if (!PrevMTI) { /* nothing preallocated */
6300       entry = 0;
6301       SUMA_LH("First entry or nothing pre-allocated.\n");
6302    } else { /* returning a used MTI, check number of facesets */
6303       if (N_FaceSet_Previous != N_FaceSet) { /* must reallocate */
6304          SUMA_LH("Reallocating for MTI, a change in number of FaceSets.\n");
6305          /* free current MTI */
6306          PrevMTI = SUMA_Free_MT_intersect_triangle (PrevMTI);
6307          entry = 0;
6308       }else if (LocalHead) fprintf(SUMA_STDERR,"%s: Reusing.\n", FuncName);
6309    }
6310 
6311    if (!entry) {
6312       MTI = (SUMA_MT_INTERSECT_TRIANGLE *)
6313                      SUMA_calloc(1,sizeof(SUMA_MT_INTERSECT_TRIANGLE));
6314       if (MTI == NULL) {
6315          fprintf(SUMA_STDERR,"Error %s: Failed to allocate for MTI\n", FuncName);
6316          SUMA_RETURN (NULL);
6317       }
6318       MTI->t = NULL;
6319       MTI->u = NULL;
6320       MTI->v = NULL;
6321       MTI->isHit = NULL;
6322       MTI->N_hits = 0; MTI->N_poshits = 0; MTI->ifacemin = 0;
6323    } else {
6324       MTI = PrevMTI;
6325       MTI->N_hits = 0; MTI->N_poshits = 0; MTI->ifacemin = 0;
6326    }
6327 
6328    /* direction from two points */
6329    orig[0] = (double)P0[0];
6330    orig[1] = (double)P0[1];
6331    orig[2] = (double)P0[2];
6332 
6333    dir[0] = (double)P1[0] - orig[0];
6334    dir[1] = (double)P1[1] - orig[1];
6335    dir[2] = (double)P1[2] - orig[2];
6336    dirn = sqrt(dir[0]*dir[0]+dir[1]*dir[1]+dir[2]*dir[2]);
6337    dir[0] /= dirn;
6338    dir[1] /= dirn;
6339    dir[2] /= dirn;
6340 
6341    if (!entry) {
6342       MTI->isHit = (SUMA_Boolean *)SUMA_malloc(N_FaceSet*sizeof(SUMA_Boolean));
6343       MTI->t = (float *)SUMA_calloc(N_FaceSet, sizeof(float));
6344       MTI->u = (float *)SUMA_calloc(N_FaceSet, sizeof(float));
6345       MTI->v = (float *)SUMA_calloc(N_FaceSet, sizeof(float));
6346 
6347       if (MTI->isHit == NULL || MTI->t == NULL || MTI->u == NULL
6348                              || MTI->v == NULL) {
6349          SUMA_S_Err("Failed to allocate for MTI->*\n");
6350          SUMA_RETURN (NULL);
6351       }
6352    }
6353 
6354    MTI->N_hits = 0; MTI->N_poshits = 0;
6355    ND = 3;
6356    NP = 3;
6357    for (iface= 0; iface < N_FaceSet; ++iface) {/* iface */
6358       /* set up the coordinates in a humane nomenclature */
6359       ip = NP * iface;
6360       id = ND * FaceSetList[ip];
6361       vert0[0] = (double)NodeList[id];
6362        vert0[1] = (double)NodeList[id+1];
6363       vert0[2] = (double)NodeList[id+2];
6364 
6365       id = ND * FaceSetList[ip+1];
6366       vert1[0] = (double)NodeList[id];
6367        vert1[1] = (double)NodeList[id+1];
6368       vert1[2] = (double)NodeList[id+2];
6369 
6370       id = ND * FaceSetList[ip+2];
6371       vert2[0] = (double)NodeList[id];
6372        vert2[1] = (double)NodeList[id+1];
6373       vert2[2] = (double)NodeList[id+2];
6374 
6375 
6376       /* find vectors for two edges sharing vert0 */
6377       SUMA_MT_SUB(edge1, vert1, vert0);
6378       SUMA_MT_SUB(edge2, vert2, vert0);
6379 
6380       /* begin calculating determinant - also used to calculate U parameter */
6381       SUMA_MT_CROSS(pvec, dir, edge2);
6382 
6383       /* if determinant is near zero, ray lies in plane of triangle */
6384       det = SUMA_MT_DOT(edge1, pvec);
6385 
6386    #ifdef SUMA_MT_TEST_CULL         /* define TEST_CULL if culling is desired */
6387       if (det > -SUMA_EPSILON && det < SUMA_EPSILON)
6388          MTI->isHit[iface] = NOPE;
6389       else {
6390          /* calculate distance from vert0 to ray origin */
6391          SUMA_MT_SUB(tvec, orig, vert0);
6392 
6393          /* calculate U parameter and test bounds */
6394          MTI->u[iface] = (float)SUMA_MT_DOT(tvec, pvec);
6395          if (MTI->u[iface] < 0.0 || MTI->u[iface] > det)
6396             MTI->isHit[iface] = NOPE;
6397          else {
6398             /* prepare to test V parameter */
6399             SUMA_MT_CROSS(qvec, tvec, edge1);
6400 
6401              /* calculate V parameter and test bounds */
6402             MTI->v[iface] = (float)SUMA_MT_DOT(dir, qvec);
6403             if (MTI->v[iface] < 0.0 || MTI->u[iface] + MTI->v[iface] > det)
6404                MTI->isHit[iface] = NOPE;
6405             else {
6406                /* calculate t, scale parameters, ray intersects triangle */
6407                MTI->t[iface] = (float)SUMA_MT_DOT(edge2, qvec);
6408                inv_det = 1.0 / det;
6409                MTI->t[iface] *= (float)inv_det;
6410                MTI->u[iface] *= (float)inv_det;
6411                MTI->v[iface] *= (float)inv_det;
6412                MTI->isHit[iface] = YUP;
6413                ++MTI->N_hits;
6414                /* store shortest distance triangle info */
6415                if (MTI->t[iface] < 0) {
6416                   if (posonly>0) continue;
6417                   disttest = -MTI->t[iface];
6418                }   else  {
6419                   if (posonly<0) continue;
6420                   disttest = MTI->t[iface]; ++MTI->N_poshits;
6421                }
6422                if (disttest < tmin) {
6423                   tmin = disttest;
6424                   MTI->ifacemin = iface;
6425                   /* calculate the location of the intersection in XYZ coords */
6426                   MTI->P[0] = vert0[0] + MTI->u[iface] * (vert1[0] - vert0[0] ) +
6427                                          MTI->v[iface] * (vert2[0] - vert0[0] );
6428                   MTI->P[1] = vert0[1] + MTI->u[iface] * (vert1[1] - vert0[1] ) +
6429                                          MTI->v[iface] * (vert2[1] - vert0[1] );
6430                   MTI->P[2] = vert0[2] + MTI->u[iface] * (vert1[2] - vert0[2] ) +
6431                                          MTI->v[iface] * (vert2[2] - vert0[2] );
6432                   /* find out which node is closest to P */
6433                   MTI->inodeminlocal = 0;
6434                   MTI->d = (vert0[0] - MTI->P[0])*(vert0[0] - MTI->P[0]) +
6435                            (vert0[1] - MTI->P[1])*(vert0[1] - MTI->P[1]) +
6436                            (vert0[2] - MTI->P[2])*(vert0[2] - MTI->P[2]);
6437                   dii = (vert1[0] - MTI->P[0])*(vert1[0] - MTI->P[0]) +
6438                         (vert1[1] - MTI->P[1])*(vert1[1] - MTI->P[1]) +
6439                         (vert1[2] - MTI->P[2])*(vert1[2] - MTI->P[2]);
6440                   if (dii < MTI->d) {
6441                      MTI->d = dii;
6442                      MTI->inodeminlocal = 1;
6443                   }
6444                   dii = (vert2[0] - MTI->P[0])*(vert2[0] - MTI->P[0]) +
6445                         (vert2[1] - MTI->P[1])*(vert2[1] - MTI->P[1]) +
6446                         (vert2[2] - MTI->P[2])*(vert2[2] - MTI->P[2]);
6447                   if (dii < MTI->d) {
6448                      MTI->d = dii;
6449                      MTI->inodeminlocal = 2;
6450                   }
6451                   MTI->d = (float)sqrt((double)MTI->d);
6452                }
6453                if (disttest > tmax) {
6454                   tmax = disttest;
6455                   MTI->ifacemax = iface;
6456                }
6457             }
6458          }
6459       }
6460    #else                    /* the non-culling branch */
6461       if (det > -SUMA_EPSILON && det < SUMA_EPSILON)
6462          MTI->isHit[iface] = NOPE;
6463       else {
6464          inv_det = 1.0 / det;
6465 
6466          /* calculate distance from vert0 to ray origin */
6467          SUMA_MT_SUB(tvec, orig, vert0);
6468 
6469          /* calculate U parameter and test bounds */
6470          MTI->u[iface] = (float)SUMA_MT_DOT(tvec, pvec) * inv_det;
6471          if (MTI->u[iface] < 0.0 || MTI->u[iface] > 1.0)
6472             MTI->isHit[iface] = NOPE;
6473          else {
6474             /* prepare to test V parameter */
6475             SUMA_MT_CROSS(qvec, tvec, edge1);
6476 
6477             /* calculate V parameter and test bounds */
6478             MTI->v[iface] = (float)SUMA_MT_DOT(dir, qvec) * inv_det;
6479             if (MTI->v[iface] < 0.0 || MTI->u[iface] + MTI->v[iface] > 1.0)
6480                MTI->isHit[iface] = NOPE;
6481             else {
6482                /* calculate t, ray intersects triangle */
6483                MTI->t[iface] = (float)SUMA_MT_DOT(edge2, qvec) * inv_det;
6484                MTI->isHit[iface] = YUP;
6485                ++MTI->N_hits;
6486                /* store shortest distance triangle info */
6487                if (MTI->t[iface] < 0) {
6488                   if (posonly>0) continue;
6489                   disttest = -MTI->t[iface];
6490                }   else  {
6491                   if (posonly<0) continue;
6492                   disttest = MTI->t[iface]; ++MTI->N_poshits;
6493                }
6494                if (disttest < tmin) {
6495                   tmin = disttest;
6496                   MTI->ifacemin = iface;
6497                   /* calculate the location of the intersection in XYZ coords */
6498                   MTI->P[0] = vert0[0] + MTI->u[iface] * (vert1[0] - vert0[0] ) +
6499                                          MTI->v[iface] * (vert2[0] - vert0[0] );
6500                   MTI->P[1] = vert0[1] + MTI->u[iface] * (vert1[1] - vert0[1] ) +
6501                                          MTI->v[iface] * (vert2[1] - vert0[1] );
6502                   MTI->P[2] = vert0[2] + MTI->u[iface] * (vert1[2] - vert0[2] ) +
6503                                          MTI->v[iface] * (vert2[2] - vert0[2] );
6504                   /* find out which node is closest to P */
6505                   MTI->inodeminlocal = 0;
6506                   MTI->d = (vert0[0] - MTI->P[0])*(vert0[0] - MTI->P[0]) +
6507                            (vert0[1] - MTI->P[1])*(vert0[1] - MTI->P[1]) +
6508                            (vert0[2] - MTI->P[2])*(vert0[2] - MTI->P[2]);
6509                   dii =    (vert1[0] - MTI->P[0])*(vert1[0] - MTI->P[0]) +
6510                            (vert1[1] - MTI->P[1])*(vert1[1] - MTI->P[1]) +
6511                            (vert1[2] - MTI->P[2])*(vert1[2] - MTI->P[2]);
6512                   if (dii < MTI->d) {
6513                      MTI->d = dii;
6514                      MTI->inodeminlocal = 1;
6515                   }
6516                   dii =    (vert2[0] - MTI->P[0])*(vert2[0] - MTI->P[0]) +
6517                            (vert2[1] - MTI->P[1])*(vert2[1] - MTI->P[1]) +
6518                            (vert2[2] - MTI->P[2])*(vert2[2] - MTI->P[2]);
6519                   if (dii < MTI->d) {
6520                      MTI->d = dii;
6521                      MTI->inodeminlocal = 2;
6522                   }
6523                   MTI->d = (float)sqrt((double)MTI->d);
6524                   ip = NP * iface + MTI->inodeminlocal;
6525                   MTI->inodemin = FaceSetList[ip];
6526                }
6527                if (disttest > tmax) {
6528                   tmax = disttest;
6529                   MTI->ifacemax = iface;
6530                }
6531             }
6532          }
6533       }
6534    #endif
6535    }/*iface */
6536    MTI->N_el = N_FaceSet;
6537 
6538    ++entry;
6539    N_FaceSet_Previous = N_FaceSet;
6540 
6541    SUMA_RETURN (MTI);
6542 }
6543 
6544 /*!
6545    Yet a another version of SUMA_MT_intersect_triangle intended
6546    just to count the number of triangles intersected by a segment.
6547 
6548    v0, v1 (void *): Segment end points.
6549                   1: then v0 and v1 are node indices (int)
6550                   0: v0 and v1 are coordinate 3vectors (float *)
6551                   2: v0 is a coordinate 3vectors, v1 is a direction vector
6552 
6553 
6554    N_hits: (int*) At entry to call:
6555                      If the number of triangles hit reach or exceed *N_hits
6556                      return, no need to continue. If set to 0, the limit
6557                      is automatically set to N_FaceSet
6558                   At return from call:
6559                      Contains the number of triangles hit (see caveat in
6560                      index_input).
6561    tris_hit (int *) If not null, will contain the indices of triangles
6562                     hit. If you use it, make sure *N_hits is the length
6563                     of the pre-allocated array so that the function
6564                     knows not to overshoot it.
6565    OnlyBetween 1: Only count as hits triangles between P0 && P1
6566                   This parameter is ignored with index_input is 2
6567 
6568    index_input: 1 means input are node indices. Also means to ignore
6569                triangles that contain either n0 or n1
6570                 0 means input are coordinates.
6571 */
6572 
SUMA_MT_count_intersect_triangle(void * v0,void * v1,float * NodeList,int N_Node,int * FaceSetList,int N_FaceSet,int * N_hits,int * tris_hit,byte OnlyBetween,byte * nmask,int index_input,float * min_dist,int * iface_min_dist,float * proj)6573 SUMA_Boolean SUMA_MT_count_intersect_triangle(void *v0, void *v1,
6574                            float *NodeList, int N_Node,
6575                            int *FaceSetList, int N_FaceSet,
6576                            int *N_hits, int *tris_hit,
6577                            byte OnlyBetween, byte *nmask,
6578                            int index_input,
6579                            float *min_dist, int *iface_min_dist, float *proj)
6580 {
6581    static char FuncName[]={"SUMA_MT_count_intersect_triangle"};
6582    double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
6583    double det,inv_det;
6584    int iface, ND, id, NP, ip, MaxHits, isbetween, n0, n1;
6585    double vert0[3], vert1[3], vert2[3], dir[3], dirn, orig[3], tip[3],
6586           uu, vv, P[3]={0.0, 0.0, 0.0};
6587    float *P0, *P1, this_dist = 0.0, *ftmp=NULL, Ptmp[3]={0.0, 0.0, 0.0};
6588    SUMA_Boolean LocalHead = NOPE;
6589 
6590    SUMA_ENTRY;
6591 
6592    if (!NodeList || !FaceSetList || !N_hits) {
6593       SUMA_S_Err("NULL input");
6594       SUMA_RETURN(NOPE);
6595    }
6596 
6597    if ((min_dist && !iface_min_dist) || (!min_dist && iface_min_dist)) {
6598       SUMA_S_Err("Both min_dist and iface_min_dist must be either NULL or not");
6599       SUMA_RETURN(NOPE);
6600    }
6601    if (min_dist) { *min_dist = 1000000.0; *iface_min_dist = -1; }
6602 
6603    ND = 3;
6604    NP = 3;
6605 
6606    switch (index_input) {
6607       case 1:
6608          n0 = (int)(long)v0; n1 = (int)(long)v1;
6609          P0 = NodeList+n0*ND;
6610          P1 = NodeList+n1*ND;
6611          SUMA_LHv("Nodes %d and %d at the ready.\n", n0, n1);
6612          break;
6613       case 0:
6614          P0 = (float *)v0; P1 = (float *)v1;
6615          n0=-1; n1=-1;
6616          break;
6617       case 2: /* one node and a direction, turn off OnlyBetween*/
6618          n0=-1; n1=-1;
6619          P0 = (float *)v0;
6620          P1 = Ptmp;
6621          ftmp = (float *)v1;
6622          P1[0] = P0[0]+1000.0*ftmp[0];
6623          P1[1] = P0[1]+1000.0*ftmp[1];
6624          P1[2] = P0[2]+1000.0*ftmp[2];
6625          OnlyBetween = 0;
6626          break;
6627       default:
6628          SUMA_S_Errv("Bad index_input (%d)\n", index_input);
6629          SUMA_RETURN(NOPE);
6630          break;
6631    }
6632 
6633    if (*N_hits<=0) MaxHits =  N_FaceSet;
6634    else MaxHits = *N_hits;
6635 
6636    /* direction from two points */
6637    orig[0] = (double)P0[0];
6638    orig[1] = (double)P0[1];
6639    orig[2] = (double)P0[2];
6640 
6641 
6642    dir[0] = (double)P1[0] - orig[0];
6643    dir[1] = (double)P1[1] - orig[1];
6644    dir[2] = (double)P1[2] - orig[2];
6645    dirn = sqrt(dir[0]*dir[0]+dir[1]*dir[1]+dir[2]*dir[2]);
6646    dir[0] /= dirn;
6647    dir[1] /= dirn;
6648    dir[2] /= dirn;
6649 
6650    *N_hits = 0;
6651    for (iface= 0; iface < N_FaceSet; ++iface) {/* iface */
6652       /* set up the coordinates in a humane nomenclature */
6653       ip = NP * iface;
6654       if (nmask) { /* skip if all nodes are outside mask */
6655          if (!nmask[FaceSetList[ip]] &&
6656              !nmask[FaceSetList[ip+1]] &&
6657              !nmask[FaceSetList[ip+2]]) continue;
6658       }
6659       if (n0 >= 0 && (
6660                          n0 == FaceSetList[ip  ] ||
6661                          n0 == FaceSetList[ip+1] ||
6662                          n0 == FaceSetList[ip+2] ||
6663                          n1 == FaceSetList[ip  ] ||
6664                          n1 == FaceSetList[ip+1] ||
6665                          n1 == FaceSetList[ip+2] ) ) {
6666          /* One of the segment's tips is at a node of this triangle
6667             This would be an intersection, but it is a trivial condition
6668             which will muck up the count of N_hits for the purposes
6669             of determining a surface intersection.
6670             Hence this condition will be considered a non-intersection.
6671          */
6672          continue;
6673       }
6674       /* SUMA_LHv("Triangle %d will be processed: [%d %d %d]\n",
6675                   iface,
6676                   FaceSetList[ip], FaceSetList[ip+1], FaceSetList[ip+2]);*/
6677       id = ND * FaceSetList[ip];
6678       vert0[0] = (double)NodeList[id];
6679        vert0[1] = (double)NodeList[id+1];
6680       vert0[2] = (double)NodeList[id+2];
6681 
6682       id = ND * FaceSetList[ip+1];
6683       vert1[0] = (double)NodeList[id];
6684        vert1[1] = (double)NodeList[id+1];
6685       vert1[2] = (double)NodeList[id+2];
6686 
6687       id = ND * FaceSetList[ip+2];
6688       vert2[0] = (double)NodeList[id];
6689        vert2[1] = (double)NodeList[id+1];
6690       vert2[2] = (double)NodeList[id+2];
6691 
6692 
6693       /* find vectors for two edges sharing vert0 */
6694       SUMA_MT_SUB(edge1, vert1, vert0);
6695       SUMA_MT_SUB(edge2, vert2, vert0);
6696 
6697       /* begin calculating determinant - also used to calculate U parameter */
6698       SUMA_MT_CROSS(pvec, dir, edge2);
6699 
6700       /* if determinant is near zero, ray lies in plane of triangle */
6701       det = SUMA_MT_DOT(edge1, pvec);
6702 
6703       /* the non-culling branch */
6704       if (det > -SUMA_EPSILON && det < SUMA_EPSILON) {
6705          /* no hit */
6706       } else {
6707          inv_det = 1.0 / det;
6708 
6709          /* calculate distance from vert0 to ray origin */
6710          SUMA_MT_SUB(tvec, orig, vert0);
6711 
6712          /* calculate U parameter and test bounds */
6713          uu = SUMA_MT_DOT(tvec, pvec) * inv_det;
6714          if (uu < 0.0 || uu > 1.0) {
6715             /* no hit */
6716          } else {
6717             /* prepare to test V parameter */
6718             SUMA_MT_CROSS(qvec, tvec, edge1);
6719 
6720             /* calculate V parameter and test bounds */
6721             vv = SUMA_MT_DOT(dir, qvec) * inv_det;
6722             if (vv < 0.0 || uu + vv > 1.0) {
6723                /* no hit */
6724             } else {
6725                SUMA_LHv("  Triangle %d [%d %d %d] is a hit, N_hits was %d\n",
6726                            iface,
6727                            FaceSetList[ip], FaceSetList[ip+1], FaceSetList[ip+2],
6728                            *N_hits);
6729                if (OnlyBetween || min_dist || proj) {
6730                   P[0] = vert0[0] + uu * (vert1[0] - vert0[0] ) +
6731                                     vv * (vert2[0] - vert0[0] );
6732                   P[1] = vert0[1] + uu * (vert1[1] - vert0[1] ) +
6733                                     vv * (vert2[1] - vert0[1] );
6734                   P[2] = vert0[2] + uu * (vert1[2] - vert0[2] ) +
6735                                     vv * (vert2[2] - vert0[2] );
6736                }
6737                isbetween=1;
6738                if (OnlyBetween) { /* Should you want to know if intersection if
6739                            between segment ends */
6740                   /* calculate the location of the intersection in XYZ coords */
6741                   tip[0] = (double)P1[0];
6742                   tip[1] = (double)P1[1];
6743                   tip[2] = (double)P1[2];
6744 
6745                   isbetween = SUMA_IS_POINT_IN_SEGMENT(P, orig, tip);
6746                   SUMA_LHv("     Its betweenness is %d \n"
6747                            "        [%.4f %.4f %.4f \n"
6748                            "         %.4f %.4f %.4f \n"
6749                            "         %.4f %.4f %.4f]\n",
6750                           isbetween,
6751                           orig[0], orig[1], orig[2],
6752                           P[0], P[1], P[2],
6753                           tip[0], tip[1], tip[2]);
6754                }
6755                if (isbetween) {
6756                   if (tris_hit) tris_hit[*N_hits]=iface;
6757                   if (min_dist) {
6758                      if (*N_hits == 0) {
6759                         SUMA_SEG_LENGTH(orig, P, (*min_dist));
6760                         *iface_min_dist = iface;
6761                         if (proj) {
6762                            proj[0]=P[0]; proj[1]=P[1]; proj[2]=P[2];
6763                         }
6764                     } else {
6765                         SUMA_SEG_LENGTH(orig, P, (this_dist));
6766                         if (this_dist < *min_dist) {
6767                            *min_dist = this_dist;
6768                            *iface_min_dist = iface;
6769                            if (proj) {
6770                               proj[0]=P[0]; proj[1]=P[1]; proj[2]=P[2];
6771                            }
6772                         }
6773                      }
6774                   }
6775                   *N_hits = *N_hits+1;
6776                   if (*N_hits >= MaxHits) SUMA_RETURN (YUP);
6777                }
6778             }
6779          }
6780       }
6781    }/*iface */
6782 
6783    SUMA_RETURN (YUP);
6784 }
6785 
6786 /*!
6787 Show contents of SUMA_MT_INTERSECT_TRIANGLE structure
6788 */
SUMA_Show_MT_intersect_triangle(SUMA_MT_INTERSECT_TRIANGLE * MTI,FILE * Out,char * preamble)6789 SUMA_Boolean SUMA_Show_MT_intersect_triangle(
6790                SUMA_MT_INTERSECT_TRIANGLE *MTI, FILE *Out, char *preamble)
6791 {
6792    static char FuncName[]={"SUMA_Show_MT_intersect_triangle"};
6793    int MaxShow = 5, i,j, mxs;
6794 
6795    SUMA_ENTRY;
6796 
6797    if (Out == NULL) Out = stdout;
6798 
6799    if (preamble) {
6800       fprintf (Out, "%s", preamble);
6801    }
6802    if (MTI == NULL) {
6803       fprintf (Out, "NULL Surface Object Pointer\n");
6804       SUMA_RETURN(NOPE);
6805    }
6806 
6807    fprintf (Out,"\n---------------------------------\n");
6808    if (!MTI->N_el) {
6809       fprintf (Out,"Zero elements in structure\n");
6810       SUMA_RETURN (YUP);
6811    }
6812 
6813    if (MTI->isHit == NULL) {
6814       fprintf (SUMA_STDERR,
6815          "Error SUMA_Show_MT_intersect_triangle: isHit is NULL\n\n");
6816       SUMA_RETURN (NOPE);
6817    }
6818    else {
6819       if (MaxShow > MTI->N_el) mxs = MTI->N_el;
6820       else mxs = MaxShow;
6821       fprintf (Out,
6822          "   Intersection results (showing max of %d out of %d elements):\n",
6823                mxs, MTI->N_el);
6824       for (i=0; i < mxs; ++i)   {
6825          fprintf (Out, "      isHit: %d t %f u %f v %f\n",
6826             MTI->isHit[i], MTI->t[i], MTI->u[i],MTI->v[i]);
6827       }
6828          fprintf (Out, "\n");
6829 
6830       if (MTI->N_hits) {
6831          if (MaxShow > MTI->N_hits) mxs = MTI->N_hits;
6832          else mxs = MaxShow;
6833          fprintf (Out, "\n%d hits, (%d hits with positive distance).\n",
6834                   MTI->N_hits, MTI->N_poshits);
6835          fprintf (Out, "Minimum Distance on triangle %d of t=%f u %f v %f\n",
6836                   MTI->ifacemin, MTI->t[MTI->ifacemin],
6837                   MTI->u[MTI->ifacemin],MTI->v[MTI->ifacemin]);
6838          fprintf (Out, "   Intersection point P on Minimum Distance FaceSet:\n"
6839                        "      %f, %f, %f\n",
6840                   MTI->P[0], MTI->P[1], MTI->P[2]);
6841          fprintf (Out,"   Closest node is number %d in Minimum Distance Faceset "
6842                        "(%d in NodeList) at %f distance.\n",
6843                   MTI->inodeminlocal, MTI->inodemin, MTI->d);
6844          fprintf (Out, "Maximum Distance on triangle %d of t=%f u %f v %f\n\n",
6845                   MTI->ifacemax, MTI->t[MTI->ifacemax],
6846                   MTI->u[MTI->ifacemax],MTI->v[MTI->ifacemax]);
6847          fprintf (Out, "   Intersection of ray with surface "
6848                        "(showing at most %d out of %d elements):\n",
6849                   mxs, MTI->N_el);
6850          i = 0;
6851          j = 0;
6852          while (i< MTI->N_el && j < mxs) {
6853             if (MTI->isHit[i]) {
6854                ++j;
6855                fprintf (Out, "   isHit: %d t %f u %f v %f\n",
6856                         MTI->isHit[i], MTI->t[i], MTI->u[i],MTI->v[i]);
6857             }
6858             ++i;
6859          }
6860          fprintf (Out, "\n");
6861       } else {
6862          fprintf (Out, "No Intersection of ray with surface\n");
6863       }
6864 
6865    }
6866    SUMA_RETURN (YUP);
6867 }
6868 /*!
6869 \brief free structure SUMA_MT_INTERSECT_TRIANGLE, returns NULL so you should use it as such:
6870 MTI = SUMA_Free_MT_intersect_triangle (MTI);
6871 
6872 \sa SUMA_MT_intersect_triangle to find out why it is important to set MTI to NULL after freeing it
6873 */
SUMA_Free_MT_intersect_triangle(SUMA_MT_INTERSECT_TRIANGLE * MTI)6874 void * SUMA_Free_MT_intersect_triangle(SUMA_MT_INTERSECT_TRIANGLE *MTI)
6875 {
6876    static char FuncName[]={"SUMA_Free_MT_intersect_triangle"};
6877 
6878    SUMA_ENTRY;
6879 
6880    if (MTI->t) SUMA_free(MTI->t);
6881    if (MTI->u) SUMA_free(MTI->u);
6882    if (MTI->v) SUMA_free(MTI->v);
6883    if (MTI->isHit) SUMA_free(MTI->isHit);
6884    if (MTI) SUMA_free(MTI);
6885    SUMA_RETURN(NULL);
6886 }
6887 
6888 /*!
6889    Code from Tomas M�ller, John Hughes 1999:
6890    Tomas M�ller and John F. Hughes.
6891    Efficiently building a matrix to rotate one vector to another.
6892    Journal of graphics tools, 4(4):1-4, 1999
6893 
6894 SUMA_Boolean SUMA_FromToRotation (float *v0, float *v1, float **mtx)
6895 
6896 determines rotation matrix required to rotate vector from to vector to
6897 \param v0 (float *) 3x1 vector to be rotated into v1
6898 \param v1 (float *) 3x1 vector
6899 \param mtx (float *) 4x4 matrix containing 3x3 rotation  matrix in the top left corner
6900 
6901 \ret YUP/NOPE
6902 
6903 \sa SUMA_mattoquat
6904 */
SUMA_FromToRotation(float * v0,float * v1,float ** mtx)6905 SUMA_Boolean SUMA_FromToRotation (float *v0, float *v1, float **mtx)
6906 {/* SUMA_FromToRotation */
6907    static char FuncName[]={"SUMA_FromToRotation"};
6908    float v[3], vn;
6909    float e, h, f;
6910 
6911    SUMA_ENTRY;
6912 
6913    if (!v0 || !v1) {
6914       SUMA_S_Err("NULL input");
6915       SUMA_RETURN (NOPE);
6916    }
6917 
6918    /*normalize both vectors */
6919    vn = sqrt(v0[0]*v0[0] + v0[1]*v0[1] + v0[2]*v0[2]);
6920    if (vn == 0.0) {
6921       fprintf(SUMA_STDERR,"Error %s: v0 is null.\n",FuncName);
6922       SUMA_RETURN (NOPE);
6923    }
6924    v0[0] /= vn;
6925    v0[1] /= vn;
6926    v0[2] /= vn;
6927 
6928    vn = sqrt(v1[0]*v1[0] + v1[1]*v1[1] + v1[2]*v1[2]);
6929    if (vn == 0.0) {
6930       fprintf(SUMA_STDERR,"Error %s: v1 is null.\n",FuncName);
6931       SUMA_RETURN (NOPE);
6932    }
6933    v1[0] /= vn;
6934    v1[1] /= vn;
6935    v1[2] /= vn;
6936 
6937    SUMA_MT_CROSS(v, v0, v1);
6938    e = SUMA_MT_DOT(v0, v1);
6939    f = (e < 0)? -e:e;
6940    if (f > 1.0 - SUMA_EPSILON)     /* "v0" and "v1"-vector almost parallel */
6941    {
6942       float u[3], v[3]; /* temporary storage vectors */
6943       float x[3];       /* vector most nearly orthogonal v1 "v0" */
6944       float c1, c2, c3; /* coefficients for later use */
6945       int i, j;
6946 
6947       x[0] = (v0[0] > 0.0)? v0[0] : -v0[0];
6948       x[1] = (v0[1] > 0.0)? v0[1] : -v0[1];
6949       x[2] = (v0[2] > 0.0)? v0[2] : -v0[2];
6950 
6951       if (x[0] < x[1])
6952       {
6953          if (x[0] < x[2])
6954          {
6955            x[0] = 1.0; x[1] = x[2] = 0.0;
6956          }
6957          else
6958          {
6959            x[2] = 1.0; x[0] = x[1] = 0.0;
6960          }
6961       }
6962       else
6963       {
6964          if (x[1] < x[2])
6965          {
6966            x[1] = 1.0; x[0] = x[2] = 0.0;
6967          }
6968          else
6969          {
6970            x[2] = 1.0; x[0] = x[1] = 0.0;
6971          }
6972       }
6973 
6974       u[0] = x[0] - v0[0]; u[1] = x[1] - v0[1]; u[2] = x[2] - v0[2];
6975       v[0] = x[0] - v1[0];   v[1] = x[1] - v1[1];   v[2] = x[2] - v1[2];
6976 
6977       c1 = 2.0 / SUMA_MT_DOT(u, u);
6978       c2 = 2.0 / SUMA_MT_DOT(v, v);
6979       c3 = c1 * c2  * SUMA_MT_DOT(u, v);
6980 
6981       for (i = 0; i < 3; i++) {
6982          for (j = 0; j < 3; j++) {
6983            mtx[i][j] =  - c1 * u[i] * u[j]
6984                         - c2 * v[i] * v[j]
6985                         + c3 * v[i] * u[j];
6986          }
6987          mtx[i][i] += 1.0;
6988       }
6989    }
6990    else  /* the most common case, unless "v0"="v1", or "v0"=-"v1" */
6991    {
6992       #if 0
6993          /* unoptimized version - a good compiler will optimize this. */
6994          h = (1.0 - e)/SUMA_MT_DOT(v, v);
6995          mtx[0][0] = e + h * v[0] * v[0];
6996          mtx[0][1] = h * v[0] * v[1] - v[2];
6997          mtx[0][2] = h * v[0] * v[2] + v[1];
6998 
6999          mtx[1][0] = h * v[0] * v[1] + v[2];
7000          mtx[1][1] = e + h * v[1] * v[1];
7001          mtx[1][2] = h * v[1] * v[2] - v[0];
7002 
7003          mtx[2][0] = h * v[0] * v[2] - v[1];
7004          mtx[2][1] = h * v[1] * v[2] + v[0];
7005          mtx[2][2] = e + h * v[2] * v[2];
7006       #else
7007          /* ...otherwise use this hand optimized version (9 mults less) */
7008          float hvx, hvz, hvxy, hvxz, hvyz;
7009          h = (1.0 - e)/SUMA_MT_DOT(v, v);
7010          hvx = h * v[0];
7011          hvz = h * v[2];
7012          hvxy = hvx * v[1];
7013          hvxz = hvx * v[2];
7014          hvyz = hvz * v[1];
7015          mtx[0][0] = e + hvx * v[0];
7016          mtx[0][1] = hvxy - v[2];
7017          mtx[0][2] = hvxz + v[1];
7018 
7019          mtx[1][0] = hvxy + v[2];
7020          mtx[1][1] = e + h * v[1] * v[1];
7021          mtx[1][2] = hvyz - v[0];
7022 
7023          mtx[2][0] = hvxz - v[1];
7024          mtx[2][1] = hvyz + v[0];
7025          mtx[2][2] = e + hvz * v[2];
7026       #endif
7027    }
7028 
7029    mtx[0][3] = 0.0;
7030    mtx[1][3] = 0.0;
7031    mtx[2][3] = 0.0;
7032    mtx[3][0] = 0.0;
7033    mtx[3][1] = 0.0;
7034    mtx[3][2] = 0.0;
7035    mtx[3][3] = 1.0;
7036    SUMA_RETURN (YUP);
7037 }
7038 
7039 /*
7040 From Advanced Animation and Rendering Techniques, by Alan Watt & Mark Watt
7041 Addison & Wesley, 1998, pp 363-364
7042 SUMA_Boolean   SUMA_mattoquat (float **mat, float *q)
7043 
7044 transforms a rotation matrix into a quaternion
7045 \param mat (float **) 4x4 rotation matrix
7046 \param q (float *) 4x1 vector containing the quaternion computed from mat
7047 
7048 \ret YUP/NOPE
7049 
7050 \sa SUMA_FromToRotation
7051 */
SUMA_mattoquat(float ** mat,float * q)7052 SUMA_Boolean   SUMA_mattoquat (float **mat, float *q)
7053 {
7054    double tr, s;
7055    int i,j,k, nxt[3] = {1, 2, 0};
7056    static char FuncName[]={"SUMA_mattoquat"};
7057 
7058    SUMA_ENTRY;
7059 
7060    /* calculate the trace */
7061    tr = mat[0][0] + mat[1][1] + mat[2][2];
7062    if (tr > 0.0) {
7063       s = sqrt(tr + 1.0);
7064       q[3] = s * 0.5;
7065       s = 0.5/s;
7066 
7067       q[0] = (mat[1][2] - mat[2][1])*s;
7068       q[1] = (mat[2][0] - mat[0][2])*s;
7069       q[2] = (mat[0][1] - mat[1][0])*s;
7070 
7071    } /* tr > 0.0 */ else {
7072       i = 0;
7073       if (mat[1][1] > mat[0][0]) i = 1;
7074       if (mat[2][2] > mat[i][i]) i = 2;
7075       j = nxt[i]; k = nxt[j];
7076 
7077       s = sqrt( (mat[i][i] - (mat[j][j]+mat[k][k])) + 1.0);
7078       q[i] = s * 0.5;
7079       s = 0.5/s;
7080       q[3] = (mat[j][k] - mat[k][j])*s;
7081       q[j] = (mat[i][j] + mat[j][i])*s;
7082       q[k] = (mat[i][k] + mat[k][i])*s;
7083    } /* tr < 0.0 */
7084    SUMA_RETURN (YUP);
7085 }
7086 
7087 /*------------------------- Triangle Consistency Functions BEGIN --------------------------------------- */
7088 typedef enum {SUMA_NO_NEIGHB, SUMA_NO_MORE_TO_VISIT, SUMA_VISITED_ALL, SUMA_BAD_SEED} SUMA_TAKE_A_HIKE;
7089 
7090 /*!
7091    \brief This function determines which triangle, if any is formed by the specified nodes
7092    Tri = SUMA_wichTri (EL, n1, n2, n3);
7093    \param EL (SUMA_EDGE_LIST *) structure to edge list
7094    \param n1 (int) first node
7095    \param n2 (int) second node
7096    \param n3 (int) third node
7097    \param IOtrace (int) this function is called a lot, set
7098    IOtrace to 1 if you want IOtracing to be enabled (if 1 then
7099    the function will trace if DBG_trace is not 0)
7100    \return Tri index of triangle containing n1, n2 and n3
7101          -1 if no such triangle was found
7102 
7103 */
SUMA_whichTri(SUMA_EDGE_LIST * EL,int n1,int n2,int n3,int IOtrace,byte quiet)7104 int SUMA_whichTri (SUMA_EDGE_LIST * EL, int n1, int n2, int n3, int IOtrace,
7105                    byte quiet)
7106 {
7107    static char FuncName[]={"SUMA_whichTri"};
7108    int IncTri_E1[100], IncTri_E2[100], N_IncTri_E1 = 0,
7109        N_IncTri_E2 = 0, i, j, Tri= -1;
7110    SUMA_Boolean Found = NOPE;
7111 
7112    if (IOtrace) SUMA_ENTRY;
7113 
7114    Tri = -1;
7115    /* find incident triangles to n1-n2 edge */
7116    if (!SUMA_Get_Incident(n1, n2, EL, IncTri_E1, &N_IncTri_E1, IOtrace, quiet)) {
7117       if (!quiet) fprintf (SUMA_STDERR,
7118                "Error %s: Failed in SUMA_Get_Incident for nodes A B %d %d.\n",
7119                FuncName, n1, n2);
7120    } else if (!SUMA_Get_Incident(n1, n3, EL,
7121                                  IncTri_E2, &N_IncTri_E2, IOtrace, quiet)) {
7122       /* find incident triangles to n1-n3 edge */
7123       if (!quiet) fprintf (SUMA_STDERR,
7124                "Error %s: Failed in SUMA_Get_Incident for nodes A C %d %d.\n",
7125                FuncName, n1, n3);
7126    } else if (N_IncTri_E1 > 99 || N_IncTri_E2 > 99 ) {
7127       /* check that we did not go overboard */
7128       fprintf (SUMA_STDERR,"Error %s: Exceeded preallocated space.\n", FuncName);
7129    } else {
7130       /* find triangle incident to both edges */
7131       i=0;
7132       Found = NOPE;
7133       while (i < N_IncTri_E1 && !Found) {
7134          j = 0;
7135          while (j < N_IncTri_E2 && !Found) {
7136             if (IncTri_E2[j] == IncTri_E1[i]) {
7137                Found = YUP;
7138                Tri = IncTri_E2[j];
7139             }
7140             ++j;
7141          }
7142          ++i;
7143       }
7144    }
7145    if (IOtrace) { SUMA_RETURN (Tri); }
7146    else return(Tri);
7147 }
7148 
SUMA_whichTri_e(SUMA_EDGE_LIST * EL,int E1,int E2,int IOtrace,byte quiet)7149 int SUMA_whichTri_e (SUMA_EDGE_LIST * EL, int E1, int E2, int IOtrace,
7150                      byte quiet)
7151 {
7152    static char FuncName[]={"SUMA_whichTri_e"};
7153    int IncTri_E1[100], IncTri_E2[100], N_IncTri_E1 = 0,
7154        N_IncTri_E2 = 0, i, j, Tri= -1;
7155    int n1, n2, n3;
7156    SUMA_Boolean Found = NOPE;
7157 
7158    if (IOtrace) SUMA_ENTRY;
7159 
7160    n1 = EL->EL[E1][0];
7161    n2 = EL->EL[E1][1];
7162    n3 = EL->EL[E2][0];
7163    if (n3 == n2 || n3 == n1) n3 = EL->EL[E2][1];
7164    if (n3 == n2 || n3 == n1) {
7165       if (IOtrace) { SUMA_RETURN (Tri); }
7166       else return(Tri);
7167    }
7168 
7169    Tri = -1;
7170    /* find incident triangles to n1-n2 edge */
7171    if (!SUMA_Get_Incident(n1, n2, EL, IncTri_E1, &N_IncTri_E1, IOtrace, quiet)) {
7172       if (!quiet)
7173          fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_Get_Incident.\n",
7174                   FuncName);
7175    } else if (!SUMA_Get_Incident(n1, n3, EL,
7176                                  IncTri_E2, &N_IncTri_E2, IOtrace, quiet)) {
7177       /* find incident triangles to n1-n3 edge */
7178       if (!quiet)
7179          fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_Get_Incident.\n",
7180                   FuncName);
7181    } else if (N_IncTri_E1 > 99 || N_IncTri_E2 > 99 ) {
7182       /* check that we did not go overboard */
7183       fprintf (SUMA_STDERR,"Error %s: Exceeded preallocated space.\n", FuncName);
7184    } else {
7185       /* find triangle incident to both edges */
7186       i=0;
7187       Found = NOPE;
7188       while (i < N_IncTri_E1 && !Found) {
7189          j = 0;
7190          while (j < N_IncTri_E2 && !Found) {
7191             if (IncTri_E2[j] == IncTri_E1[i]) {
7192                Found = YUP;
7193                Tri = IncTri_E2[j];
7194             }
7195             ++j;
7196          }
7197          ++i;
7198       }
7199    }
7200    if (IOtrace) { SUMA_RETURN (Tri); }
7201    else return(Tri);
7202 }
7203 
7204 /*!
7205    \brief   This function determines how many nodes two triangles share.
7206    N_cn = SUMA_isTriLinked (T, t, cn);
7207    \param T (int *) a b c nodes forming the reference triangle
7208    \param t (int *) d c b (or whatever combination you choose, c b d for example)
7209    \param cn (int *) vector of three elements to contain the indices of nodes
7210          common to the two triangles when the function returns.
7211    \return N_cn (int) number of common nodes. Values in cn beyond N_cn - 1 are undefined.
7212 
7213 */
SUMA_isTriLinked(int * T,int * t,int * cn)7214 int SUMA_isTriLinked (int*T, int *t, int *cn)
7215 {
7216    static char FuncName[]={"SUMA_isTriLinked"};
7217    int ic, in;
7218 
7219    SUMA_ENTRY;
7220 
7221    ic = 0;   /* common node index*/
7222    in = 0; /* number of node searched in T */
7223    while (ic < 2 && in < 3) {
7224       if (t[0] == T[in]) {
7225          cn[ic] = t[0];
7226          ++ic;
7227       }else {
7228          if (t[1] == T[in]) {
7229             cn[ic] = t[1];
7230             ++ic;
7231          }else {
7232             if (t[2] == T[in]) {
7233                cn[ic] = t[2];
7234                ++ic;
7235             }
7236          }
7237       }
7238       ++in; /* look for next node */
7239    }
7240 
7241    SUMA_RETURN (ic);
7242 }
7243 
7244 /*!
7245    This function compares the winding of two triangles, determines their consistency
7246    and corrects it.
7247 
7248    \param T (int *) a b c nodes forming the reference triangle
7249    \param t (int *) d c b (or whatever combination you choose, c b d for example)
7250    \return 1: Consistent
7251        -1: Inconsisten
7252         0: less than 2 nodes shared
7253 */
SUMA_isConsistent(int * T,int * t)7254 int SUMA_isConsistent (int *T, int *t)
7255 {
7256    static char FuncName[]={"SUMA_isConsistent"};
7257    static int ic, in, LOC[2], loc[2], d, D;
7258 
7259    SUMA_ENTRY;
7260 
7261    ic = 0;   /* common node index*/
7262    in = 0; /* number of node searched in T */
7263    while (ic < 2 && in < 3) {
7264       if (t[0] == T[in]) {
7265          LOC[ic] = in; /* location of icth node in 1st triangle */
7266          loc[ic] = 0; /* location of icth node in 2nt triangle */
7267          ++ic;
7268       }else {
7269          if (t[1] == T[in]) {
7270             LOC[ic] = in; /* location of icth node in 1st triangle */
7271             loc[ic] = 1; /* location of icth node in 2nt triangle */
7272             ++ic;
7273          }else {
7274             if (t[2] == T[in]) {
7275                LOC[ic] = in; /* location of icth node in 1st triangle */
7276                loc[ic] = 2; /* location of icth node in 2nt triangle */
7277                ++ic;
7278             }
7279          }
7280       }
7281       ++in; /* look for next node */
7282    }
7283    if (ic != 2) {
7284       fprintf(SUMA_STDERR,"Error %s: Triangles do not share 2 nodes.\n", FuncName);
7285       SUMA_RETURN (0);
7286    }
7287 
7288    D = (LOC[1]-LOC[0]);
7289    d = (loc[1]-loc[0]);
7290    /*fprintf(SUMA_STDERR,"%s: T[%d, %d, %d], t[%d, %d, %d]\n", FuncName, T[0], T[1], T[2], t[0], t[1], t[2]);
7291    fprintf(SUMA_STDERR,"%s: LOC[0,1]=[%d, %d], loc[0,1] = [%d, %d]\n", FuncName, LOC[0], LOC[1], loc[0], loc[1]);
7292    fprintf(SUMA_STDERR,"%s: D = %d, d = %d\n", FuncName, D, d);*/
7293    if (d > 1 || d < -1) d = - d /2 ;
7294    if (D > 1 || D < -1) D = - D /2 ;
7295    /*fprintf(SUMA_STDERR,"%s: D = %d, d = %d\n", FuncName, D, d);*/
7296 
7297    if (d != D) {
7298       /*fprintf(SUMA_STDERR,"%s: Triangles consistent.\n", FuncName);*/
7299       SUMA_RETURN (1);
7300    }
7301 
7302 
7303    /*fprintf(SUMA_STDERR,"%s: Triangles NOT consistent.\n", FuncName);*/
7304    in = t[0];
7305    t[0] = t[2];
7306    t[2] = in;
7307    SUMA_RETURN (-1);
7308 }
7309 
7310 
7311 /*!
7312    This function returns the best available seed, for use in SUMA_Take_A_Hike
7313    The first time you call the function, the seed is a triangle with three
7314    neighbors. The next time you call, the seed is a triangle that was visited by
7315    SUMA_Take_A_Hike and has preferably two neighbors left unvisited.
7316 
7317 */
SUMA_Next_Best_Seed(SUMA_FACESET_FIRST_EDGE_NEIGHB * SFFN,int * visited,int N_FL)7318 int SUMA_Next_Best_Seed (SUMA_FACESET_FIRST_EDGE_NEIGHB *SFFN, int * visited, int N_FL)
7319 {
7320    static int entry = 0, seed=-1;
7321    int Found1 = -1, Found2 = -1, i, N_NotVisNeighb, itry;
7322    static char FuncName[]={"SUMA_Next_Best_Seed"};
7323 
7324    SUMA_ENTRY;
7325 
7326    if (!entry) { /* entry = 0 */
7327       for (i=0; i < N_FL; ++i) {
7328          if (SFFN->N_Neighb[i] == 3) {
7329             seed = i; ++entry; SUMA_RETURN(seed);
7330          }
7331          if (SFFN->N_Neighb[i] == 2) Found2 = i;
7332          if (SFFN->N_Neighb[i] == 1) Found1 = i;
7333       }
7334 
7335       if (Found2 > 0) {
7336          ++entry;
7337          SUMA_RETURN (Found2);
7338       }
7339 
7340       if (Found1 > 0) {
7341          ++entry;
7342          SUMA_RETURN (Found1);
7343       }
7344 
7345       SUMA_RETURN (-1); /* No seeds found */
7346    }/* entry = 0 */
7347    else {/* entry > 0 */
7348       for (i=0; i < N_FL; ++i) {
7349          if (visited[i]) { /* a candidate */
7350             /* count the number of unvisited neighbors */
7351             N_NotVisNeighb = 0;
7352             itry = 0;
7353             while (itry < SFFN->N_Neighb[i]) {
7354                if (!visited[SFFN->FirstNeighb[i][itry]]) ++N_NotVisNeighb;
7355                ++itry;
7356             }
7357             if (N_NotVisNeighb == 2) {
7358                seed = i; ++entry; SUMA_RETURN (seed);
7359             }
7360             if (N_NotVisNeighb == 1) {
7361                Found1 = i;
7362             }
7363          } /* a candidate */
7364       }
7365       if (Found1 > 0) {
7366          ++entry;
7367          SUMA_RETURN (Found1);
7368       }
7369       SUMA_RETURN (-1); /* No seeds found */
7370    }/* entry > 0 */
7371 }
7372 
7373 /*!
7374    This function starts at one triangle and proceeds from edge to edge without going through the same triangle twice.
7375    The very first time you call the function, the seed is at a triangle that has not been visited yet.
7376    The next calls require that the seed triangle is a visited one.
7377    It is very unlikely to visit all triangles with one seed. So, the function needs to be called multiple
7378    times with different seeds and because of that, it is very slow.
7379    When a triangle is visited, it's winding order is compared the the precursor triangle. If need be, the order is
7380    corrected.
7381 
7382    \sa SUMA_Next_Best_Seed
7383    \sa SUMA_isConsistent
7384 */
SUMA_Take_A_Hike(SUMA_FACESET_FIRST_EDGE_NEIGHB * SFFN,int * visited,int * N_visited,int * Consistent,int * FL,int N_FL,int seed)7385 SUMA_TAKE_A_HIKE SUMA_Take_A_Hike (SUMA_FACESET_FIRST_EDGE_NEIGHB *SFFN, int *visited, int *N_visited, int *Consistent, int *FL, int N_FL, int seed)
7386 {
7387    static char FuncName[]={"SUMA_Take_A_Hike"};
7388    int NotFound, itry, curface, nxtface, ipcur, ipnxt, NP;
7389    static int entry=0;
7390 
7391    SUMA_ENTRY;
7392    NP = 3;
7393    curface = seed;
7394    if (!visited[curface]) { /* a new visit this should only happen on the first call */
7395       if (!entry) {
7396          *N_visited += 1;
7397          visited[curface] = 1;
7398          Consistent[curface] = 1;
7399          /*fprintf (SUMA_STDERR, "%s: visited %d\n", FuncName, curface);*/
7400       }else {
7401          fprintf (SUMA_STDERR, "Error %s: You should not send unvisited seeds, except at the very first call.\n", FuncName);
7402          SUMA_RETURN (SUMA_BAD_SEED);
7403       }
7404    }
7405    if (SFFN->N_Neighb[curface] == 0) {
7406       SUMA_RETURN (SUMA_NO_NEIGHB);
7407    }
7408    ++entry;
7409 
7410    while (*N_visited <= N_FL) {
7411       /* try the neighbors */
7412       itry = 0; /* index into neighbors */
7413       NotFound = 1; /* now new unvisited neighbor found */
7414       do {
7415          nxtface = SFFN->FirstNeighb[curface][itry];
7416          if (visited[nxtface]) {
7417             /* already visited try another neighbor */
7418             ++itry;
7419          }else {
7420             if (SFFN->N_Neighb[nxtface] == 1) {
7421                /* that's a loner, do it and continue with the neighbors */
7422                /*fprintf (SUMA_STDERR, "%s: LONER!\n", FuncName);*/
7423                visited[nxtface] = 1;
7424                Consistent[nxtface] = SUMA_isConsistent (&(FL[curface*NP]), &(FL[nxtface*NP]));
7425                /*fprintf (SUMA_STDERR, "%s: visited %d\n", FuncName, nxtface);*/
7426                *N_visited = *N_visited+1;
7427                ++itry;
7428             } else {
7429                /* that's a good one to follow */
7430                Consistent[nxtface] = SUMA_isConsistent (&(FL[curface*NP]), &(FL[nxtface*NP]));
7431                visited[nxtface] = 1;
7432                curface = nxtface;
7433                /*fprintf (SUMA_STDERR, "%s: visited %d\n", FuncName, curface);*/
7434                *N_visited = *N_visited+1;
7435                NotFound = 0;
7436                itry = 100;
7437             }
7438          }
7439       } while (itry < SFFN->N_Neighb[curface]) ;
7440 
7441       if (NotFound) { /* no more useful neighbors on this walk, get outa here */
7442          /*fprintf (SUMA_STDERR, "%s:  N_visited = %d, N_tot = %d\n", FuncName, *N_visited, N_FL);*/
7443          SUMA_RETURN (SUMA_NO_MORE_TO_VISIT);
7444       }
7445 
7446    }
7447 
7448    SUMA_RETURN (SUMA_VISITED_ALL);
7449 }
7450 
7451 /*!
7452    SUMA_Show_Edge_List (SEL, File *Out)
7453    \param SEL (SUMA_EDGE_LIST *)
7454    \param Out (FILE *) file pointer or stdout if Out is NULL
7455 */
SUMA_Show_Edge_List(SUMA_EDGE_LIST * EL,FILE * Out)7456 void SUMA_Show_Edge_List (SUMA_EDGE_LIST *EL, FILE *Out)
7457 {
7458    static char FuncName[]={"SUMA_Show_Edge_List"};
7459    int i;
7460 
7461    SUMA_ENTRY;
7462 
7463    if (Out == NULL) Out = stdout;
7464 
7465    fprintf(Out,"\nEL contents:\n");
7466    if (EL->idcode_str) fprintf(Out,"IDcode: %s\n", EL->idcode_str);
7467    else fprintf(Out,"IDcode: NULL\n");
7468 
7469    fprintf(Out,"Average InterNodal Distance: %f\n"
7470                "EL->EL = %p, EL->ELps=%p, EL->Le=%p\n",
7471                EL->AvgLe, EL->EL, EL->ELps, EL->Le);
7472    fprintf(Out,"i-\t[EL[i][0] EL[i][1]]\t"
7473                "[ELps[i][0] ELps[i][1] ELps[i][2]]\tLe[i]\n");
7474    for (i=0; i < EL->N_EL; ++i) {
7475       fprintf(Out,"%d-\t[%d %d]\t",
7476                i, EL->EL[i][0], EL->EL[i][1]);
7477       fprintf(Out,"[%d %d %d]\t",
7478                EL->ELps[i][0], EL->ELps[i][1], EL->ELps[i][2]);
7479       fprintf(Out,"%f\t", EL->Le[i]);
7480       fprintf(Out,"\n");
7481    }
7482    fprintf(Out,"\nTriLimb contents:\n");
7483    fprintf(Out,"ti-\t[Edge1 Edge2 Edge3]\n");
7484    for (i=0; i < EL->N_EL/3; ++i) {
7485       fprintf(Out,"t%d-\t[%d %d %d]\n",
7486          i, EL->Tri_limb[i][0], EL->Tri_limb[i][1],EL->Tri_limb[i][2]);
7487    }
7488 
7489    SUMA_RETURNe;
7490 }
7491 
7492 /*!
7493    SUMA_free_Edge_List (SEL)
7494    \param SEL (SUMA_EDGE_LIST *)
7495 
7496 */
SUMA_free_Edge_List(SUMA_EDGE_LIST * SEL)7497 void SUMA_free_Edge_List (SUMA_EDGE_LIST *SEL)
7498 {
7499    static char FuncName[]={"SUMA_free_Edge_List"};
7500 
7501    SUMA_ENTRY;
7502    if (!SEL) SUMA_RETURNe;
7503    if (SEL->N_links) {
7504       SEL = (SUMA_EDGE_LIST*)SUMA_UnlinkFromPointer((void *)SEL);
7505       SUMA_RETURNe;
7506    }
7507 
7508    if (SEL->EL) SUMA_free2D((char **)SEL->EL, SEL->N_EL);
7509    if (SEL->ELloc) SUMA_free(SEL->ELloc);
7510    if (SEL->ELps) SUMA_free2D((char **)SEL->ELps, SEL->N_EL);
7511    if (SEL->Tri_limb) SUMA_free2D((char **)SEL->Tri_limb, SEL->N_EL/3);
7512    if (SEL->idcode_str) SUMA_free(SEL->idcode_str);
7513    if (SEL->Le) SUMA_free(SEL->Le);
7514    if (SEL) SUMA_free(SEL);
7515    SUMA_RETURNe;
7516 }
7517 
7518 /*!
7519  * call engine with debug flag set                    20 Oct 2003 [rickr]
7520 */
SUMA_Make_Edge_List(int * FL,int N_FL,int N_Node,float * NodeList,char * ownerid)7521 SUMA_EDGE_LIST * SUMA_Make_Edge_List (int *FL, int N_FL, int N_Node, float *NodeList, char *ownerid)
7522 {
7523    static char FuncName[]={"SUMA_Make_Edge_List"};
7524 
7525    SUMA_ENTRY;
7526 
7527    SUMA_RETURN(SUMA_Make_Edge_List_eng(FL, N_FL, N_Node, NodeList, 1, ownerid));
7528 }
7529 
7530 
7531 /* - appended _eng to name of engine function          20 Oct 2003 [rickr]
7532  * - added debug parameter
7533  * - print non-error info when debug flag is set
7534 */
7535 /*!
7536    ans = SUMA_Make_Edge_List_eng (FL, N_FL, N_Node, NodeList, debug);
7537 
7538    This function creates a list of all the edges making up the FaceSets
7539    \param FL (int *) FaceSetList vector (was matrix, prior to SUMA 1.2 ( N_FL x 3)
7540    \param N_FL (int) number of facesets (triangles) in FL
7541    \param N_Node (int) number of nodes forming the mesh
7542    \param NodeList (float *) vector containing XYZ of each node. This was added to compute
7543                              the length of each edge.
7544    \param debug (int) flag to request extra output
7545    \ret ans (SUMA_EDGE_LIST *) NULL/failure or the following fields
7546        EL (int **) sorted edge list
7547        ELps (int **) edge list properties
7548        Le (float *) length of each edge in EL. Since EL can have multiple edges,
7549                     which are shared by different triangles, Le would also have
7550                     duplicate length values. This is tolerated for efficiency of
7551                     indexing.
7552       N_EL    (int)  Number of edges
7553       see SUMA_define.h for more info
7554 
7555    to free    ans, use SUMA_free_Edge_List
7556 
7557    DO NOT MODIFY WHAT THIS FUNCTION RETURNS without serious thought.
7558    Complicated functions depend on it.
7559 */
SUMA_Make_Edge_List_eng(int * FL,int N_FL,int N_Node,float * NodeList,int debug,char * ownerid)7560 SUMA_EDGE_LIST * SUMA_Make_Edge_List_eng (
7561                      int *FL, int N_FL, int N_Node,
7562                      float *NodeList, int debug, char *ownerid)
7563 {
7564    static char FuncName[]={"SUMA_Make_Edge_List_eng"};
7565    int i, ie, ip, *isort_EL=NULL, **ELp=NULL, lu, ht,
7566        *iTri_limb=NULL, icur, in1, in2, N_Node_Alloc;
7567    float dx, dy, dz;
7568    SUMA_EDGE_LIST *SEL=NULL;
7569    SUMA_Boolean LocalHead = NOPE;
7570 
7571    SUMA_ENTRY;
7572 
7573    if (debug > 1) LocalHead = YUP;
7574    if (!FL) {
7575       SUMA_SL_Err("Null FL");
7576       SUMA_RETURN(NULL);
7577    }
7578    if (LocalHead) {
7579       fprintf(SUMA_STDERR,"%s: %d Facesets to work with.\n", FuncName, N_FL);
7580    }
7581    if (!N_FL) {
7582       SUMA_SL_Err("zero N_FL");
7583       SUMA_RETURN(NULL);
7584    }
7585    /* allocate and form the List of edges */
7586    SUMA_LH("New SEL next");
7587    SEL = (SUMA_EDGE_LIST *) SUMA_calloc(1,sizeof(SUMA_EDGE_LIST));
7588    SUMA_LH("New ID next");
7589    SEL->idcode_str = NULL;
7590    SUMA_NEW_ID(SEL->idcode_str, NULL);
7591    SEL->N_links = 0;
7592    SUMA_LH("Ownerid next");
7593    if (ownerid) sprintf(SEL->owner_id, "%s", ownerid);
7594    else SEL->owner_id[0] = '\0';
7595    SEL->LinkedPtrType = SUMA_LINKED_OVERLAY_TYPE;
7596    SEL->do_type = not_DO_type;
7597 
7598    N_Node_Alloc = FL[0];
7599    for (i=1; i<3*N_FL; ++i) if (N_Node_Alloc < FL[i]) N_Node_Alloc=FL[i];
7600    ++N_Node_Alloc;
7601 
7602    SEL->AvgLe = 0.0;
7603    SEL->N_EL = 3 * N_FL;
7604    SUMA_LHv("N-EL = %d\n", SEL->N_EL);
7605    SEL->EL = (int **) SUMA_allocate2D (SEL->N_EL, 2, sizeof(int));
7606                                           /* edge list */
7607    SEL->ELloc = (int *)SUMA_calloc(N_Node_Alloc, sizeof(int));
7608    SEL->N_ELloc = N_Node_Alloc;
7609 
7610    SEL->Le = (float *) SUMA_calloc (SEL->N_EL, sizeof(float));
7611                                           /* length of each edge */
7612    ELp = (int **) SUMA_allocate2D (SEL->N_EL, 2, sizeof(int));
7613                           /* edge property list */
7614             /* 1st column, 1 = is flipped from orientation in triangle,
7615                            -1 as present in triangle
7616                2nd column, index of triangle (FaceSet) that edge is a part of */
7617    SEL->ELps = (int **) SUMA_allocate2D (SEL->N_EL, 3, sizeof(int));
7618                            /*sorted edge property list */
7619    /*fprintf(SUMA_STDERR, "%s: SEL->NEL %d\n", FuncName, SEL->N_EL/3);*/
7620 
7621    SEL->Tri_limb = (int **) SUMA_allocate2D (SEL->N_EL/3, 3, sizeof(int));
7622    iTri_limb = (int *)SUMA_calloc (SEL->N_EL/3,sizeof(int));
7623 
7624    if (SEL == NULL || SEL->EL == NULL || ELp == NULL || SEL->ELps == NULL ||
7625        SEL->Tri_limb == NULL || iTri_limb== NULL || SEL->ELloc == NULL) {
7626       fprintf(SUMA_STDERR, "Error %s: Failed to allocate for EL, ELp.\n",
7627                            FuncName);
7628       SUMA_RETURN (NULL);
7629    }
7630 
7631    /* form the edge list */
7632    SUMA_LH("Forming Edge List...\n");
7633    for (i=0; i< N_FL; ++i) {/* begin, form edge list */
7634       /* first edge, 0->1*/
7635       ie = 3*i;
7636       ip = 3*i;
7637       if (FL[ip] > FL[ip+1]) {
7638          /* flip it, to make sorting easier */
7639          SEL->EL[ie][0] = FL[ip+1];
7640          SEL->EL[ie][1] = FL[ip];
7641          /* store parameters */
7642          ELp[ie][0] = 1; /* flip happened */
7643       } else {
7644          /* no flip necessary */
7645          SEL->EL[ie][0] = FL[ip];
7646          SEL->EL[ie][1] = FL[ip+1];
7647          ELp[ie][0] = -1; /* NO flip happened */
7648       }
7649       ELp[ie][1] = i; /* FaceSetMember */
7650 
7651       /* second edge, 1->2*/
7652       ie += 1;
7653       if (FL[ip+1] > FL[ip+2]) {
7654          /* flip it, to make sorting easier */
7655          SEL->EL[ie][0] = FL[ip+2];
7656          SEL->EL[ie][1] = FL[ip+1];
7657          /* store parameters */
7658          ELp[ie][0] = 1; /* flip happened */
7659       } else {
7660          /* no flip necessary */
7661          SEL->EL[ie][0] = FL[ip+1];
7662          SEL->EL[ie][1] = FL[ip+2];
7663          ELp[ie][0] = -1; /* NO flip happened */
7664       }
7665       ELp[ie][1] = i; /* FaceSetMember */
7666 
7667       /* third edge, 2->0*/
7668       ie += 1;
7669       if (FL[ip+2] > FL[ip]) {
7670          /* flip it, to make sorting easier */
7671          SEL->EL[ie][0] = FL[ip];
7672          SEL->EL[ie][1] = FL[ip+2];
7673          /* store parameters */
7674          ELp[ie][0] = 1; /* flip happened */
7675       } else {
7676          /* no flip necessary */
7677          SEL->EL[ie][0] = FL[ip+2];
7678          SEL->EL[ie][1] = FL[ip];
7679          ELp[ie][0] = -1; /* NO flip happened */
7680       }
7681       ELp[ie][1] = i; /* FaceSetMember */
7682 
7683    }/* end, form edge list */
7684    SUMA_LH("Edge list done.");
7685 
7686 
7687    #if 0
7688    if (LocalHead) {
7689       fprintf(SUMA_STDERR,"%s: Node1 Node2 | FlipVal Triangle\n", FuncName);
7690       for (i=0; i < SEL->N_EL; ++i) {
7691          fprintf (SUMA_STDERR,
7692                   "%d %d | %d %d\n",
7693                   SEL->EL[i][0], SEL->EL[i][1], ELp[i][0], ELp[i][1]);
7694       }
7695    }
7696    #endif
7697 
7698    /* now sort the Edge list */
7699    SUMA_LH("Sorting edge list...");
7700    isort_EL = SUMA_dqsortrow (SEL->EL, SEL->N_EL, 2);
7701 
7702    /* reorder ELp to match sorted EL */
7703    for (i=0; i< SEL->N_EL; ++i) {
7704       SEL->ELps[i][0] = ELp[isort_EL[i]][0];
7705       SEL->ELps[i][1] = ELp[isort_EL[i]][1];
7706    }
7707    SUMA_LH("Sorting edge list done.");
7708 
7709    if (isort_EL) SUMA_free(isort_EL);
7710    isort_EL = NULL;
7711 
7712 
7713    #if 1
7714    if (LocalHead) {
7715       fprintf(SUMA_STDERR,"%s: Node1 Node2 | FlipVal Triangle\n", FuncName);
7716       for (i=0; i < SEL->N_EL; ++i) {
7717          fprintf (SUMA_STDERR,
7718                   "%d %d | %d %d\n",
7719                   SEL->EL[i][0], SEL->EL[i][1],
7720                   SEL->ELps[i][0], SEL->ELps[i][1]);
7721       }
7722    }
7723    #endif
7724 
7725    /* calculate the length of each edge */
7726    SEL->AvgLe = 0.0;
7727    if (NodeList) {
7728       SUMA_LHv("Calculating average length of %d edges\n", SEL->N_EL);
7729       for (ie=0; ie < SEL->N_EL; ++ie) {
7730          in1 = 3 * SEL->EL[ie][0]; in2 = 3 * SEL->EL[ie][1];
7731          dx = (NodeList[in2] - NodeList[in1]);
7732          dy = (NodeList[in2+1] - NodeList[in1+1]);
7733          dz = (NodeList[in2+2] - NodeList[in1+2]);
7734          SEL->Le[ie] = (float) sqrt (  dx * dx + dy * dy + dz * dz );
7735          SEL->AvgLe += SEL->Le[ie];
7736       }
7737       SEL->AvgLe = SEL->AvgLe / (float)SEL->N_EL;
7738          /* This is an approximate average
7739                    lenght, since some edges may counted more than others */
7740       SUMA_LHv("Average segment length of %f\n", SEL->AvgLe);
7741    } else {
7742       SUMA_LH("Null NodeList, no distances computed");
7743    }
7744    /* free unsorted ELp */
7745    if (ELp) SUMA_free2D((char **)ELp, SEL->N_EL);
7746    ELp = NULL;
7747 
7748    SEL->max_N_Hosts = -1;
7749    SEL->min_N_Hosts = 1000;
7750 
7751    /* do a search for some funky stuff */
7752    SUMA_LH("Searching SEL for funky stuff");
7753    SEL->N_Distinct_Edges = 0;
7754    i=0;
7755    while (i < SEL->N_EL) {
7756       /* store the location of this edge for the triangle hosting it */
7757       ht = SEL->ELps[i][1]; /* host triangle index */
7758       SEL->Tri_limb[ht][iTri_limb[ht]] = i;
7759       iTri_limb[ht] += 1;
7760       SEL->N_Distinct_Edges += 1; /* a new edge */
7761       SEL->ELps[i][2] = 1; /* number of triangles hosting edge */
7762       lu = 1;
7763       while (i+lu < SEL->N_EL) {
7764          if (  SEL->EL[i+lu][0] == SEL->EL[i][0] &&
7765                SEL->EL[i+lu][1] == SEL->EL[i][1]) {/* found matching edge */
7766             SEL->ELps[i][2] += 1; /* number of triangles hosting edge */
7767             SEL->ELps[i+lu][2] = -1;
7768                /* flag to mean that this edge is a duplicte in the list */
7769 
7770             /* store the location of this edge for the triangle hosting it */
7771             ht = SEL->ELps[i+lu][1]; /* host triangle index */
7772             SEL->Tri_limb[ht][iTri_limb[ht]] = i+lu;
7773             iTri_limb[ht] += 1;
7774 
7775             ++lu;
7776          }else break;
7777 
7778       }
7779       if (SEL->max_N_Hosts < SEL->ELps[i][2]) SEL->max_N_Hosts = SEL->ELps[i][2];
7780       if (SEL->min_N_Hosts > SEL->ELps[i][2]) SEL->min_N_Hosts = SEL->ELps[i][2];
7781       i += lu;
7782    }
7783    SUMA_LH("Do adjust your radio.\nNo funk here");
7784 
7785    if (SEL->max_N_Hosts == -1 || SEL->min_N_Hosts == 1000) {
7786       SUMA_SL_Crit("Bad bad news.\n"
7787                    "Could not calculate max_N_Hosts &/| min_N_Hosts");
7788       SUMA_free_Edge_List(SEL); SEL = NULL;
7789       SUMA_RETURN(SEL);
7790    }
7791 
7792    {
7793       int winedonce = 0;
7794       if (debug && (SEL->min_N_Hosts == 1 || SEL->max_N_Hosts == 1)) {
7795          winedonce = 1;
7796          SUMA_S_Notev(
7797                   "Min/Max number of edge hosting triangles: [%d/%d] \n"
7798                   " You have edges that form a border in the surface.\n\n",
7799                   SEL->min_N_Hosts, SEL->max_N_Hosts);
7800       }
7801       if (SEL->min_N_Hosts > 2 || SEL->max_N_Hosts > 2) {
7802          winedonce = 1;
7803          fprintf(SUMA_STDERR,
7804                   "Warning %s:\n"
7805                   "Min/Max number of edge hosting triangles: [%d/%d] \n",
7806                   FuncName, SEL->min_N_Hosts, SEL->max_N_Hosts);
7807          fprintf(SUMA_STDERR,
7808                   "Warning %s:\n"
7809                   " You have edges that belong to more than two triangles.\n"
7810                   " Bad for analysis assuming surface is a 2-manifold.\n",
7811                   FuncName);
7812          if (debug) {
7813             int iii=0;
7814             fprintf(SUMA_STDERR,
7815                      " These edges are formed by the following nodes:\n");
7816             for (iii = 0; iii < SEL->N_EL; ++iii) {
7817                if (SEL->ELps[iii][2] > 2)
7818                   fprintf (SUMA_STDERR,
7819                            " %d: Edge [%d %d] shared by %d triangles.\n",
7820                            iii+1, SEL->EL[iii][0],
7821                            SEL->EL[iii][1] , SEL->ELps[iii][2] );
7822             }
7823          }
7824       }
7825       if (debug && !winedonce && SEL->min_N_Hosts!=2 && SEL->max_N_Hosts != 2)
7826          fprintf( SUMA_STDERR,
7827                   "%s: Min/Max number of edge hosting triangles: [%d/%d] \n",
7828                   FuncName, SEL->min_N_Hosts, SEL->max_N_Hosts);
7829    }
7830    #if 0
7831       fprintf(SUMA_STDERR,
7832                "%s:(ELindex) Node1 Node2 | FlipVal Triangle N_hosts\n",
7833                FuncName);
7834       for (i=0; i < SEL->N_EL; ++i) {
7835          fprintf (SUMA_STDERR,
7836                   "(%d) %d %d | %d %d %d\n",
7837                   i, SEL->EL[i][0], SEL->EL[i][1],
7838                   SEL->ELps[i][0], SEL->ELps[i][1], SEL->ELps[i][2]);
7839       }
7840       fprintf(SUMA_STDERR,"%s:Tri_limb\n", FuncName);
7841       for (i=0; i < SEL->N_EL/3; ++i) {
7842          fprintf (SUMA_STDERR, "%d %d %d\n",
7843                   SEL->Tri_limb[i][0], SEL->Tri_limb[i][1], SEL->Tri_limb[i][2]);
7844       }
7845    #endif
7846 
7847    /* store where each node's listing begins
7848    ELloc is used to quickly find a certain edge in EL
7849    to find the edge formed by nodes na-nb
7850    find the minimum of na and nb (say it's nb)
7851    the first reference of an edge containing nb starts at EL(ELloc(nb),:)
7852    NOTE: ELloc contains an entry for each node in FaceSetList,
7853    except the largest node index since that's never in the
7854    first column of EL */
7855 
7856    SUMA_LH("storing locations ...");
7857    for (i=0; i < SEL->N_ELloc; ++i) SEL->ELloc[i] = -1;
7858    i = 0;
7859    icur = SEL->EL[0][0];
7860    SEL->ELloc[icur] = i;
7861    while (i < SEL->N_EL) {
7862       if (SEL->EL[i][0] != icur) {
7863          icur = SEL->EL[i][0];
7864          SEL->ELloc[icur] = i;
7865       }
7866       ++i;
7867    }
7868 
7869    if (iTri_limb) SUMA_free(iTri_limb); /* Thanks B. Argall */
7870    SUMA_LH("Done with storage, returning...\n");
7871 
7872    if (LocalHead) SUMA_Show_Edge_List(SEL,stderr);
7873 
7874    SUMA_RETURN (SEL);
7875 }
7876 
7877 /*!
7878    \brief finds the index of an edge in EL of an edge formed by nodes n1 n2 and belonging to triangle Tri
7879    eloc = SUMA_FindEdgeInTri (EL, int n1, int n2, int Tri);
7880    \param EL (SUMA_EDGE_LIST *) Pointer to edge list structure
7881    \param n1 (int) index of node 1
7882    \param n2 (int) index of node 2
7883    \param Tri (int) index of triangle containing the edge you are looking for
7884    \return eloc (int) index into EL of edge formed by nodes n1, n2 and belonging to Tri
7885             -1 if no edge is found.
7886 */
SUMA_FindEdgeInTri(SUMA_EDGE_LIST * EL,int n1,int n2,int Tri)7887 int SUMA_FindEdgeInTri (SUMA_EDGE_LIST *EL, int n1, int n2, int Tri)
7888 {
7889    static char FuncName[]={"SUMA_FindEdgeInTri"};
7890    int eloc;
7891 
7892    SUMA_ENTRY;
7893 
7894    /* make sure n1 is smallest*/
7895    if (n2 < n1) {
7896       eloc = n2;
7897       n2 = n1;
7898       n1 = eloc;
7899    }
7900 
7901    /* first location of edge starting with n1 */
7902    eloc = EL->ELloc[n1];
7903 
7904    /* from there on, look for first occurence of n2 and Tri for hosting triangle*/
7905    do {
7906       if (EL->EL[eloc][1] == n2 && EL->ELps[eloc][1] == Tri) SUMA_RETURN (eloc);
7907       ++eloc;
7908    } while (eloc < EL->N_EL && EL->EL[eloc][0] == n1);
7909 
7910    /* not found */
7911    SUMA_RETURN (-1);
7912 }
7913 
7914 
7915 /*!
7916    \brief finds the first occurence in EL of an edge formed by nodes n1 n2
7917    eloc = SUMA_FindEdge (EL, int n1, int n2);
7918    \param EL (SUMA_EDGE_LIST *) Pointer to edge list structure
7919    \param n1 (int) index of node 1
7920    \param n2 (int) index of node 2
7921    \return eloc (int) index into EL of first occurence of edge formed by nodes n1, n2
7922             -1 if no edge is found.
7923    \sa SUMA_FIND_EDGE macro
7924 */
SUMA_FindEdge(SUMA_EDGE_LIST * EL,int n1,int n2)7925 int SUMA_FindEdge (SUMA_EDGE_LIST *EL, int n1, int n2)
7926 {
7927    static char FuncName[]={"SUMA_FindEdge"};
7928    int eloc, done;
7929    SUMA_Boolean LocalHead = NOPE;
7930 
7931    SUMA_ENTRY;
7932 
7933    /* make sure n1 is smallest*/
7934    if (n2 < n1) {
7935       eloc = n2;
7936       n2 = n1;
7937       n1 = eloc;
7938    }
7939 
7940    /* first location of edge starting with n1 */
7941    if ((eloc = EL->ELloc[n1]) < 0) {
7942       SUMA_S_Err ("Edge location of n1 not found. WEIRD");
7943       SUMA_RETURN (-1);
7944    }
7945 
7946    /* from there on, look for first occurence of n2 */
7947    done = 0;
7948    do {
7949       /* if (LocalHead) fprintf (SUMA_STDERR,
7950                                  "%s: eloc %d, N_EL %d\n",
7951                                  FuncName, eloc, EL->N_EL);*/
7952       if (EL->EL[eloc][1] == n2) SUMA_RETURN (eloc);
7953       ++eloc;
7954       if (eloc < EL->N_EL) {
7955          if (EL->EL[eloc][0] != n1) done = 1;
7956       } else done = 1;
7957    } while (!done);
7958 
7959    /* not found */
7960    SUMA_RETURN (-1);
7961 }
7962 
7963 /*!
7964    \brief finds triangles incident to a node
7965    ans = SUMA_Get_NodeIncident(n1, SEL, Incident, N_Incident);
7966 
7967    \param n1 (int) node 1
7968    \param SO (SUMA_SurfaceObject *)
7969    \param Incident (int *) a pre-allocated vector where incident triangle indices will be stored.
7970                            MAKE SURE you allocate enough and when you call SUMA_Get_NodeIncident,
7971                            preset N_Incident to the maximum allowed.
7972    \param N_Incident (int *) pointer where the number of incident triangles is stored
7973 
7974    \ret ans (SUMA_Boolean) YUP/NOPE
7975 
7976    \sa SUMA_Make_Edge_List
7977    \sa SUMA_Get_Incident
7978 */
SUMA_Get_NodeIncident(int n1,SUMA_SurfaceObject * SO,int * Incident,int * N_Incident)7979 SUMA_Boolean SUMA_Get_NodeIncident( int n1, SUMA_SurfaceObject *SO,
7980                                     int *Incident, int *N_Incident)
7981 {
7982    static char FuncName[] = {"SUMA_Get_NodeIncident"};
7983    int i, n3, N_Neighb, N_max;
7984 
7985    SUMA_ENTRY;
7986 
7987    N_max = *N_Incident;
7988    if (N_max < 1 || N_max > 1000) { /* aribtrary upper limit, can be increased if necessary...*/
7989       SUMA_S_Err("Likely junk (< 0 or > 1000) sent in N_Incident!, Initialize properly");
7990       SUMA_RETURN(NOPE);
7991    }
7992    *N_Incident = 0;
7993 
7994    N_Neighb = SO->FN->N_Neighb[n1];
7995    if (N_Neighb < 3) {
7996       fprintf (SUMA_STDERR, "Warning %s: Node %d has less than 3 neighbors.\n", FuncName, n1);
7997       /* nothing found */
7998       SUMA_RETURN(YUP);
7999    }
8000 
8001    i = 0;
8002    while ((i < N_Neighb )) {
8003       if ( i+1 == N_Neighb) n3 = SO->FN->FirstNeighb[n1][0];
8004       else n3 = SO->FN->FirstNeighb[n1][i+1];
8005       if (*N_Incident < N_max) {
8006          if ((Incident[*N_Incident] = SUMA_whichTri (SO->EL, n1,
8007                                  SO->FN->FirstNeighb[n1][i], n3, 1, 0)) < 0) {
8008             fprintf (SUMA_STDERR,
8009                "Error %s: Triangle formed by nodes %d %d %d not found.\n",
8010                FuncName, n1, SO->FN->FirstNeighb[n1][i], n3);
8011             SUMA_RETURN(NOPE);
8012          }
8013          ++*N_Incident;
8014          ++i;
8015       } else {
8016          SUMA_S_Err( "More incident triangles than allocated for. "
8017                      "Increase your limit.\n");
8018          SUMA_RETURN(NOPE);
8019       }
8020    }
8021 
8022    SUMA_RETURN(YUP);
8023 }
8024 
8025 /*! \brief finds triangles incident to an edge
8026    ans = SUMA_Get_Incident( n1,  n2,  SEL, Incident, N_Incident, IOtrace, quiet);
8027 
8028    \param n1 (int) node 1
8029    \param n2 (int) node 2
8030    \param SEL (SUMA_EDGE_LIST *) Edge List structure
8031    \param Incident (int *) a pre-allocated vector where incident triangle
8032                      indices will be stored. MAKE SURE you allocate enough
8033    \param N_Incident (int *) pointer where the number of incident triangles
8034                      is stored
8035    \param IOtrace (int) if 1 then allows the use of SUMA_ENTRY and SUMA_RETURN
8036    \ret ans (SUMA_Boolean) YUP/NOPE
8037 
8038    \sa SUMA_Make_Edge_List
8039    \sa SUMA_Get_NodeIncident
8040 */
SUMA_Get_Incident(int n1,int n2,SUMA_EDGE_LIST * SEL,int * Incident,int * N_Incident,int IOtrace,byte quiet)8041 SUMA_Boolean SUMA_Get_Incident(int n1, int n2, SUMA_EDGE_LIST *SEL,
8042                                int *Incident, int *N_Incident,
8043                                int IOtrace, byte quiet)
8044 {
8045    static char FuncName[] = {"SUMA_Get_Incident"};
8046    int nt, in1, iseek, m_N_EL;
8047 
8048    if (IOtrace) SUMA_ENTRY;
8049 
8050    /*fprintf(SUMA_STDERR,"Entering %s: n1,n2 =%d,%d ...", FuncName,n1,n2);*/
8051    if (n1 > n2) {
8052       /*make the first node be the smallest */
8053       nt = n1;
8054       n1 = n2;
8055       n2 = nt;
8056    }
8057 
8058    if (n1 == n2) {
8059       if (!quiet) {
8060          SUMA_S_Errv("Identical nodes! %d %d\n", n1, n2);
8061       }
8062       if (IOtrace) { SUMA_RETURN(NOPE); }
8063       else return(NOPE);
8064    }
8065    /* find the location of the first edge with n1 */
8066    *N_Incident = 0;
8067    if (n1<SEL->N_ELloc) {
8068       if ((in1 = SEL->ELloc[n1]) < 0) {
8069          if (!quiet) {
8070             SUMA_S_Errv("Node %d is not in EL\n", n1);
8071          }
8072          if (IOtrace) { SUMA_RETURN(YUP); }
8073          else return(YUP);
8074       }
8075    } else {
8076       if (!quiet) {
8077          SUMA_S_Errv("Node %d is beyond ELloc's size of %d\n", n1, SEL->N_ELloc);
8078       }
8079       if (IOtrace) { SUMA_RETURN(YUP); }
8080       else return(YUP);
8081    }
8082    iseek = in1;
8083    m_N_EL = SEL->N_EL -1;
8084    /* fprintf(SUMA_STDERR,"%s: iseek = %d\n", FuncName, iseek); */
8085    while (SEL->EL[iseek][0] == n1) {
8086       if (SEL->EL[iseek][1] == n2) {
8087          Incident[*N_Incident] = SEL->ELps[iseek][1];
8088             /* store the faceset index containing the edge */
8089          *N_Incident = *N_Incident + 1;
8090       }
8091       ++iseek;
8092       if (iseek > m_N_EL) {
8093          if (!quiet && !*N_Incident) {
8094             SUMA_S_Warnv("No edge found for nodes %d and %d\n", n1, n2);
8095          }
8096          if (IOtrace) { SUMA_RETURN (YUP); }
8097          else return(YUP);
8098       }
8099 
8100    }
8101    if (!quiet && !*N_Incident) {
8102       SUMA_S_Warnv(  "No incident triangle found for edge simliar to %d\n"
8103                      "   and formed by nodes %d and %d\n", in1, n1, n2);
8104    }
8105    /*fprintf(SUMA_STDERR,"Leaving %s.\n", FuncName);*/
8106    if (IOtrace) { SUMA_RETURN(YUP); }
8107    else return(YUP);
8108 }
8109 
8110 /*!
8111    frees the dyamically allocated pointer of the type SUMA_FACESET_FIRST_EDGE_NEIGHB
8112    SUMA_free_FaceSet_Edge_Neighb (S)
8113    \param S (SUMA_FACESET_FIRST_EDGE_NEIGHB *)
8114 
8115    \sa SUMA_allocate_FaceSet_Edge_Neighb
8116 */
SUMA_free_FaceSet_Edge_Neighb(SUMA_FACESET_FIRST_EDGE_NEIGHB * S)8117 void SUMA_free_FaceSet_Edge_Neighb (SUMA_FACESET_FIRST_EDGE_NEIGHB * S)
8118 {
8119    static char FuncName[]={"SUMA_free_FaceSet_Edge_Neighb"};
8120 
8121    SUMA_ENTRY;
8122 
8123    if (S->FirstNeighb) SUMA_free2D((char **)S->FirstNeighb, S->N_FaceSet);
8124    if (S->N_Neighb) SUMA_free(S->N_Neighb);
8125    if (S) SUMA_free(S);
8126    SUMA_RETURNe;
8127 }
8128 
8129 /*! Allocate space for SUMA_FACESET_FIRST_EDGE_NEIGHB *
8130    S = SUMA_allocate_FaceSet_Edge_Neighb (N_FaceSet);
8131    \param N_FaceSet (int) Number of FaceSets to be searched
8132    \ret S (SUMA_FACESET_FIRST_EDGE_NEIGHB *)
8133    \sa SUMA_free_FaceSet_Edge_Neighb
8134 */
8135 
SUMA_allocate_FaceSet_Edge_Neighb(int N_FaceSet)8136 SUMA_FACESET_FIRST_EDGE_NEIGHB *SUMA_allocate_FaceSet_Edge_Neighb (int N_FaceSet)
8137 {
8138    static char FuncName[]={"SUMA_FACESET_FIRST_EDGE_NEIGHB"};
8139    SUMA_FACESET_FIRST_EDGE_NEIGHB *SFFN;
8140 
8141    SUMA_ENTRY;
8142 
8143    SFFN = SUMA_malloc(sizeof(SUMA_FACESET_FIRST_EDGE_NEIGHB));
8144    if (SFFN == NULL) {
8145       fprintf (SUMA_STDERR, "Error %s: Could not allocate for SFFN.\n", FuncName);
8146       SUMA_RETURN (NULL);
8147    }
8148 
8149    SFFN->FirstNeighb = (int **) SUMA_allocate2D(N_FaceSet, SUMA_MAX_FACESET_EDGE_NEIGHB, sizeof(int));
8150    SFFN->N_Neighb = (int *) SUMA_calloc (N_FaceSet, sizeof(int));
8151    if (SFFN->FirstNeighb == NULL || SFFN->N_Neighb == NULL) {
8152       fprintf (SUMA_STDERR, "Error %s: Could not allocate for FirstNeighb or N_Neighb.\n", FuncName);
8153       SUMA_RETURN (NULL);
8154    }
8155 
8156    SFFN->N_Neighb_max = -1; /* ridiculously low */
8157    SFFN->N_FaceSet = N_FaceSet;
8158    SFFN->N_Neighb_min = 100; /* ridiculously high */
8159    SUMA_RETURN (SFFN);
8160 }
8161 
8162 /*!
8163    returns the FaceSet neighbor list.
8164    Neighboring triangles share one edge
8165    SFEN = SUMA_FaceSet_Edge_Neighb (EL, ELp, N_EL);
8166 
8167    \param EL (int **) sorted edge list, output of SUMA_Make_Edge_List
8168    \param ELps (int **) accompanying properties matrix, output of SUMA_Make_Edge_List
8169    \param N_EL (int) number of edges. IT IS ASSUMED THAT N_FACES = N_EL/3
8170    \ret SFEN (SUMA_FACESET_FIRST_EDGE_NEIGHB *) structure containing the neighbor list
8171       see its typedef in SUMA_define.h for more info
8172       To free this pointer, make sure you use SUMA_free_FaceSet_Edge_Neighb first
8173 */
SUMA_FaceSet_Edge_Neighb(int ** EL,int ** ELps,int N_EL)8174 SUMA_FACESET_FIRST_EDGE_NEIGHB *SUMA_FaceSet_Edge_Neighb (int **EL, int **ELps, int N_EL)
8175 {
8176    static char FuncName[]={"SUMA_FaceSet_Edge_Neighb"};
8177    int i, i1, F0, F1, in0, in1;
8178    SUMA_FACESET_FIRST_EDGE_NEIGHB *SFFN;
8179 
8180    SUMA_ENTRY;
8181 
8182 
8183    SFFN = SUMA_allocate_FaceSet_Edge_Neighb(N_EL/3);
8184    if (SFFN == NULL) {
8185       fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_allocate_FaceSet_Edge_Neighb.\n", FuncName);
8186       SUMA_RETURN (NULL);
8187    }
8188 
8189    i = 0;
8190    while (i < N_EL-1) {
8191       i1 = i + 1;
8192       if (EL[i][0] != EL[i1][0] || EL[i][1] != EL[i1][1]) {
8193          /* edge is part of one triangle only, a cut edge */
8194          i += 1; /* move to next edge */
8195       } else {
8196          F0 = ELps[i][1]; F1 = ELps[i1][1];
8197          in0 = SFFN->N_Neighb[F0]; in1 = SFFN->N_Neighb[F1];
8198          if (in0 > SUMA_MAX_FACESET_EDGE_NEIGHB -1 || in1 > SUMA_MAX_FACESET_EDGE_NEIGHB -1) {
8199             fprintf (SUMA_STDERR, "Error %s: A faceset has more than three neighbors. Bad surface or non triangular mesh\n", FuncName);
8200             SUMA_RETURN (NULL);
8201          }
8202          SFFN->FirstNeighb[F0][in0] = F1;
8203          SFFN->FirstNeighb[F1][in1] = F0;
8204          SFFN->N_Neighb[F0] ++;
8205          SFFN->N_Neighb[F1] ++;
8206          if (SFFN->N_Neighb[F0] > SFFN->N_Neighb_max) {
8207             SFFN->N_Neighb_max = SFFN->N_Neighb[F0];
8208          }
8209          if (SFFN->N_Neighb[F1] > SFFN->N_Neighb_max) {
8210             SFFN->N_Neighb_max = SFFN->N_Neighb[F1];
8211          }
8212          if (SFFN->N_Neighb[F0] < SFFN->N_Neighb_min) {
8213             SFFN->N_Neighb_min = SFFN->N_Neighb[F0];
8214          }
8215          if (SFFN->N_Neighb[F1] < SFFN->N_Neighb_min) {
8216             SFFN->N_Neighb_min = SFFN->N_Neighb[F1];
8217          }
8218 
8219          i += 2;
8220       }
8221 
8222    }
8223 
8224    fprintf (SUMA_STDERR, "%s: Done with FaceSet neighbors.\nN_Neighb_max = %d, N_Neighb_min = %d.\n", FuncName, SFFN->N_Neighb_max, SFFN->N_Neighb_min);
8225    #if 0
8226    for (i=0; i< N_FL; ++i) {
8227       fprintf (SUMA_STDERR, "%s: Tri %d, %d neighbs = ", FuncName, i, SFFN->N_Neighb[i]);
8228       for (i1=0; i1<SFFN->N_Neighb[i]; ++i1) {
8229          fprintf (SUMA_STDERR, "%d, ", SFFN->FirstNeighb[i][i1]);
8230       }
8231       fprintf (SUMA_STDERR, "\n");
8232    }
8233    #endif
8234 
8235    SUMA_RETURN (SFFN);
8236 }
8237 
8238 /*!
8239    Makes sure the triangles in FaceSetList are of a consistent orientation.
8240 
8241    ans = SUMA_MakeConsistent (FaceSetList, N_FaceSet, SEL, detail, trouble)
8242 
8243    \param FaceSetList (int *) N_FaceSet x 3 vector (was matrix prior to SUMA 1.2)                               containing triangle definition
8244    \param N_FaceSet int
8245    \param SEL (SUMA_EDGE_LIST *) pointer Edgelist structure as output
8246                                  by SUMA_Make_Edge_List
8247    \param detail (int)  0: quiet, except for errors and warnings
8248                         1: report at end
8249                         2: LocalHead gets turned on
8250    \param trouble (int *): a flag that is set to 1 if the surface
8251                            had inconsistent mesh
8252                            or if the surface could not be fully traversed.
8253                            0 if all went well and the mesh looks good
8254                            (for the purposes of this function)
8255    \ret ans (SUMA_Boolean) YUP, NOPE
8256 
8257    \sa SUMA_Make_Edge_List
8258 
8259 */
SUMA_MakeConsistent(int * FL,int N_FL,SUMA_EDGE_LIST * SEL,int detail,int * trouble)8260 SUMA_Boolean SUMA_MakeConsistent (int *FL, int N_FL, SUMA_EDGE_LIST *SEL,
8261                                   int detail, int *trouble)
8262 {
8263    static char FuncName[]={"SUMA_MakeConsistent"};
8264    /* see for more documentation labbook NIH-2 test mesh  p61 */
8265    int i, it, NP, ip, N_flip=0, *isflip, *ischecked, ht0, ht1,
8266        NotConsistent, miss, miss_cur, N_iter, EdgeSeed, TriSeed, N_checked,
8267        N_bad=0;
8268    SUMA_FACESET_FIRST_EDGE_NEIGHB *SFFN;
8269    SUMA_Boolean LocalHead = NOPE;
8270 
8271    SUMA_ENTRY;
8272 
8273    if (detail > 1) LocalHead = YUP;
8274 
8275    if (!SEL || !FL) {
8276       SUMA_SL_Err("NULL input!");
8277       SUMA_RETURN (NOPE);
8278    }
8279 
8280    NP = 3;
8281    isflip = (int *)SUMA_calloc(SEL->N_EL/3, sizeof(int));
8282    ischecked = (int *)SUMA_calloc(SEL->N_EL/3, sizeof(int));
8283 
8284    if (isflip == NULL || ischecked == NULL ) {
8285       SUMA_S_Err("Failed to allocate for isflip");
8286       SUMA_RETURN (NOPE);
8287    }
8288 
8289 
8290    /* Now, go through the sorted edge list and flip what needs flipping*/
8291    N_iter = 0;
8292    miss = 0;
8293    miss_cur = SEL->N_EL;
8294    N_checked = 1;
8295    while (miss_cur != miss) {
8296       miss_cur = miss;
8297       miss = 0;
8298 
8299       /* both methods work just fine here */
8300       #if 0
8301          /*start with the first edge as an edge seed */
8302          EdgeSeed = 0;
8303          i=EdgeSeed;
8304          ht0 = SEL->ELps[i][1];
8305       #else
8306          /* start with the first edge of the seed triangle as an edge seed */
8307          TriSeed = 0;
8308          i = SEL->Tri_limb[TriSeed][0];
8309          ht0 = TriSeed;
8310       #endif
8311 
8312       ischecked[ht0] = 1;
8313       while (i < SEL->N_EL) {
8314          ht0 = SEL->ELps[i][1];
8315          /* make sure edge is not part of three triangles, if it is, skip it */
8316          if (SEL->ELps[i][2] > 2) {
8317             ++i;
8318             ++N_bad;
8319             if (N_bad < 50) {
8320                fprintf(SUMA_STDERR,
8321     "%s: Bad edge (#%d: %d--%d), part of more than 2 triangles, skipping it\n",
8322                FuncName, i, SEL->EL[i][0], SEL->EL[i][1]);
8323                if (N_bad == 49) {
8324                   fprintf(SUMA_STDERR,
8325                      "No more Bad edge warnings will be output to stderr. \n"
8326                      "See BadEdgeNodes file if it is a part of the output.\n");
8327                }
8328             }
8329             continue;
8330          }
8331          if (SEL->ELps[i][2] == 2) {
8332             /* that's a good edge, see if the next edge after it is consistent */
8333             NotConsistent = SEL->ELps[i][0] * SEL->ELps[i+1][0]; /* if 1 then edges were either both flipped or not flipped in the list */
8334             ht1 = SEL->ELps[i+1][1];
8335             if (ischecked[ht0] && !ischecked[ht1]) {
8336                if (NotConsistent == 0) {
8337                   fprintf(SUMA_STDERR, "Error %s: NotConsistent = 0 here. This should not be.\n", FuncName);
8338                   SUMA_RETURN (NOPE);
8339                }
8340                if (NotConsistent < 0) {
8341                   /* triangles hosting these edges are consistent */
8342                   /* next triangle needs no flipping */
8343                   ischecked[ht1] = 1;
8344                   ++N_checked;
8345                } else {
8346                   /* triangles hosting these edges are NOT consistent */
8347                   /* flip the next triangle */
8348                   ip = NP * ht1;
8349                   it = FL[ip];
8350                   FL[ip] = FL[ip+2];
8351                   FL[ip+2] = it;
8352                   /* Now make sure the flip is reflected in ELps */
8353                   it = SEL->Tri_limb[ht1][0]; SEL->ELps[it][0] *= -1;
8354                   it = SEL->Tri_limb[ht1][1]; SEL->ELps[it][0] *= -1;
8355                   it = SEL->Tri_limb[ht1][2]; SEL->ELps[it][0] *= -1;
8356                   N_flip += 1;
8357                   isflip[ht1] = 1;
8358                   ischecked[ht1] = 1;
8359                   ++N_checked;
8360                }
8361                ++i;
8362                continue;
8363             }
8364 
8365             /*try if next edge's host is in good shape */
8366             if (ischecked [ht1] && !ischecked[ht0]) {
8367                if (NotConsistent == 0) {
8368                   fprintf(SUMA_STDERR, "Error %s: NotConsistent = 0 here. This should not be.\n", FuncName);
8369                   SUMA_RETURN (NOPE);
8370                }
8371                if (NotConsistent < 0) {
8372                   /* triangles hosting these edges are consistent */
8373                   /* 1st triangle needs no flipping */
8374                   ischecked[ht0] = 1;
8375                   ++N_checked;
8376                } else {
8377                   /* triangles hosting these edges are NOT consistent */
8378                   /* flip the 1st triangle */
8379                   ip = NP * ht0;
8380                   it = FL[ip];
8381                   FL[ip] = FL[ip+2];
8382                   FL[ip+2] = it;
8383                   /* Now make sure the flip is reflected in ELps */
8384                   it = SEL->Tri_limb[ht0][0]; SEL->ELps[it][0] *= -1;
8385                   it = SEL->Tri_limb[ht0][1]; SEL->ELps[it][0] *= -1;
8386                   it = SEL->Tri_limb[ht0][2]; SEL->ELps[it][0] *= -1;
8387                   N_flip += 1;
8388                   isflip[ht0] = 1;
8389                   ischecked[ht0] = 1;
8390                   ++N_checked;
8391                }
8392                ++i;
8393                continue;
8394             }
8395             if (!ischecked[ht0] && !ischecked [ht1]) {
8396                         /* a good lead that was missed on this pass */
8397                SUMA_LH("Miss = %d, MissCur = %d\n", miss, miss_cur);
8398                ++miss;
8399             }
8400          }
8401          ++i;
8402       }
8403       if (LocalHead) fprintf(SUMA_STDERR,"%s: Miss = %d, MissCur = %d\n", FuncName, miss, miss_cur);
8404       ++N_iter;
8405    }
8406 
8407    *trouble = 0;
8408    if (LocalHead) fprintf(SUMA_STDERR,"%s: %d iterations required to check the surface.\n", FuncName, N_iter);
8409    if (detail) fprintf(SUMA_STDERR,"%s: %d/%d (%f%%) triangles checked.\n", FuncName, N_checked, SEL->N_EL/3, (float)N_checked/(SEL->N_EL/3)*100.0);
8410    if (N_checked != SEL->N_EL/3) {
8411       *trouble = 1;
8412    }
8413    if (N_flip) {
8414       *trouble = 1;
8415       if (detail) fprintf(SUMA_STDERR,"%s: %d triangles were flipped to make them consistent with the triangle containing the first edge in the list.\n", FuncName, N_flip);
8416    } else if (detail) fprintf(SUMA_STDERR,"%s: All checked triangles were consistent with the triangle containing the first edge in the list.\n", FuncName);
8417    if (miss) {
8418       if (detail) fprintf(SUMA_STDERR,"%s: %d segments with two neighbors were skipped. Not good in general.\n", FuncName, miss);
8419       *trouble = 1;
8420    }
8421 
8422    if (N_bad) {
8423       if (detail) fprintf(SUMA_STDERR,"%s: A total of %d segments were part of more than 2 triangles.\n", FuncName, N_bad);
8424       *trouble = 1;
8425    }
8426    #if 0
8427       /* now show the fixed mesh list */
8428       fprintf (SUMA_STDERR,"%s: %d triangles were flipped \n", FuncName, N_flip);
8429       for (i=0; i < SEL->N_EL/3; ++i) {
8430          ip = NP * i;
8431          if (isflip[i]) fprintf (SUMA_STDERR,"\t%d %d %d\t(%d)\t*\n", FL[ip], FL[ip+1], FL[ip+2], ischecked[i]);
8432             else fprintf (SUMA_STDERR,"\t%d %d %d\t(%d)\n", FL[ip], FL[ip+1], FL[ip+2], ischecked[i]);
8433       }
8434    #endif
8435 
8436    /* freedom */
8437    if (LocalHead) fprintf(SUMA_STDERR,"%s: Free time \n", FuncName);
8438    if (isflip) SUMA_free(isflip);
8439    if (ischecked) SUMA_free(ischecked);
8440    if (LocalHead) fprintf(SUMA_STDERR,"%s: returning.\n", FuncName);
8441 
8442    SUMA_RETURN (YUP);
8443 }
8444 
8445 
8446 /*------------------------- Triangle Consistency Functions END--------------------------------------- */
8447 
8448 /*-------------------------Node Attributes, smoothing functions BEGIN ------------------- */
8449 /*!
8450    Smooth the attributes of the nodes based on the neighboring values.
8451    Nodes are neighbors if they are connected by an edge in the triangulation.
8452 
8453    \param attr (float *) pointer to vector of type tp containing a
8454                            node's attribute
8455    \param N_attr (int) number of elements in attr.
8456    \param attr_sm (float *) pointer to smoothed version of attr.
8457             If you pass NULL then the pointer is allocated and returned
8458             from the function.
8459             If attr_sm is not null then it is assumed to have the
8460             required allocated space for the proper type.
8461    \param fn (SUMA_NODE_FIRST_NEIGHB) structure containing the first order
8462             neighbors of the nodes.
8463             It is assumed that fn contains the neighbors info for all nodes
8464             whose attributes are in attr.
8465             That is from 0 to N_attr.
8466    \param nr (int) number of values per node in attr (for multiplexed vectors).
8467                    So, if attr was R0G0Bo R1 G1 B1, ..., RnGnBn then nr = 3
8468                    Only row major multiplexing is allowed.
8469    \param nmask (byte *) if not NULL, then attributes are smoothed ONLY
8470                          for nodes n where nmask[n] = 1
8471    \return attr_sm (float *) pointer to smoothed version of attr
8472 
8473    \sa   SUMA_SmoothAttr_Neighb_Rec
8474    \sa SUMA_SmoothAttr_Neighb_wght (bugs here == bugs there)
8475 */
SUMA_SmoothAttr_Neighb(float * attr,int N_attr,float * attr_sm,SUMA_NODE_FIRST_NEIGHB * fn,int nr,byte * nmask,byte strict_mask)8476 float * SUMA_SmoothAttr_Neighb ( float *attr, int N_attr, float *attr_sm,
8477                                  SUMA_NODE_FIRST_NEIGHB *fn, int nr,
8478                                  byte *nmask, byte strict_mask)
8479 {
8480    static char FuncName[]={"SUMA_SmoothAttr_Neighb"};
8481    int ni, im, offs, j, nj, wgt;
8482 
8483    SUMA_ENTRY;
8484 
8485    if (attr_sm && attr_sm == attr) {
8486       fprintf (SUMA_STDERR, "Error %s: attr and attr_sm point to the same location. BAD!\n",FuncName);
8487       SUMA_RETURN (NULL);
8488    }
8489    if (fn == NULL) {
8490       fprintf (SUMA_STDERR, "Error %s: fn is null, nothing to do.\n",FuncName);
8491       SUMA_RETURN (NULL);
8492    }
8493    if (nr*fn->N_Node != N_attr) {
8494       fprintf (SUMA_STDERR, "Error %s: N_attr (%d) must be equal to nr * fn->N_Node (%d * %d = %d).\n",
8495                FuncName, N_attr, nr, fn->N_Node, nr * fn->N_Node);
8496       SUMA_RETURN (NULL);
8497    }
8498 
8499    attr_sm = (float *)attr_sm;
8500    if (attr_sm == NULL) {
8501       attr_sm = (float *)SUMA_calloc (N_attr, sizeof(float));
8502    }
8503 
8504    if (attr_sm == NULL)
8505    {
8506       fprintf (SUMA_STDERR, "Error %s: Failed to allocate for returning variable.\n", FuncName);
8507       SUMA_RETURN (NULL);
8508    }
8509 
8510 
8511    for (ni=0; ni < fn->N_Node; ++ni) { /* a counter for node index */
8512       /* make sure node id corresponds to ni. That is you have a full set of nodes 0..fn->N_Node */
8513       if (fn->NodeId[ni] != ni) {
8514          /* It's OK not to die here. This does occur in patches */
8515          /*fprintf (SUMA_STDERR,
8516                      "Warning %s: fn does not seem to contain an explicit list of neighbors, from 0..N_attr. "
8517                      "fn->NodeId[ni] = %d, ni = %d. Skipping node %d.\n",
8518             FuncName, fn->NodeId[ni], ni, ni); */
8519          /*SUMA_free(attr_sm);
8520          attr_sm = NULL;
8521          SUMA_RETURN (attr_sm);*/
8522          continue;
8523       }
8524       offs = nr * ni;
8525       if (nmask) {
8526          if (nmask[fn->NodeId[ni]]) {  /* the node is in the mask */
8527             for (im=0; im<nr; ++im) {
8528                attr_sm[offs+im] = attr[offs+im];
8529                {
8530                   wgt = 0;
8531                   for (j=0; j < fn->N_Neighb[ni]; ++j)
8532                   {
8533                      nj = fn->FirstNeighb[ni][j];
8534                      if (nmask[nj] || !strict_mask) { /* the neighbor is in the
8535                                              mask or we take in all neighbors */
8536                         attr_sm[offs+im] += attr[nr*nj+im]; ++wgt;
8537                      }
8538                   }
8539                   attr_sm[offs+im] /= ((float)wgt+1.0);
8540                }
8541             }
8542          } else { /* the node is not in the mask */
8543             for (im=0; im<nr; ++im) attr_sm[offs+im] = attr[offs+im];
8544          }
8545       } else {
8546          for (im=0; im<nr; ++im) {
8547             attr_sm[offs+im] = attr[offs+im];
8548             for (j=0; j < fn->N_Neighb[ni]; ++j)
8549             {
8550                attr_sm[offs+im] += attr[nr*fn->FirstNeighb[ni][j]+im];
8551             }
8552             attr_sm[offs+im] /= (fn->N_Neighb[ni]+1);
8553          }
8554       }
8555    }
8556 
8557    SUMA_RETURN (attr_sm);
8558 }
8559 
8560 /*!
8561    \sa SUMA_SmoothAttr_Neighb (bugs here == bugs there)
8562 */
SUMA_SmoothAttr_Neighb_wght(float * attr,int N_attr,float * wght,float * attr_sm,SUMA_NODE_FIRST_NEIGHB * fn,int nr,byte * nmask,byte strict_mask)8563 float * SUMA_SmoothAttr_Neighb_wght (float *attr, int N_attr, float *wght,
8564                                      float *attr_sm, SUMA_NODE_FIRST_NEIGHB *fn,
8565                                      int nr, byte *nmask, byte strict_mask)
8566 {
8567    static char FuncName[]={"SUMA_SmoothAttr_Neighb_wght"};
8568    int ni, im, offs, j, nj;
8569    float wgt;
8570 
8571    SUMA_ENTRY;
8572 
8573    if (attr_sm && attr_sm == attr) {
8574       SUMA_S_Err("attr and attr_sm point to the same location. BAD!\n");
8575       SUMA_RETURN (NULL);
8576    }
8577 
8578    if (!wght) SUMA_RETURN(SUMA_SmoothAttr_Neighb(attr, N_attr, attr_sm,
8579                                                 fn, nr, nmask, strict_mask));
8580 
8581    if (fn == NULL) {
8582       fprintf (SUMA_STDERR, "Error %s: fn is null, nothing to do.\n",FuncName);
8583       SUMA_RETURN (NULL);
8584    }
8585    if (nr*fn->N_Node != N_attr) {
8586       SUMA_S_Errv("N_attr (%d) must be equal to "
8587                   "nr * fn->N_Node (%d * %d = %d).\n",
8588                N_attr, nr, fn->N_Node, nr * fn->N_Node);
8589       SUMA_RETURN (NULL);
8590    }
8591 
8592    attr_sm = (float *)attr_sm;
8593    if (attr_sm == NULL) {
8594       attr_sm = (float *)SUMA_calloc (N_attr, sizeof(float));
8595    }
8596 
8597    if (attr_sm == NULL)
8598    {
8599       fprintf (SUMA_STDERR,
8600          "Error %s: Failed to allocate for returning variable.\n", FuncName);
8601       SUMA_RETURN (NULL);
8602    }
8603 
8604 
8605    for (ni=0; ni < fn->N_Node; ++ni) { /* a counter for node index */
8606       /* make sure node id corresponds to ni.
8607          That is you have a full set of nodes 0..fn->N_Node */
8608       if (fn->NodeId[ni] != ni) {
8609          /* It's OK not to die here.  This does occur in patches */
8610          /* SUMA_S_Warnv("fn does not seem to contain an explicit list of"
8611                       " neighbors, from 0..N_attr. "
8612                       "fn->NodeId[ni] = %d, ni = %d. Skipping node %d.\n",
8613                       fn->NodeId[ni], ni, ni); */
8614          /*SUMA_free(attr_sm);
8615          attr_sm = NULL;
8616          SUMA_RETURN (attr_sm);*/
8617          continue;
8618       }
8619       offs = nr * ni;
8620       if (nmask) {
8621          if (nmask[fn->NodeId[ni]]) {  /* the node is in the mask */
8622             for (im=0; im<nr; ++im) {
8623                attr_sm[offs+im] = wght[fn->NodeId[ni]] * attr[offs+im];
8624                wgt = wght[fn->NodeId[ni]];
8625                {
8626                   wgt = 0;
8627                   for (j=0; j < fn->N_Neighb[ni]; ++j)
8628                   {
8629                      nj = fn->FirstNeighb[ni][j];
8630                      if (nmask[nj] || !strict_mask) {
8631                         /* the neighbor is in the mask or we take in
8632                            all neighbors */
8633                         attr_sm[offs+im] += (wght[nj] * attr[nr*nj+im]);
8634                         wgt += wght[nj];
8635                      }
8636                   }
8637                   attr_sm[offs+im] /= ((float)wgt);
8638                }
8639             }
8640          } else { /* the node is not in the mask */
8641             for (im=0; im<nr; ++im) attr_sm[offs+im] = attr[offs+im];
8642          }
8643       } else {
8644          for (im=0; im<nr; ++im) {
8645             attr_sm[offs+im] = wght[fn->NodeId[ni]] * attr[offs+im];
8646             wgt = wght[fn->NodeId[ni]];
8647             for (j=0; j < fn->N_Neighb[ni]; ++j)
8648             {
8649                nj = fn->FirstNeighb[ni][j];
8650                attr_sm[offs+im] +=
8651                   (wght[nj] * attr[nr*fn->FirstNeighb[ni][j]+im]);
8652                wgt += wght[nj];
8653             }
8654             attr_sm[offs+im] /= ((float)wgt);
8655          }
8656       }
8657    }
8658 
8659    SUMA_RETURN (attr_sm);
8660 }
8661 
8662 
8663 /*!
8664    \brief float * SUMA_SmoothAttr_Neighb_Rec (float *attr, int N_attr,
8665                                              float *attr_sm_orig,
8666                                              SUMA_NODE_FIRST_NEIGHB *fn,
8667                                              int nr, int N_rep)
8668    A wrapper function to call SUMA_SmoothAttr_Neighb repeatedly
8669    See SUMA_SmoothAttr_Neighb for input and output options. The only additional
8670    option is N_Rec the number of repeated smoothing calls.
8671 
8672 */
SUMA_SmoothAttr_Neighb_Rec(float * attr,int N_attr,float * attr_sm_orig,SUMA_NODE_FIRST_NEIGHB * fn,int nr,int N_rep,byte * mask,byte strict_mask)8673 float * SUMA_SmoothAttr_Neighb_Rec (float *attr, int N_attr,
8674                                     float *attr_sm_orig,
8675                                     SUMA_NODE_FIRST_NEIGHB *fn,
8676                                     int nr, int N_rep,
8677                                     byte *mask, byte strict_mask)
8678 {
8679    static char FuncName[]={"SUMA_SmoothAttr_Neighb_Rec"};
8680    int i;
8681    float *curr_attr=NULL, *attr_sm=NULL;
8682    SUMA_Boolean LocalHead = NOPE;
8683 
8684    SUMA_ENTRY;
8685 
8686    if (N_rep < 1) {
8687       SUMA_SL_Err("N_rep < 1");
8688       SUMA_RETURN(NULL);
8689    }
8690 
8691    if (N_rep == 1 && attr == attr_sm_orig) {
8692       SUMA_SL_Err("attr = attr_sm_orig && N_rep == 1. BAD.\n");
8693       SUMA_RETURN(NULL);
8694    }
8695 
8696    i = 1;
8697    curr_attr = attr; /* initialize with user's data */
8698    while (i < N_rep) {
8699       /* intermediary calls */
8700       attr_sm = SUMA_SmoothAttr_Neighb (curr_attr, N_attr, NULL, fn, nr,
8701                                         mask, strict_mask);
8702       if (i > 1)  { /* second or more time in */
8703          /* free input to previous calculation */
8704          if (curr_attr) SUMA_free(curr_attr);
8705       }
8706       curr_attr = attr_sm; /* setup for next calculation */
8707       ++i;
8708    }
8709 
8710    /* last call, honor the user's return pointer */
8711    attr_sm = SUMA_SmoothAttr_Neighb (curr_attr, N_attr, attr_sm_orig, fn, nr,
8712                                      mask, strict_mask);
8713 
8714    /* free curr_attr if i > 1, i.e. it is not the user's original copy */
8715    if (i > 1) {
8716       if (curr_attr) SUMA_free(curr_attr);
8717    }
8718 
8719    SUMA_RETURN (attr_sm);
8720 }
8721 
8722 /*--------- Node Attributes, smoothing functions END ------ */
8723 
8724 /*!
8725    build the node neighbor structure. Nodes are neighbors is they share an edge
8726    ans =  SUMA_Build_FirstNeighb (EL, N_Node)
8727 
8728    \param EL (SUMA_EDGE_LIST *) pointer to the EdgeList structure
8729                                  (usually SO->EL)
8730    \param N_Node (int) total number of nodes
8731                               (ALWAYS pass SO->N_Node to avoid headaches)
8732    \ret FN (SUMA_NODE_FIRST_NEIGHB *) pointer to the neighbor list structure
8733 
8734 */
SUMA_Build_FirstNeighb(SUMA_EDGE_LIST * el,int N_Node,char * ownerid,int verb)8735 SUMA_NODE_FIRST_NEIGHB * SUMA_Build_FirstNeighb (SUMA_EDGE_LIST *el,
8736                                                  int N_Node, char *ownerid,
8737                                                  int verb)
8738 {
8739    static char FuncName[]={"SUMA_Build_FirstNeighb"};
8740    int i, j, n1, n2,  **FirstNeighb, N_ELm1, jj, tmp, TessErr_Cnt=0, IOtrace = 0;
8741    SUMA_Boolean skp, LocalHead = NOPE;
8742    SUMA_NODE_FIRST_NEIGHB *FN;
8743    static int nwarn=0;
8744 
8745    SUMA_ENTRY;
8746 
8747    if (DBG_trace > 1) IOtrace = 1;
8748    if (verb > 1) LocalHead = YUP;
8749 
8750    if (el == NULL || N_Node == 0) {
8751       fprintf( SUMA_STDERR,
8752                "Error %s: el == NULL or N_Node == 0, nothing to do.\n",
8753                FuncName);
8754       SUMA_RETURN (NULL);
8755    }
8756 
8757    FN = (SUMA_NODE_FIRST_NEIGHB *)SUMA_malloc(sizeof(SUMA_NODE_FIRST_NEIGHB));
8758    if (FN == NULL) {
8759       fprintf(SUMA_STDERR,
8760                "Error %s: Could not allocate space for FN\n", FuncName);
8761       SUMA_RETURN (NULL);
8762    }
8763 
8764    FN->N_links = 0;
8765    if (ownerid) sprintf(FN->owner_id, "%s", ownerid);
8766    else FN->owner_id[0] = '\0';
8767    FN->LinkedPtrType = SUMA_LINKED_ND_FRST_NEI_TYPE;
8768    FN->do_type = not_DO_type;
8769 
8770    FN->idcode_str = NULL;
8771    SUMA_NEW_ID(FN->idcode_str, NULL);
8772 
8773    /* allocate space for FN's matrices */
8774    FN->N_Node = N_Node; /*  That works for regular surfaces,
8775                                  But in rare cases when working on
8776                                  chunks of surfaces, N_Node is not
8777                                  the highest node index in EL
8778                                  So check for this ...*/
8779    --N_Node;
8780    for (j=0; j < el->N_EL; ++j) {
8781       if (el->EL[j][0] > N_Node) N_Node = el->EL[j][0];
8782       if (el->EL[j][1] > N_Node) N_Node = el->EL[j][1];
8783    }
8784    ++N_Node;
8785    if (N_Node > FN->N_Node) {
8786       SUMA_LHv("N_Node %d too small for nodes in EL.\n"
8787                  "Had to allocate for a max of %d\n",
8788                    FN->N_Node, N_Node);
8789       FN->N_Node = N_Node;
8790    }
8791    FN->N_Neighb_max = 0;
8792 
8793    FN->FirstNeighb = (int **) SUMA_allocate2D(FN->N_Node,
8794                                  SUMA_MAX_NUMBER_NODE_NEIGHB+1, sizeof (int));
8795    FN->N_Neighb = (int *) SUMA_calloc (FN->N_Node, sizeof(int));
8796    FN->NodeId = (int *) SUMA_calloc (FN->N_Node, sizeof(int));
8797 
8798    if (FN->FirstNeighb == NULL || FN->N_Neighb == NULL || FN->NodeId == NULL ){
8799       fprintf(SUMA_STDERR,
8800              "Error %s: Could not allocate space forFN->FirstNeighb &/|\n"
8801              "FN->N_Neighb &/| FN->NodeId.\n", FuncName);
8802       SUMA_RETURN (NULL);
8803    }
8804 
8805    /*fprintf(SUMA_STDOUT, "%s: Creating list ...\n", FuncName);*/
8806 
8807    FN->N_Neighb_max = 0;
8808    N_ELm1 = el->N_EL-1;
8809    j=0;
8810    while (j < el->N_EL)
8811    {
8812       n1 = el->EL[j][0];
8813       n2 = el->EL[j][1];
8814       if (  n1 < 0 || n2 < 0 || /*n1 >= FN->N_Node || n2 >= FN->N_Node ||*/
8815             FN->N_Neighb[n1] > SUMA_MAX_NUMBER_NODE_NEIGHB ||
8816             FN->N_Neighb[n2] > SUMA_MAX_NUMBER_NODE_NEIGHB) {
8817          if (verb > 1 || !nwarn) {
8818             fprintf(SUMA_STDERR,
8819       "Warning %s:"
8820       "Bad node index! %d and/or %d\n"
8821       "Maximum number of node neighbors for node %d or node %d exceeds %d"
8822       " (SUMA_MAX_NUMBER_NODE_NEIGHB)\n "
8823       "SUMA will try to launch but some functions may not work properly.",
8824             FuncName, n1, n2, n1, n2, SUMA_MAX_NUMBER_NODE_NEIGHB);
8825             if (verb < 2) {
8826                fprintf(SUMA_STDERR, "\nFuture similar messages muted.\n");
8827             } else {
8828                fprintf(SUMA_STDERR, "\n");
8829             }
8830          }
8831          ++nwarn;
8832       }else {
8833          /*register the neighbors for both nodes*/
8834          FN->NodeId[n1] = n1; /* this field may come in handy when operations
8835             need to be performed on subsets of the nodes making up the surface */
8836          FN->NodeId[n2] = n2;
8837          FN->FirstNeighb[n1][FN->N_Neighb[n1]] = n2;
8838          FN->FirstNeighb[n2][FN->N_Neighb[n2]] = n1;
8839 
8840          /* increment neighbor count for nodes in edge */
8841          FN->N_Neighb[n1] += 1;
8842          FN->N_Neighb[n2] += 1;
8843 
8844          if (FN->N_Neighb[n1] > FN->N_Neighb_max)
8845             FN->N_Neighb_max = FN->N_Neighb[n1];
8846          if (FN->N_Neighb[n2] > FN->N_Neighb_max)
8847             FN->N_Neighb_max = FN->N_Neighb[n2];
8848 
8849          /* skip duplicate edges */
8850          if (j < N_ELm1) {
8851             skp = NOPE;
8852             do {
8853                if (  el->EL[j+1][0] == el->EL[j][0] &&
8854                      el->EL[j+1][1] == el->EL[j][1]) {
8855                   ++j;
8856                } else {
8857                   skp = YUP;
8858                }
8859             } while (!skp && j < N_ELm1);
8860          }
8861       }
8862 
8863       ++j;
8864    }/* for j */
8865 
8866    /* now SUMA_reallocate for final FirstNeighb */
8867    FirstNeighb = (int **) SUMA_allocate2D(FN->N_Node,
8868                               FN->N_Neighb_max, sizeof(int));
8869    if (FirstNeighb == NULL){
8870       fprintf(SUMA_STDERR,
8871          "Error %s: Could not allocate space for FirstNeighb\n", FuncName);
8872       SUMA_Free_FirstNeighb (FN);
8873       SUMA_RETURN (NULL);
8874    }
8875 
8876    /* crop left over allocated space and rearrange neighboring nodes in order */
8877    for (i=0; i < FN->N_Node; ++i) {
8878       #ifdef NoOrder
8879       for (j=0; j < FN->N_Neighb[i]; ++j) {
8880           FirstNeighb[i][j] = FN->FirstNeighb[i][j];
8881       }
8882       #else /* ordered nodes, Tue Jan  7 13:21:57 EST 2003 */
8883         /* copy first node */
8884         FirstNeighb[i][0] = FN->FirstNeighb[i][0];
8885         j = 1;
8886         jj = 1;
8887         while (j < FN->N_Neighb[i]) {
8888             if (SUMA_whichTri (el, i, FirstNeighb[i][jj-1],
8889                                FN->FirstNeighb[i][j], IOtrace, 1) >= 0) {
8890                FirstNeighb[i][jj] = FN->FirstNeighb[i][j];
8891                /* now swap in FN->FirstNeighb[i] the positions of jj and j */
8892                tmp =  FN->FirstNeighb[i][jj];
8893                FN->FirstNeighb[i][jj] = FN->FirstNeighb[i][j];
8894                FN->FirstNeighb[i][j] = tmp;
8895                ++jj;
8896                j = jj;
8897             } else {
8898                ++j;
8899             }
8900         }
8901         if (jj != FN->N_Neighb[i] &&
8902             FN->N_Neighb[i]) {      /* The FN->N_Neighb[i] condition was added
8903                                        because with patches you can have nodes
8904                                        that are not in the edge list, and
8905                                        therefore are neighborless. Do not whine
8906                                        when that happens */
8907             if (!TessErr_Cnt) {
8908                if (verb && !(el->min_N_Hosts == 1 && el->max_N_Hosts == 2) ) {
8909                                        /* do not complain if surface is open */
8910                   SUMA_S_Notev("(Ignore notice for open surfaces)\n"
8911                      " Failed in copying neighbor list.\n"
8912                      " If surface is closed, there is likely \n"
8913                      " a tessellation error. One or more edges may not \n"
8914                      " be part of 2 and only 2 triangles. \n"
8915                      " Neighbor list for node %d will not be ordered as \n"
8916                      " connected vertices (jj=%d, FN->N_Neighb[%d]=%d). \n"
8917                      " Further occurences of this error will not be reported.\n"
8918                                           , i, jj, i, FN->N_Neighb[i]);
8919                   }
8920             }
8921             ++TessErr_Cnt;
8922             while (jj < FN->N_Neighb[i]) {
8923                FirstNeighb[i][jj] = FN->FirstNeighb[i][jj];
8924                ++jj;
8925             }
8926         }
8927       #endif
8928    }
8929    if (TessErr_Cnt && verb) {
8930       if ( !(el->min_N_Hosts == 1 && el->max_N_Hosts == 2) ) {
8931          if (TessErr_Cnt > 1) fprintf (SUMA_STDERR,
8932             " %d similar occurences were found in this mesh.\n",
8933             TessErr_Cnt);
8934          else  fprintf (SUMA_STDERR,
8935             " %d occurence was found in this mesh.\n",
8936             TessErr_Cnt);
8937       }
8938    }
8939    SUMA_free2D((char **)FN->FirstNeighb, FN->N_Node);
8940    FN->FirstNeighb = FirstNeighb;
8941    /* SUMA_disp_dmat (FN->FirstNeighb, N_Node, FN->N_Neighb_max, 0); */
8942    SUMA_RETURN (FN);
8943 }
8944 
8945 /*!
8946    frees the Node Neighbor structure formed in SUMA_Build_FirstNeighb
8947 */
SUMA_Free_FirstNeighb(SUMA_NODE_FIRST_NEIGHB * FN)8948 SUMA_Boolean SUMA_Free_FirstNeighb (SUMA_NODE_FIRST_NEIGHB *FN)
8949 {
8950    static char FuncName[]={"SUMA_Free_FirstNeighb"};
8951    SUMA_Boolean LocalHead = NOPE;
8952 
8953    SUMA_ENTRY;
8954    SUMA_LH("Entered");
8955    if (!FN) SUMA_RETURN(YUP);
8956 
8957    if (FN->N_links) {
8958       SUMA_LH("Just a link release");
8959       FN = (SUMA_NODE_FIRST_NEIGHB *)SUMA_UnlinkFromPointer((void *)FN);
8960       SUMA_RETURN (YUP);
8961    }
8962 
8963    /* no more links, go for it */
8964    SUMA_LH("No more links, here we go");
8965    if (FN->idcode_str) SUMA_free(FN->idcode_str);
8966    if (FN->NodeId) SUMA_free(FN->NodeId);
8967    if (FN->N_Neighb) SUMA_free(FN->N_Neighb);
8968    if (FN->FirstNeighb) SUMA_free2D ((char **)FN->FirstNeighb, FN->N_Node);
8969    if (FN) SUMA_free(FN);
8970    SUMA_RETURN (YUP);
8971 }
8972 
8973 /*! calculate the normal to a triangle
8974    A = SUMA_TriNorm (n1, n2, n3, normal)
8975    \param n1 (float *)pointer to vector containing XYZ of node 1
8976    \param n2 (float *)pointer to vector containing XYZ of node 2
8977    \param n3 (float *)pointer to vector containing XYZ of node 3
8978    \param normal (float *)pointer to vector to contain normal of triangle.
8979    \return A (SUMA_Boolean) NOPE if the norm of the normal = 0. In that case, occuring with FreeSurfer surfaces, normal is 1.0 1.0 1.0
8980    \sa SUMA_SurfNorm
8981 
8982 */
SUMA_TriNorm(float * n0,float * n1,float * n2,float * norm)8983 SUMA_Boolean SUMA_TriNorm (float *n0, float *n1, float *n2, float *norm)
8984 {
8985    static char FuncName[]={"SUMA_TriNorm"};
8986    int i;
8987    float d1[3], d2[3], d;
8988 
8989    SUMA_ENTRY;
8990 
8991    for (i=0; i<3; ++i) {
8992          d1[i] = n0[i] - n1[i];
8993          d2[i] = n1[i] - n2[i];
8994    }
8995    norm[0] = d1[1]*d2[2] - d1[2]*d2[1];
8996    norm[1] = d1[2]*d2[0] - d1[0]*d2[2];
8997    norm[2] = d1[0]*d2[1] - d1[1]*d2[0];
8998 
8999    d = sqrt(norm[0] * norm[0] + norm[1] * norm[1] + norm[2] * norm[2]);
9000 
9001    if (d==0.0) {
9002       norm[0] = norm[1] = norm[2] = 1.0;
9003       SUMA_RETURN (NOPE);
9004    }else {
9005       for (i=0; i<3; ++i) norm[i] /= d;
9006       SUMA_RETURN (YUP);
9007    }
9008 }
9009 
9010 /*! calculate the area of a triangle
9011    A = SUMA_TriSurf3 (n1, n2, n3, normal)
9012    \param n1 (float *)pointer to vector containing XYZ of node 1
9013    \param n2 (float *)pointer to vector containing XYZ of node 2
9014    \param n3 (float *)pointer to vector containing XYZ of node 3
9015    \param normal (float *)pointer to vector containing normal of triangle.
9016    \return A (float) area of triangle
9017    \sa SUMA_PolySurf3
9018    \sa SUMA_TriNorm
9019    \sa SUMA_TRI_AREA for macro version
9020 */
9021 
SUMA_TriSurf3(float * n0,float * n1,float * n2)9022 float SUMA_TriSurf3 (float *n0, float *n1, float *n2)
9023 {
9024    static char FuncName[]={"SUMA_TriSurf3"};
9025    float dv[3], dw[3], cross[3], A;
9026    int i, ii, coord, kk, jj;
9027 
9028    SUMA_ENTRY;
9029 
9030    SUMA_MT_SUB (dv, n1, n0);
9031    SUMA_MT_SUB (dw, n2, n0);
9032    SUMA_MT_CROSS(cross,dv,dw);
9033    SUMA_NORM(A, cross);
9034    A *= 0.5;
9035 
9036    SUMA_RETURN (A);
9037 }
9038 
9039 /*! calculate the area of a triangle
9040    A = SUMA_TriSurf3v (NodeList, FaceSets, N_FaceSet, )
9041    \param NodeList (float *)pointer to vector containing XYZ of nodes  (typically SO->NodeList)
9042    \param FaceSets (int *) pointer to vector (3*N_FaceSet long) containing triangle indices  (typically SO->FaceSetList)
9043    \param N_FaceSet (int) number of triangles, (typically SO->N_FaceSet)
9044    \return A (float *) vector of triangle areas (N_FaceSet elements long)
9045 
9046    \sa SUMA_PolySurf3
9047    \sa SUMA_TriNorm
9048    \sa SUMA_TRI_AREA for macro version
9049 */
9050 
SUMA_TriSurf3v(float * NodeList,int * FaceSets,int N_FaceSet)9051 float * SUMA_TriSurf3v (float *NodeList, int *FaceSets, int N_FaceSet)
9052 {
9053    static char FuncName[]={"SUMA_TriSurf3v"};
9054    float *A = NULL, *n0, *n1, *n2, a;
9055    int i, i3;
9056 
9057    SUMA_ENTRY;
9058 
9059    A = (float *) SUMA_calloc (N_FaceSet, sizeof(float));
9060    if (A == NULL ) {
9061       fprintf(SUMA_STDERR,"Error %s; Failed to allocate for A \n", FuncName);
9062       SUMA_RETURN (NULL);
9063    }
9064 
9065    for (i=0;  i<N_FaceSet; ++i) {
9066       i3 = 3*i;
9067       n0 = &(NodeList[3*FaceSets[i3]]);
9068       n1 = &(NodeList[3*FaceSets[i3+1]]);
9069       n2 = &(NodeList[3*FaceSets[i3+2]]);
9070       SUMA_TRI_AREA( n0, n1, n2, A[i]);
9071       /* A[i] = SUMA_TriSurf3 (n0, n1, n2); */
9072    }
9073 
9074    SUMA_RETURN (A);
9075 }
9076 
9077 /*!
9078    Calculate the area of planar polygons
9079    A = SUMA_PolySurf3 (NodeList, int N_Node, int *FaceSets, int N_FaceSet, int PolyDim, float *FaceNormList, SUMA_Boolean SignedArea)
9080    \param NodeList (float *)  (N_Node x 3) vector containing XYZ of each node
9081    \param N_Node number of nodes in NodeList
9082    \param FaceSets (int *) vector (matrix, prior to SUMA 1.2) (N_FaceSet x PolyDim) defining the polygons by their indices into NodeList
9083    \param N_FaceSet (int) number of polygons
9084    \param PolyDim (int) dimension of polygons (3 triangles)
9085    \param FaceNormList (float *) N_FaceSet x 3 vector of normals to polygons
9086    \param SignedArea (SUMA_Boolean) signed or unsigned areas
9087       positive means the vertices are oriented counterclockwise around the polygon when viewed from the side of the plane pointed to by the normal
9088    \return A (float *) vector containing the area of each polygon in FaceSets
9089 
9090 
9091    \sa SUMA_TriSurf3
9092 
9093    Algorithm by Dan Sunday http://geometryalgorithms.com
9094 */
SUMA_PolySurf3(float * NodeList,int N_Node,int * FaceSets,int N_FaceSet,int PolyDim,float * FaceNormList,SUMA_Boolean SignedArea)9095 float * SUMA_PolySurf3 (float *NodeList, int N_Node, int *FaceSets, int N_FaceSet, int PolyDim, float *FaceNormList, SUMA_Boolean SignedArea)
9096 {
9097    static char FuncName[]={"SUMA_PolySurf3"};
9098    float **V, *A, ax, ay, az, an;
9099    int i, ii, coord, kk, jj, id, ND, ip, NP;
9100 
9101    SUMA_ENTRY;
9102 
9103    ND = 3;
9104    NP = PolyDim;
9105    A = (float *) SUMA_calloc (N_FaceSet, sizeof(float));
9106    V = (float **) SUMA_allocate2D(PolyDim+2, 3, sizeof(float));
9107 
9108    if (A == NULL || V == NULL) {
9109       fprintf(SUMA_STDERR,"Error %s; Failed to allocate for A or V\n", FuncName);
9110       SUMA_RETURN (NULL);
9111    }
9112 
9113    for (i=0; i < N_FaceSet; ++i) {
9114       ip = NP * i;
9115       if (FaceNormList[ip] > 0) ax = FaceNormList[ip];
9116          else ax = -FaceNormList[ip];
9117 
9118       if (FaceNormList[ip+1] > 0) ay = FaceNormList[ip+1];
9119          else ay = -FaceNormList[ip+1];
9120 
9121       if (FaceNormList[ip+2] > 0) az = FaceNormList[ip+2];
9122          else az = -FaceNormList[ip+2];
9123 
9124 
9125       coord = 3;
9126       if (ax > ay) {
9127          if (ax > az) coord = 1;
9128       } else {
9129          if (ay > az) coord = 2;
9130       }
9131 
9132       for (ii=0; ii< PolyDim; ++ii) {
9133          ip = NP * i;
9134          id = ND * FaceSets[ip+ii];
9135          V[ii][0] = NodeList[id];
9136          V[ii][1] = NodeList[id+1];
9137          V[ii][2] = NodeList[id+2];
9138       }
9139       ii = PolyDim;
9140       V[ii][0] = V[0][0]; V[ii][1] = V[0][1]; V[ii][2] = V[0][2];
9141       ii = PolyDim + 1;
9142       V[ii][0] = V[1][0]; V[ii][1] = V[1][1]; V[ii][2] = V[1][2];
9143 
9144       /* compute area of 2D projection */
9145       jj = 2;
9146       kk = 0;
9147       for (ii=1; ii < PolyDim+1; ++ii) {
9148          switch (coord) {
9149             case 1:
9150                A[i] = A[i] + ( V[ii][1] * (V[jj][2] - V[kk][2]) );
9151                break;
9152             case 2:
9153                A[i] = A[i] + ( V[ii][0] * (V[jj][2] - V[kk][2]) );
9154                break;
9155             case 3:
9156                A[i] = A[i] + ( V[ii][0] * (V[jj][1] - V[kk][1]) );
9157                break;
9158          }
9159 
9160          ++jj;
9161          ++kk;
9162 
9163       }
9164 
9165       /* scale to get area before projection  */
9166       an = (float) sqrt(ax * ax + ay * ay + az * az);
9167       switch (coord) {
9168          case 1:
9169             A[i] = (A[i] * (an / (2*ax)));
9170             break;
9171          case 2:
9172             A[i] = (A[i] * (an / (2*ay)));
9173             break;
9174          case 3:
9175             A[i] = (A[i] * (an / (2*az)));
9176             break;
9177       }
9178 
9179       if (!SignedArea) {
9180          if (A[i] < 0) A[i] = -A[i];
9181       }
9182    } /* for i*/
9183 
9184    SUMA_free2D((char **)V, PolyDim+2);
9185    SUMA_RETURN (A);
9186 }
9187 
9188 /* choose debug level for SUMA_Surface_Curvature, _1 gvies a pacifier, _2 gives a lot of info, _3 pauses for each node */
9189 #define MAX_INCIDENT_TRI 200
9190 #define DBG_1
9191 
9192 #ifdef DBG_3
9193    #define DBG_2
9194 #endif
9195 
9196 #ifdef DBG_2
9197    #define DBG_1
9198 #endif
9199 /*! function to calculate the curvature tensor at each node
9200    SC = SUMA_Surface_Curvature (NodeList, N_Node, NodeNormList, A, N_FaceSet, FN, SUMA_EDGE_LIST *SEL, char *odbg_name)
9201 
9202    \param NodeList (float *) N_Node x 3 vector containing the XYZ coordinates of the nodes
9203    \param N_Node (int)  number of nodes in NodeList
9204    \param NodeNormList (float *) N_Node x 3 vector (was matrix prior to SUMA 1.2) containing the normal vector at each node
9205    \param A (float *) N_FaceSet x 1 vector containing the area of each triangle making up the mesh
9206    \param N_FaceSet (int) number of triangles making up the mesh
9207    \param FN (SUMA_NODE_FIRST_NEIGHB *) structure containing Node Neighbors
9208    \param SEL (SUMA_EDGE_LIST *) structure containing the Edge List
9209    \param odbg_name (char *) a name to use for outputing the results. For debugging mostly. NULL if you want no output to disk.
9210 
9211    \ret SC (SUMA_SURFACE_CURVATURE *) structure containing the curvature info, see typedef of struct for more info
9212 
9213    \sa SUMA_Free_SURFACE_CURVATURE for freeing SC
9214    \sa SUMA_Build_FirstNeighb for creating FN
9215    \sa SUMA_Make_Edge_List for creating SEL
9216 
9217    The algorithm is the one presented in G. Taubin Estimating the tensor of curvature of surface from a polyhedral approximation
9218    see also labbook NIH-2 pp 65 and (Test_)SUMA_Surface_Curvature.m script
9219 */
9220 
9221 
SUMA_Surface_Curvature(float * NodeList,int N_Node,float * NodeNormList,float * A,int N_FaceSet,SUMA_NODE_FIRST_NEIGHB * FN,SUMA_EDGE_LIST * SEL,char * odbg_name,int verb)9222 SUMA_SURFACE_CURVATURE * SUMA_Surface_Curvature (
9223                            float *NodeList, int N_Node, float *NodeNormList,
9224                            float *A, int N_FaceSet, SUMA_NODE_FIRST_NEIGHB *FN,
9225                            SUMA_EDGE_LIST *SEL,  char *odbg_name, int verb)
9226 {
9227    static char FuncName[] = {"SUMA_Surface_Curvature"};
9228    int i, N_Neighb, j, ji, Incident[MAX_INCIDENT_TRI], N_Incident,
9229        kk, ii, id, ND;
9230    float  Ntmp[3],  vi[3], vj[3], *Num, NumNorm, num, denum, sWij,
9231           T1e[3], T2e[3], mg, c, s;
9232    float **fa33, **fb33, **fc33, **Ni, **Nit, *Wij, *Kij, **Tij, **I, **Mi,
9233          **Q, **Qt, **fa22, **mMi, **mMir;
9234    SUMA_Boolean *SkipNode;
9235    SUMA_SURFACE_CURVATURE *SC;
9236 
9237    SUMA_ENTRY;
9238 
9239    if (!A || !NodeList || !NodeNormList || !FN || !SEL) {
9240       fprintf (SUMA_STDERR, "Error %s: One of your inputs is NULL.\n", FuncName);
9241       SUMA_RETURN(NULL);
9242    }
9243 
9244    SC = (SUMA_SURFACE_CURVATURE *)SUMA_malloc (sizeof(SUMA_SURFACE_CURVATURE));
9245    if (!SC) {
9246       fprintf (SUMA_STDERR, "Error %s: Failed to allocate for SC.\n", FuncName);
9247       SUMA_RETURN(NULL);
9248    }
9249 
9250    Wij = (float *)SUMA_calloc (FN->N_Neighb_max, sizeof(float));
9251    Kij = (float *)SUMA_calloc (FN->N_Neighb_max, sizeof(float));
9252    Num = (float *)SUMA_calloc (3, sizeof(float));
9253    SkipNode = (SUMA_Boolean *) SUMA_calloc (N_Node, sizeof(SUMA_Boolean));
9254    mMi = (float **) SUMA_allocate2D (2,2, sizeof(float));
9255    mMir =(float **) SUMA_allocate2D (2,2, sizeof(float));
9256    fa22 =(float **) SUMA_allocate2D (2,2, sizeof(float));
9257    Tij = (float **) SUMA_allocate2D (FN->N_Neighb_max, 3, sizeof(float));
9258    Ni =  (float **) SUMA_allocate2D (3, 1, sizeof(float));
9259    Nit = (float **) SUMA_allocate2D (1, 3, sizeof(float));
9260    fa33 =(float **) SUMA_allocate2D (3, 3, sizeof(float));
9261    fb33 =(float **) SUMA_allocate2D (3, 3, sizeof(float));
9262    fc33 =(float **) SUMA_allocate2D (3, 3, sizeof(float));
9263    I =   (float **) SUMA_allocate2D (3, 3, sizeof(float));
9264    Q =   (float **) SUMA_allocate2D (3, 3, sizeof(float));
9265    Qt =  (float **) SUMA_allocate2D (3, 3, sizeof(float));
9266    Mi =  (float **) SUMA_allocate2D (3, 3, sizeof(float));
9267    SC->T1 = (float **) SUMA_allocate2D (N_Node, 3, sizeof(float));
9268    SC->T2 = (float **) SUMA_allocate2D (N_Node, 3, sizeof(float));
9269    SC->Kp1 =(float *)SUMA_calloc (N_Node, sizeof(float));
9270    SC->Kp2 =(float *)SUMA_calloc (N_Node, sizeof(float));
9271 
9272    if ( !fa22 || !mMir || !mMi || !Wij || !Kij || !Tij || !Ni || !Nit || !fa33 ||
9273         !fb33 || !fc33 || !I || !Num || !SkipNode || !Mi || !Q || !Qt ||
9274         !SC->T1 || !SC->T2 || !SC->Kp1 || !SC->Kp2) {
9275       SUMA_S_Err("Failed to allocate for Wij, Kij, Tij.\n");
9276       if (Wij) SUMA_free(Wij);
9277       if (Kij) SUMA_free(Kij);
9278       if (Num) SUMA_free(Num);
9279       if (SkipNode) SUMA_free(SkipNode);
9280       if (mMi) SUMA_free2D((char **)mMi, 2);
9281       if (mMir) SUMA_free2D((char **)mMir, 2);
9282       if (fa22) SUMA_free2D((char **)fa22, 2);
9283       if (Tij) SUMA_free2D((char **)Tij, FN->N_Neighb_max);
9284       if (Ni) SUMA_free2D((char **)Ni, 3);
9285       if (Nit) SUMA_free2D((char **)Nit, 1);
9286       if (fa33) SUMA_free2D((char **)fa33, 3);
9287       if (fb33) SUMA_free2D((char **)fb33, 3);
9288       if (I) SUMA_free2D((char **)I, 3);
9289       if (Q) SUMA_free2D((char **)Q, 3);
9290       if (Qt) SUMA_free2D((char **)Qt, 3);
9291       if (Mi) SUMA_free2D((char **)Mi, 3);
9292       if (SC) SUMA_Free_SURFACE_CURVATURE (SC);
9293       SUMA_RETURN(NULL);
9294    }
9295 
9296    /* 3x3 identity matrix */
9297    I[0][0] = I[1][1] = I[2][2] = 1.0;
9298    I[0][1] = I[0][2] = I[1][0] = I[1][2] = I[2][0] = I[2][1] = 0.0;
9299 
9300    /* initialize SC */
9301    SC->N_SkipNode = 0;
9302    SC->N_Node = N_Node;
9303 
9304    if (verb)
9305       fprintf (SUMA_STDERR, "%s: Beginning curvature computations:\n", FuncName);
9306 
9307    ND = 3;
9308    SC->N_SkipNode = 0;
9309    for (i=0; i < N_Node; ++i) { /* for i */
9310       #ifdef DBG_1
9311          if (!(i%10000)) {
9312             if (verb)
9313                fprintf (SUMA_STDERR,
9314                         "%s: [%d]/[%d] %.2f/100%% completed\n",
9315                         FuncName, i, N_Node, (float)i / N_Node * 100);
9316          }
9317       #endif
9318       SkipNode[i] = NOPE;
9319       /* sanity copies */
9320       N_Neighb = FN->N_Neighb[i];
9321       id = ND * i;
9322       Ni[0][0] = NodeNormList[id];
9323       Ni[1][0] = NodeNormList[id+1];
9324       Ni[2][0] = NodeNormList[id+2]; /* Normal vector at i*/
9325       Nit[0][0] = NodeNormList[id];
9326       Nit[0][1] = NodeNormList[id+1];
9327       Nit[0][2] = NodeNormList[id+2]; /* transpose of Ni */
9328       vi[0] = NodeList[id]; vi[1] = NodeList[id+1]; vi[2] = NodeList[id+2];
9329       #ifdef DBG_2
9330          if (verb > 1)
9331             fprintf (SUMA_STDERR,
9332                      "%s: Looping over neighbors, i = %d\n", FuncName, i);
9333       #endif
9334       j=0;
9335       sWij = 0.0;
9336       while (j < N_Neighb) {
9337          ji = FN->FirstNeighb[i][j]; /* index of the jth first neighbor of i */
9338          id = ND * ji;
9339          /* node coordinate vector at jth neighbor */
9340          vj[0] = NodeList[id]; vj[1] = NodeList[id+1]; vj[2] = NodeList[id+2];
9341 
9342          /* calculate Tij */
9343          #ifdef DBG_2
9344             if (verb > 1)
9345                fprintf (SUMA_STDERR, "%s: Mat Op j=%d\n", FuncName, j);
9346          #endif
9347 
9348          /* fa33 = Ni*Ni' */
9349          SUMA_MULT_MAT(Ni,Nit,fa33,3,1,3,float,float,float);
9350 
9351          /* fb33 = I - fa33 */
9352          SUMA_SUB_MAT(I, fa33, fb33, 3, 3, float, float, float);
9353 
9354          /* fa33 = vi - vj (only 1st column is meaningful)*/
9355          fa33[0][0] = vi[0] - vj[0];
9356          fa33[1][0] = vi[1] - vj[1];
9357          fa33[2][0] = vi[2] - vj[2];
9358 
9359          /* Num = fc33 = (I - Ni*Ni') * (vi - vj)
9360             (only 1st column in fc33 is meaningful)*/
9361          SUMA_MULT_MAT(fb33, fa33, fc33, 3, 3, 1, float, float, float);
9362          Num[0] = fc33[0][0]; Num[1] = fc33[1][0]; Num[2] = fc33[2][0];
9363 
9364          /* Calculate Tij at this j, a 3x1 vector unit length normalized
9365             projection projection of vj-vi onto the plane perp. to Ni */
9366          NumNorm = (float)sqrt(Num[0]*Num[0] + Num[1]*Num[1] + Num[2]*Num[2]);
9367          if (NumNorm == 0) {
9368             if (verb)
9369                fprintf (SUMA_STDERR,
9370                         "Warning %s: NumNorm = 0 for node %d.\n", FuncName, i);
9371             SkipNode[i] = YUP;
9372             SC->N_SkipNode++;
9373             break;
9374          }
9375 
9376          Tij[j][0] = Num[0] / NumNorm;
9377          Tij[j][1] = Num[1] / NumNorm;
9378          Tij[j][2] = Num[2] / NumNorm;
9379 
9380          #ifdef DBG_2
9381             if (verb > 1)
9382                fprintf(SUMA_STDOUT,
9383                         "%s: i,j, ji =%d,%d, %d Ni = %f %f %f\n"
9384                         "Tij(%d,:) = %f %f %f.\n",
9385                   FuncName, i, j, ji,Ni[0][0], Ni[1][0], Ni[2][0],
9386                                j, Tij[j][0], Tij[j][1], Tij[j][2]);
9387          #endif
9388 
9389          /* calculate Kij(j) the directional curvature along ij*/
9390          /* fa33 = (vj - vi) (only 1st column is meaningful)*/
9391          fa33[0][0] = (vj[0] - vi[0]);
9392          fa33[1][0] = (vj[1] - vi[1]);
9393          fa33[2][0] = (vj[2] - vi[2]);
9394          /* Num = fb33 = Ni' * fa33 (only 1st value in fb33 is meaningful)*/
9395          SUMA_MULT_MAT(Nit, fa33, fb33, 1, 3, 1, float, float, float);
9396          num = fb33[0][0];
9397          /* denum = sum((vj - vi)^2) */
9398          denum =  fa33[0][0] * fa33[0][0] +
9399                   fa33[1][0] * fa33[1][0]+ fa33[2][0] * fa33[2][0];
9400 
9401          Kij[j] = 2 * num / denum;
9402          #ifdef DBG_2
9403             if (verb > 1)
9404                fprintf(SUMA_STDOUT,"%s: Kij[%d] = %f\n", FuncName, j, Kij[j]);
9405          #endif
9406 
9407          /* calculate the weights for integration, Wij */
9408             /* find the incident triangles */
9409             if (!SUMA_Get_Incident(i, ji, SEL, Incident, &N_Incident, 1, !verb))
9410             {
9411                SUMA_S_Err("Failed in SUMA_Get_Incident.\n");
9412                if (Wij) SUMA_free(Wij);
9413                if (Kij) SUMA_free(Kij);
9414                if (Num) SUMA_free(Num);
9415                if (SkipNode) SUMA_free(SkipNode);
9416                if (mMi) SUMA_free2D((char **)mMi, 2);
9417                if (mMir) SUMA_free2D((char **)mMir, 2);
9418                if (fa22) SUMA_free2D((char **)fa22, 2);
9419                if (Tij) SUMA_free2D((char **)Tij, FN->N_Neighb_max);
9420                if (Ni) SUMA_free2D((char **)Ni, 3);
9421                if (Nit) SUMA_free2D((char **)Nit, 1);
9422                if (fa33) SUMA_free2D((char **)fa33, 3);
9423                if (fb33) SUMA_free2D((char **)fb33, 3);
9424                if (I) SUMA_free2D((char **)I, 3);
9425                if (Q) SUMA_free2D((char **)Q, 3);
9426                if (Qt) SUMA_free2D((char **)Qt, 3);
9427                if (Mi) SUMA_free2D((char **)Mi, 3);
9428                if (SC) SUMA_Free_SURFACE_CURVATURE (SC);
9429                SUMA_RETURN(NULL);
9430             }
9431 
9432             #ifdef DBG_2
9433                if (verb > 1) {
9434                   fprintf (SUMA_STDERR,"%s: Incidents ...\n", FuncName);
9435                   for (kk=0; kk < N_Incident; ++kk) {
9436                      fprintf (SUMA_STDERR,"\t %d", Incident[kk]);
9437                   }
9438                   fprintf (SUMA_STDERR,"\n");
9439                }
9440             #endif
9441 
9442             if (N_Incident != 2 && N_Incident != 1)
9443             {
9444                if (verb)
9445                   SUMA_S_Warnv("Unexpected N_Incident = %d at i,j = %d,%d\n",
9446                                N_Incident, i, j);
9447                SkipNode[i] = YUP;
9448                ++SC->N_SkipNode;
9449                break;
9450             }
9451             Wij[j] = 0.0;
9452             for (ii=0; ii < N_Incident; ++ii) {
9453                Wij[j] = Wij[j] + fabs(A[Incident[ii]]);
9454             }
9455             sWij += Wij[j];
9456             if (Wij[j] == 0.0) {
9457                if (verb) SUMA_S_Warnv("Null Wij[%d] at i,j=%d,%d\n", j, i, j);
9458                SkipNode[i] = YUP;
9459                ++SC->N_SkipNode;
9460                break;
9461             }
9462 
9463          ++j;
9464 
9465       }/* while j*/
9466       if (!SkipNode[i]) {
9467             /* make the sum of the weights be equal to 1*/
9468             #ifdef DBG_2
9469                if (verb > 1) fprintf (SUMA_STDERR,"%s: Wij:\n", FuncName);
9470             #endif
9471             for (ii=0; ii < N_Neighb; ++ii) {
9472                Wij[ii] /= sWij;
9473                /*   fprintf (SUMA_STDERR,"Wij[%d]=%f\t", ii, Wij[ii]);*/
9474             }
9475             #ifdef DBG_2
9476                if (verb > 1) fprintf (SUMA_STDERR,"\n");
9477             #endif
9478             /* calculate Mi */
9479             Mi[0][0] = Mi[1][0] = Mi[2][0] = Mi[0][1] = Mi[1][1] = Mi[2][1] = Mi[0][2] = Mi[1][2] = Mi[2][2] = 0.0;
9480             for (j=0; j < N_Neighb; ++j) {
9481                /* calculate fc33 = Tij(j,:)' * Tij(j,:) transpose on Tij is flipped from equation because Tij(j,:) should be a column vector */
9482                 fa33[0][0] = Tij[j][0]; fa33[1][0] = Tij[j][1]; fa33[2][0] = Tij[j][2];
9483                fb33[0][0] = Tij[j][0]; fb33[0][1] = Tij[j][1]; fb33[0][2] = Tij[j][2];
9484                SUMA_MULT_MAT (fa33, fb33, fc33, 3, 1, 3, float, float, float);
9485 
9486                for (ii=0; ii < 3; ++ii) {
9487                   for (kk=0; kk < 3; ++kk) {
9488                      Mi[ii][kk] = Mi[ii][kk] + Wij[j] * Kij[j] * fc33[ii][kk];
9489                   }
9490                }
9491             }
9492             #ifdef DBG_2
9493                if (verb > 1) SUMA_disp_mat (Mi, 3, 3, 1);
9494             #endif
9495             /* calculate Householder of Ni */
9496             Ntmp[0] = Ni[0][0]; Ntmp[1] = Ni[1][0]; Ntmp[2] = Ni[2][0];
9497             if (!SUMA_Householder(Ntmp, Q)) {
9498                fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_Householder for node %d.\n ", FuncName, i);
9499                mg = 0.0;
9500                SkipNode[i] = YUP;
9501                SC->N_SkipNode++;
9502             } else {
9503                T1e[0] = Q[0][1]; T1e[1] = Q[1][1]; T1e[2] = Q[2][1];
9504                T2e[0] = Q[0][2]; T2e[1] = Q[1][2]; T2e[2] = Q[2][2];  /* T tilda 1, T tilda2 */
9505                SUMA_TRANSP_MAT (Q, Qt, 3, 3, float, float);
9506                #ifdef DBG_2
9507                   if (verb > 1) {
9508                      SUMA_disp_mat (Q, 3, 3, 1);
9509                      SUMA_disp_mat (Qt, 3, 3, 1);
9510                   }
9511                #endif
9512 
9513                /* Mi (aka fb33) = Q' * Mi * Q; Mi should become a 3x3 with 2x2  non zero minor in lower right */
9514                SUMA_MULT_MAT (Qt, Mi, fa33, 3, 3, 3, float, float, float);
9515                SUMA_MULT_MAT (fa33, Q, Mi, 3, 3, 3, float, float, float);
9516                #ifdef DBG_2
9517                   if (verb > 1) SUMA_disp_mat (Mi, 3, 3, 1);
9518                #endif
9519                mMi[0][0] = Mi[1][1]; mMi[0][1] = Mi[1][2];
9520                mMi[1][0] = Mi[2][1]; mMi[1][1] = Mi[2][2];
9521 
9522                /*compute c ( = cos(theta) ) & s ( = sin(theta) )from the Givens rotation to null out the bottom left element of the non zero minor mMi*/
9523                mg = sqrt(mMi[0][0]*mMi[0][0] + mMi[1][0]*mMi[1][0]);
9524                c = mMi[0][0] / mg;
9525                s = mMi[1][0] / mg;
9526                /* rotate mMi */
9527                fa22[0][0] =  c; fa22[0][1] = s;
9528                fa22[1][0] = -s; fa22[1][1] = c;
9529                SUMA_MULT_MAT(fa22, mMi, mMir, 2, 2, 2, float, float, float);
9530                #ifdef DBG_2
9531                   if (verb > 1) fprintf (SUMA_STDERR,"%s: mg = %f, c = %f, s = %f\n", FuncName,  mg, c, s);
9532                #endif
9533                /* calculate the principal directions */
9534                SC->T1[i][0] = c * T1e[0] - s * T2e[0];
9535                SC->T1[i][1] = c * T1e[1] - s * T2e[1];
9536                SC->T1[i][2] = c * T1e[2] - s * T2e[2];
9537 
9538                SC->T2[i][0] = s * T1e[0] + c * T2e[0];
9539                SC->T2[i][1] = s * T1e[1] + c * T2e[1];
9540                SC->T2[i][2] = s * T1e[2] + c * T2e[2];
9541 
9542                /* calculate the principal curvatures and mean curvatures etc ... */
9543                SC->Kp1[i] = 3 * mMir[0][0] - mMir[1][1];
9544                SC->Kp2[i] = 3 * mMir[1][1] - mMir[0][0];
9545                #ifdef DBG_2
9546                   if (verb > 1) fprintf (SUMA_STDERR,"%s: SC->Kp1[i] = %f, SC->Kp2[i] = %f, mKp[i] = %f\n", FuncName,  SC->Kp1[i], SC->Kp2[i], (SC->Kp1[i]+SC->Kp2[i])/2);
9547                #endif
9548             }
9549 
9550          #ifdef DBG_3
9551             if (verb > 2) SUMA_PAUSE_PROMPT("Done with node, waiting to move to next");
9552          #endif
9553 
9554       } /* not skipped (yet)*/
9555       if (SkipNode[i]) {
9556          SC->T1[i][0] = SC->T1[i][1] = SC->T1[i][2] = 0.0;
9557          SC->T2[i][0] = SC->T2[i][1] = SC->T2[i][2] = 0.0;
9558          SC->Kp1[i] = SC->Kp2[i] = 0.0;
9559       }
9560    }/* for i */
9561 
9562    /* write out the results to a file (debugging only)*/
9563    if (odbg_name) {
9564       FILE *fid;
9565       fprintf(SUMA_STDOUT,"%s: Writing Kp1 & Kp2 to %s ...", FuncName, odbg_name );
9566       fid = fopen(odbg_name,"w");
9567       for (ii=0; ii < SC->N_Node; ++ii) {
9568          /*fprintf(fid,"%f %f\n", (SC->Kp1[ii]+SC->Kp2[ii])/2, SC->Kp1[ii]*SC->Kp2[ii]);*/
9569          fprintf(fid,"%f %f\n", SC->Kp1[ii], SC->Kp2[ii]);
9570       }
9571       fclose (fid);
9572 
9573       fprintf(SUMA_STDOUT,"%s: Done.\n", FuncName);
9574    }
9575 
9576    /* free the left overs */
9577    if (Wij) SUMA_free(Wij);
9578    if (Kij) SUMA_free(Kij);
9579    if (Num) SUMA_free(Num);
9580    if (SkipNode) SUMA_free(SkipNode);
9581    if (mMi) SUMA_free2D((char **)mMi, 2);
9582    if (mMir) SUMA_free2D((char **)mMir, 2);
9583    if (fa22) SUMA_free2D((char **)fa22, 2);
9584    if (Tij) SUMA_free2D((char **)Tij, FN->N_Neighb_max);
9585    if (Ni) SUMA_free2D((char **)Ni, 3);
9586    if (Nit) SUMA_free2D((char **)Nit, 1);
9587    if (fa33) SUMA_free2D((char **)fa33, 3);
9588    if (fb33) SUMA_free2D((char **)fb33, 3);
9589    if (I) SUMA_free2D((char **)I, 3);
9590    if (Q) SUMA_free2D((char **)Q, 3);
9591    if (Qt) SUMA_free2D((char **)Qt, 3);
9592    if (Mi) SUMA_free2D((char **)Mi, 3);
9593 
9594    if (verb) fprintf (SUMA_STDERR,
9595                       "%s: Done with curvature computations.\n", FuncName);
9596 
9597    SUMA_RETURN (SC);
9598 }
9599 
SUMA_CurvatureToDset(SUMA_SURFACE_CURVATURE * SC,char * OutPrefix)9600 SUMA_DSET *SUMA_CurvatureToDset(SUMA_SURFACE_CURVATURE *SC, char *OutPrefix)
9601 {
9602    static char FuncName[]={"SUMA_CurvatureToDset"};
9603    int i=0;
9604    float *Kpmag = NULL;
9605    float *fvtmp = NULL;
9606    SUMA_DSET *ndset=NULL;
9607 
9608    SUMA_ENTRY;
9609 
9610    if (!SC || !SC->N_Node || !SC->T1 || !SC->Kp1) SUMA_RETURN(NULL);
9611 
9612    if (!OutPrefix) OutPrefix = FuncName;
9613    if (!(Kpmag = (float*)SUMA_calloc(SC->N_Node, sizeof(float)))) {
9614       SUMA_S_Err("Failed to allocate for Kpmag");
9615       SUMA_RETURN(NULL);
9616    }
9617    if (!(fvtmp = (float*)SUMA_calloc(SC->N_Node, sizeof(float)))) {
9618       SUMA_S_Err("Failed to allocate for fvtmp");
9619       SUMA_free(Kpmag);
9620       SUMA_RETURN(NULL);
9621    }
9622    for (i=0; i < SC->N_Node; ++i) {
9623       Kpmag[i] = sqrt(SC->Kp1[i]*SC->Kp1[i]+
9624                    SC->Kp2[i]*SC->Kp2[i]);
9625    }
9626 
9627    ndset =  SUMA_CreateFullDsetPointer(
9628             OutPrefix,
9629             SUMA_NODE_BUCKET,
9630             NULL,
9631             NULL,
9632             SC->N_Node );
9633 
9634 
9635    for (i=0; i < SC->N_Node; ++i) fvtmp[i]=SC->T1[i][0];
9636    if (!SUMA_AddDsetNelCol(ndset, "P1x", SUMA_NODE_FLOAT,
9637                            (void *)fvtmp, NULL, 1)) {
9638       SUMA_S_Err("Failed to add col P1x");
9639       exit(1);
9640    }
9641    for (i=0; i < SC->N_Node; ++i) fvtmp[i]=SC->T1[i][1];
9642    if (!SUMA_AddDsetNelCol(ndset, "P1y", SUMA_NODE_FLOAT,
9643                            (void *)fvtmp, NULL, 1)) {
9644       SUMA_S_Err("Failed to add col P1y");
9645       exit(1);
9646    }
9647    for (i=0; i < SC->N_Node; ++i) fvtmp[i]=SC->T1[i][2];
9648    if (!SUMA_AddDsetNelCol(ndset, "P1z", SUMA_NODE_FLOAT,
9649                            (void *)fvtmp, NULL, 1)) {
9650       SUMA_S_Err("Failed to add col P1z");
9651       exit(1);
9652    }
9653    for (i=0; i < SC->N_Node; ++i) fvtmp[i]=SC->T2[i][0];
9654    if (!SUMA_AddDsetNelCol(ndset, "P2x", SUMA_NODE_FLOAT,
9655                            (void *)fvtmp, NULL, 1)) {
9656       SUMA_S_Err("Failed to add col P2x");
9657       exit(1);
9658    }
9659    for (i=0; i < SC->N_Node; ++i) fvtmp[i]=SC->T2[i][1];
9660    if (!SUMA_AddDsetNelCol(ndset, "P2y", SUMA_NODE_FLOAT,
9661                            (void *)fvtmp, NULL, 1)) {
9662       SUMA_S_Err("Failed to add col P2y");
9663       exit(1);
9664    }
9665    for (i=0; i < SC->N_Node; ++i) fvtmp[i]=SC->T2[i][2];
9666    if (!SUMA_AddDsetNelCol(ndset, "P2z", SUMA_NODE_FLOAT,
9667                            (void *)fvtmp, NULL, 1)) {
9668       SUMA_S_Err("Failed to add col P2z");
9669       exit(1);
9670    }
9671    if (!SUMA_AddDsetNelCol(ndset, "Kp1", SUMA_NODE_FLOAT,
9672                            (void *)SC->Kp1, NULL, 1)) {
9673       SUMA_S_Err("Failed to add col Kp1");
9674       exit(1);
9675    }
9676    if (!SUMA_AddDsetNelCol(ndset, "Kp2", SUMA_NODE_FLOAT,
9677                            (void *)SC->Kp2, NULL, 1)) {
9678       SUMA_S_Err("Failed to add col Kp2");
9679       exit(1);
9680    }
9681    if (!SUMA_AddDsetNelCol(ndset, "Kpmag", SUMA_NODE_FLOAT,
9682                            (void *)Kpmag, NULL, 1)) {
9683       SUMA_S_Err("Failed to add col Kp");
9684       exit(1);
9685    }
9686    SUMA_free(Kpmag); Kpmag=NULL;
9687 
9688    SUMA_RETURN(ndset);
9689 }
9690 
9691 /*!
9692    free the SUMA_SURFACE_CURVATURE structure
9693 */
SUMA_Free_SURFACE_CURVATURE(SUMA_SURFACE_CURVATURE * SC)9694 void SUMA_Free_SURFACE_CURVATURE (SUMA_SURFACE_CURVATURE *SC)
9695 {
9696    static char FuncName[]={"SUMA_Free_SURFACE_CURVATURE"};
9697 
9698    SUMA_ENTRY;
9699 
9700    if (SC == NULL) SUMA_RETURNe;
9701    if (SC->Kp1) SUMA_free(SC->Kp1);
9702    if (SC->Kp2) SUMA_free(SC->Kp2);
9703    if (SC->T1) SUMA_free2D ((char **)SC->T1, SC->N_Node);
9704    if (SC->T2) SUMA_free2D ((char **)SC->T2, SC->N_Node);
9705    if (SC) SUMA_free(SC);
9706    SUMA_RETURNe;
9707 }
9708 
9709 /*!
9710    Computes the householder matrix for a 3x1 vector
9711    Vh = Q * V will have all elements but the first = 0
9712 
9713    ans = SUMA_Householder (float *V, float **Q)
9714 
9715    \param V (float *) 3x1 column vector
9716    \param Q (float **) 3x3 (pre-allocated) matrix that will contain the Householder matrix
9717 
9718    \ret ans (SUMA_Boolean) YUP/NOPE (failure)
9719 
9720    The code for this function contains two algorithms, one is identical to
9721    Taubin's suggestion and one is a generic Householder algorithm.
9722 
9723 */
9724 #define TAUBIN_Householder
SUMA_Householder(float * Ni,float ** Q)9725 SUMA_Boolean SUMA_Householder (float *Ni, float **Q)
9726 {
9727    static char FuncName[] = {"SUMA_Householder"};
9728    float mNi, e[3], b[3], mb;
9729    int ii;
9730    #ifdef TAUBIN_Householder
9731    float d[3], s[3], nd, ns;
9732    #endif
9733 
9734    SUMA_ENTRY;
9735 
9736    e[0] = 1.0; e[1] = 0.0; e[2] = 0.0;
9737 
9738    #ifndef TAUBIN_Householder
9739       /* generic algorithm */
9740       mNi = sqrt(Ni[0] * Ni[0] + Ni[1] * Ni[1] + Ni[2] * Ni[2]);
9741       for (ii=0; ii < 3; ++ii)
9742          b[ii] = Ni[ii] + mNi * e[ii];
9743       mb = sqrt(b[0] * b[0] + b[1] * b[1] + b[2] * b[2]);
9744 
9745       if (mb == 0) {
9746          fprintf (SUMA_STDERR,"Error %s: mb = 0\n",FuncName);
9747          SUMA_RETURN (NOPE);
9748       }
9749 
9750       b[0] /= mb; b[1] /= mb; b[2] /= mb;
9751    #else
9752       /* Taubin's algorithm Estimating the tensor of curvature of a surface from a polyhedral approximation */
9753       /* calculate difference and sum vectors with their norms (save sqrt for later) */
9754 
9755       d[0] = e[0] - Ni[0]; d[1] = e[1] - Ni[1]; d[2] = e[2] - Ni[2];
9756       nd = d[0]*d[0] + d[1]*d[1] + d[2]*d[2];
9757 
9758       s[0] = e[0] + Ni[0]; s[1] = e[1] + Ni[1]; s[2] = e[2] + Ni[2];
9759       ns = s[0]*s[0] + s[1]*s[1] + s[2]*s[2];
9760 
9761       if (!nd || !ns) {
9762          fprintf (SUMA_STDERR,"Error %s: nd || ns = 0\n",FuncName);
9763          SUMA_RETURN (NOPE);
9764       }
9765 
9766       if (nd > ns) {
9767          nd = sqrt(nd);
9768          b[0] = d[0] / nd;
9769          b[1] = d[1] / nd;
9770          b[2] = d[2] / nd;
9771          /*Q(:,1) will be equal to -Ni*/
9772 
9773       } else {
9774          ns = sqrt(ns);
9775          b[0] = s[0] / ns;
9776          b[1] = s[1] / ns;
9777          b[2] = s[2] / ns;
9778          /*Q(:,1) will be equal to  Ni */
9779       }
9780 
9781    #endif
9782 
9783    /* calc Q = I - 2 b * b' */
9784    Q[0][0] = 1 - 2 * b[0] * b[0];
9785    Q[1][0] = - 2 * b[1] * b[0];
9786    Q[2][0] = - 2 * b[2] * b[0];
9787 
9788    Q[0][1] = - 2 * b[0] * b[1];
9789    Q[1][1] = 1 - 2 * b[1] * b[1];
9790    Q[2][1] = - 2 * b[2] * b[1];
9791 
9792    Q[0][2] = - 2 * b[0] * b[2];
9793    Q[1][2] = - 2 * b[1] * b[2];
9794    Q[2][2] = 1 - 2 * b[2] * b[2];
9795 
9796    SUMA_RETURN (YUP);
9797 }
9798 /*!
9799    C = SUMA_Convexity (NodeList, N_Node, NodeNormList, FN, thisone)
9800 
9801    \param NodeList (float *) N_Node x 3 vector containing the coordinates
9802                               for each node
9803    \param N_Node (int) number of nodes
9804    \param NodeNormList (float *) N_Node x 3 vector (was matrix prior to SUMA 1.2)
9805                               containing the unit normals at each node
9806    \param FN (SUMA_NODE_FIRST_NEIGHB *) first order node neighbor structure
9807    \ret C (float *) N_Node x 1 vector containing the curvature at each node.
9808                     The convexity is the sum of the signed distance of all
9809                     the neighboring nodes to the tangent plane.
9810                     The sign of C[i] indicates the convexity.
9811 
9812    C[i] = -Sum(dj/dij) over all neighbors j of i
9813                         (the - sign was added May 06 04 )
9814    dj is the distance of neighboring node j to the tangent plane at i
9815    dij is the length of the segment ij
9816 
9817    You can consider the magnitude of C as a measure of the curvature at the node.
9818    Use it wisely.
9819 
9820    The Normals are assumed to be unit vectors
9821 
9822    Aug 14 03
9823    This function actually calls SUMA_Convexity_Engine with NULL for DetailFile parameter.
9824    See SUMA_Convexity_Engine
9825    May 06 04:
9826    This function was modified to return +ve values for convex regions and negative
9827    for concave ones. It used to be the opposite.
9828 */
9829 
SUMA_Convexity(float * NL,int N_N,float * NNL,SUMA_NODE_FIRST_NEIGHB * FN,float * usethis)9830 float * SUMA_Convexity (float *NL, int N_N, float *NNL,
9831                         SUMA_NODE_FIRST_NEIGHB *FN, float *usethis)
9832 {
9833    static char FuncName[]={"SUMA_Convexity"};
9834    float *C=NULL;
9835 
9836    SUMA_ENTRY;
9837 
9838    C = SUMA_Convexity_Engine (NL, N_N, NNL, FN, NULL, usethis);
9839 
9840    SUMA_RETURN(C);
9841 
9842 }
9843 /*!
9844    \brief float * SUMA_Convexity_Engine (float *NL, int N_N, float *NNL, SUMA_NODE_FIRST_NEIGHB *FN, char *DetailFile)
9845    This function does the computations for SUMA_Convexity with the additional option of outputing detailed results
9846    to an ASCII file for debugging.
9847 
9848    See documentation for SUMA_Convexity for all parameters except DetailFile
9849    \param DetailFile (char *) if not NULL, then you'll get an output file named
9850                               by DetailFile with debugging info:
9851                               i  n  d1 d1ij d1/d1ij .. dn dnij dn/dnij
9852                                  where i is node index
9853                                  n = FN->N_Neighb[i]
9854                                  d1 and d1ij are the distances (read the function
9855                                  for details...
9856                                  The matlab function ProcessConv_detail is used
9857                                  to parse the contents of DetailFile
9858                                  Make sure changes made to this file are reflected in
9859                                  that function.
9860                               NOTE: Pre-existing files will get overwritten.
9861    MAY 06 04: The values are +ve for concave areas (i.e. fundus of sulcus) and
9862    negative for convex areas. This is counter to the name of the function and the
9863    user's expectation (want fundus to have lower value --> dark color).
9864    So to fix this injustice I changed the sign of C
9865 */
SUMA_Convexity_Engine(float * NL,int N_N,float * NNL,SUMA_NODE_FIRST_NEIGHB * FN,char * DetailFile,float * usethis)9866 float * SUMA_Convexity_Engine (float *NL, int N_N, float *NNL,
9867                                SUMA_NODE_FIRST_NEIGHB *FN, char *DetailFile,
9868                                float *usethis)
9869 {
9870    static char FuncName[]={"SUMA_Convexity_Engine"};
9871    float *C, d, D, dij;
9872    int i, j, jj, in, id, ind, ND;
9873    FILE *fid = NULL;
9874 
9875    SUMA_ENTRY;
9876 
9877    C = NULL;
9878    if (usethis) C = usethis;
9879 
9880    if (!C) {
9881       /* allocate for C */
9882       C = (float *)SUMA_calloc (N_N, sizeof(float));
9883    }
9884    if (C == NULL) {
9885       fprintf (SUMA_STDERR,"Error %s: Could not allocate for C.\n", FuncName);
9886       SUMA_RETURN (C);
9887    }
9888 
9889 
9890    if (DetailFile) {
9891       fprintf (SUMA_STDERR,"%s:\nSaving convexity Info to %s.\n", FuncName, DetailFile);
9892       fid = fopen(DetailFile,"w");
9893    }
9894 
9895    ND = 3;
9896    for (i=0; i < N_N; ++i) {
9897       id = ND * i;
9898       /* the plane at node i, having normal [NNL(id), NNL(id+1), NNL(id+2)] (id = 3*i) has the equation A X + B Y + C Z + D = 0
9899       NNL[id] NL[id]  + NNL[id+1] NNL[id+1]  + NNL[id+2] NL[id+2] + D = 0 */
9900 
9901       D = -NNL[id] * NL[id] - NNL[id+1] * NL[id+1] - NNL[id+2] * NL[id+2];
9902 
9903       if (DetailFile) fprintf(fid,"%d   %d   ", i, FN->N_Neighb[i]);
9904 
9905       for (j=0; j < FN->N_Neighb[i]; ++j) {
9906          /* find the distance between the neighboring node j and the tangent plane at i
9907          d = (A X + B Y + C Z + D ) / (sqrt(A*A + B*B + C*C))
9908          denominator is norm of Normals which should be 1
9909          */
9910          in = FN->FirstNeighb[i][j];
9911          ind = in * ND;
9912          d = NNL[id] * NL[ind] + NNL[id+1] * NL[ind+1] + NNL[id+2] * NL[ind+2] + D ;
9913 
9914          /* calculate the distance between node i and it's neighbor */
9915          dij = sqrt( (NL[ind] - NL[id]) * (NL[ind] - NL[id]) + (NL[ind+1] - NL[id+1]) * (NL[ind+1] - NL[id+1]) + (NL[ind+2] - NL[id+2]) * (NL[ind+2] - NL[id+2]));
9916 
9917          /* assuming normals are normalized d is the cosine of the angle between the two vectors */
9918          /* if d > 0, then angle is > 0..90 degrees */
9919 
9920          /* as a measure of curvature, compute the sum of signed distances of negihbors to tangent plane at i.
9921          use distances normalized by length of segment ij to account for differences in segment length */
9922 
9923          if (dij > SUMA_EPSILON) C[i] -= d/dij; /* used to be C[i] += d/dij; prior to May 06 04 */
9924          else C[i] = 0.0;
9925 
9926          if (DetailFile) fprintf(fid,"%f\t%f\t%f\t", d, dij, d/dij);
9927 
9928       }
9929 
9930       if (DetailFile) {
9931          /* fill with -1 until you reach FN->N_Neighb_max */
9932          for (jj=FN->N_Neighb[i]; jj < FN->N_Neighb_max; ++jj) fprintf(fid,"-1\t-1\t-1\t");
9933          fprintf(fid,"\n");
9934       }
9935 
9936    }
9937 
9938    if (DetailFile) fclose (fid);  /* close previous file */
9939 
9940    #if 0
9941    {
9942       /* Now write the results to disk just for debugging */
9943       fprintf(SUMA_STDOUT,"%s: Writing convexity to Conv.txt ...", FuncName);
9944       fid = fopen("Conv.txt","w");
9945       for (i=0; i < N_N; ++i) {
9946          fprintf(fid,"%f\n", C[i]);
9947       }
9948       fclose (fid);
9949 
9950       fprintf(SUMA_STDOUT,"%s: Done.\n", FuncName);
9951    }
9952    #endif
9953 
9954    SUMA_RETURN (C);
9955 }
9956 
9957 /*!
9958    Function to pad a string to a certain length
9959 
9960       char * SUMA_pad_str (char *str, char pad_val , int pad_ln , int opt)
9961 
9962        str, (char *) string with the original string
9963        pad_char, (char )  padding character
9964        pad_ln, (int) final padded lenght,
9965        opt, (int) 0 if padding occurs to the left of str (00005)
9966                    1 if padding occurs to the right of str (50000)
9967    Returns :
9968        a pointer to the padded string .
9969 
9970 */
9971 
SUMA_pad_str(char * str,char pad_val,int pad_ln,int opt)9972 char * SUMA_pad_str ( char *str, char pad_val , int pad_ln , int opt)
9973 {/*SUMA_pad_str*/
9974    static char FuncName[]={"SUMA_pad_str"};
9975    int lo,i, nb1;
9976    char *strp , *buf1;
9977 
9978    SUMA_ENTRY;
9979 
9980    assert (str);
9981 
9982    lo = (int)strlen(str);
9983 
9984    buf1 = (char *)SUMA_calloc (pad_ln-lo+2,sizeof (char));
9985    strp = (char *)SUMA_calloc (pad_ln+lo+2,sizeof (char));
9986 
9987    nb1 = 0;
9988    for (i=0;i<pad_ln-lo;++i) {
9989       buf1[nb1++]=pad_val;
9990    }
9991    buf1[nb1] = '\0';
9992    if (opt == 0)
9993        sprintf (strp,"%s%s",buf1,str);
9994    else if (opt == 1) {
9995       sprintf (strp,"%s%s",str,buf1);
9996    } else {
9997       SUMA_S_Err("Wrong opt paramter, only (0,1) allowed\n");
9998       SUMA_free(strp);
9999       SUMA_free(buf1);
10000       SUMA_RETURN (NULL);
10001    }
10002 
10003    SUMA_free(buf1);
10004 
10005    SUMA_RETURN (strp);
10006 }/*SUMA_pad_str*/
10007 
10008 
SUMA_ReadCharStdin(char def,int case_sensitive,char * allowed)10009 char SUMA_ReadCharStdin (char def, int case_sensitive, char *allowed)
10010 {
10011    static char FuncName[]={"SUMA_ReadCharStdin"};
10012    char str[500], *strback;
10013    char cbuf;
10014    int Done, i, nc, nss;
10015 
10016    SUMA_ENTRY;
10017    do {
10018       Done = 1;
10019       /* fpurge (stdin); */ /* fpurge is not standard on all systems! */
10020       str[0] = def;
10021       str[0] = getchar(); do { str[1] = getchar(); } while (str[1] != '\n'); str[1] = '\0';
10022       cbuf = str[0];
10023       if (SUMA_IS_BLANK(str[0])) {
10024          cbuf = def;
10025       }
10026 
10027       if (!case_sensitive) {
10028          if (cbuf >= 'A' && cbuf <= 'Z') cbuf = cbuf + 'a' - 'A';
10029       }
10030 
10031       if (allowed && cbuf) {
10032          /* make sure that the character is allowed */
10033          nc = strlen(allowed);
10034          for (i=0; i<nc;++i) {
10035             if (cbuf == allowed[i]) SUMA_RETURN(cbuf);
10036          }
10037          Done = 0;
10038          /* rewind */
10039          fprintf(stdout,"\abad input, try again: "); fflush(stdout);
10040       }
10041    } while (!Done);
10042    SUMA_RETURN(cbuf);
10043 }
10044 
10045 /*!
10046    Function to get a bunch of numbers from stdin
10047 
10048    int SUMA_ReadNumStdin (float *fv, int nv)
10049 
10050     \param fv (float *) pointer to nv x 1 vector that will hold the input.
10051    \param nr (int) number of values to be read and stored in fv
10052    \ret nvr (int) number of values actually read from stdin
10053    -1 in case of error
10054 
10055 */
10056 
10057 
SUMA_ReadNumStdin(float * fv,int nv)10058 int SUMA_ReadNumStdin (float *fv, int nv)
10059 {
10060    int i=0, nvr = 0;
10061    char *endp, *strtp, s[SUMA_MAX_STRING_LENGTH], cbuf;
10062    static char FuncName[]={"SUMA_ReadNumStdin"};
10063    SUMA_Boolean eos, LocalHead = NOPE;
10064 
10065    SUMA_ENTRY;
10066 
10067    fflush (stdin);
10068 
10069    while ((cbuf = getc(stdin)) != '\n' && i < SUMA_MAX_STRING_LENGTH-1) {
10070       if (cbuf == ',' || cbuf == '\t') {/* change , and tab  to space*/
10071          cbuf = ' ';
10072       }
10073          s[i] = cbuf;
10074          ++ i;
10075    }
10076 
10077    if (i == SUMA_MAX_STRING_LENGTH-1) {
10078       SUMA_S_Errv("No more than %d characters are allowed on stdin.\n",
10079                   SUMA_MAX_STRING_LENGTH-1);
10080       fflush(stdin);
10081       SUMA_RETURN(-1);
10082    }
10083 
10084    s[i] = '\0';
10085 
10086    if (!i) SUMA_RETURN(0);
10087 
10088    /* parse s */
10089    strtp = s;
10090    endp = NULL;
10091    nvr = 0;
10092    eos = NOPE;
10093    while (nvr < nv && !eos) {
10094       errno = 0;
10095       fv[nvr] = strtod(strtp, &endp);
10096       SUMA_LHv("ERANGE: %d, EDOM %d, errno %d\n", ERANGE, EDOM, errno);
10097 
10098       if (endp == strtp) {
10099          eos = YUP;
10100       } else {
10101          ++nvr;
10102          strtp = endp;
10103       }
10104    }
10105 
10106    if (eos && nvr < nv) {
10107       SUMA_S_Warnv("Expected to read %d elements, read only %d.\n", nv, nvr);
10108    }
10109 
10110    SUMA_RETURN(nvr);
10111 }
10112 
10113 
10114 /***
10115 
10116 File : SUMA_Find_inIntVect.c
10117 Author : Ziad Saad
10118 Date : Thu Nov 12 21:57:12 CST 1998
10119 
10120 Purpose :
10121 
10122 
10123 
10124 Input paramters :
10125    x      int *      :   vector containing integer values
10126    xsz   int      :   number of elements in x
10127    val   int      :   value to look for
10128    nValLocation   int *      :   integer containing the number of points in the SUMA_RETURNed vector
10129 
10130 
10131 Usage :
10132    ValLocation   = SUMA_Find_inIntVect (int *x, int xsz, int val, int *nValLocation)
10133 
10134 
10135 Returns :
10136    ValLocation   int * :
10137 
10138    a pointer to a vector of integers that contains the indices into x where val was found
10139    the vector contains *nValLocation elements
10140 
10141 
10142 
10143 Support :
10144 
10145 
10146 
10147 Side effects :
10148    The function does not use any fast searching mechanisms, might want to make it faster in
10149    the future (use binary searches and such)
10150 
10151 
10152 ***/
SUMA_Find_inIntVect(int * x,int xsz,int val,int * nValLocation)10153 int * SUMA_Find_inIntVect (int *x, int xsz, int val, int *nValLocation)
10154 {/*SUMA_Find_inIntVect*/
10155    int k, *tmp, *ValLocation;
10156    static char FuncName[]={"SUMA_Find_inIntVect"};
10157    SUMA_Boolean LocalHead = NOPE;
10158 
10159    SUMA_ENTRY;
10160 
10161    /* allocate the maximum  space for ValLocation */
10162    tmp = (int *) SUMA_calloc(xsz,sizeof(int));
10163 
10164    *nValLocation = 0;
10165    for (k = 0 ; k < xsz ; ++k)
10166    {
10167       if (x[k] == val)
10168          {
10169             tmp[*nValLocation] = k;
10170             ++*nValLocation;
10171          }
10172 
10173    }
10174 
10175    if (!*nValLocation)
10176       {
10177          SUMA_free (tmp);
10178          SUMA_RETURN (NULL);
10179       }
10180 
10181    /* Now, allocate just enough space for the SUMA_RETURNing vector */
10182       ValLocation = (int *) SUMA_calloc(*nValLocation,sizeof(int));
10183    /*copy the data into ValLocation*/
10184       SUMA_SCALE_VEC(tmp,ValLocation,1,*nValLocation,int,int);
10185    /* get rid of big array */
10186       SUMA_free(tmp);
10187 
10188    SUMA_RETURN (ValLocation);
10189 
10190 }/*SUMA_Find_inIntVect*/
10191 
SUMA_FindFirst_inIntVect(int * x0,int * x1,int val)10192 int SUMA_FindFirst_inIntVect (int *x0, int *x1, int val)
10193 {/*SUMA_FindFirst_inIntVect*/
10194    int *xi=x0;
10195    while(x0<x1) if (*x0==val) return((int)(x0-xi)); else ++x0;
10196    return(-1);
10197 }
10198 
10199 /***
10200 
10201 File : SUMA_UniqueInt.c
10202 Author : Ziad Saad
10203 Date : Fri Nov 13 16:07:23 CST 1998
10204 
10205 Purpose :
10206 
10207 
10208 
10209 Input paramters :
10210    x      int *      : a pointer to a vector of integers
10211    xsz   int       : a scalar indicating the number of elements in x
10212    kunq  int *      : a pointer to an integer that will tell you the number
10213                   of unique elements in x (length of kunq)
10214    Sorted   int   : a falg indicating whether x is sorted or not
10215                      if x is sorted, use 1 otherwise use 0
10216 
10217 
10218 
10219 Usage :
10220       xunq = SUMA_UniqueInt (int *x, int xsz, int *kunq, int Sorted );
10221 
10222 
10223 Returns :
10224    xunq   int *   : a pointer to the vector containing the unique values of x
10225 
10226 
10227 Support :
10228 
10229 
10230 
10231 Side effects :
10232 
10233 
10234 
10235 ***/
SUMA_UniqueInt(int * y,int xsz,int * kunq,int Sorted)10236 int * SUMA_UniqueInt (int *y, int xsz, int *kunq, int Sorted )
10237 {/*SUMA_UniqueInt*/
10238    int *xtmp, *xunq, k ,*x;
10239    SUMA_Boolean LocalHead = NOPE;
10240    static char FuncName[]={"SUMA_UniqueInt"};
10241 
10242    SUMA_ENTRY;
10243    *kunq = 0;
10244 
10245    if (!xsz)
10246     {
10247       SUMA_RETURN(NULL);
10248    }
10249    if (!Sorted)
10250     {/* must sort y , put in a new location so that y is not disturbed*/
10251       x = (int *)SUMA_calloc(xsz, sizeof(int));
10252       if (!x)
10253          {
10254             fprintf (SUMA_STDERR,"Error %s: Failed to allocate for x.", FuncName);
10255             SUMA_RETURN (NULL);
10256          }
10257       for (k=0; k < xsz; ++k)
10258          x[k] = y[k];
10259       qsort(x,xsz,sizeof(int), (int(*) (const void *, const void *)) SUMA_compare_int);
10260    }
10261    else
10262       x = y;
10263 
10264    if (!xsz)   /* Nothing sent ! */
10265     SUMA_RETURN (NULL);
10266 
10267    xtmp = (int *) SUMA_calloc(xsz,sizeof(int));
10268    if (xtmp == NULL)
10269     {
10270       fprintf (SUMA_STDERR,"Error %s: Could not allocate memory", FuncName);
10271       SUMA_RETURN (NULL);
10272    }
10273 
10274    *kunq = 0;
10275    xtmp[0] = x[0];
10276    for (k=1;k<xsz;++k)
10277     {
10278       if ((x[k] != x[k - 1]))
10279          {
10280             ++*kunq;
10281             xtmp[*kunq] = x[k];
10282          }
10283    }
10284    ++*kunq;
10285 
10286 
10287    /* get rid of extra space allocated */
10288    xunq = (int *) SUMA_calloc(*kunq,sizeof(int));
10289    SUMA_COPY_VEC(xtmp,xunq,*kunq,int,int);
10290 
10291    SUMA_free(xtmp);
10292 
10293    if (!Sorted)
10294       SUMA_free (x);
10295 
10296    SUMA_RETURN (xunq);
10297 }/*SUMA_UniqueInt*/
10298 
10299 /*!
10300    \brief In addition to returning the unique set of values,
10301    The function creates a vector of indices specifying
10302    which values in y were retained
10303 
10304    yu = SUMA_UniqueInt_ind (y, N_y, N_yu, Sorted, iu);
10305 
10306    \param y (int *) SORTED input vector
10307    \param N_y (int) number of elements in y
10308    \param N_yu (int *) to contain number of elements in yu
10309    \param iu (int **) to contain pointer to vector containing
10310                       indices into y of the values retained in
10311                       yu
10312 
10313    \sa SUMA_UniqueInt_ind
10314    \sa SUMA_z_dqsort
10315 
10316    -Make sure y is sorted ahead of time
10317    -remember to free yu and *iu after you are done with them
10318 */
SUMA_UniqueInt_ind(int * ys,int N_y,int * kunq,int ** iup)10319 int * SUMA_UniqueInt_ind (int *ys, int N_y, int *kunq, int **iup)
10320 {/*SUMA_UniqueInt*/
10321    int *yu=NULL, k ,*iu=NULL;
10322    SUMA_Boolean LocalHead = NOPE;
10323    static char FuncName[]={"SUMA_UniqueInt_ind"};
10324 
10325    SUMA_ENTRY;
10326 
10327    *kunq = 0;
10328 
10329    if (!N_y)
10330     {
10331       SUMA_RETURN(NULL);
10332    }
10333 
10334    if (!N_y)   /* Nothing sent ! */
10335     SUMA_RETURN (NULL);
10336 
10337    yu = (int *) SUMA_calloc(N_y,sizeof(int));
10338    iu = (int *) SUMA_calloc(N_y,sizeof(int));
10339    if (!yu || !iu)
10340     {
10341       fprintf (SUMA_STDERR,"Error %s: Could not allocate memory", FuncName);
10342       SUMA_RETURN (NULL);
10343    }
10344 
10345    *kunq = 0;
10346    yu[0] = ys[0];
10347    iu[0] = 0;
10348    for (k=1;k<N_y;++k)
10349     {
10350       if ((ys[k] != ys[k - 1]))
10351          {
10352             ++*kunq;
10353             yu[*kunq] = ys[k];
10354             iu[*kunq] = k;
10355          }
10356    }
10357    ++*kunq;
10358 
10359 
10360    /* get rid of extra space allocated */
10361    yu = (int *) SUMA_realloc(yu, *kunq*sizeof(int));
10362    iu = (int *) SUMA_realloc(iu, *kunq*sizeof(int));
10363 
10364    *iup = iu;
10365    SUMA_RETURN (yu);
10366 }/*SUMA_UniqueInt_ind*/
10367 
10368 
10369 
SUMA_ShowFromTo(char * f,char * t,char * head)10370 void SUMA_ShowFromTo(char *f, char *t, char *head){
10371    if (head) {
10372       fprintf(SUMA_STDERR, "%s", head);
10373    } else {
10374       fprintf(SUMA_STDERR, "Chunk in question:\n"
10375                            "------------------\n");
10376    }
10377    while (f<t) {
10378       fprintf(SUMA_STDERR, "%c", *f); ++f;
10379    }
10380    fprintf(SUMA_STDERR, "\n");
10381    return;
10382 }
10383 
SUMA_LineNumbersFromTo(char * f,char * t)10384 int SUMA_LineNumbersFromTo(char *f, char *t){
10385    int N_line = 0;
10386 
10387    while (f<t) {
10388       if (SUMA_IS_LINE_END(*f)) ++N_line;
10389       ++f;
10390    }
10391    return(N_line);
10392 }
10393 
SUMA_makepow2(int val)10394 int SUMA_makepow2(int val)
10395 {
10396    int power = 0;
10397    if(!val) return 0;
10398 
10399    while(val >>= 1) power++;
10400 
10401    return(1 << power);
10402 }
10403 
10404 
10405