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