1
2 #include "SUMA_suma.h"
3 #include "PLY/ply.h"
4
5 /*!
6 \brief a function to simplify loading surfaces the old way
7 The only difference with SUMA_Load_Surface_Object_eng is that it
8 takes the file names needed in the first three character pointers
9 usually: if_name1: (char *) name of entire surface file or the coordinates file
10 if_name2: (char *) name of triangulation file
11 vp_name: (char *) name of volume parent file, just for SureFit surfaces.
12 */
SUMA_Load_Surface_Object_Wrapper(char * if_name,char * if_name2,char * vp_name,SUMA_SO_File_Type SO_FT,SUMA_SO_File_Format SO_FF,char * sv_name,int debug)13 SUMA_SurfaceObject *SUMA_Load_Surface_Object_Wrapper (
14 char *if_name, char *if_name2, char *vp_name,
15 SUMA_SO_File_Type SO_FT, SUMA_SO_File_Format SO_FF,
16 char *sv_name, int debug)
17 {
18 static char FuncName[]={"SUMA_Load_Surface_Object_Wrapper"};
19 SUMA_SurfaceObject *SO=NULL;
20 void *SO_name=NULL;
21 SUMA_SFname *SF_name = NULL;
22 SUMA_Boolean LocalHead = NOPE;
23
24 SUMA_ENTRY;
25
26 switch (SO_FT) {
27 case SUMA_SUREFIT:
28 SF_name = (SUMA_SFname *) SUMA_malloc(sizeof(SUMA_SFname));
29 sprintf(SF_name->name_coord,"%s", if_name);
30 sprintf(SF_name->name_topo,"%s", if_name2);
31 if (!vp_name) { /* initialize to empty string */
32 SF_name->name_param[0] = '\0';
33 }
34 else {
35 sprintf(SF_name->name_param,"%s", vp_name);
36 }
37 SO_name = (void *)SF_name;
38 if (debug > 0)
39 fprintf (SUMA_STDOUT,
40 "Reading %s and %s...\n",
41 SF_name->name_coord, SF_name->name_topo);
42 SO = SUMA_Load_Surface_Object (SO_name, SUMA_SUREFIT,
43 SUMA_ASCII, sv_name);
44 break;
45 case SUMA_VEC:
46 SF_name = (SUMA_SFname *) SUMA_malloc(sizeof(SUMA_SFname));
47 sprintf(SF_name->name_coord,"%s", if_name);
48 sprintf(SF_name->name_topo,"%s", if_name2);
49 SO_name = (void *)SF_name;
50 if (debug > 0)
51 fprintf (SUMA_STDOUT,
52 "Reading %s and %s...\n",
53 SF_name->name_coord, SF_name->name_topo);
54 SO = SUMA_Load_Surface_Object (SO_name, SUMA_VEC, SUMA_ASCII, sv_name);
55 break;
56 case SUMA_FREE_SURFER:
57 case SUMA_FREE_SURFER_PATCH:
58 SO_name = (void *)if_name;
59 if (debug > 0)
60 fprintf (SUMA_STDOUT,"Reading %s ...\n",if_name);
61 if (SUMA_isExtension(SO_name, ".asc"))
62 SO = SUMA_Load_Surface_Object (SO_name, SUMA_FREE_SURFER,
63 SUMA_ASCII, sv_name);
64 else
65 SO = SUMA_Load_Surface_Object_eng ( SO_name, SUMA_FREE_SURFER,
66 SUMA_BINARY_BE, sv_name, 0);
67 break;
68 case SUMA_OPENDX_MESH:
69 SO_name = (void *)if_name;
70 if (debug > 0)
71 fprintf (SUMA_STDOUT,"Reading %s ...\n",if_name);
72 SO = SUMA_Load_Surface_Object ( SO_name, SUMA_OPENDX_MESH,
73 SUMA_ASCII, sv_name);
74 break;
75 case SUMA_OBJ_MESH:
76 SO_name = (void *)if_name;
77 if (debug > 0)
78 fprintf (SUMA_STDOUT,"Reading %s ...\n",if_name);
79 SO = SUMA_Load_Surface_Object ( SO_name, SUMA_OBJ_MESH,
80 SUMA_ASCII, sv_name);
81 break;
82 case SUMA_PREDEFINED:
83 SO_name = (void *)if_name;
84 if (debug > 0)
85 fprintf (SUMA_STDOUT,"Creating %s ...\n",if_name);
86 SO = SUMA_Load_Surface_Object ( SO_name, SUMA_PREDEFINED,
87 SUMA_ASCII, sv_name);
88 break;
89 case SUMA_PLY:
90 SO_name = (void *)if_name;
91 if (debug > 0)
92 fprintf (SUMA_STDOUT,"Reading %s ...\n",if_name);
93 SO = SUMA_Load_Surface_Object ( SO_name, SUMA_PLY,
94 SUMA_FF_NOT_SPECIFIED, sv_name);
95 break;
96 case SUMA_STL:
97 SO_name = (void *)if_name;
98 if (debug > 0)
99 fprintf (SUMA_STDOUT,"Reading %s ...\n",if_name);
100 SO = SUMA_Load_Surface_Object ( SO_name, SUMA_STL,
101 SUMA_FF_NOT_SPECIFIED, sv_name);
102 break;
103 case SUMA_MNI_OBJ:
104 SO_name = (void *)if_name;
105 if (debug > 0)
106 fprintf (SUMA_STDOUT,"Reading %s ...\n",if_name);
107 SO = SUMA_Load_Surface_Object ( SO_name, SUMA_MNI_OBJ,
108 SUMA_ASCII, sv_name);
109 break;
110 case SUMA_BRAIN_VOYAGER:
111 SO_name = (void *)if_name;
112 if (debug > 0)
113 fprintf (SUMA_STDOUT,"Reading %s ...\n",if_name);
114 SO = SUMA_Load_Surface_Object ( SO_name, SUMA_BRAIN_VOYAGER,
115 SUMA_BINARY, sv_name);
116 break;
117 case SUMA_BYU:
118 SO_name = (void *)if_name;
119 if (debug > 0)
120 fprintf (SUMA_STDOUT,"Reading %s ...\n",if_name);
121 SO = SUMA_Load_Surface_Object (SO_name, SUMA_BYU, SUMA_ASCII, sv_name);
122 break;
123 case SUMA_GIFTI:
124 SO_name = (void *)if_name;
125 if (debug > 0)
126 fprintf (SUMA_STDOUT,"Reading %s ...\n",if_name);
127 SO = SUMA_Load_Surface_Object ( SO_name, SUMA_GIFTI,
128 SUMA_FF_NOT_SPECIFIED, sv_name);
129 break;
130
131 default:
132 SUMA_S_Err("Bad format %d.\n", SO_FT);
133 SUMA_DUMP_TRACE("Trace at Bad format");
134 exit(1);
135 }
136
137 if (SF_name) SUMA_free(SF_name); SF_name = NULL;
138 SUMA_RETURN(SO);
139 }
140
141 /*!
142 \brief Removes the standard extension from a surface filename
143 \param Name (char *) name
144 \param form SUMA_DSET_FORMAT
145 \return (char *) no_extension (you have to free that one with SUMA_free)
146 */
147
SUMA_RemoveSurfNameExtension(char * Name,SUMA_SO_File_Type oType)148 char *SUMA_RemoveSurfNameExtension (char*Name, SUMA_SO_File_Type oType)
149 {
150 static char FuncName[]={"SUMA_RemoveSurfNameExtension"};
151 char *noex = NULL, *tmp = NULL;
152
153 SUMA_ENTRY;
154
155 if (!Name) { SUMA_SL_Err("NULL Name"); SUMA_RETURN(NULL); }
156 if (oType == SUMA_FT_NOT_SPECIFIED) {
157 oType = SUMA_GuessSurfFormatFromExtension(Name, NULL);
158 }
159 switch (oType) {
160 case SUMA_SUREFIT:
161 tmp = SUMA_Extension(Name, ".coord", YUP);
162 noex = SUMA_Extension(tmp, ".topo", YUP); SUMA_free(tmp); tmp = NULL;
163 break;
164 case SUMA_VEC:
165 tmp = SUMA_Extension(Name, ".1D.coord", YUP);
166 noex = SUMA_Extension(tmp, ".1D.topo", YUP);
167 SUMA_free(tmp); tmp = NULL;
168 break;
169 case SUMA_FREE_SURFER:
170 case SUMA_FREE_SURFER_PATCH:
171 noex = SUMA_Extension(Name, ".asc", YUP);
172 break;
173 case SUMA_PLY:
174 noex = SUMA_Extension(Name,".ply" , YUP);
175 break;
176 case SUMA_STL:
177 noex = SUMA_Extension(Name,".stl" , YUP);
178 break;
179 case SUMA_MNI_OBJ:
180 noex = SUMA_Extension(Name,".obj" , YUP);
181 break;
182 case SUMA_OPENDX_MESH:
183 noex = SUMA_Extension(Name,".dx" , YUP);
184 break;
185 case SUMA_OBJ_MESH:
186 noex = SUMA_Extension(Name,".obj" , YUP);
187 break;
188 case SUMA_INVENTOR_GENERIC:
189 noex = SUMA_Extension(Name,".iv" , YUP);
190 break;
191 case SUMA_BRAIN_VOYAGER:
192 noex = SUMA_Extension(Name,".srf" , YUP);
193 break;
194 case SUMA_BYU:
195 tmp = SUMA_Extension(Name,".byu" , YUP);
196 noex = SUMA_Extension(tmp, ".g", YUP); SUMA_free(tmp); tmp = NULL;
197 break;
198 case SUMA_GIFTI:
199 noex = SUMA_Extension(Name,".gii" , YUP);
200 break;
201 case SUMA_PREDEFINED:
202 noex = SUMA_copy_string(Name);
203 break;
204 default:
205 /* do nothing,
206 get back fprintf (SUMA_STDERR,"Warning %s: Bad format.\n", FuncName); */
207 noex = SUMA_copy_string(Name);
208 break;
209 }
210
211 SUMA_RETURN(noex);
212 }
213
214 /*!
215 \brief much like SUMA_Prefix2SurfaceName, but handles the case where namecoord and nametopo are not the same
216 consider it a more general version of SUMA_Prefix2SurfaceName
217 */
SUMA_2Prefix2SurfaceName(char * namecoord,char * nametopo,char * path,char * vp_name,SUMA_SO_File_Type oType,SUMA_Boolean * exists)218 void * SUMA_2Prefix2SurfaceName (char *namecoord, char *nametopo, char *path,
219 char *vp_name, SUMA_SO_File_Type oType,
220 SUMA_Boolean *exists)
221 {
222 static char FuncName[]={"SUMA_2Prefix2SurfaceName"};
223 SUMA_Boolean exist1, exist2;
224 SUMA_SFname *SF_name1 = NULL, *SF_name2 = NULL;
225
226 SUMA_ENTRY;
227
228 *exists = YUP; /* initialize to bad case, for safety */
229
230 if (!nametopo && !namecoord) { SUMA_RETURN(NULL); }
231
232 if (!nametopo)
233 SUMA_RETURN(SUMA_Prefix2SurfaceName (namecoord, path, vp_name,
234 oType, exists));
235 if (!namecoord) SUMA_RETURN(SUMA_Prefix2SurfaceName (nametopo, path, vp_name,
236 oType, exists));
237
238 if (strcmp(namecoord, nametopo) == 0)
239 SUMA_RETURN(SUMA_Prefix2SurfaceName (nametopo, path, vp_name,
240 oType, exists));
241 if (oType != SUMA_SUREFIT && oType != SUMA_VEC) {
242 SUMA_SL_Err("Wrong usage of function, namecoord and nametopo \n"
243 "are different but surface type is neither "
244 "SUMA_SUREFIT nor SUMA_VEC");
245 SUMA_RETURN(NULL);
246 }
247
248 /* the pain in the behind case */
249 SF_name1 = SUMA_Prefix2SurfaceName (namecoord, path, vp_name, oType, &exist1);
250 if (!SF_name1) {
251 SUMA_SL_Err("Failed to create name");
252 SUMA_RETURN(NULL);
253 }
254 SF_name2 = SUMA_Prefix2SurfaceName (nametopo, path, vp_name, oType, &exist2);
255 if (!SF_name2) {
256 SUMA_free(SF_name1); SF_name1= NULL;
257 SUMA_SL_Err("Failed to create name");
258 SUMA_RETURN(NULL);
259 }
260
261 if (exist1 || exist2) *exists = YUP;
262 else *exists = NOPE; /* 4 Nov 2005 [rickr] */
263
264 sprintf(SF_name1->name_topo, "%s", SF_name2->name_topo);
265 SUMA_free(SF_name2); SF_name2= NULL;
266
267 SUMA_RETURN(SF_name1);
268 }
269 /*!
270 \brief A function to take a prefix (or name) and turn it into the structure needed
271 by SUMA_Save_Surface_Object
272 also sets *exists = YUP if completed filename exists on disk. For surfaces requiring
273 two files, *exists = YUP if any of the files exists
274 - free returned pointer with SUMA_free
275
276 \sa SUMA_2Prefix2SurfaceName if you have a surface with different names for coord and topo )
277 */
278
SUMA_Prefix2SurfaceName(char * prefix_in,char * path,char * vp_name,SUMA_SO_File_Type oType,SUMA_Boolean * exists)279 void * SUMA_Prefix2SurfaceName ( char *prefix_in, char *path, char *vp_name,
280 SUMA_SO_File_Type oType, SUMA_Boolean *exists)
281 {
282 static char FuncName[]={"SUMA_Prefix2SurfaceName"};
283 SUMA_SFname *SF_name = NULL;
284 char *ppref = NULL, *prefix=NULL;
285 void *SO_name = NULL;
286
287 SUMA_ENTRY;
288
289 if (!prefix_in) {
290 fprintf (SUMA_STDERR,"Error %s: NULL name input\n", FuncName);
291 SUMA_RETURN(NULL);
292 }
293 /* trim the prefix if necessary */
294 if (!(prefix = SUMA_RemoveSurfNameExtension (prefix_in, oType))) {
295 fprintf (SUMA_STDERR,"Error %s: Failed to remove extension\n", FuncName);
296 SUMA_RETURN(NULL);
297 }
298
299 if (path) {
300 if (path[strlen(path)-1] == '/') {
301 ppref = SUMA_append_replace_string(path, prefix, "", 0);
302 } else {
303 ppref = SUMA_append_replace_string(path, prefix, "/", 0);
304 }
305 } else {
306 ppref = SUMA_copy_string(prefix);
307 }
308
309 switch (oType) {
310 case SUMA_SUREFIT:
311 SF_name = (SUMA_SFname *) SUMA_malloc(sizeof(SUMA_SFname));
312 snprintf(SF_name->name_coord,
313 (SUMA_MAX_FILENAME_LENGTH)*sizeof(char),
314 "%s.coord", ppref);
315 snprintf(SF_name->name_topo,
316 (SUMA_MAX_FILENAME_LENGTH)*sizeof(char),
317 "%s.topo", ppref);
318 if ( SUMA_filexists(SF_name->name_topo) ||
319 SUMA_filexists(SF_name->name_coord)) *exists = YUP;
320 else *exists = NOPE;
321 if (!vp_name) { /* initialize to empty string */
322 SF_name->name_param[0] = '\0';
323 }
324 else {
325 snprintf(SF_name->name_param,
326 (SUMA_MAX_FILENAME_LENGTH)*sizeof(char),
327 "%s", vp_name);
328 }
329 SO_name = (void *)SF_name;
330 break;
331 case SUMA_VEC:
332 if (SF_name) SUMA_free(SF_name);
333 SF_name = (SUMA_SFname *) SUMA_malloc(sizeof(SUMA_SFname));
334 snprintf(SF_name->name_coord,
335 (SUMA_MAX_FILENAME_LENGTH)*sizeof(char),
336 "%s.1D.coord", ppref);
337 snprintf(SF_name->name_topo,
338 (SUMA_MAX_FILENAME_LENGTH)*sizeof(char),
339 "%s.1D.topo", ppref);
340 if ( SUMA_filexists(SF_name->name_topo) ||
341 SUMA_filexists(SF_name->name_coord)) *exists = YUP;
342 else *exists = NOPE;
343 SO_name = (void *)SF_name;
344 break;
345 case SUMA_FREE_SURFER:
346 case SUMA_FREE_SURFER_PATCH:
347 SO_name = (void *)SUMA_append_string(ppref,".asc");
348 if (SUMA_filexists((char*)SO_name)) *exists = YUP;
349 else *exists = NOPE;
350 break;
351 case SUMA_OPENDX_MESH:
352 SO_name = (void *)SUMA_append_string(ppref,".dx");
353 if (SUMA_filexists((char*)SO_name)) *exists = YUP;
354 else *exists = NOPE;
355 break;
356 case SUMA_OBJ_MESH:
357 SO_name = (void *)SUMA_append_string(ppref,".obj");
358 if (SUMA_filexists((char*)SO_name)) *exists = YUP;
359 else *exists = NOPE;
360 break;
361 case SUMA_PLY:
362 SO_name = (void *)SUMA_append_string(ppref,".ply");
363 if (SUMA_filexists((char*)SO_name)) *exists = YUP;
364 else *exists = NOPE;
365 break;
366 case SUMA_STL:
367 SO_name = (void *)SUMA_append_string(ppref,".stl");
368 if (SUMA_filexists((char*)SO_name)) *exists = YUP;
369 else *exists = NOPE;
370 break;
371 case SUMA_MNI_OBJ:
372 SO_name = (void *)SUMA_append_string(ppref,".obj");
373 if (SUMA_filexists((char*)SO_name)) *exists = YUP;
374 else *exists = NOPE;
375 break;
376 case SUMA_BRAIN_VOYAGER:
377 SO_name = (void *)SUMA_append_string(ppref,".srf");
378 if (SUMA_filexists((char*)SO_name)) *exists = YUP;
379 else *exists = NOPE;
380 break;
381 case SUMA_BYU:
382 SO_name = (void *)SUMA_append_string(ppref,".g");
383 if (SUMA_filexists((char*)SO_name)) *exists = YUP;
384 else *exists = NOPE;
385 break;
386 case SUMA_INVENTOR_GENERIC:
387 SO_name = (void *)SUMA_append_string(ppref,".iv");
388 if (SUMA_filexists((char*)SO_name)) *exists = YUP;
389 else *exists = NOPE;
390 break;
391 case SUMA_GIFTI:
392 case SUMA_PREDEFINED:
393 SO_name = (void *)SUMA_append_string(ppref,".gii");
394 if (SUMA_filexists((char*)SO_name)) *exists = YUP;
395 else *exists = NOPE;
396 break;
397 default:
398 fprintf (SUMA_STDERR,"Error %s: Unknown format.\n", FuncName);
399 SO_name = (void *)SUMA_copy_string(ppref);
400 if (SUMA_filexists((char*)SO_name)) *exists = YUP;
401 else *exists = NOPE;
402 break;
403 }
404
405 if (ppref) SUMA_free(ppref);
406 if (prefix) SUMA_free(prefix);
407
408 SUMA_RETURN(SO_name);
409 }
410
411 /*! Read MNI_OBJ surface */
SUMA_MNI_OBJ_Read(char * f_name,SUMA_SurfaceObject * SO)412 SUMA_Boolean SUMA_MNI_OBJ_Read(char * f_name, SUMA_SurfaceObject *SO)
413 {
414 static char FuncName[]={"SUMA_MNI_OBJ_Read"};
415 char *fl=NULL, *flp = NULL;
416 int ii=0, Found = 0, nread=0;
417 double num = 0;
418 int LocalHead = NOPE;
419
420 SUMA_ENTRY;
421
422 SUMA_LH("Sucking file");
423
424 nread = SUMA_suck_file( f_name , &fl ) ;
425 if (!fl) {
426 SUMA_SL_Err("Failed to read file.");
427 SUMA_RETURN(NOPE);
428 }
429
430 /* find 'P' */
431 ii = 0; flp = fl;
432 while (ii<nread && *flp != 'P') ++flp;
433 if (ii == nread) {
434 SUMA_S_Err("Failed to find 'P'");
435 SUMA_RETURN(NOPE);
436 }
437 SUMA_SKIP_TO_NEXT_BLANK(flp, NULL);
438
439 /* P is followed by 6 values, the last one being the number of points */
440 ii=0;
441 Found = 1;
442 while (ii < 5) {
443 if (Found) {
444 SUMA_ADVANCE_PAST_NUM(flp, num, Found);
445 } else {
446 SUMA_S_Err("Don't understand format");
447 SUMA_RETURN(NOPE);
448 }
449 ++ii;
450 }
451 /* get the sixth number */
452 SUMA_ADVANCE_PAST_INT(flp, SO->N_Node, Found);
453 if (!Found || SO->N_Node < 0 || SO->N_Node > 999999999) {
454 SUMA_S_Errv("Bad N_Node of %d\n", SO->N_Node);
455 SUMA_RETURN(NOPE);
456 }
457 SUMA_LHv("Expecting %d nodes\n", SO->N_Node);
458 SO->NodeDim = 3;
459 if (!(SO->NodeList = (float *)
460 SUMA_strtol_vec(flp, SO->NodeDim*SO->N_Node, &Found,
461 SUMA_float, &flp))) {
462 SUMA_S_Err("Failed to read node XYZ");
463 SUMA_RETURN(NOPE);
464 }
465 SUMA_LHv("Reading %d node normals\n", SO->N_Node);
466 if (!(SO->NodeNormList = (float *)
467 SUMA_strtol_vec(flp, SO->NodeDim*SO->N_Node, &Found,
468 SUMA_float, &flp))) {
469 SUMA_S_Err("Failed to read node XYZ");
470 SUMA_RETURN(NOPE);
471 }
472 if (LocalHead) {
473 fprintf(SUMA_STDERR,"%s: >>", FuncName);
474 for (ii=0; ii<200; ++ii) {
475 fprintf(SUMA_STDERR,"%c", flp[ii]);
476 }
477 fprintf(SUMA_STDERR,"\n");
478 }
479
480 SO->FaceSetDim = 3;
481 SUMA_ADVANCE_PAST_INT(flp, SO->N_FaceSet, Found);
482 if (!Found || SO->N_FaceSet < 0 || SO->N_FaceSet > 999999999) {
483 SUMA_S_Errv("Bad N_FaceSet of %d\n", SO->N_FaceSet);
484 SUMA_RETURN(NOPE);
485 }
486 SUMA_LHv("Expecting to reading %d triangles\n", SO->N_FaceSet);
487
488 /* skip past 5+SO->N_FaceSet integers for some reason */
489 ii=0;
490 Found = 1;
491 while (ii < 5+SO->N_FaceSet) {
492 if (Found) {
493 SUMA_ADVANCE_PAST_NUM(flp, num, Found);
494 } else {
495 SUMA_S_Err("Don't understand format");
496 SUMA_RETURN(NOPE);
497 }
498 ++ii;
499 }
500 SUMA_SKIP_BLANK(flp, NULL);
501
502 if (LocalHead) {
503 fprintf(SUMA_STDERR,"%s: >>", FuncName);
504 if (LocalHead) for (ii=0; ii<500 && flp[ii]; ++ii) {
505 fprintf(SUMA_STDERR,"%c", flp[ii]);
506 }
507 fprintf(SUMA_STDERR,"\n");
508 }
509 if (!(SO->FaceSetList = (int *)
510 SUMA_strtol_vec(flp, SO->FaceSetDim*SO->N_FaceSet, &Found,
511 SUMA_int, &flp))) {
512 SUMA_S_Err("Failed to read node XYZ");
513 SUMA_RETURN(NOPE);
514 }
515
516 if (LocalHead) {
517 for (ii=0; ii<10; ++ii) {fprintf(SUMA_STDERR,"%d ", SO->FaceSetList[ii]);}
518 }
519 /* fill up a few more fields */
520 SO->FileType = SUMA_MNI_OBJ;
521 SO->FileFormat = SUMA_ASCII;
522
523 SO->Name = SUMA_StripPath(f_name);
524
525 SUMA_RETURN(YUP);
526 }
SUMA_MNI_OBJ_Write(char * f_name_in,SUMA_SurfaceObject * SO)527 SUMA_Boolean SUMA_MNI_OBJ_Write(char * f_name_in, SUMA_SurfaceObject *SO)
528 {
529 static char FuncName[]={"SUMA_MNI_OBJ_Write"};
530 int ii=0;
531 char *f_name=NULL, *f_name2=NULL;
532 FILE *fid = NULL;
533 SUMA_Boolean LocalHead = NOPE;
534
535 SUMA_ENTRY;
536
537 if (!SO || !SO->NodeList || !SO->FaceSetList) {
538 SUMA_S_Err("Null or incomplete surface");
539 SUMA_RETURN(NOPE);
540 }
541 if (SO->NodeDim != 3 || SO->FaceSetDim != 3) {
542 SUMA_S_Err("NodeDim and FaceSetDim must be 3\n");
543 SUMA_RETURN(NOPE);
544 }
545 if (!SO->NodeNormList) {
546 SUMA_RECOMPUTE_NORMALS(SO)
547 }
548 if (!f_name_in) {
549 fprintf (SUMA_STDERR, "Error %s: NULL filename\n", FuncName);
550 SUMA_RETURN (NOPE);
551 }
552
553 f_name = SUMA_Extension(f_name_in,".obj" , YUP);
554 f_name2 = SUMA_append_string(f_name,".obj");
555 if (!THD_ok_overwrite() && SUMA_filexists (f_name2)) {
556 fprintf (SUMA_STDERR,
557 "Error %s: file %s exists, will not overwrite.\n",
558 FuncName, f_name2);
559 SUMA_free(f_name2);f_name2 = NULL;
560 SUMA_free(f_name);f_name = NULL;
561 SUMA_RETURN (NOPE);
562 }
563 SUMA_free(f_name); f_name = NULL;
564 f_name = f_name2; f_name2 = NULL;
565
566 if (!(fid = fopen(f_name,"w"))) {
567 SUMA_S_Err("Could not open file for writing");
568 SUMA_free(f_name); f_name = NULL;
569 SUMA_RETURN(NOPE);
570 }
571
572
573 fprintf(fid,"P 0.3 0.3 0.4 10 1 %d\n", SO->N_Node);
574 /* don't know what numbers between O and SO->N_Node mean ...*/
575 for (ii=0; ii < SO->N_Node; ++ii) {
576 fprintf(fid," %f", SO->NodeList[3*ii]);
577 fprintf(fid," %f", SO->NodeList[3*ii+1]);
578 fprintf(fid," %f\n", SO->NodeList[3*ii+2]);
579 }
580 for (ii=0; ii < SO->N_Node; ++ii) {
581 fprintf(fid," %f", SO->NodeNormList[3*ii]);
582 fprintf(fid," %f", SO->NodeNormList[3*ii+1]);
583 fprintf(fid," %f\n", SO->NodeNormList[3*ii+2]);
584 }
585
586 /* number of triangles */
587 fprintf(fid,"\n %d\n", SO->N_FaceSet);
588
589 /* stuff I don't understand */
590 fprintf(fid," 0 1 1 1 1\n"); /* dunno what that is */
591 for (ii=0; ii<SO->N_FaceSet; ++ii) {
592 if (!(ii%8)) fprintf(fid,"\n");
593 fprintf(fid," %d", ii); /* that is just a space filler. Don't quite
594 know what these indices refer to in MNI_OBJ */
595 }
596
597 /* the triangle list */
598 for (ii=0; ii<SO->FaceSetDim*SO->N_FaceSet; ++ii) {
599 if (!(ii%8)) fprintf(fid,"\n");
600 fprintf(fid," %d", SO->FaceSetList[ii]);
601 }
602
603 fprintf(fid,"\n");
604
605 SUMA_free(f_name); f_name = NULL;
606
607 fclose (fid);
608
609 SUMA_RETURN(YUP);
610 }
611
612 /*!**
613 Function: SUMA_SureFit_Read_Coord
614 Usage :
615 Ret = SUMA_SureFit_Read_Coord (coordname, SureFit)
616
617
618 Input paramters :
619 \param coordname (char *) name of .coord file
620 \param SureFit (SUMA_SureFit_struct *) pointer to the SureFit structure
621
622 Returns :
623 \return (SUMA_Boolean) YUP/NOPE for success/failure
624
625 Support :
626 \sa
627 \sa
628
629 Side effects :
630
631
632
633 ***/
SUMA_SureFit_Read_Coord(char * f_name,SUMA_SureFit_struct * SF)634 SUMA_Boolean SUMA_SureFit_Read_Coord ( char * f_name, SUMA_SureFit_struct *SF)
635 {/*SUMA_SureFit_Read_Coord*/
636 static char FuncName[]={"SUMA_SureFit_Read_Coord"};
637 FILE *sf_file;
638 int ex, EndHead, FoundHead, evl, cnt, skp, ND, id;
639 char stmp[100], head_strt[100], head_end[100],
640 s[1000], delimstr[] = {' ', '\0'}, *st;
641 byte *isallzeros=NULL;
642 int LocalHead = 0;
643
644 SUMA_ENTRY;
645
646 ND = 3;
647
648 /* check for existence */
649 if (!SUMA_filexists(f_name)) {
650 fprintf(SUMA_STDERR,"File %s does not exist or cannot be read.\n", f_name);
651 SUMA_RETURN (NOPE);
652 }
653
654 sprintf(SF->name_coord, "%s", f_name);
655
656 /* start reading */
657 sf_file = fopen (f_name,"r");
658 if (sf_file == NULL)
659 {
660 SUMA_error_message (FuncName,"Could not open input file ",0);
661 SUMA_RETURN (NOPE);
662 }
663
664 /* read until you reach the begin header BeginHeader */
665 ex = 1;
666 FoundHead = 0;
667 sprintf(head_strt,"BeginHeader");
668 while (ex != EOF && !FoundHead)
669 {
670 ex = fscanf (sf_file,"%s",s);
671 if (strlen (s) >= strlen(head_strt))
672 {
673 evl = SUMA_iswordin (s,head_strt);
674 if (evl == 1) FoundHead = 1;
675 }
676 }
677
678 if (!FoundHead) {
679 fprintf( SUMA_STDERR,
680 "Error %s: BeginHeader not found in %s.\n"
681 "Perhaps you are using old versions of Caret/SureFit files.\n",
682 FuncName, f_name);
683 SUMA_RETURN (NOPE);
684 }
685 EndHead = 0;
686 sprintf(head_end,"EndHeader");
687 sprintf(delimstr," ");
688
689 while (ex != EOF && !EndHead) {
690 ex = fscanf (sf_file,"%s",s);
691 /*fprintf(stdout,"%s\n", s);*/
692 if (strlen (s) >= strlen(head_end))
693 {
694 evl = SUMA_iswordin (s,head_end);
695 if (evl == 1) EndHead = 1;
696 }
697 /* look for some tokens */
698 skp = 0;
699 if (!EndHead) {
700 st = strtok(s, delimstr);
701 sprintf(stmp,"encoding");
702 if (!skp && SUMA_iswordin (st, stmp) == 1) {
703 /*fprintf(stdout,"Found encoding\n");*/
704 ex = fscanf (sf_file,"%s",(SF->encoding_coord));
705 skp = 1;
706 }
707
708 sprintf(stmp,"configuration_id");
709 if (!skp && SUMA_iswordin (st, stmp) == 1) {
710 /*fprintf(stdout,"Found configuration_id\n");*/
711 ex = fscanf (sf_file,"%s",(SF->configuration_id));
712 skp = 1;
713 }
714
715 sprintf(stmp,"coordframe_id");
716 if (!skp && SUMA_iswordin (st, stmp) == 1) {
717 /*fprintf(stdout,"Found configuration_id\n");*/
718 ex = fscanf (sf_file,"%s",(SF->coordframe_id));
719 skp = 1;
720 }
721
722 sprintf(stmp,"caret-version");
723 if (!skp && SUMA_iswordin (st, stmp) == 1) {
724 /*fprintf(stdout,"Found caret-version\n");*/
725 ex = fscanf (sf_file,"%f",&(SF->caret_version));
726 skp = 1;
727 }
728
729 sprintf(stmp,"Caret-Version");
730 if (!skp && SUMA_iswordin (st, stmp) == 1) {
731 /*fprintf(stdout,"Found caret-version\n");*/
732 ex = fscanf (sf_file,"%f",&(SF->caret_version));
733 skp = 1;
734 }
735
736 }
737 }
738 /* Now read the Number of Nodes */
739 fscanf(sf_file, "%d", &SF->N_Node);
740 if (LocalHead) fprintf (stdout,"Expecting %d nodes.\n", SF->N_Node);
741 if (SF->N_Node <= 3) {
742 SUMA_S_Err("Too few nodes!");
743 SUMA_RETURN (NOPE);
744 }
745
746 /* allocate space */
747 SF->NodeList = (float *)SUMA_calloc(SF->N_Node * ND, sizeof(float));
748 SF->NodeId = (int *)SUMA_calloc (SF->N_Node, sizeof(int));
749 SF->allzerocoord = (byte *)SUMA_calloc(SF->N_Node, sizeof(byte));
750
751
752 if (SF->NodeList == NULL || SF->NodeId == NULL || !SF->allzerocoord) {
753 fprintf(SUMA_STDERR,
754 "Error %s: Could not allocate space for NodeList &/| NodeId.\n",
755 FuncName);
756 SUMA_RETURN (NOPE);
757 }
758
759 /* Now read the nodes until the end of the file */
760 cnt = 0;
761 while (ex != EOF && cnt < SF->N_Node) {
762 id = cnt * ND;
763 ex = fscanf (sf_file,"%d %f %f %f",&(SF->NodeId[cnt]),
764 &(SF->NodeList[id]), &(SF->NodeList[id+1]),
765 &(SF->NodeList[id+2]));
766 #if 0
767 if (SF->NodeList[id] == 0.0f &&
768 SF->NodeList[id+1] == 0.0f &&
769 SF->NodeList[id+2] == 0.0f )
770 SF->allzerocoord[cnt] = 1;
771 #else
772 /* looser test works, but not needed */
773 if (SUMA_ABS(SF->NodeList[id] -0.0f) < 0.000001 &&
774 SUMA_ABS(SF->NodeList[id+1] -0.0f) < 0.000001 &&
775 SUMA_ABS(SF->NodeList[id+2] -0.0f) < 0.000001 )
776 SF->allzerocoord[cnt] = 1;
777 #endif
778 ++cnt;
779 }
780 if (cnt != SF->N_Node) {
781 fprintf(SUMA_STDERR, "Error %s: Expecting %d Nodes, read %d.\n"
782 "First triplet: %f %f %f\n"
783 "Last triplet: %f %f %f\n", FuncName, SF->N_Node, cnt,
784 SF->NodeList[0], SF->NodeList[1], SF->NodeList[2],
785 SF->NodeList[3*(cnt-1)], SF->NodeList[3*(cnt-1)+1],
786 SF->NodeList[3*(cnt-1)+2]);
787 SUMA_RETURN (NOPE);
788 }
789 fclose (sf_file);
790 SUMA_RETURN (YUP);
791 }/*SUMA_SureFit_Read_Coord*/
792
SUMA_SureFit_Read_Topo(char * f_name,SUMA_SureFit_struct * SF)793 SUMA_Boolean SUMA_SureFit_Read_Topo (char * f_name, SUMA_SureFit_struct *SF)
794 {/*SUMA_SureFit_Read_Topo*/
795 static char FuncName[]={"SUMA_SureFit_Read_Topo"};
796 int ex = 0, EndHead, FoundHead, evl, cnt, skp, jnk,
797 i, ip, NP, nread=0, iwarn=0;
798 char stmp[100], head_strt[100], head_end[100], s[1000],
799 delimstr[] = {' ', '\0'}, *st, *eop, *fl0, *fl1, *op2, *fl,
800 *fleh, *flns, *flbh;
801 int LocalHead = 0, Found=0;
802 double tmpdbl;
803
804 SUMA_ENTRY;
805
806 /* check for existence */
807 if (!SUMA_filexists(f_name)) {
808 fprintf(SUMA_STDERR,"File %s does not exist or cannot be read.\n", f_name);
809 SUMA_RETURN (NOPE);
810 }
811
812 SUMA_LH("Sucking file");
813
814 nread = SUMA_suck_file( f_name , &fl ) ;
815 if (!fl) {
816 SUMA_SL_Err("Failed to read file.");
817 SUMA_RETURN(NOPE);
818 }
819
820 sprintf(SF->name_topo, "%s", f_name);
821
822 /* find BeginHeader and EndHeader tags*/
823 fl0 = fl; /* beginning */
824 fl1 = fl + nread; /* end */
825
826 eop = SUMA_MIN_PAIR(fl1, fl+5000);
827 SUMA_ADVANCE_PAST(fl,eop,"BeginHeader",Found,1);
828 if (!Found) {
829 fprintf(SUMA_STDERR,"Error %s: BeginHeader not found in %s.\nPerhaps you are using old versions of Caret/SureFit files.\n", FuncName, f_name);
830 SUMA_RETURN (NOPE);
831 }
832 flbh = fl;
833
834
835 SUMA_ADVANCE_PAST(fl,eop,"EndHeader",Found,1);
836 if (!Found) {
837 fprintf(SUMA_STDERR,"Error %s: EndHeader not found in %s.\n"
838 "Perhaps you are using old versions of Caret/SureFit files.\n",
839 FuncName, f_name);
840 SUMA_RETURN (NOPE);
841 }
842 fleh = fl;
843
844 /* find the header fields */
845 fl = flbh;
846 SUMA_ADVANCE_PAST(fl,fleh,"encoding",Found,1);
847 if (Found) {
848 op2 = fl;
849 SUMA_SKIP_LINE(op2, fleh);
850 snprintf(SF->encoding_topo, SUMA_MIN_PAIR(100,(op2-fl))*sizeof(char),
851 "%s", fl);
852 if (LocalHead) {
853 fprintf(SUMA_STDERR,"%s: Found encoding (%d) >>>%s<<<\n",
854 FuncName, (int)(op2-fl), SF->encoding_topo);
855 }
856 }
857 fl = flbh;
858 SUMA_ADVANCE_PAST(fl,fleh,"perimeter_id",Found,1);
859 if (Found) {
860 op2 = fl;
861 SUMA_SKIP_LINE(op2, fleh);
862 snprintf(SF->perimeter_id, SUMA_MIN_PAIR(100,(op2-fl))*sizeof(char),
863 "%s", fl);
864 if (LocalHead) {
865 fprintf(SUMA_STDERR,"%s: Found perimeter_id >>>%s<<<\n",
866 FuncName, SF->perimeter_id);
867 }
868 }
869
870 fl = flbh;
871 SUMA_ADVANCE_PAST(fl,fleh,"date",Found,1);
872 if (Found) {
873 op2 = fl;
874 SUMA_SKIP_LINE(op2, fleh);
875 snprintf(SF->date, SUMA_MIN_PAIR(100,(op2-fl))*sizeof(char), "%s", fl);
876 if (LocalHead) {
877 fprintf(SUMA_STDERR,"%s: Found date >>>%s<<<\n", FuncName, SF->date);
878 }
879 }
880
881
882 /* is next string a number ? */
883 fl = fleh;
884 SUMA_ADVANCE_PAST_NUM(fl, tmpdbl, Found);
885 if (Found) {
886 SF->N_Node_Specs = (int)tmpdbl;
887 SUMA_LH("Expecting %d Node_Specs .\n", SF->N_Node_Specs);
888 SF->N_FaceSet = -1; /* got to read it later*/
889 SF->tag_version = -1; /* don't know */
890 goto NODE_SPECS;
891 }else {
892 fl = fleh;
893 eop = SUMA_MIN_PAIR(fl1, fl+500);
894 SUMA_ADVANCE_PAST(fl, eop, "tag-version", Found, 0);
895 if (Found) {
896 /* read tag-version */
897 SUMA_ADVANCE_PAST_NUM(fl, tmpdbl, Found);
898 SF->tag_version = (float) tmpdbl;
899 if (Found) {
900 if (LocalHead) fprintf (stdout,"Found tag-version %f\n", tmpdbl);
901 if ((int)tmpdbl != 1) {
902 SUMA_S_Warn("tag-version not equal to 1.\n"
903 "SUMA may not know how to read this file.\n");
904 }
905 } else {
906 SUMA_LH("Found tag-version but no number! Trying hope.\n");
907 /* skip till end of line */
908 SUMA_SKIP_LINE(fl, eop);
909 }
910
911 SUMA_ADVANCE_PAST_NUM(fl, tmpdbl, Found);
912 if (Found) {
913 SF->N_FaceSet = (int)tmpdbl;
914 SUMA_LH("Found number of FaceSets: %d\n", SF->N_FaceSet);
915 } else {
916 SUMA_S_Err("No FaceSets number!");
917 SUMA_RETURN (NOPE);
918 }
919 SF->N_Node_Specs = -1; /* not set */
920 goto FACESETS;
921 }else {
922 SUMA_S_Err("Don't know how to interpret file!");
923 SUMA_RETURN (NOPE);
924 }
925 }
926
927
928 NODE_SPECS:
929 SF->FN.N_Node = SF->N_Node_Specs;
930 SF->FN.N_Neighb_max = 0;
931
932 /* allocate for Node Specs Matrix and First_Neighb structure*/
933 SF->Specs_mat = (int **) SUMA_allocate2D(SF->N_Node_Specs, 6, sizeof(int));
934 /*assume maximum number of neighbors is SUMA_MAX_NUMBER_NODE_NEIGHB */
935 SF->FN.FirstNeighb = (int **) SUMA_allocate2D(SF->FN.N_Node,
936 SUMA_MAX_NUMBER_NODE_NEIGHB, sizeof (int));
937 SF->FN.N_Neighb = (int *) SUMA_calloc (SF->FN.N_Node, sizeof(int));
938 SF->FN.NodeId = (int *) SUMA_calloc (SF->FN.N_Node, sizeof(int));
939
940 if ( SF->Specs_mat == NULL || SF->FN.FirstNeighb == NULL ||
941 SF->FN.N_Neighb == NULL || SF->FN.NodeId == NULL ){
942 fprintf(SUMA_STDERR, "Error %s: Could not allocate space for SF->Specs_mat &/| SF->FN.FirstNeighb &/| SF->FN.N_Neighb &/| SF->FN.NodeId.\n", FuncName);
943 SUMA_RETURN (NOPE);
944 }
945
946 /* Now read the node specs */
947 if (LocalHead) fprintf (stdout,"About to read specs\n");
948 cnt = 0;
949 do {
950 for (i=0; i<6; ++i) {
951 SUMA_ADVANCE_PAST_NUM(fl, tmpdbl, Found);
952 if (Found) {
953 SF->Specs_mat[cnt][i] = (int)tmpdbl;
954 } else {
955 fprintf(SUMA_STDERR, "Error %s: Failed reading Specs_mat at number %d\n", FuncName, cnt);
956 SUMA_RETURN (NOPE);
957 }
958 }
959 SF->FN.NodeId[cnt] = SF->Specs_mat[cnt][0];
960 SF->FN.N_Neighb[cnt] = SF->Specs_mat[cnt][1];
961 if (SF->FN.N_Neighb[cnt] > SUMA_MAX_NUMBER_NODE_NEIGHB-1) {
962 fprintf (SUMA_STDERR,"Error %s: Node %d has more neighbors (%d) than the maximum allowed (%d)\n", \
963 FuncName, SF->FN.NodeId[cnt], SF->FN.N_Neighb[cnt], SUMA_MAX_NUMBER_NODE_NEIGHB-1);
964 SUMA_RETURN (NOPE);
965 }
966 if (SF->FN.N_Neighb[cnt] > SF->FN.N_Neighb_max) SF->FN.N_Neighb_max = SF->FN.N_Neighb[cnt];
967
968 /* Now Read in the Neighbors info */
969 for (i=0; i < SF->FN.N_Neighb[cnt]; ++ i) {
970 SUMA_ADVANCE_PAST_NUM(fl, tmpdbl, Found); /* skip first number */
971 SUMA_ADVANCE_PAST_NUM(fl, tmpdbl, Found);
972 if (Found) {
973 SF->FN.FirstNeighb[cnt][i] = (int)tmpdbl;
974 } else {
975 fprintf (SUMA_STDERR,"Error %s: Failed to read neighbor index! cnt = %d, i = %d\n", FuncName, cnt, i);
976 SUMA_RETURN (NOPE);
977 }
978 }
979 /* seal with -1 */
980 SF->FN.FirstNeighb[cnt][SF->FN.N_Neighb[cnt]] = -1;
981
982 ++cnt;
983 } while (cnt < SF->N_Node_Specs);
984
985 if (cnt != SF->N_Node_Specs) {
986 fprintf(SUMA_STDERR, "Error %s: Expecting %d NodeSpecs, read %d.\n", FuncName, SF->N_Node_Specs, cnt);
987 SUMA_RETURN (NOPE);
988 }
989
990 FACESETS:
991 if (SF->N_FaceSet < 0) {
992 /* have to read it still */
993 SUMA_ADVANCE_PAST_NUM(fl, tmpdbl, Found);
994 if (Found) {
995 SF->N_FaceSet = (int)tmpdbl;
996 if (LocalHead) fprintf (stdout,"Found number of FaceSets: %d\n", SF->N_FaceSet);
997 } else {
998 SUMA_S_Err("No FaceSets number!");
999 SUMA_RETURN (NOPE);
1000 }
1001 }
1002
1003 if (LocalHead) fprintf (stdout, "Reading facesets\n");
1004 if (SF->N_FaceSet < 3) {
1005 fprintf(SUMA_STDERR, "Error %s: Too few (%d) triangles.\n", FuncName, SF->N_FaceSet);
1006 SUMA_RETURN (NOPE);
1007 }
1008
1009 NP = 3;
1010 SF->FaceSetList = (int *)SUMA_strtol_vec(fl, SF->N_FaceSet * NP,
1011 &ex, SUMA_int, NULL);
1012 if (!SF->FaceSetList || ex != SF->N_FaceSet * NP) {
1013 fprintf(SUMA_STDERR, "Error %s: Failed to read all FaceSets. "
1014 "Expected %d vals, read %d.\nOr NULL output.\n",
1015 FuncName, SF->N_FaceSet*NP, ex);
1016 SUMA_RETURN (NOPE);
1017 }
1018
1019 /* remove all zeros coords? */
1020 i=0;
1021 while(i<SF->N_FaceSet) {
1022 if (SF->allzerocoord[SF->FaceSetList[NP*i]] ||
1023 SF->allzerocoord[SF->FaceSetList[NP*i+1]] ||
1024 SF->allzerocoord[SF->FaceSetList[NP*i+2]] ) {
1025 if (!iwarn) {
1026 SUMA_S_Notev("Triangle %d in %s has a node with all zero coords.\n"
1027 "Triangle removed from list.\n"
1028 "Similar messages will be muted.\n",
1029 i, f_name);
1030 }
1031 ++iwarn;
1032 --SF->N_FaceSet;
1033 SF->FaceSetList[NP*i] = SF->FaceSetList[NP*SF->N_FaceSet];
1034 SF->FaceSetList[NP*i+1] = SF->FaceSetList[NP*SF->N_FaceSet+1];
1035 SF->FaceSetList[NP*i+2] = SF->FaceSetList[NP*SF->N_FaceSet+2];
1036 } else {
1037 ++i;
1038 }
1039 }
1040 if (iwarn) {
1041 SUMA_S_Notev("A total of %d triangles in %s with "
1042 "all zero coords were removed.\n", iwarn, f_name);
1043 }
1044 SUMA_RETURN (YUP);
1045 }/*SUMA_SureFit_Read_Topo*/
1046
1047 /* Old version , could not handle versions with tag-version string */
SUMA_SureFit_Read_Topo_old(char * f_name,SUMA_SureFit_struct * SF)1048 SUMA_Boolean SUMA_SureFit_Read_Topo_old (char * f_name, SUMA_SureFit_struct *SF)
1049 {/*SUMA_SureFit_Read_Topo_old*/
1050 static char FuncName[]={"SUMA_SureFit_Read_Topo_old"};
1051 FILE *sf_file;
1052 int ex, EndHead, FoundHead, evl, cnt, skp, jnk, i, ip, NP;
1053 char stmp[100], head_strt[100], head_end[100], s[1000], delimstr[] = {' ', '\0'}, *st;
1054 int LocalHead = 1;
1055
1056 SUMA_ENTRY;
1057
1058 /* check for existence */
1059 if (!SUMA_filexists(f_name)) {
1060 fprintf(SUMA_STDERR,"File %s does not exist or cannot be read.\n", f_name);
1061 SUMA_RETURN (NOPE);
1062 }
1063
1064 sprintf(SF->name_topo, "%s", f_name);
1065
1066 /* start reading */
1067 sf_file = fopen (f_name,"r");
1068 if (sf_file == NULL)
1069 {
1070 SUMA_error_message (FuncName,"Could not open input file ",0);
1071 SUMA_RETURN (NOPE);
1072 }
1073
1074 /* read until you reach the begin header BeginHeader */
1075 ex = 1;
1076 FoundHead = 0;
1077 sprintf(head_strt,"BeginHeader");
1078 while (ex != EOF && !FoundHead)
1079 {
1080 ex = fscanf (sf_file,"%s",s);
1081 if (strlen (s) >= strlen(head_strt))
1082 {
1083 evl = SUMA_iswordin (s,head_strt);
1084 if (evl == 1) FoundHead = 1;
1085 }
1086 }
1087 if (!FoundHead) {
1088 fprintf(SUMA_STDERR,"Error %s: BeginHeader not found in %s.\nPerhaps you are using old versions of Caret/SureFit files.\n", FuncName, f_name);
1089 SUMA_RETURN (NOPE);
1090 }
1091 EndHead = 0;
1092 sprintf(head_end,"EndHeader");
1093 sprintf(delimstr," ");
1094
1095 while (ex != EOF && !EndHead) {
1096 ex = fscanf (sf_file,"%s",s);
1097 /*fprintf(stdout,"%s\n", s);*/
1098 if (strlen (s) >= strlen(head_end))
1099 {
1100 evl = SUMA_iswordin (s,head_end);
1101 if (evl == 1) EndHead = 1;
1102 }
1103 /* look for some tokens */
1104 skp = 0;
1105 if (!EndHead) {
1106 st = strtok(s, delimstr);
1107 sprintf(stmp,"encoding");
1108 if (!skp && SUMA_iswordin (st, stmp) == 1) {
1109 /*fprintf(stdout,"Found encoding\n");*/
1110 ex = fscanf (sf_file,"%s",(SF->encoding_topo));
1111 skp = 1;
1112 }
1113
1114 sprintf(stmp,"perimeter_id");
1115 if (!skp && SUMA_iswordin (st, stmp) == 1) {
1116 /*fprintf(stdout,"Found perimeter_id\n");*/
1117 ex = fscanf (sf_file,"%s",(SF->perimeter_id));
1118 skp = 1;
1119 }
1120
1121 sprintf(stmp,"date");
1122 if (!skp && SUMA_iswordin (st, stmp) == 1) {
1123 /*fprintf(stdout,"Found date\n");*/
1124 ex = fscanf (sf_file,"%s\n",(SF->date));
1125 skp = 1;
1126 }
1127
1128 }
1129 }
1130 /* Now read the Number of Nodes Specs */
1131 ex = fscanf (sf_file,"%s",s);
1132 SF->N_Node_Specs = atoi(s);
1133 /* fscanf(sf_file, "%d", &SF->N_Node_Specs); */
1134 if (LocalHead) fprintf (stdout,"Expecting %d Node_Specs (from string %s) .\n", SF->N_Node_Specs, s);
1135
1136 if (!SF->N_Node_Specs || SUMA_iswordin (s, "tag-") == 1) {
1137 if (LocalHead) fprintf (stdout,"Looks like SF file is in new format (%s).\n", s);
1138 goto FACESETS;
1139 }
1140
1141 SF->FN.N_Node = SF->N_Node_Specs;
1142 SF->FN.N_Neighb_max = 0;
1143
1144 /* allocate for Node Specs Matrix and First_Neighb structure*/
1145 SF->Specs_mat = (int **) SUMA_allocate2D(SF->N_Node_Specs, 6, sizeof(int));
1146 /*assume maximum number of neighbors is SUMA_MAX_NUMBER_NODE_NEIGHB */
1147 SF->FN.FirstNeighb = (int **) SUMA_allocate2D(SF->FN.N_Node, SUMA_MAX_NUMBER_NODE_NEIGHB, sizeof (int));
1148 SF->FN.N_Neighb = (int *) SUMA_calloc (SF->FN.N_Node, sizeof(int));
1149 SF->FN.NodeId = (int *) SUMA_calloc (SF->FN.N_Node, sizeof(int));
1150
1151 if (SF->Specs_mat == NULL || SF->FN.FirstNeighb == NULL || SF->FN.N_Neighb == NULL || SF->FN.NodeId == NULL ){
1152 fprintf(SUMA_STDERR, "Error %s: Could not allocate space for SF->Specs_mat &/| SF->FN.FirstNeighb &/| SF->FN.N_Neighb &/| SF->FN.NodeId.\n", FuncName);
1153 SUMA_RETURN (NOPE);
1154 }
1155
1156 /* Now read the node specs */
1157 /*fprintf (stdout,"About to read specs\n");*/
1158 cnt = 0;
1159 while (ex != EOF && cnt < SF->N_Node_Specs) {
1160 ex = fscanf (sf_file,"%d %d %d %d %d %d",&(SF->Specs_mat[cnt][0]), &(SF->Specs_mat[cnt][1]), \
1161 &(SF->Specs_mat[cnt][2]), &(SF->Specs_mat[cnt][3]), &(SF->Specs_mat[cnt][4]), &(SF->Specs_mat[cnt][5]));
1162 SF->FN.NodeId[cnt] = SF->Specs_mat[cnt][0];
1163 SF->FN.N_Neighb[cnt] = SF->Specs_mat[cnt][1];
1164 if (SF->FN.N_Neighb[cnt] > SUMA_MAX_NUMBER_NODE_NEIGHB-1) {
1165 fprintf (SUMA_STDERR,"Error %s: Node %d has more neighbors (%d) than the maximum allowed (%d)\n", \
1166 FuncName, SF->FN.NodeId[cnt], SF->FN.N_Neighb[cnt], SUMA_MAX_NUMBER_NODE_NEIGHB-1);
1167 SUMA_RETURN (NOPE);
1168 }
1169 if (SF->FN.N_Neighb[cnt] > SF->FN.N_Neighb_max) SF->FN.N_Neighb_max = SF->FN.N_Neighb[cnt];
1170
1171 /* Now Read in the Neighbors info */
1172 for (i=0; i < SF->FN.N_Neighb[cnt]; ++ i) {
1173 ex = fscanf (sf_file,"%d %d", &jnk, &(SF->FN.FirstNeighb[cnt][i]));
1174 }
1175 /* seal with -1 */
1176 SF->FN.FirstNeighb[cnt][SF->FN.N_Neighb[cnt]] = -1;
1177
1178 ++cnt;
1179 }
1180 if (cnt != SF->N_Node_Specs) {
1181 fprintf(SUMA_STDERR, "Error %s: Expecting %d NodeSpecs, read %d.\n", FuncName, SF->N_Node_Specs, cnt);
1182 SUMA_RETURN (NOPE);
1183 }
1184
1185 FACESETS:
1186
1187 /*fprintf (stdout, "Done with Node Specs.\n");*/
1188 ex = fscanf (sf_file,"%d", &(SF->N_FaceSet));
1189 if (LocalHead) fprintf (stdout, "Expecting to read %d facesets.\n", SF->N_FaceSet);
1190 if (SF->N_FaceSet < 3) {
1191 fprintf(SUMA_STDERR, "Error %s: Too few (%d) triangles.\n", FuncName, SF->N_FaceSet);
1192 SUMA_RETURN (NOPE);
1193 }
1194
1195 NP = 3;
1196 SF->FaceSetList = (int *) SUMA_calloc(SF->N_FaceSet * 3, sizeof(int));
1197 if (SF->FaceSetList == NULL){
1198 fprintf(SUMA_STDERR, "Error %s: Could not allocate space for SF->FaceSetList.\n", FuncName);
1199 SUMA_RETURN (NOPE);
1200 }
1201
1202 /*fprintf (stdout,"About to read FaceSets\n");*/
1203 cnt = 0;
1204 while (ex != EOF && cnt < SF->N_FaceSet) {
1205 ip = NP * cnt;
1206 ex = fscanf (sf_file,"%d %d %d ",&(SF->FaceSetList[ip]), &(SF->FaceSetList[ip+1]), \
1207 &(SF->FaceSetList[ip+2]));
1208 ++cnt;
1209 }
1210 if (cnt != SF->N_FaceSet) {
1211 fprintf(SUMA_STDERR, "Error %s: Expecting %d FaceSets, read %d.\n", FuncName, SF->N_FaceSet, cnt);
1212 SUMA_RETURN (NOPE);
1213 }
1214 fclose (sf_file);
1215
1216 SUMA_RETURN (YUP);
1217 }/*SUMA_SureFit_Read_Topo_old*/
1218
1219 /*!
1220 Show data structure containing SureFit surface object
1221 */
SUMA_Show_SureFit(SUMA_SureFit_struct * SF,FILE * Out)1222 void SUMA_Show_SureFit (SUMA_SureFit_struct *SF, FILE *Out)
1223 { int cnt, id, ND, NP;
1224 static char FuncName[]={"SUMA_Show_SureFit"};
1225
1226 SUMA_ENTRY;
1227
1228 ND = 3;
1229 NP = 3;
1230 if (Out == NULL) Out = SUMA_STDOUT;
1231 fprintf (Out, "\n%s: Coord Info\n", SF->name_coord);
1232 fprintf (Out, "caret-version %f\n", SF->caret_version);
1233 fprintf (Out, "N_Node %d\n", SF->N_Node);
1234 fprintf (Out, "encoding_coord: %s\nconfiguration id: %s, coordframe_id: %s \n", SF->encoding_coord,SF->configuration_id, SF->coordframe_id);
1235 if (!SF->NodeId) {
1236 fprintf (Out, "NULL NodeId:\n");
1237 }
1238 if (!SF->allzerocoord) {
1239 fprintf (Out, "NULL allzerocoord:\n");
1240 }
1241 if (!SF->NodeList) {
1242 fprintf (Out, "NULL NodeList:\n");
1243 }
1244 if (SF->NodeId && SF->NodeList) {
1245 fprintf (Out, "First 2 points [id] X Y Z:\n\t[%d] %f %f %f\n\t[%d] %f %f %f\n",
1246 SF->NodeId[0], SF->NodeList[0], SF->NodeList[1], SF->NodeList[2],
1247 SF->NodeId[1], SF->NodeList[3], SF->NodeList[4], SF->NodeList[5]);
1248 if (SF->N_Node > 2) {
1249 fprintf (Out, "Last 2 points [id] X Y Z:\n\t[%d] %f %f %f\n\t[%d] %f %f %f\n", \
1250 SF->NodeId[SF->N_Node-2], SF->NodeList[ND*(SF->N_Node-2)], SF->NodeList[ND*(SF->N_Node-2)+1], SF->NodeList[ND*(SF->N_Node-2)+2],
1251 SF->NodeId[SF->N_Node-1], SF->NodeList[ND*(SF->N_Node-1)], SF->NodeList[ND*(SF->N_Node-1)+1], SF->NodeList[ND*(SF->N_Node-1)+2]);
1252 }
1253 }
1254 fprintf (Out, "\n%s: Topo Info\n", SF->name_topo);
1255 fprintf (Out, "N_Node_Specs %d\n", SF->N_Node_Specs);
1256 fprintf (Out, "ecnoding_topo: %s, date %s\n", SF->encoding_topo, SF->date);
1257 fprintf (Out, "N_FaceSet %d\n", SF->N_FaceSet);
1258 if (!SF->FaceSetList) {
1259 fprintf (Out, "NULL SF->FaceSetList:\n");
1260 }
1261 if (SF->N_FaceSet > 2 && SF->FaceSetList) {
1262 fprintf (Out, "First 2 polygons:\n\t%d %d %d\n\t%d %d %d\n",
1263 SF->FaceSetList[0], SF->FaceSetList[1], SF->FaceSetList[2],
1264 SF->FaceSetList[3], SF->FaceSetList[4], SF->FaceSetList[5]);
1265 fprintf (Out, "Last 2 polygons:\n\t%d %d %d\n\t%d %d %d\n",
1266 SF->FaceSetList[NP*(SF->N_FaceSet-2)],
1267 SF->FaceSetList[NP*(SF->N_FaceSet-2) + 1],
1268 SF->FaceSetList[NP*(SF->N_FaceSet-2) + 2],
1269 SF->FaceSetList[NP*(SF->N_FaceSet-1)],
1270 SF->FaceSetList[NP*(SF->N_FaceSet-1) + 1],
1271 SF->FaceSetList[NP*(SF->N_FaceSet-1) + 2]);
1272 } else if (SF->FaceSetList){
1273 fprintf (Out, "First polygon:\n\t%d %d %d\n",
1274 SF->FaceSetList[0], SF->FaceSetList[1], SF->FaceSetList[2] );
1275 }
1276 fprintf (Out, "\nNode Specs (%d):\n", SF->N_Node_Specs);
1277 if (SF->Specs_mat) {
1278 fprintf (Out, "First Entry: \t%d %d %d %d %d %d\n",
1279 SF->Specs_mat[0][0], SF->Specs_mat[0][1],SF->Specs_mat[0][2],
1280 SF->Specs_mat[0][3],SF->Specs_mat[0][4], SF->Specs_mat[0][5]);
1281 } else {
1282 fprintf (Out, "NULL SF->Specs_mat\n");
1283 }
1284 if (SF->FN.FirstNeighb) {
1285 cnt = 0;
1286 while (cnt < SF->FN.N_Neighb[0]) {
1287 fprintf (Out, "\t%d %d\n", cnt, SF->FN.FirstNeighb[0][cnt]);
1288 ++cnt;
1289 }
1290 } else {
1291 fprintf (Out, "NULL SF->FN.FirstNeighb\n");
1292 }
1293 if (SF->Specs_mat) {
1294 fprintf (Out, "Last Entry: \t%d %d %d %d %d %d\n",
1295 SF->Specs_mat[SF->N_Node_Specs-1][0],
1296 SF->Specs_mat[SF->N_Node_Specs-1][1],
1297 SF->Specs_mat[SF->N_Node_Specs-1][2],
1298 SF->Specs_mat[SF->N_Node_Specs-1][3],
1299 SF->Specs_mat[SF->N_Node_Specs-1][4],
1300 SF->Specs_mat[SF->N_Node_Specs-1][5]);
1301 }
1302 if (SF->FN.N_Neighb) {
1303 cnt = 0;
1304 while (cnt < SF->FN.N_Neighb[SF->N_Node_Specs-1]) {
1305 fprintf (Out, "\t%d %d\n",
1306 cnt, SF->FN.FirstNeighb[SF->N_Node_Specs-1][cnt]);
1307 ++cnt;
1308 }
1309 }
1310
1311 SUMA_RETURNe;
1312 }
1313
1314 /*!
1315 \brief writes a surface in SureFit format
1316 ans = SUMA_SureFit_Write (Fname,SO);
1317
1318 \param Fname (SUMA_SFname *) uses the SureFit filename structure to store
1319 the names (and paths) of the NodeList (name_coord)
1320 and the FaceSetList (name_topo) files.
1321 If strlen(name_coord) == 0 then the coord file is not
1322 written out.
1323 If strlen(name_topo) == 0 then topo file is not written out
1324 \param SO (SUMA_SurfaceObject *) pointer to SO structure.
1325 \return YUP/NOPE
1326
1327 \sa SUMA_SureFit_Read_Topo()
1328 \sa SUMA_SureFit_Read_Coord()
1329
1330 The function will not overwrite pre-existing files.
1331
1332
1333 NOTE: Header info is incomplete.
1334 for .coord:
1335 BeginHeader
1336 configuration_id NA
1337 coordframe_id NA
1338 encoding ASCII
1339 EndHeader
1340
1341 for .topo:
1342 BeginHeader
1343 date NA
1344 encoding ASCII
1345 perimeter_id NA
1346 EndHeader
1347
1348 also, the last 4 integers in the node neighbor list lines are set to 0. I have never used them and do not know what they are for.
1349
1350 The naming convention of SureFit surfaces is not enforced.
1351
1352 */
SUMA_SureFit_Write(SUMA_SFname * Fname,SUMA_SurfaceObject * SO)1353 SUMA_Boolean SUMA_SureFit_Write (SUMA_SFname *Fname, SUMA_SurfaceObject *SO)
1354 {
1355
1356 static char FuncName[]={"SUMA_SureFit_Write"};
1357 int i, j;
1358 FILE *outFile = NULL;
1359
1360 SUMA_ENTRY;
1361
1362 if (strlen(Fname->name_coord)) {
1363 if (!THD_ok_overwrite() && SUMA_filexists(Fname->name_coord)) {
1364 fprintf (SUMA_STDERR,
1365 "Error %s: file %s exists, will not overwrite.\n",
1366 FuncName, Fname->name_coord);
1367 SUMA_RETURN (NOPE);
1368 }
1369 }
1370
1371 if (strlen(Fname->name_topo)) {
1372 if (!THD_ok_overwrite() && SUMA_filexists(Fname->name_topo)) {
1373 fprintf (SUMA_STDERR,
1374 "Error %s: file %s exists, will not overwrite.\n",
1375 FuncName, Fname->name_topo);
1376 SUMA_RETURN (NOPE);
1377 }
1378 }
1379
1380 if (SO->NodeDim != 3 || SO->FaceSetDim != 3) {
1381 fprintf (SUMA_STDERR,
1382 "Error %s: Must have NodeDim and FaceSetDim = 3.\n",FuncName);
1383 SUMA_RETURN (NOPE);
1384 }
1385
1386 if (strlen(Fname->name_coord)) {
1387 outFile = fopen(Fname->name_coord, "w");
1388 if (!outFile) {
1389 fprintf (SUMA_STDERR,
1390 "Error %s: Failed in opening %s for writing.\n",
1391 FuncName, Fname->name_coord);
1392 SUMA_RETURN (NOPE);
1393 }
1394
1395 /* write header */
1396 fprintf (outFile, "BeginHeader\nconfiguration_id NA\n"
1397 "coordframe_id NA\nencoding ASCII\nEndHeader\n");
1398 fprintf (outFile,"%d\n", SO->N_Node);
1399
1400 j=0;
1401 for (i=0; i<SO->N_Node; ++i) {
1402 j=SO->NodeDim * i;
1403 fprintf (outFile, "%d %f %f %f\n",
1404 i, SO->NodeList[j], SO->NodeList[j+1], SO->NodeList[j+2]);
1405 }
1406
1407 fclose (outFile);
1408 }
1409
1410 if (strlen(Fname->name_topo)) {
1411 outFile = fopen(Fname->name_topo, "w");
1412 if (!outFile) {
1413 fprintf (SUMA_STDERR,
1414 "Error %s: Failed in opening %s for writing.\n",
1415 FuncName, Fname->name_topo);
1416 SUMA_RETURN (NOPE);
1417 }
1418
1419 /* make sure you have the first neighbor list ! */
1420 if (!SO->FN) {
1421 fprintf (SUMA_STDERR,
1422 "%s: Must compute Node Neighborhood list.\n", FuncName);
1423 if (!SUMA_SurfaceMetrics(SO, "EdgeList", NULL)){
1424 fprintf (SUMA_STDERR,
1425 "Error %s: Failed in SUMA_SurfaceMetrics.\n", FuncName);
1426 SUMA_RETURN (NOPE);
1427 }
1428
1429 }
1430 /* write header */
1431 fprintf (outFile, "BeginHeader\ndate NA\nencoding ASCII\n"
1432 "perimeter_id NA\nEndHeader\n");
1433 fprintf (outFile,"%d\n", SO->N_Node);
1434 j = 0;
1435 while (j < SO->FN->N_Node) {
1436 /* dunno what last 4 ints of upcoming line are */
1437 fprintf (outFile,
1438 "%d %d 0 0 0 0\n", SO->FN->NodeId[j], SO->FN->N_Neighb[j]);
1439
1440 /* Now write the Neighbors info */
1441 for (i=0; i < SO->FN->N_Neighb[j]; ++ i) {
1442 fprintf (outFile,"%d %d\n", i, SO->FN->FirstNeighb[j][i]);
1443 }
1444 ++j;
1445 }
1446
1447 fprintf (outFile,"%d\n", SO->N_FaceSet);
1448
1449 j=0;
1450 for (i=0; i<SO->N_FaceSet; ++i) {
1451 j = SO->FaceSetDim * i;
1452 fprintf (outFile, "%d %d %d\n",
1453 SO->FaceSetList[j],
1454 SO->FaceSetList[j+1],
1455 SO->FaceSetList[j+2]);
1456 }
1457
1458 fclose (outFile);
1459 }
1460 SUMA_RETURN (YUP);
1461
1462 }
1463
1464 /*!
1465 free data structure containing SureFit surface object
1466 */
SUMA_Free_SureFit(SUMA_SureFit_struct * SF)1467 SUMA_Boolean SUMA_Free_SureFit (SUMA_SureFit_struct *SF)
1468 {
1469 static char FuncName[]={"SUMA_Free_SureFit"};
1470 SUMA_Boolean LocalHead = NOPE;
1471
1472 SUMA_ENTRY;
1473
1474 if (!SF) SUMA_RETURN (YUP);
1475 if (LocalHead) {
1476 fprintf(SUMA_STDERR,"%p, %p, %p, %p, %p, %p, %p\n",
1477 SF->NodeList, SF->NodeId, SF->Specs_mat, SF->FN.FirstNeighb,
1478 SF->FN.N_Neighb, SF->FN.NodeId, SF->FaceSetList);
1479 }
1480 if (SF->NodeList != NULL) SUMA_free(SF->NodeList);
1481 if (SF->NodeId != NULL) SUMA_free(SF->NodeId);
1482 if (SF->allzerocoord != NULL) SUMA_free(SF->allzerocoord);
1483 if (SF->Specs_mat != NULL)
1484 SUMA_free2D ((char **)SF->Specs_mat, SF->N_Node_Specs);
1485 if (SF->FN.FirstNeighb != NULL)
1486 SUMA_free2D((char **)SF->FN.FirstNeighb, SF->FN.N_Node);
1487 if (SF->FN.N_Neighb != NULL) SUMA_free(SF->FN.N_Neighb);
1488 if (SF->FN.NodeId != NULL) SUMA_free(SF->FN.NodeId);
1489 if (SF->FaceSetList != NULL) SUMA_free(SF->FaceSetList);
1490 if (SF!= NULL) SUMA_free(SF);
1491
1492 SUMA_RETURN (YUP);
1493 }
1494
1495 /*!
1496 Read in some parameters from a .param file
1497 */
SUMA_Read_SureFit_Param(char * f_name,SUMA_SureFit_struct * SF)1498 SUMA_Boolean SUMA_Read_SureFit_Param (char *f_name, SUMA_SureFit_struct *SF)
1499 {
1500 static char FuncName[]={"SUMA_Read_SureFit_Param"};
1501 int ex, evl;
1502 FILE *sf_file;
1503 SUMA_Boolean Done;
1504 char delimstr[] = {' ', '\0'}, stmp[100], s[1000], *st;
1505 SUMA_Boolean LocalHead = NOPE;
1506
1507 SUMA_ENTRY;
1508
1509 /* check for existence */
1510 if (!SUMA_filexists(f_name)) {
1511 fprintf(SUMA_STDERR,"File %s does not exist or cannot be read.\n", f_name);
1512 SUMA_RETURN (NOPE);
1513 }
1514
1515 sprintf(SF->name_param, "%s", f_name);
1516
1517 /* start reading */
1518 sf_file = fopen (f_name,"r");
1519 if (sf_file == NULL)
1520 {
1521 fprintf (SUMA_STDERR,"Error %s: Could not open input file ",FuncName);
1522 SUMA_RETURN (NOPE);
1523 }
1524
1525 /* read until you reach something you like */
1526 SF->AC_WholeVolume[0] = SF->AC_WholeVolume[1] = SF->AC_WholeVolume[2] = 0.0f;
1527 SF->AC[0] = SF->AC[1] = SF->AC[2] = 0.0f;
1528 SF->CropMax[0] = SF->CropMax[1] = SF->CropMax[2] = 0.0f;
1529 SF->CropMin[0] = SF->CropMin[1] = SF->CropMin[2] = 0.0f;
1530
1531 ex = 1;
1532 Done = NOPE;
1533 sprintf(delimstr,"=");
1534 while (ex != EOF && !Done)
1535 {
1536 ex = fscanf (sf_file,"%s",s);
1537 if (LocalHead) fprintf(SUMA_STDERR, "Working >>>%s<<<\n", s);
1538 sprintf(stmp,"ACx_WholeVolume");
1539 evl = SUMA_iswordin (s,stmp);
1540 if (evl == 1) {
1541 /* found ACx_WholeVolume */
1542 if (LocalHead) fprintf(SUMA_STDERR, "Found ACx_WholeVolume:");
1543 /* go past the = sign and grab the value */
1544 st = strtok(s, delimstr);
1545 st = strtok(NULL, delimstr);
1546 if (st) {
1547 SF->AC_WholeVolume[0] = atof(st);
1548 if (LocalHead) fprintf(SUMA_STDERR, " %f\n", SF->AC_WholeVolume[0]);
1549 } else {
1550 if (LocalHead) fprintf(SUMA_STDERR, "Empty field.\n");
1551 }
1552 continue;
1553 }
1554 sprintf(stmp,"ACy_WholeVolume");
1555 evl = SUMA_iswordin (s,stmp);
1556 if (evl == 1) {
1557 /* found ACy_WholeVolume */
1558 if (LocalHead) fprintf(SUMA_STDERR, "Found ACy_WholeVolume:");
1559 /* go past the = sign and grab the value */
1560 st = strtok(s, delimstr);
1561 st = strtok(NULL, delimstr);
1562 if (st) {
1563 SF->AC_WholeVolume[1] = atof(st);
1564 if (LocalHead) fprintf(SUMA_STDERR, " %f\n", SF->AC_WholeVolume[1]);
1565 } else {
1566 if (LocalHead) fprintf(SUMA_STDERR, "Empty field.\n");
1567 }
1568
1569 continue;
1570 }
1571 sprintf(stmp,"ACz_WholeVolume");
1572 evl = SUMA_iswordin (s,stmp);
1573 if (evl == 1) {
1574 /* found ACz_WholeVolume */
1575 if (LocalHead) fprintf(SUMA_STDERR, "Found ACz_WholeVolume:");
1576 /* go past the = sign and grab the value */
1577 st = strtok(s, delimstr);
1578 st = strtok(NULL, delimstr);
1579 if (st) {
1580 SF->AC_WholeVolume[2] = atof(st);
1581 if (LocalHead) fprintf(SUMA_STDERR, " %f\n", SF->AC_WholeVolume[2]);
1582 } else {
1583 if (LocalHead) fprintf(SUMA_STDERR, "Empty field.\n");
1584 }
1585 continue;
1586 }
1587
1588 sprintf(stmp,"ACx");
1589 evl = SUMA_iswordin (s,stmp);
1590 if (evl == 1) {
1591 /* found ACx */
1592 if (LocalHead) fprintf(SUMA_STDERR, "Found ACx:");
1593 /* go past the = sign and grab the value */
1594 st = strtok(s, delimstr);
1595 st = strtok(NULL, delimstr);
1596 if (st) {
1597 SF->AC[0] = atof(st);
1598 if (LocalHead) fprintf(SUMA_STDERR, " %f\n", SF->AC[0]);
1599 } else {
1600 if (LocalHead) fprintf(SUMA_STDERR, "Empty field.\n");
1601 }
1602 continue;
1603 }
1604 sprintf(stmp,"ACy");
1605 evl = SUMA_iswordin (s,stmp);
1606 if (evl == 1) {
1607 /* found ACy */
1608 if (LocalHead) fprintf(SUMA_STDERR, "Found ACy:");
1609 /* go past the = sign and grab the value */
1610 st = strtok(s, delimstr);
1611 st = strtok(NULL, delimstr);
1612 if (st) {
1613 SF->AC[1] = atof(st);
1614 if (LocalHead) fprintf(SUMA_STDERR, " %f\n", SF->AC[1]);
1615 } else {
1616 if (LocalHead) fprintf(SUMA_STDERR, "Empty field.\n");
1617 }
1618 continue;
1619 }
1620 sprintf(stmp,"ACz");
1621 evl = SUMA_iswordin (s,stmp);
1622 if (evl == 1) {
1623 /* found ACz */
1624 if (LocalHead) fprintf(SUMA_STDERR, "Found ACz:");
1625 /* go past the = sign and grab the value */
1626 st = strtok(s, delimstr);
1627 st = strtok(NULL, delimstr);
1628 if (st) {
1629 SF->AC[2] = atof(st);
1630 if (LocalHead) fprintf(SUMA_STDERR, " %f\n", SF->AC[2]);
1631 } else {
1632 if (LocalHead) fprintf(SUMA_STDERR, "Empty field.\n");
1633 }
1634 continue;
1635 }
1636
1637 sprintf(stmp,"CropMinX");
1638 evl = SUMA_iswordin (s,stmp);
1639 if (evl == 1) {
1640 /* found CropMinX */
1641 if (LocalHead) fprintf(SUMA_STDERR, "Found CropMinX:");
1642 /* go past the = sign and grab the value */
1643 st = strtok(s, delimstr);
1644 st = strtok(NULL, delimstr);
1645 if (st) {
1646 SF->CropMin[0] = atof(st);
1647 if (LocalHead) fprintf(SUMA_STDERR, " %f\n", SF->CropMin[0]);
1648 } else {
1649 if (LocalHead) fprintf(SUMA_STDERR, "Empty field.\n");
1650 }
1651 continue;
1652 }
1653 sprintf(stmp,"CropMinY");
1654 evl = SUMA_iswordin (s,stmp);
1655 if (evl == 1) {
1656 /* found CropMinY */
1657 if (LocalHead) fprintf(SUMA_STDERR, "Found CropMinY:");
1658 /* go past the = sign and grab the value */
1659 st = strtok(s, delimstr);
1660 st = strtok(NULL, delimstr);
1661 if (st) {
1662 SF->CropMin[1] = atof(st);
1663 if (LocalHead) fprintf(SUMA_STDERR, " %f\n", SF->CropMin[1]);
1664 } else {
1665 if (LocalHead) fprintf(SUMA_STDERR, "Empty field.\n");
1666 }
1667 continue;
1668 }
1669 sprintf(stmp,"CropMinZ");
1670 evl = SUMA_iswordin (s,stmp);
1671 if (evl == 1) {
1672 /* found CropMinZ */
1673 if (LocalHead) fprintf(SUMA_STDERR, "Found CropMinZ:");
1674 /* go past the = sign and grab the value */
1675 st = strtok(s, delimstr);
1676 st = strtok(NULL, delimstr);
1677 if (st) {
1678 SF->CropMin[2] = atof(st);
1679 if (LocalHead) fprintf(SUMA_STDERR, " %f\n", SF->CropMin[2]);
1680 } else {
1681 if (LocalHead) fprintf(SUMA_STDERR, "Empty field.\n");
1682 }
1683 continue;
1684 }
1685
1686 sprintf(stmp,"CropMaxX");
1687 evl = SUMA_iswordin (s,stmp);
1688 if (evl == 1) {
1689 /* found CropMaxX */
1690 if (LocalHead) fprintf(SUMA_STDERR, "Found CropMaxX:");
1691 /* go past the = sign and grab the value */
1692 st = strtok(s, delimstr);
1693 st = strtok(NULL, delimstr);
1694 if (st) {
1695 SF->CropMax[0] = atof(st);
1696 if (LocalHead) fprintf(SUMA_STDERR, " %f\n", SF->CropMax[0]);
1697 } else {
1698 if (LocalHead) fprintf(SUMA_STDERR, "Empty field.\n");
1699 }
1700 continue;
1701 }
1702 sprintf(stmp,"CropMaxY");
1703 evl = SUMA_iswordin (s,stmp);
1704 if (evl == 1) {
1705 /* found CropMaxY */
1706 if (LocalHead) fprintf(SUMA_STDERR, "Found CropMaxY:");
1707 /* go past the = sign and grab the value */
1708 st = strtok(s, delimstr);
1709 st = strtok(NULL, delimstr);
1710 if (st) {
1711 SF->CropMax[1] = atof(st);
1712 if (LocalHead) fprintf(SUMA_STDERR, " %f\n", SF->CropMax[1]);
1713 } else {
1714 if (LocalHead) fprintf(SUMA_STDERR, "Empty field.\n");
1715 }
1716 continue;
1717 }
1718 sprintf(stmp,"CropMaxZ");
1719 evl = SUMA_iswordin (s,stmp);
1720 if (evl == 1) {
1721 /* found CropMaxZ */
1722 if (LocalHead) fprintf(SUMA_STDERR, "Found CropMaxZ:");
1723 /* go past the = sign and grab the value */
1724 st = strtok(s, delimstr);
1725 st = strtok(NULL, delimstr);
1726 if (st) {
1727 SF->CropMax[2] = atof(st);
1728 if (LocalHead) fprintf(SUMA_STDERR, " %f\n", SF->CropMax[2]);
1729 } else {
1730 if (LocalHead) fprintf(SUMA_STDERR, "Empty field.\n");
1731 }
1732 continue;
1733 }
1734
1735 }
1736
1737 fclose(sf_file);
1738
1739 /* Sanity Checks */
1740 if (SF->AC[0] == 0.0f && SF->AC[1] == 0.0f && SF->AC[2] == 0.0f) {
1741 if (SF->caret_version < 5.2) fprintf (SUMA_STDERR,"Warning %s: All values for AC are 0.0.\n", FuncName);
1742 /* SUMA_RETURN (NOPE); */
1743 }
1744
1745 if (SF->AC_WholeVolume[0] == 0.0f && SF->AC_WholeVolume[1] == 0.0f && SF->AC_WholeVolume[2] == 0.0f) {
1746 if (SF->caret_version < 5.2) fprintf (SUMA_STDERR,"Warning %s: All values for AC_WholeVolume are 0.0. \n", FuncName);
1747 /* SUMA_RETURN (NOPE); */
1748 }
1749
1750 if (SF->AC[0] == SF->AC_WholeVolume[0] && SF->AC[1] == SF->AC_WholeVolume[1] && SF->AC[2] == SF->AC_WholeVolume[2])
1751 {
1752 if (SF->caret_version < 5.2) SUMA_SL_Warn("Idetincal values for AC and AC_WholeVolume.\nCheck your params file if not using Talairach-ed surfaces.\n");
1753 /* looks like that's OK for TLRC surfaces ...*/
1754 /*
1755 fprintf (SUMA_STDERR,"Error %s: Idetincal values for AC and AC_WholeVolume. Check your params file.\n", FuncName);
1756 SUMA_RETURN (NOPE);
1757 */
1758 }
1759 if (SF->AC[0] < 0.0f || SF->AC[1] < 0.0f || SF->AC[2] < 0.0f || SF->AC_WholeVolume[0] < 0.0f || SF->AC_WholeVolume[1] < 0.0f || SF->AC_WholeVolume[2] < 0.0f)
1760 {
1761 fprintf (SUMA_STDERR,"Error %s: Negative values in AC or AC_WholeVolume. Check your params file.\n", FuncName);
1762 SUMA_RETURN (NOPE);
1763 }
1764
1765 SUMA_RETURN (YUP);
1766 }
1767
1768
1769 /*! Functions to read and manipulate FreeSurfer surfaces*/
1770
1771
SUMA_CreateFS_ColorTable(int nbins,int len,SUMA_FS_COLORTABLE * cto)1772 SUMA_FS_COLORTABLE *SUMA_CreateFS_ColorTable(int nbins,
1773 int len, SUMA_FS_COLORTABLE *cto)
1774 {
1775 static char FuncName[]={"SUMA_CreateFS_ColorTable"};
1776 SUMA_COLOR_MAP_HASH_DATUM *hd=NULL;
1777 SUMA_FS_COLORTABLE *ct = NULL;
1778
1779 SUMA_ENTRY;
1780
1781 if (!cto) {
1782 ct = (SUMA_FS_COLORTABLE*) SUMA_calloc(1,sizeof(SUMA_FS_COLORTABLE));
1783 if (!ct) {
1784 SUMA_SL_Crit("Failed to allocate for ct");
1785 SUMA_RETURN(NULL);
1786 }
1787 ct->chd = NULL;
1788 ct->nbins = nbins;
1789 ct->bins = (SUMA_FS_COLORTABLE_ENTRY *)
1790 SUMA_calloc(nbins, sizeof(SUMA_FS_COLORTABLE_ENTRY));
1791
1792 ct->fname = (char *)SUMA_malloc((len + 1)*sizeof(char));
1793 if (!ct->bins || !ct->fname) {
1794 SUMA_SL_Crit("Failed to allocate for ct fields");
1795 SUMA_DUMP_TRACE("%s",FuncName);
1796 if (ct->bins) SUMA_free(ct->bins);
1797 if (ct->fname) SUMA_free(ct->fname);
1798 SUMA_free(ct);
1799 SUMA_RETURN(NULL);
1800 }
1801 ct->fname[0] = '\0';
1802 SUMA_RETURN(ct);
1803 } else {
1804 cto->bins = (SUMA_FS_COLORTABLE_ENTRY *) SUMA_realloc(cto->bins, nbins *
1805 sizeof(SUMA_FS_COLORTABLE_ENTRY));
1806 cto->nbins = nbins;
1807 if (cto->chd) {
1808 SUMA_S_Note("Wiping out old hash");
1809 while (cto->chd) {
1810 hd = cto->chd;
1811 HASH_DEL( cto->chd, hd);
1812 SUMA_free(hd); hd = NULL;
1813 }
1814 cto->chd=NULL;
1815 }
1816 SUMA_RETURN(cto);
1817 }
1818 }
1819
SUMA_FreeFS_ColorTable(SUMA_FS_COLORTABLE * ct)1820 SUMA_FS_COLORTABLE *SUMA_FreeFS_ColorTable (SUMA_FS_COLORTABLE *ct)
1821 {
1822 static char FuncName[]={"SUMA_FreeFS_ColorTable"};
1823 SUMA_COLOR_MAP_HASH_DATUM *hd=NULL;
1824
1825 SUMA_ENTRY;
1826
1827 if (!ct) SUMA_RETURN(NULL);
1828
1829 if (ct->bins) SUMA_free(ct->bins);
1830 if (ct->fname) SUMA_free(ct->fname);
1831
1832 /* destroy hash */
1833 while (ct->chd) {
1834 hd = ct->chd; /* will delete the head of the hash table list */
1835 HASH_DEL( ct->chd, hd); /* remove the head from the list, after
1836 this macro, SM->chd points to the next
1837 item in the list; the new head */
1838 SUMA_free(hd); hd = NULL; /* free hd, no longer needed */
1839 }
1840
1841
1842 SUMA_free(ct);
1843
1844 SUMA_RETURN(NULL);
1845 }
1846
SUMA_FS_ColorTable_Info(SUMA_FS_COLORTABLE * ct)1847 char *SUMA_FS_ColorTable_Info(SUMA_FS_COLORTABLE *ct)
1848 {
1849 static char FuncName[]={"SUMA_FS_ColorTable_Info"};
1850 char *s=NULL;
1851 int i;
1852 SUMA_STRING *SS = NULL;
1853
1854 SUMA_ENTRY;
1855
1856 SS = SUMA_StringAppend (NULL, NULL);
1857
1858 if (!ct) SS = SUMA_StringAppend(SS,"NULL ct");
1859 else {
1860 if (ct->fname)
1861 SS = SUMA_StringAppend_va(SS,
1862 "FS fname: %s\nnbins: %d\n", ct->fname, ct->nbins);
1863 else SS = SUMA_StringAppend_va(SS, "fname: NULL\nnbins: %d\n", ct->nbins);
1864 if (!ct->bins) SS = SUMA_StringAppend_va(SS, "NULL bins\n");
1865 else {
1866 for (i=0; i<ct->nbins; ++i) {
1867 SS = SUMA_StringAppend_va(SS,
1868 "bin[%d]: %d %d %d %d %d : %s\n",
1869 i, ct->bins[i].i, ct->bins[i].r, ct->bins[i].g,
1870 ct->bins[i].b, ct->bins[i].flag,
1871 ct->bins[i].name);
1872 }
1873 }
1874 }
1875
1876 SS = SUMA_StringAppend(SS,NULL);
1877 s = SS->s;
1878 SUMA_free(SS);
1879
1880 SUMA_RETURN(s);
1881
1882 }
1883
SUMA_Show_FS_ColorTable(SUMA_FS_COLORTABLE * ct,FILE * fout)1884 SUMA_Boolean SUMA_Show_FS_ColorTable(SUMA_FS_COLORTABLE *ct, FILE *fout)
1885 {
1886 static char FuncName[]={"SUMA_Show_FS_ColorTable"};
1887 char *s=NULL;
1888
1889 SUMA_ENTRY;
1890
1891 if (!fout) fout = stdout;
1892
1893 s = SUMA_FS_ColorTable_Info(ct);
1894 if (s) {
1895 fprintf(fout, "%s\n", s);
1896 SUMA_free(s);
1897 } else {
1898 SUMA_SL_Err("Failed in SUMA_FS_ColorTable_Info");
1899 SUMA_RETURN(NOPE);
1900 }
1901
1902 SUMA_RETURN(YUP);
1903 }
1904
SUMA_readFScolorLUT(char * f_name,SUMA_FS_COLORTABLE ** ctp)1905 SUMA_Boolean SUMA_readFScolorLUT(char *f_name, SUMA_FS_COLORTABLE **ctp)
1906 {
1907 static char FuncName[]={"SUMA_readFScolorLUT"};
1908 SUMA_FS_COLORTABLE *ct=NULL;
1909 SUMA_FS_COLORTABLE_ENTRY *ce;
1910 SUMA_COLOR_MAP_HASH_DATUM *hd=NULL;
1911 char *fl=NULL, *fl2=NULL, *colfile=NULL, *florig=NULL, *name=NULL, *fle=NULL;
1912 double dum;
1913 float mxcol;
1914 int i, r, g, b, v, nalloc, nchar, ok, ans, cnt, ism=0;
1915 SUMA_Boolean state = YUP;
1916 SUMA_Boolean LocalHead = NOPE;
1917
1918 SUMA_ENTRY;
1919
1920 if (f_name) colfile = f_name;
1921 else {
1922 char *eee = getenv("FREESURFER_HOME");
1923 if (eee) {
1924 colfile =
1925 SUMA_append_replace_string(eee,"FreeSurferColorLUT.txt", "/", 0);
1926 } else {
1927 SUMA_S_Err("FREESURFER_HOME environment variable not set");
1928 SUMA_RETURN(NOPE);
1929 }
1930 }
1931 if (ctp && *ctp) {
1932 SUMA_S_Err("Colortable pointer pointer must point to null!");
1933 SUMA_RETURN(NOPE);
1934 }
1935 if (!SUMA_filexists(colfile)) {
1936 SUMA_S_Errv("File %s not found.\n", colfile);
1937 state = NOPE; goto CLEANUP;
1938 SUMA_RETURN(NOPE);
1939 }
1940 /* suck file */
1941
1942 if (!(fl = florig = SUMA_file_suck(colfile, &nchar))) {
1943 SUMA_S_Errv("Faile to read %s\n", colfile);
1944 state = NOPE; goto CLEANUP;
1945 }
1946 fle = fl+nchar;
1947 nalloc = 256;
1948 ct = SUMA_CreateFS_ColorTable(nalloc, strlen(colfile), NULL);
1949 snprintf(ct->fname, (strlen(colfile)+1)*sizeof(char),"%s", colfile);
1950 ok = 1;
1951 cnt = 0; mxcol = 0;
1952 while (ok && fl < fle) {
1953 SUMA_SKIP_BLANK(fl, fle);
1954 do {
1955 /* skip comment, if any */
1956 SUMA_IS_COMMENT_LINE(fl, fle, '#', ans);
1957 if (ans) {
1958 SUMA_LH("Skipping comment...");
1959 SUMA_SKIP_LINE(fl, fle);
1960 }
1961 } while (ans);
1962 SUMA_SKIP_BLANK(fl, fle); if (fl == fle) goto DONEREAD;
1963 if (cnt >= nalloc) {
1964 nalloc = nalloc+256;
1965 ct = SUMA_CreateFS_ColorTable(nalloc, -1, ct);
1966 }
1967 ce = &ct->bins[cnt];
1968
1969 /* read first number */
1970 SUMA_ADVANCE_PAST_NUM(fl, dum, ok);
1971 if (!ok && fl!=fle) {
1972 SUMA_S_Err("Failed to read i"); state = NOPE; goto CLEANUP;
1973 }
1974 SUMA_LHv("index %f\n", dum);
1975 ce->i=(int)dum;
1976 SUMA_GET_BETWEEN_BLANKS(fl, NULL, fl2);
1977 if (fl2 > fl) {
1978 SUMA_COPY_TO_STRING(fl, fl2, name);
1979 SUMA_LHv("name %s\n", name);
1980 snprintf((ce->name), (SUMA_FS_STRLEN-1)*sizeof(char), "%s", name);
1981 SUMA_free(name); name = NULL;
1982 fl = fl2;
1983 }
1984 SUMA_ADVANCE_PAST_NUM(fl, dum, ok);
1985 if (!ok) { SUMA_S_Err("Failed to read r"); state = NOPE; goto CLEANUP; }
1986 SUMA_LHv("r %f\n", dum);
1987 ce->r=(int)(dum*1000);
1988 SUMA_ADVANCE_PAST_NUM(fl, dum, ok);
1989 if (!ok) { SUMA_S_Err("Failed to read g"); state = NOPE; goto CLEANUP; }
1990 SUMA_LHv("g %f\n", dum);
1991 ce->g=(int)(dum*1000);
1992 SUMA_ADVANCE_PAST_NUM(fl, dum, ok);
1993 if (!ok) { SUMA_S_Err("Failed to read b"); state = NOPE; goto CLEANUP; }
1994 SUMA_LHv("b %f\n", dum);
1995 ce->b=(int)(dum*1000);
1996 SUMA_ADVANCE_PAST_NUM(fl, dum, ok);
1997 if (!ok) { SUMA_S_Err("Failed to read v"); state = NOPE; goto CLEANUP; }
1998 SUMA_LHv("v %f\n", dum);
1999 ce->flag=(int)(dum*1000);
2000 if (ce->r > mxcol) mxcol=ce->r;
2001 if (ce->g > mxcol) mxcol=ce->g;
2002 if (ce->b > mxcol) mxcol=ce->b;
2003 if (ce->flag > mxcol) mxcol=ce->flag;
2004 ++cnt;
2005 }
2006
2007 DONEREAD:
2008 if (mxcol < 1.1*1000) { /* range is 0 -- 1 */
2009 mxcol = 255.0/1000.0; /* recycle to scale */
2010 } else { /* range is 0 -- 255, just undo 1000 scaling */
2011 mxcol = 1.0/1000.0;
2012 }
2013 for (ism=0; ism<cnt; ++ism) {
2014 ce = &ct->bins[ism];
2015 ce->r = (int)((float)ce->r*mxcol);
2016 ce->g = (int)((float)ce->g*mxcol);
2017 ce->b = (int)((float)ce->b*mxcol);
2018 ce->flag = (int)((float)ce->flag*mxcol);
2019 }
2020
2021 ct = SUMA_CreateFS_ColorTable(cnt, -1, ct);
2022
2023 /* Hash the colormap */
2024 for (ism=0; ism<ct->nbins; ++ism) {
2025 HASH_FIND_INT(ct->chd, &(ct->bins[ism].i), hd);
2026 if (hd) {
2027 SUMA_S_Errv("iLabel %d already in hash table!\n",
2028 ct->bins[ism].i);
2029 state = NOPE; goto CLEANUP;
2030 } else {
2031 hd = (SUMA_COLOR_MAP_HASH_DATUM *)
2032 SUMA_calloc(1, sizeof(SUMA_COLOR_MAP_HASH_DATUM));
2033 hd->id = ct->bins[ism].i;
2034 hd->colmapindex = ism;
2035
2036 HASH_ADD_INT(ct->chd, id, hd);
2037 }
2038 }
2039
2040 if (LocalHead) SUMA_Show_FS_ColorTable(ct, NULL);
2041
2042 CLEANUP:
2043 if (ctp) *ctp = ct;
2044 if (!f_name && colfile) SUMA_free(colfile); colfile = NULL;
2045 if (florig) SUMA_free(florig);
2046
2047 SUMA_RETURN(state);
2048 }
2049
SUMA_FScolutToColorMap(char * fscolutname,int lbl1,int lbl2,int show,int idISi)2050 SUMA_COLOR_MAP *SUMA_FScolutToColorMap(char *fscolutname,
2051 int lbl1, int lbl2, int show, int idISi)
2052 {
2053 static char FuncName[]={"SUMA_FScolutToColorMap"};
2054 SUMA_FS_COLORTABLE *ct=NULL;
2055 SUMA_COLOR_MAP *SM=NULL;
2056 SUMA_Boolean LocalHead = NOPE;
2057
2058 SUMA_ENTRY;
2059
2060 if (!(SUMA_readFScolorLUT(fscolutname, &ct))) {
2061 SUMA_S_Err("Failed baby, failed.");
2062 SUMA_RETURN(SM);
2063 }
2064
2065 SM = SUMA_FScolutToColorMap_eng(ct, lbl1, lbl2, show, idISi);
2066
2067 ct = SUMA_FreeFS_ColorTable(ct);
2068
2069 SUMA_RETURN(SM);
2070
2071 }
2072
SUMA_FScolutToColorMap_eng(SUMA_FS_COLORTABLE * ct,int lbl1,int lbl2,int show,int idISi)2073 SUMA_COLOR_MAP *SUMA_FScolutToColorMap_eng(SUMA_FS_COLORTABLE *ct,
2074 int lbl1, int lbl2, int show, int idISi)
2075 {
2076 static char FuncName[]={"SUMA_FScolutToColorMap_eng"};
2077 SUMA_COLOR_MAP *SM=NULL;
2078 int cnt =0, cntmax = 0, ism = 0, suc= 0;
2079 char stmp[256]={""};
2080 NI_group *ngr = NULL;
2081 SUMA_COLOR_MAP_HASH_DATUM *hd=NULL;
2082 SUMA_Boolean LocalHead = NOPE;
2083
2084 SUMA_ENTRY;
2085
2086 if (!ct) {
2087 SUMA_S_Err("NULL input");
2088 SUMA_RETURN(SM);
2089 }
2090 if (show || LocalHead) {
2091 SUMA_Show_FS_ColorTable(ct, NULL);
2092 }
2093
2094
2095 /* first find lbl1 */
2096 cnt = 0;
2097 if (lbl1 < 0) {
2098 /* begin at 1st one */
2099 lbl1 = ct->bins[cnt].i;
2100 } else {
2101 while (cnt < ct->nbins && ct->bins[cnt].i < lbl1) ++cnt;
2102 }
2103 if (cnt >= ct->nbins) {
2104 SUMA_S_Err("Could not find start");
2105 SUMA_RETURN(SM);
2106 }
2107
2108 cntmax = cnt;
2109 if (lbl2 < 0) {
2110 /* stop at last */
2111 cntmax = ct->nbins;
2112 lbl2 = ct->bins[cntmax-1].i;
2113 } else {
2114 while (cntmax < ct->nbins && ct->bins[cntmax].i < lbl2) ++cntmax;
2115 if (cntmax >= ct->nbins) {
2116 SUMA_LHv("Failed to find lbl2 %d, clipping at %d\n",
2117 lbl2, ct->bins[ct->nbins-1].i);
2118 lbl2 = ct->bins[ct->nbins-1].i;
2119 }
2120 }
2121
2122
2123 SUMA_LHv("Creating colormap from ilabels [%d to %d] (%d) colors\n",
2124 lbl1, lbl2, lbl2-lbl1+1);
2125 /* allocate for SM */
2126 SM = (SUMA_COLOR_MAP*) SUMA_calloc(1,sizeof(SUMA_COLOR_MAP));
2127 SM->top_frac = 0.0f;
2128 SM->SO = NULL;
2129 SM->N_M[0] = lbl2-lbl1+1; SM->N_M[1] = 4;
2130 SM->idvec = (int *)SUMA_calloc(SM->N_M[0], sizeof(int));;
2131 SM->cname = (char **)SUMA_calloc(SM->N_M[0], sizeof(char*));
2132 SM->M = (float**)SUMA_allocate2D (SM->N_M[0], SM->N_M[1], sizeof(float));
2133 sprintf(stmp,"-%d_%d", lbl1, lbl2);
2134 SM->Name = SUMA_append_string(SUMA_FnameGet(ct->fname,"fne", NULL), stmp);
2135 SM->Sgn = 0;
2136 SM->frac = NULL;
2137
2138
2139 #if 0 /* worked for 2005 version. NOT for 2009 */
2140 if (ct->bins[cnt].i == lbl1) {
2141 /* Found the starting point (redundant check)*/
2142 ism = 0;
2143 while (cnt < ct->nbins && ct->bins[cnt].i <= lbl2 && ism < SM->N_M[0]) {
2144 SUMA_LHv("ct->bins[%d].i=%d <> lbl1+ism=%d\n",
2145 cnt, ct->bins[cnt].i, lbl1+ism);
2146 if (ct->bins[cnt].i == lbl1+ism) {
2147 SM->M[ism][0] = (float)(ct->bins[cnt].r) / 255.0;
2148 SM->M[ism][1] = (float)(ct->bins[cnt].g) / 255.0;
2149 SM->M[ism][2] = (float)(ct->bins[cnt].b) / 255.0;
2150 SM->M[ism][3] = 1.0;
2151 SM->cname[ism] = SUMA_copy_string(ct->bins[cnt].name);
2152 SM->idvec[ism] = ct->bins[cnt].r |
2153 ct->bins[cnt].g << 8 |
2154 ct->bins[cnt].b << 16;
2155 /* that's how annotation files encode a node's id */
2156 SUMA_LHv("FSi %d --> SMi %d\n", ct->bins[cnt].i, ism);
2157 ++cnt;
2158 } else {
2159 SM->M[ism][0] = SM->M[ism][1] = SM->M[ism][2] = SUMA_DUNNO_GRAY;
2160 SM->M[ism][3] = 0.0;
2161 SM->cname[ism] = SUMA_copy_string("undefined");
2162 SM->idvec[ism] = 0;
2163 SUMA_LH("Got gap\n");
2164 }
2165 ++ism;
2166 }
2167 }
2168 #else /* March 1 2010 */
2169 ism = 0;
2170 while (lbl1 <= lbl2) {
2171 HASH_FIND_INT(ct->chd, &(lbl1), hd);
2172 if (hd) {
2173 cnt = hd->colmapindex;
2174 SM->M[ism][0] = (float)(ct->bins[cnt].r) / 255.0;
2175 SM->M[ism][1] = (float)(ct->bins[cnt].g) / 255.0;
2176 SM->M[ism][2] = (float)(ct->bins[cnt].b) / 255.0;
2177 SM->M[ism][3] = 1.0;
2178 SM->cname[ism] = SUMA_copy_string(ct->bins[cnt].name);
2179 if (idISi) {
2180 /* for non-freesurfer maps */
2181 SM->idvec[ism] = ct->bins[cnt].i;
2182 } else {
2183 SM->idvec[ism] = ct->bins[cnt].r |
2184 ct->bins[cnt].g << 8 |
2185 ct->bins[cnt].b << 16;
2186 /* that's how annotation files encode a node's id,
2187 This annotation is OK for surfaces, Not
2188 for FreeSurfer's volumes*/
2189 }
2190 SUMA_LHv("FSi %d --> SMi %d\n", ct->bins[cnt].i, ism);
2191 ++ism;
2192 } else {
2193 SM->M[ism][0] = SM->M[ism][1] = SM->M[ism][2] = SUMA_DUNNO_GRAY;
2194 SM->M[ism][3] = 0.0;
2195 SM->cname[ism] = SUMA_copy_string("undefined");
2196 SM->idvec[ism] = 0;
2197 SUMA_LHv("iLabel %d not found in ct\n", lbl1);
2198 ++ism;
2199 }
2200 ++lbl1;
2201 }
2202 #endif
2203
2204 SM->M0[0] = SM->M[0][0];
2205 SM->M0[1] = SM->M[0][1];
2206 SM->M0[2] = SM->M[0][2];
2207 SM->M0[3] = SM->M[0][3];
2208
2209 SUMA_RETURN(SM);
2210 }
2211
2212
2213 /*!
2214 \brief
2215 function to read FS's annotation file
2216
2217 \param f_name (char *)
2218 \param ROIout (FILE *)
2219 \param cmapout (FILE *)
2220
2221 - If a colormap is found, it should be added to SUMAg_CF->scm
2222 - Based on code provided by Bruce Fischl
2223 */
SUMA_readFSannot(char * f_name,char * f_ROI,char * f_cmap,char * f_col,int Showct,char * ctfile,int lbl1,int lbl2,SUMA_DSET ** dsetp)2224 SUMA_Boolean SUMA_readFSannot (char *f_name,
2225 char *f_ROI, char *f_cmap, char *f_col,
2226 int Showct, char *ctfile,
2227 int lbl1, int lbl2,
2228 SUMA_DSET **dsetp)
2229 {
2230 static char FuncName[]={"SUMA_readFSannot"};
2231 int n_labels = -1, ex, ni, chnk, j, annot, r, g, b, imap;
2232 int tg, len, nbins, i;
2233 FILE *fl=NULL;
2234 FILE *fr=NULL;
2235 FILE *fc=NULL;
2236 FILE *fo=NULL;
2237 SUMA_FS_COLORTABLE *ct=NULL;
2238 SUMA_COLOR_MAP_HASH_DATUM *hd=NULL;
2239 SUMA_FS_COLORTABLE_ENTRY *cte;
2240 SUMA_Boolean bs = NOPE;
2241 int *rv=NULL, *gv=NULL, *bv=NULL, *anv=NULL, *niv=NULL;
2242 SUMA_COLOR_MAP *CM = NULL;
2243 SUMA_DSET *dset=NULL;
2244 NI_group *ngrcmp=NULL;
2245 SUMA_Boolean LocalHead = NOPE;
2246
2247 SUMA_ENTRY;
2248
2249 if (dsetp) *dsetp=NULL;
2250
2251 /* check for existence */
2252 if (!SUMA_filexists(f_name)) {
2253 SUMA_S_Errv("File %s does not exist or cannot be read.\n",
2254 f_name);
2255 SUMA_RETURN (NOPE);
2256 }else if (LocalHead) {
2257 fprintf( SUMA_STDERR,
2258 "%s: File %s exists and will be read.\n",
2259 FuncName, f_name);
2260 }
2261
2262 if (ctfile) {
2263 if (!(SUMA_readFScolorLUT(ctfile, &ct))) {
2264 SUMA_S_Errv("Failed to read FS color table %s\n", ctfile);
2265 SUMA_RETURN (NOPE);
2266 }
2267 }
2268
2269 if (f_ROI) { /* check for existence of ROI file */
2270 if (SUMA_filexists(f_ROI) && !THD_ok_overwrite()) {
2271 fprintf( SUMA_STDERR,
2272 "Error %s: File %s exists, will not overwrite.\n",
2273 FuncName, f_ROI);
2274 SUMA_RETURN (NOPE);
2275 }else {
2276 fr = fopen(f_ROI, "w");
2277 if (!fr) {
2278 SUMA_SL_Err("Failed to open file for writing.\n");
2279 SUMA_RETURN(NOPE);
2280 }
2281 }
2282 }
2283
2284 if (f_cmap) { /* check for existence of ROI file */
2285 if (SUMA_filexists(f_cmap) && !THD_ok_overwrite()) {
2286 fprintf( SUMA_STDERR,
2287 "Error %s: File %s exists, will not overwrite.\n",
2288 FuncName, f_cmap);
2289 SUMA_RETURN (NOPE);
2290 }else {
2291 fc = fopen(f_cmap, "w");
2292 if (!fc) {
2293 SUMA_SL_Err("Failed to open file for writing.\n");
2294 SUMA_RETURN(NOPE);
2295 }
2296 }
2297 }
2298
2299 if (f_col) { /* check for existence of ROI file */
2300 if (SUMA_filexists(f_col) && !THD_ok_overwrite()) {
2301 fprintf(SUMA_STDERR,
2302 "Error %s: File %s exists, will not overwrite.\n",
2303 FuncName, f_col);
2304 SUMA_RETURN (NOPE);
2305 }else {
2306 fo = fopen(f_col, "w");
2307 if (!fo) {
2308 SUMA_SL_Err("Failed to open file for writing.\n");
2309 SUMA_RETURN(NOPE);
2310 }
2311 }
2312 }
2313
2314 bs = NOPE;
2315 fl = fopen(f_name, "r");
2316 if (!fl) {
2317 SUMA_SL_Err("Failed to open file for reading.\n");
2318 SUMA_RETURN(NOPE);
2319 }
2320 chnk = sizeof(int);
2321 ex = fread (&n_labels, chnk, 1, fl);
2322 if (n_labels < 0 || n_labels > 500000) { /* looks like swapping is needed */
2323 if (LocalHead) {
2324 SUMA_SL_Warn("Byte swapping binary data.");
2325 }
2326 SUMA_swap_4( &n_labels ) ;
2327 bs = YUP;
2328 }
2329
2330
2331 niv = (int *) SUMA_malloc(sizeof(int)*n_labels);
2332 rv = (int *) SUMA_malloc(sizeof(int)*n_labels);
2333 gv = (int *) SUMA_malloc(sizeof(int)*n_labels);
2334 bv = (int *) SUMA_malloc(sizeof(int)*n_labels);
2335 anv = (int *) SUMA_malloc(sizeof(int)*n_labels);
2336 if (!rv || !gv || !bv || !anv || !niv) {
2337 SUMA_SL_Crit("Failed to allocate.");
2338 SUMA_RETURN(NOPE);
2339 }
2340
2341 if (ex != EOF) {
2342 if (LocalHead)
2343 fprintf( SUMA_STDERR,
2344 "%s:\n Expecting to read %d labels\n",
2345 FuncName, n_labels);
2346 }
2347 SUMA_LH("Reading annotations...");
2348 for (j=0; j<n_labels; ++j) {
2349 SUMA_READ_INT (&ni, bs, fl, ex);
2350 if (ni < 0 || ni >= n_labels) {
2351 fprintf(SUMA_STDERR,
2352 "Error %s:\n"
2353 " Read a node index of %d. Bad because < 0 or > %d\n",
2354 FuncName, ni, n_labels);
2355 SUMA_RETURN(NOPE);
2356 }
2357 SUMA_READ_INT (&annot, bs, fl, ex);
2358 niv[j] = ni;
2359 anv[j] = annot;
2360 rv[j] = annot & 0x0000ff;
2361 gv[j] = (annot >> 8) & 0x0000ff;
2362 bv[j] = (annot >> 16) & 0x0000ff;
2363 if (LocalHead && (LocalHead > 1 || j < 5 || j > n_labels - 5)) {
2364 int recon = (rv[j]) |
2365 (gv[j] << 8) |
2366 (bv[j] << 16);
2367 fprintf (SUMA_STDERR, "annot[%d]: %d = %d %d %d --- %d\n",
2368 ni, anv[j], rv[j], gv[j], bv[j], recon);
2369 }
2370
2371 }
2372
2373 if (!ct) {
2374 SUMA_LH("Searching for colortables");
2375 while (!feof(fl)) {
2376 SUMA_READ_INT (&tg, bs, fl, ex);
2377 SUMA_LHv("tg = %d (%d is FS_ANNOT_TAG_COLORTABLE)\n",
2378 tg, SUMA_FS_ANNOT_TAG_COLORTABLE);
2379 if (tg == SUMA_FS_ANNOT_TAG_COLORTABLE) {
2380 if (ct) {
2381 SUMA_S_Warn("Already have a color table\n"
2382 "ignoring second one in file.\n"
2383 "If you want it, post a message to\n"
2384 "AFNI's message board\n");
2385 break;
2386 }
2387 SUMA_READ_INT (&nbins, bs, fl, ex);
2388 SUMA_READ_INT (&len, bs, fl, ex);
2389 SUMA_LHv("Found color table (nbins %d, len %d)\n", nbins, len);
2390 if ( nbins <= 0 || nbins > 500 ||
2391 len <= 0 || len > 500 ) { /* upper limit is just a guess ... */
2392 SUMA_S_Warnv("bad nbins (%d) or len (%d).\n"
2393 "Color table will not be created, \n"
2394 "and annotation values will be used instead \n"
2395 "of indices into a colormap.\n\n"
2396 "You can use -FScmap option to specify\n"
2397 "a colormap in an external file.\n\n",
2398 nbins, len);
2399 break;
2400 }
2401 ct = SUMA_CreateFS_ColorTable(nbins, len, NULL);
2402 fread(ct->fname, sizeof(char), len, fl) ;
2403 SUMA_LHv("coltable fname: %s\n", ct->fname);
2404 for (i = 0 ; i < nbins ; i++)
2405 {
2406 cte = &ct->bins[i] ; cte->i = i;
2407 SUMA_READ_INT (&len, bs, fl, ex);
2408 if (len < 0 || len > SUMA_FS_STRLEN ) {
2409 SUMA_SL_Err("Too long a name");
2410 SUMA_RETURN(NOPE);
2411 }
2412 fread(cte->name, sizeof(char), len, fl) ;
2413 SUMA_READ_INT (&(cte->r), bs, fl, ex);
2414 SUMA_READ_INT (&(cte->g), bs, fl, ex);
2415 SUMA_READ_INT (&(cte->b), bs, fl, ex);
2416 SUMA_READ_INT (&(cte->flag), bs, fl, ex);
2417 SUMA_LHv("name: %s, r,g,b,f = %d %d %d %d\n",
2418 cte->name, cte->r, cte->g, cte->b, cte->flag);
2419 }
2420
2421 }
2422 /* reset flag values, on mac for some reason feof seems
2423 to fail even if on linux say feof(fl) would return true
2424 at that point. When that happens,
2425 tg keeps its last value and a new colortable of junk gets built
2426 */
2427 tg = -1; nbins = -1;
2428 }
2429 lbl1=-1; lbl2=-1; /* use whole colormap */
2430 /* Hash the colormap */
2431 /* check for ct 29 Oct 2018 [rickr] */
2432 if( ct ) {
2433 for (i=0; i<ct->nbins; ++i) {
2434 HASH_FIND_INT(ct->chd, &(ct->bins[i].i), hd);
2435 if (hd) {
2436 SUMA_S_Errv("iLabel %d already in hash table!\n",
2437 ct->bins[i].i);
2438 } else {
2439 hd = (SUMA_COLOR_MAP_HASH_DATUM *)
2440 SUMA_calloc(1, sizeof(SUMA_COLOR_MAP_HASH_DATUM));
2441 hd->id = ct->bins[i].i;
2442 hd->colmapindex = i;
2443
2444 HASH_ADD_INT(ct->chd, id, hd);
2445 }
2446 }
2447 }
2448
2449 } else {
2450 SUMA_LHv("Using colortable from %s between labels %d and %d\n",
2451 ctfile, lbl1, lbl2);
2452 }
2453
2454 if (fc && ct) { /* write the colormap to a file */
2455 fprintf(fc, "#Cmap from %s.\n"
2456 "#Comment line content:\n"
2457 " #name (ilabel) (r g b) (surf annotation)\n"
2458 "#Data line content:\n"
2459 " #bin r g b flag \n",
2460 ctfile ? ctfile:"annotation file");
2461 for (i=0; i<ct->nbins; ++i) {
2462 fprintf(fc, "#%s (%d) (%d %d %d) (%d)\n", ct->bins[i].name,
2463 ct->bins[i].i,
2464 ct->bins[i].r,ct->bins[i].g,ct->bins[i].b,
2465 (ct->bins[i].r) |
2466 (ct->bins[i].g << 8) |
2467 (ct->bins[i].b << 16) );
2468 fprintf(fc, "%d %f %f %f %d\n",
2469 i, (float)ct->bins[i].r/255.0, (float)ct->bins[i].g/255.0,
2470 (float)ct->bins[i].b/255.0, ct->bins[i].flag );
2471 }
2472 }
2473
2474 if (fr) { /* write the annotation, ROI style */
2475 if (ct) {
2476 if (ctfile) {
2477 fprintf(fr, "#NodeID ROI(indexed into labels cmap %s) r g b \n",
2478 ctfile);
2479 } else {
2480 fprintf(fr, "#NodeID ROI(indexed into labels cmap) r g b \n");
2481 }
2482 for (i=0; i < n_labels; ++i) {
2483 j = 0;
2484 imap = -1;
2485 while (j < ct->nbins && imap < 0) {
2486 if ( SUMA_ABS(ct->bins[j].r - rv[i]) < SUMA_EPSILON &&
2487 SUMA_ABS(ct->bins[j].b - bv[i]) < SUMA_EPSILON &&
2488 SUMA_ABS(ct->bins[j].g - gv[i]) < SUMA_EPSILON ) {
2489 imap = j;
2490 }
2491 ++j;
2492 }
2493 if (imap < 0) {
2494 static int iwarn;
2495 if (!iwarn) {
2496 SUMA_SL_Warn("Node Color (label) not found in cmap.\n"
2497 "Marking with annotation value.\n"
2498 "Further occurences will not be reported.");
2499 ++iwarn;
2500 }
2501 imap = anv[i];
2502 }
2503 fprintf(fr, "%d %d %f %f %f \n",
2504 niv[i], imap,
2505 (float)rv[i]/255.0,
2506 (float)gv[i]/255.0, (float)bv[i]/255.0);
2507 }
2508 } else { /* no color map */
2509 fprintf(fr, "#NodeID Annotation r g b \n");
2510 for (i=0; i < n_labels; ++i) {
2511 fprintf(fr, "%d %d %f %f %f \n", niv[i], anv[i],
2512 (float)rv[i]/255.0,
2513 (float)gv[i]/255.0, (float)bv[i]/255.0);
2514 }
2515 }
2516 }
2517
2518 if (fo) { /* write the annotation, ROI style */
2519 if (ct) {
2520 fprintf(fo, "#NodeID r g b \n");
2521 for (i=0; i < n_labels; ++i) {
2522 fprintf(fo, "%d %f %f %f \n",
2523 niv[i], (float)rv[i]/255.0,
2524 (float)gv[i]/255.0, (float)bv[i]/255.0);
2525 }
2526 } else { /* no color map */
2527 fprintf(fo, "#NodeID r g b \n");
2528 for (i=0; i < n_labels; ++i) {
2529 /* fprintf(fo, "%d %d \n", niv[i], anv[i]); */
2530 fprintf(fo, "%d %f %f %f \n",
2531 niv[i], (float)rv[i]/255.0,
2532 (float)gv[i]/255.0, (float)bv[i]/255.0);
2533 }
2534 }
2535 }
2536
2537 if (dsetp && ct && niv && anv) {/* package the results for SUMA */
2538 /* 1- Transform ct to a SUMA_COLOR_MAP
2539 The cname field in SUMA_COLOR_MAP was created for that purpose.
2540 First allocate for cmap then use SUMA_copy_string to fill it with
2541 the names */
2542 SUMA_LH("Changing to SUMA format");
2543 CM = SUMA_FScolutToColorMap_eng(ct, lbl1, lbl2, 0, 0);
2544
2545 /* 2- Create a vector from the labels and create a data set from it */
2546 dset = SUMA_CreateDsetPointer(FuncName, SUMA_NODE_LABEL,
2547 NULL, NULL, n_labels);
2548 SUMA_AddDsetNelCol ( dset, "node index", SUMA_NODE_INDEX,
2549 (void *)niv, NULL, 1);
2550 SUMA_AddDsetNelCol ( dset, "node label", SUMA_NODE_ILABEL,
2551 (void *)anv, NULL, 1);
2552
2553 if (!SUMA_SetUniqueValsAttr(dset, 0, 1)) {
2554 SUMA_S_Err("Failed to add unique vals attribute");
2555 SUMA_RETURN(NOPE);
2556 }
2557
2558 /* Now stick in the colormap in dset*/
2559 ngrcmp = SUMA_CmapToNICmap(CM);
2560 NI_add_to_group(dset->ngr, ngrcmp);
2561
2562 /* write it out for testing*/
2563 if (LocalHead)
2564 SUMA_WriteDset_eng(FuncName, dset, SUMA_ASCII_NIML, 1, 1, 1);
2565
2566 /* freedom */
2567 SUMA_Free_ColorMap(CM); CM = NULL;
2568 *dsetp = dset;
2569 }
2570
2571 if (Showct) {
2572 if (ct) {
2573 SUMA_Show_FS_ColorTable(ct, NULL);
2574 ct = SUMA_FreeFS_ColorTable(ct);
2575 }else {
2576 fprintf(SUMA_STDOUT,"No color table found.\n");
2577 }
2578 }
2579
2580
2581 if (fl) fclose (fl); fl = NULL;
2582 if (fr) fclose (fr); fr = NULL;
2583 if (fc) fclose (fc); fc = NULL;
2584 if (fo) fclose (fo); fo = NULL;
2585
2586 if (niv) SUMA_free(niv); niv = NULL;
2587 if (rv) SUMA_free(rv); rv = NULL;
2588 if (gv) SUMA_free(gv); gv = NULL;
2589 if (bv) SUMA_free(bv); bv = NULL;
2590 if (anv) SUMA_free(anv); anv = NULL;
2591
2592 SUMA_RETURN(YUP);
2593 }
2594
2595
2596 /*!
2597
2598 \brief v = SUMA_readFScurv (curvname, nrows, ncols, rowmajor, SkipCoords);
2599 Not terribly useful of a function because it is practically a .1D
2600 format!
2601 \param curvname (char *) name of ascii curvature file
2602 \param nrows (int *) will contain the number of elements in file
2603 \param ncols (int *) will contain the number of columns in file.
2604 This is 5 for curvature files if SkipCoords is not set
2605 (node index, x, y, z, data)
2606 2 if SkipCoords
2607 (node index, data)
2608 \param rowmajor (SUMA_Boolean) if (YUP) return results in row major order, else column major
2609 \param SkipCoords (SUMA_Boolean) if (YUP) reads only node index and data value (1st and last column
2610 of curvature files (skips the intermediary coordinates)
2611 \return v (float *) vector containing curvature file data
2612
2613 */
2614
SUMA_readFScurv(char * f_name,int * nrows,int * ncols,SUMA_Boolean rowmajor,SUMA_Boolean SkipCoords)2615 float * SUMA_readFScurv (char *f_name, int *nrows, int *ncols,
2616 SUMA_Boolean rowmajor, SUMA_Boolean SkipCoords)
2617 {
2618 static char FuncName[]={"SUMA_readFScurv"};
2619 MRI_IMAGE *im = NULL;
2620 float *v = NULL, jnk, *far;
2621 int cnt, ex, id, i, ncol, nvec;
2622 char c, comment[SUMA_MAX_STRING_LENGTH];
2623 FILE *fs_file = NULL;
2624 SUMA_Boolean LocalHead = NOPE;
2625
2626 SUMA_ENTRY;
2627
2628 /* check for existence */
2629 if (!SUMA_filexists(f_name)) {
2630 SUMA_S_Errv("File %s does not exist or cannot be read.\n", f_name);
2631 SUMA_RETURN (NULL);
2632 }else if (LocalHead) {
2633 fprintf(SUMA_STDERR,"%s: File %s exists and will be read.\n",
2634 FuncName, f_name);
2635 }
2636
2637 if (SkipCoords) *ncols = 2;
2638 else *ncols = 5; /* constant */
2639
2640 if (*ncols !=2 && *ncols != 5) {
2641 SUMA_SL_Crit("ncols must be either 2 or 5");
2642 SUMA_RETURN(NULL);
2643 }
2644
2645
2646 /* now load the input data */
2647 SUMA_LH("Reading file...");
2648 im = mri_read_1D (f_name);
2649
2650 if (!im) {
2651 SUMA_SL_Err("Failed to read 1D file");
2652 SUMA_RETURN(NULL);
2653 }
2654
2655 far = MRI_FLOAT_PTR(im);
2656 nvec = im->nx;
2657 ncol = im->ny;
2658 /* data in column major order at this point */
2659
2660 if (!nvec) {
2661 SUMA_SL_Err("Empty file");
2662 SUMA_RETURN(NULL);
2663 }
2664
2665 if (ncol != 5) {
2666 SUMA_SL_Err("Must have 5 columns in data file.");
2667 mri_free(im); im = NULL; /* done with that baby */
2668 SUMA_RETURN(NULL);
2669 }
2670
2671 *nrows = nvec;
2672
2673 SUMA_LHv("Allocating for data (%dx%d) \n", *nrows, *ncols);
2674
2675 v = (float *) SUMA_calloc(*nrows * *ncols, sizeof(float));
2676
2677 if (!v) {
2678 SUMA_SL_Crit("Failed to allocate for v");
2679 SUMA_RETURN(v);
2680 }
2681
2682 if (LocalHead) fprintf (SUMA_STDOUT, "%s: Parsing file...\n", FuncName);
2683
2684 if (rowmajor) {
2685 if (*ncols == 5) {
2686 SUMA_LH("RowMajor, All Coords");
2687 for (i=0; i< *nrows; ++i) {
2688 id = *ncols*i;
2689 v[id] = far[i];
2690 v[id+1] = far[i+*nrows];
2691 v[id+2] = far[i+2 * *nrows];
2692 v[id+3] = far[i+3 * *nrows];
2693 v[id+4] = far[i+4 * *nrows];
2694 }
2695 } else {
2696 SUMA_LH("RowMajor, Skipping Coords");
2697 for (i=0; i< *nrows; ++i) {
2698 id = *ncols*i;
2699 v[id] = far[i];
2700 v[id+1] = far[i+4 * *nrows];
2701 }
2702 }
2703 } else {
2704 if (*ncols == 5) {
2705 SUMA_LH("ColMajor, All Coords");
2706 for (i=0; i<*ncols * *nrows; ++i) v[i] = far[i];
2707 } else if (*ncols == 2) {
2708 SUMA_LH("ColMajor, Skipping Coords");
2709 for (i=0; i<*nrows; ++i) v[i] = far[i];
2710 for (i=*nrows; i< 2 * *nrows; ++i) v[i] = far[i+3 * *nrows];
2711 }
2712 }
2713 mri_free(im); im = NULL; far = NULL;
2714
2715 SUMA_RETURN(v);
2716 }
2717
2718
2719 /* just call engine with debug set 20 Oct 2003 [rickr] */
SUMA_FreeSurfer_Read(char * f_name,SUMA_FreeSurfer_struct * FS)2720 SUMA_Boolean SUMA_FreeSurfer_Read (char * f_name, SUMA_FreeSurfer_struct *FS)
2721 {/* SUMA_FreeSurfer_Read */
2722 static char FuncName[]={"SUMA_FreeSurfer_Read"};
2723
2724 SUMA_ENTRY;
2725
2726 SUMA_RETURN(SUMA_FreeSurfer_Read_eng(f_name, FS, 1));
2727 }/* SUMA_FreeSurfer_Read */
2728
2729
2730 /* - changed function name to XXX_eng 20 Oct 2003 [rickr]
2731 * - added debug parameter
2732 * - print non-error info only if debug
2733 */
2734 /*!**
2735 Usage :
2736 Ret = SUMA_FreeSurfer_Read_eng (surfname, FreeSurfer, debug)
2737
2738 For a full surface definition, it is assumed that the first line can be a comment.
2739 The second line contains the number of nodes followed by the number of FaceSets
2740 The NodeList follows with X Y Z 0
2741 The FaceSetList follows with i1 i2 i3 0
2742
2743
2744 Input paramters :
2745 \param surfname (char *) name of surface (or patch) file output by:
2746 mris_convert <surface_name> <surface_name.asc>
2747 or if it is a patch by
2748 mris_convert -p <patch_name> <patch_name.asc>
2749
2750 \param FreeSurfer (SUMA_FreeSurfer_struct *) pointer to the FreeSurfer structure
2751
2752 \param debug (int) flag specifying whether to output non-error info
2753
2754 Returns :
2755 \return (SUMA_Boolean) YUP/NOPE for success/failure
2756
2757 Support :
2758 \sa LoadFreeSurf.m
2759 \sa
2760
2761 Side effects :
2762
2763
2764
2765 ***/
SUMA_FreeSurfer_Read_eng(char * f_name,SUMA_FreeSurfer_struct * FS,int debug)2766 SUMA_Boolean SUMA_FreeSurfer_Read_eng (char * f_name, SUMA_FreeSurfer_struct *FS, int debug)
2767 {/*SUMA_FreeSurfer_Read_eng*/
2768 static char FuncName[]={"SUMA_FreeSurfer_Read_eng"};
2769 char stmp[50];
2770 FILE *fs_file;
2771 int ex, cnt, jnki, amax[3], maxamax, maxamax2, id, ND, id2, NP, ip, *NodeId;
2772 float jnkf, *NodeList;
2773 char c;
2774 SUMA_Boolean LocalHead = NOPE;
2775
2776 SUMA_ENTRY;
2777
2778 /* check for existence */
2779 if (!SUMA_filexists(f_name)) {
2780 fprintf(SUMA_STDERR,"Error %s: File %s does not exist or cannot be read.\n", FuncName, f_name);
2781 SUMA_RETURN (NOPE);
2782 }else if ( debug > 1) {
2783 fprintf(SUMA_STDERR,"%s: File %s exists and will be read.\n", FuncName, f_name);
2784 }
2785
2786
2787 /* start reading */
2788 fs_file = fopen (f_name,"r");
2789 if (fs_file == NULL)
2790 {
2791 SUMA_error_message (FuncName,"Could not open input file ",0);
2792 SUMA_RETURN (NOPE);
2793 }
2794
2795 sprintf(FS->name, "%s", f_name);
2796
2797 /* read first character and check if it is a comment */
2798 ex = fscanf (fs_file,"%c",&c);
2799 if (LocalHead) fprintf (SUMA_STDOUT, "%s: --->%c<---\n", FuncName, c);
2800 if (c == '#') {
2801 if (LocalHead) fprintf (SUMA_STDOUT, "%s: Found comment\n", FuncName);
2802
2803 /*skip till next line */
2804 cnt = 0;
2805 FS->comment[cnt] = '#';
2806 while (ex != EOF && c != '\n') {
2807 ex = fscanf (fs_file,"%c",&c);
2808 if (cnt < SUMA_MAX_STRING_LENGTH-2) {
2809 ++cnt;
2810 FS->comment[cnt] = c;
2811 } else {
2812 fprintf(SUMA_STDERR,"Error %s: Too long a comment in FS file, increase SUMA_FS_MAX_COMMENT_LENGTH\n", FuncName);
2813 SUMA_RETURN (NOPE);
2814 }
2815 }
2816 ++cnt;
2817 FS->comment[cnt] = '\0';
2818 if (LocalHead) fprintf (SUMA_STDOUT, "%s: Comment:-->%s<--", FuncName, FS->comment);
2819 fprintf(stdout, "Comment: %s\n", FS->comment);
2820 }
2821
2822 /* find out if surface is patch */
2823 sprintf(stmp,"patch");
2824 if (SUMA_iswordin (FS->comment, stmp) == 1) {
2825 FS->isPatch = YUP;
2826 SUMA_LH("is patch");
2827 }
2828 else {
2829 FS->isPatch = NOPE;
2830 SUMA_LH("ain't patch");
2831 }
2832
2833 /* read in the number of nodes and the number of facesets */
2834 ex = fscanf(fs_file, "%d %d", &(FS->N_Node), &(FS->N_FaceSet));
2835
2836 if (FS->N_Node <= 0 || FS->N_FaceSet <= 0) {
2837 SUMA_SL_Crit("Trouble parsing FreeSurfer file.\nNull or negative number of nodes &/| facesets.\n");
2838 SUMA_RETURN(NOPE);
2839 }
2840
2841 if (LocalHead) fprintf (SUMA_STDOUT, "%s: Allocating for NodeList (%dx3) and FaceSetList(%dx3)\n", FuncName, FS->N_Node, FS->N_FaceSet);
2842
2843 /* allocate space for NodeList and FaceSetList */
2844 FS->NodeList = (float *)SUMA_calloc(FS->N_Node * 3, sizeof(float));
2845 FS->FaceSetList = (int *)SUMA_calloc(FS->N_FaceSet * 3, sizeof(int));
2846 FS->NodeId = (int *)SUMA_calloc(FS->N_Node, sizeof(int));
2847 if (FS->NodeList == NULL || FS->FaceSetList == NULL || FS->NodeId == NULL) {
2848 fprintf(SUMA_STDERR,"Error %s: Could not allocate for FS->NodeList &/| FS->FaceSetList &/| FS->NodeId\n", FuncName);
2849 SUMA_RETURN (NOPE);
2850 }
2851 if (FS->isPatch) {
2852 FS->FaceSetIndexInParent = (int *)SUMA_calloc(FS->N_FaceSet, sizeof(int));
2853 if (FS->FaceSetIndexInParent == NULL) {
2854 fprintf(SUMA_STDERR,"Error %s: Could not allocate for FS->FaceSetIndexInParent\n", FuncName);
2855 SUMA_RETURN (NOPE);
2856 }
2857 } else {
2858 FS->FaceSetIndexInParent = NULL;
2859 }
2860
2861 if (!FS->isPatch) { // NOT patch
2862 if (LocalHead) fprintf (SUMA_STDOUT, "%s: Reading full surface...\n", FuncName);
2863 /* read in the nodes */
2864 cnt = 0;
2865 while (ex != EOF && cnt < FS->N_Node) {
2866 FS->NodeId[cnt] = cnt;
2867 id = 3 * cnt;
2868 ex = fscanf(fs_file, "%f %f %f %f", &(FS->NodeList[id]), &(FS->NodeList[id+1]),&(FS->NodeList[id+2]), &jnkf);
2869 ++cnt;
2870 }
2871 if (cnt != FS->N_Node) {
2872 fprintf(SUMA_STDERR,"Error %s: File %s; Expected %d nodes, %d read.\n", FuncName, f_name, FS->N_Node, cnt);
2873 SUMA_RETURN (NOPE);
2874 }
2875
2876 /* read in the facesets */
2877 cnt = 0;
2878 while (ex != EOF && cnt < FS->N_FaceSet) {
2879 ip = 3 * cnt;
2880 ex = fscanf(fs_file, "%d %d %d %d", &(FS->FaceSetList[ip]), &(FS->FaceSetList[ip+1]),&(FS->FaceSetList[ip+2]), &jnki);
2881 ++cnt;
2882 }
2883
2884 if (cnt != FS->N_FaceSet) {
2885 fprintf(SUMA_STDERR,"Error %s: File %s; expected %d FaceSets, %d read.\n", FuncName, f_name, FS->N_FaceSet, cnt);
2886 SUMA_RETURN (NOPE);
2887 }
2888 } /* read a full surface */
2889 else { /* that's a patch */
2890 #if 0 /* old way, simple parsing ... */
2891 if (LocalHead) fprintf (SUMA_STDOUT, "%s: Reading patch olde way...\n", FuncName);
2892 /* Node IDs are a reference to those in the parent surface */
2893 cnt = 0;
2894 while (ex != EOF && cnt < FS->N_Node) {
2895 ex = fscanf(fs_file, "%d", &(FS->NodeId[cnt]));
2896 id = 3 * cnt;
2897 /* fprintf (SUMA_STDERR, "FS->NodeId[cnt] = %d: cnt = %d, id=%d, id1 = %d, id2 = %d\n", FS->NodeId[cnt], cnt, id, id+1, id+2); */
2898 ex = fscanf(fs_file, "%f %f %f", &(FS->NodeList[id]),&(FS->NodeList[id+1]),&(FS->NodeList[id+2]));
2899 ++cnt;
2900 }
2901 if (cnt != FS->N_Node) {
2902 fprintf(SUMA_STDERR,"Error %s: Expected %d nodes, %d read.\n", FuncName, FS->N_Node, cnt);
2903 SUMA_RETURN (NOPE);
2904 }
2905
2906 if (LocalHead) fprintf (SUMA_STDOUT, "%s: Reading FaceSets...\n", FuncName);
2907 /* read in the facesets */
2908 cnt = 0;
2909 while (ex != EOF && cnt < FS->N_FaceSet) {
2910 ex = fscanf(fs_file, "%d", &(FS->FaceSetIndexInParent[cnt]));
2911 ip = 3 * cnt;
2912 ex = fscanf(fs_file, "%d %d %d", &(FS->FaceSetList[ip]), &(FS->FaceSetList[ip+1]),&(FS->FaceSetList[ip+2]));
2913 ++cnt;
2914 }
2915 if (cnt != FS->N_FaceSet) {
2916 fprintf(SUMA_STDERR,"Error %s: Expected %d FaceSets, %d read.\n", FuncName, FS->N_FaceSet, cnt);
2917 SUMA_RETURN (NOPE);
2918 }
2919 #else
2920 {
2921 char *fl=NULL, *eop=NULL, *florig=NULL;
2922 int ans, pnodes, ptri, Found, nchar;
2923 double dbuf;
2924
2925 if (LocalHead) fprintf (SUMA_STDOUT, "%s: Reading patch new way...\n", FuncName);
2926 /* suck in the bastard, perhaps this should be done from the start, maybe in the future */
2927 fl = florig = SUMA_file_suck(f_name, &nchar);
2928 if (!nchar || !fl) {
2929 SUMA_SL_Err("Failed to read patch file.");
2930 SUMA_RETURN(NOPE);
2931 }
2932 /* skip comment, if any */
2933 SUMA_IS_COMMENT_LINE(fl, NULL, '#', ans);
2934 if (ans) {
2935 SUMA_LH("Skipping comment...");
2936 SUMA_SKIP_LINE(fl, NULL);
2937 }else {
2938 SUMA_SL_Err("Expected comment line....");
2939 }
2940 /* read in first two nums */
2941 SUMA_ADVANCE_PAST_NUM(fl, dbuf, Found); pnodes = (int)dbuf;
2942 SUMA_ADVANCE_PAST_NUM(fl, dbuf, Found); ptri = (int)dbuf;
2943
2944 /* Node IDs are a reference to those in the parent surface */
2945 Found = 1;
2946 cnt = 0;
2947 while (Found && cnt < FS->N_Node) {
2948 eop = fl+50; /* don't you dare use (fl+50) instead of eop below!, else you will serch till the end all the time!
2949 Macro Danger! */
2950 SUMA_ADVANCE_PAST(fl, eop,"vno=",Found,0); /* The new patch format ... */
2951 SUMA_ADVANCE_PAST_NUM(fl, dbuf, Found); FS->NodeId[cnt] = (int)dbuf;
2952 id = 3 * cnt;
2953 /* fprintf (SUMA_STDERR, "FS->NodeId[cnt] = %d: cnt = %d, id=%d, id1 = %d, id2 = %d\n", FS->NodeId[cnt], cnt, id, id+1, id+2); */
2954 SUMA_ADVANCE_PAST_NUM(fl, dbuf, Found); FS->NodeList[id] = (float)dbuf;
2955 SUMA_ADVANCE_PAST_NUM(fl, dbuf, Found); FS->NodeList[id+1] = (float)dbuf;
2956 SUMA_ADVANCE_PAST_NUM(fl, dbuf, Found); FS->NodeList[id+2] = (float)dbuf;
2957 ++cnt;
2958 }
2959 if (cnt != FS->N_Node) {
2960 fprintf(SUMA_STDERR,"Error %s: Expected %d nodes, %d read.\n", FuncName, FS->N_Node, cnt);
2961 SUMA_RETURN (NOPE);
2962 }
2963 if (LocalHead) fprintf (SUMA_STDOUT, "%s: Reading FaceSets...\n", FuncName);
2964 /* read in the facesets */
2965 Found = 1;
2966 cnt = 0;
2967 while (Found && cnt < FS->N_FaceSet) {
2968 SUMA_ADVANCE_PAST_NUM(fl, dbuf, Found); FS->FaceSetIndexInParent[cnt] = (int)dbuf;
2969 ip = 3 * cnt;
2970 SUMA_ADVANCE_PAST_NUM(fl, dbuf, Found); FS->FaceSetList[ip ] = (int)dbuf;
2971 SUMA_ADVANCE_PAST_NUM(fl, dbuf, Found); FS->FaceSetList[ip+1] = (int)dbuf;
2972 SUMA_ADVANCE_PAST_NUM(fl, dbuf, Found); FS->FaceSetList[ip+2] = (int)dbuf;
2973 ++cnt;
2974 }
2975 if (cnt != FS->N_FaceSet) {
2976 fprintf(SUMA_STDERR,"Error %s: Expected %d FaceSets, %d read.\n", FuncName, FS->N_FaceSet, cnt);
2977 SUMA_RETURN (NOPE);
2978 }
2979 SUMA_free(florig); fl = florig = NULL; /* */
2980 }
2981 #endif
2982
2983 /* The FaceSet List which will be read next, uses indices into the NodeList of the parent surface
2984 This means that it expects a NodeList of the size of the NodeList in the parent surface.
2985 One could read the maximum number of nodes in the parent surface and create a NodeList of that size.
2986 However, that would require keeping track of the link between the patch file and the parent file.
2987 Instead, I will search through the FaceSetList for the highest index and allocate a new nodelist to match it*/
2988
2989 SUMA_MAX_VEC(FS->FaceSetList, FS->N_FaceSet * 3, maxamax); ++maxamax;
2990 /* make sure that the node list does not refer to nodes of an index higher than that in NodeId */
2991 SUMA_MAX_VEC(FS->NodeId, FS->N_Node, maxamax2); ++maxamax2;
2992 if (maxamax2 > maxamax) {
2993 fprintf(SUMA_STDERR,"Error %s: Found NodeId in the NodeList larger than Ids found in FaceSetList.\n", FuncName);
2994 SUMA_RETURN (NOPE);
2995 }
2996 if (LocalHead) fprintf (SUMA_STDOUT, "%s: Copying NodeList, allocating for new nodelist %dx3 elements...\n", \
2997 FuncName, maxamax);
2998
2999 NodeList = (float *)SUMA_calloc(maxamax * 3, sizeof(float));
3000 NodeId = (int *)SUMA_calloc (maxamax, sizeof(int));
3001
3002 if (NodeList == NULL || NodeId == NULL)
3003 {
3004 fprintf(SUMA_STDERR,"Error %s: Could not allocate for NodeList or NodeId\n", FuncName);
3005 SUMA_RETURN (NOPE);
3006 }
3007 /*Now copy pertinent nodes into NodeList */
3008
3009 for (cnt=0; cnt< FS->N_Node; ++cnt) {
3010 id = 3*cnt;
3011 id2 = 3*FS->NodeId[cnt];
3012 /* fprintf (SUMA_STDERR, "%s: id = %d id2 = %d\n", FuncName, id, id2); */
3013 NodeList[id2] = FS->NodeList[id];
3014 NodeList[id2+1] = FS->NodeList[id+1];
3015 NodeList[id2+2] = FS->NodeList[id+2];
3016 }
3017
3018 /* this is redundant here, but should be done to match what comes out of a full surface */
3019 for (cnt=0; cnt< maxamax; ++cnt) {
3020 NodeId[cnt] = cnt;
3021 }
3022
3023 /* Now free FS->NodeList & FS->NodeId */
3024 SUMA_free(FS->NodeList);
3025 SUMA_free(FS->NodeId);
3026
3027 /*make FS->NodeList be NodeList */
3028 FS->NodeList = NodeList;
3029 FS->NodeId = NodeId;
3030 FS->N_Node = maxamax;
3031 } /* read a patch */
3032
3033 fclose (fs_file);
3034 SUMA_RETURN (YUP);
3035
3036 }/* SUMA_FreeSurfer_Read_eng*/
3037
SUMA_FreeSurfer_WritePatch(char * fileNm,SUMA_SurfaceObject * SO,char * firstLine,SUMA_SurfaceObject * SO_parent)3038 SUMA_Boolean SUMA_FreeSurfer_WritePatch (char *fileNm, SUMA_SurfaceObject *SO, char *firstLine, SUMA_SurfaceObject *SO_parent)
3039 {
3040 static char FuncName[]={"SUMA_FreeSurfer_WritePatch"};
3041 int cnt, i, iface;
3042 int *FaceSetIndexInParent=NULL;
3043 byte *isInPatch=NULL;
3044 FILE *fout=NULL;
3045
3046 SUMA_ENTRY;
3047
3048 if (!fileNm || !SO || !SO_parent || !SO_parent->EL) {
3049 SUMA_SL_Err("NULL input params");
3050 SUMA_RETURN(NOPE);
3051 }
3052
3053 if (!THD_ok_overwrite() && SUMA_filexists(fileNm)) {
3054 SUMA_SL_Err("Output file exists, will not overwrite");
3055 SUMA_RETURN(NOPE);
3056 }
3057
3058 fout = fopen(fileNm,"w");
3059 if (!fout) {
3060 SUMA_SL_Err("Failed to open file for writing.\nCheck permissions.");
3061 SUMA_RETURN(NOPE);
3062 }
3063
3064 if (firstLine) {
3065 fprintf(fout, "%s\n", firstLine);
3066 } else {
3067 if (!SO->Label && !(SO->Label = SUMA_SurfaceFileName (SO, NOPE))) {
3068 SO->Label = SUMA_copy_string("Ein_Lousy_Label");
3069 }
3070 fprintf(fout, "#!ascii version of patch %s\n", SO->Label);
3071 }
3072
3073 /* which nodes are in this patch ? */
3074 isInPatch = SUMA_MaskOfNodesInPatch(SO, &cnt);
3075 if (!isInPatch) {
3076 SUMA_SL_Crit("Failed in SUMA_MaskOfNodesInPatch");
3077 SUMA_RETURN(NOPE);
3078 }
3079
3080 /* number of nodes and number of triangles in mesh */
3081 fprintf(fout, "%d %d\n", cnt, SO->N_FaceSet);
3082 /* write the node coordinates */
3083 for (i=0; i < SO->N_Node; ++i) {
3084 if (isInPatch[i]) {
3085 fprintf(fout, "%d\n%f\t%f\t%f\n", i,
3086 SO->NodeList[3*i], SO->NodeList[3*i+1], SO->NodeList[3*i+2]);
3087 }
3088 }
3089 for (i=0; i < SO->N_FaceSet; ++i) {
3090 iface = SUMA_whichTri (SO_parent->EL, SO->FaceSetList[3*i],
3091 SO->FaceSetList[3*i+1], SO->FaceSetList[3*i+2], 0, 0);
3092 if (iface < 0) {
3093 SUMA_SL_Warn(
3094 "Parent surface does not contain triangle in patch!\n"
3095 "Triangle skipped.");
3096 } else {
3097 fprintf(fout, "%d\n%d\t%d\t%d\n",
3098 iface, SO->FaceSetList[3*i], SO->FaceSetList[3*i+1],
3099 SO->FaceSetList[3*i+2]);
3100 }
3101 }
3102
3103
3104 SUMA_free(FaceSetIndexInParent); FaceSetIndexInParent = NULL;
3105 SUMA_free(isInPatch); isInPatch = NULL;
3106
3107 fclose(fout);
3108 SUMA_RETURN(YUP);
3109 }
3110 /*!
3111
3112 Thanks for info from Graham Wideman, https://wideman-one.com/gw/brain/fs/surfacefileformats.htm
3113 */
SUMA_FreeSurfer_ReadBin_eng(char * f_name,SUMA_FreeSurfer_struct * FS,int debug)3114 SUMA_Boolean SUMA_FreeSurfer_ReadBin_eng (char * f_name, SUMA_FreeSurfer_struct *FS, int debug)
3115 {/*SUMA_FreeSurfer_ReadBin_eng*/
3116 static char FuncName[]={"SUMA_FreeSurfer_ReadBin_eng"};
3117 char stmp[50];
3118 FILE *fs_file;
3119 int ex, End, rmax, chnk, cnt, i, amax[3], maxamax, maxamax2, id, ND, id2, NP, ip, *NodeId, magic;
3120 float jnkf, *NodeList;
3121 char c;
3122 byte m1, m2, m3;
3123 SUMA_Boolean bs;
3124 SUMA_Boolean LocalHead = NOPE;
3125
3126 SUMA_ENTRY;
3127
3128 if (debug) LocalHead = YUP;
3129
3130 /* check for existence */
3131 if (!SUMA_filexists(f_name)) {
3132 fprintf(SUMA_STDERR,"Error %s: File %s does not exist or cannot be read.\n", FuncName, f_name);
3133 SUMA_RETURN (NOPE);
3134 }else if ( debug > 1) {
3135 fprintf(SUMA_STDERR,"%s: File %s exists and will be read.\n", FuncName, f_name);
3136 }
3137
3138 /* start reading */
3139 fs_file = fopen (f_name,"r");
3140 if (fs_file == NULL)
3141 {
3142 SUMA_SL_Err ("Could not open input file ");
3143 SUMA_RETURN (NOPE);
3144 }
3145
3146 SUMA_WHAT_ENDIAN(End);
3147 if (End == MSB_FIRST) {
3148 SUMA_LH("No swapping needed");
3149 bs = NOPE;
3150 } else {
3151 bs = YUP;
3152 SUMA_LH("Swapping needed");
3153 }
3154
3155 ex = fread (&m1, 1, 1, fs_file);
3156 ex = fread (&m2, 1, 1, fs_file);
3157 ex = fread (&m3, 1, 1, fs_file);
3158 magic = (m1 << 16) + (m2 << 8) + m3 ;
3159 if (magic == (-2 & 0x00ffffff)) {
3160 SUMA_LH("OK tri");
3161 } else {
3162 SUMA_SL_Err("Failed to identify magic number for a triangulated surface.\n");
3163 SUMA_RETURN(NOPE);
3164 }
3165 chnk = sizeof(char);
3166 ex = fread (&c, chnk, 1, fs_file);
3167 rmax = 0;
3168 while (c != '\n' &&rmax < 5000) {
3169 if (LocalHead) fprintf(SUMA_STDERR,"%c",c);
3170 ex = fread (&c, chnk, 1, fs_file);
3171 ++rmax;
3172 }
3173 if (rmax >= 5000) {
3174 SUMA_SL_Err("Unexpected tres tres long comment.");
3175 SUMA_RETURN(NOPE);
3176 }
3177 SUMA_LH("End of comment");
3178 /* read one more to skip second \n */
3179 ex = fread (&c, chnk, 1, fs_file);
3180 if (c != '\n') {
3181 SUMA_SL_Err("Failed to find second newline.");
3182 SUMA_RETURN(NOPE);
3183 }else {
3184 SUMA_LH("Found end of comment");
3185 }
3186
3187 /* read the number of nodes and the number of triangles */
3188 SUMA_READ_INT (&FS->N_Node, bs, fs_file, ex);
3189 if (FS->N_Node < 0 || FS->N_Node > 2000000) {
3190 SUMA_SL_Err("Failed to get number of nodes");
3191 SUMA_RETURN(NOPE);
3192 }else {
3193 if (LocalHead) fprintf(SUMA_STDERR,"%s: Expecting to read %d nodes.\n", FuncName, FS->N_Node);
3194 }
3195
3196 SUMA_READ_INT (&FS->N_FaceSet, bs, fs_file, ex);
3197 if (FS->N_FaceSet < 0 || FS->N_FaceSet > 2000000) {
3198 SUMA_SL_Err("Failed to get number of triangles");
3199 SUMA_RETURN(NOPE);
3200 }else {
3201 if (LocalHead) fprintf(SUMA_STDERR,"%s: Expecting to read %d triangles.\n", FuncName, FS->N_FaceSet);
3202 }
3203
3204 /* allocate */
3205 FS->NodeList = (float *)SUMA_calloc(FS->N_Node * 3, sizeof(float));
3206 FS->FaceSetList = (int *)SUMA_calloc(FS->N_FaceSet * 3, sizeof(int));
3207 if (!FS->NodeList || !FS->FaceSetList) {
3208 SUMA_SL_Err("Failed to allocate");
3209 SUMA_RETURN(NOPE);
3210 }
3211
3212 /*read in the meat */
3213 for (i=0; i<FS->N_Node * 3; ++i) {
3214 SUMA_READ_FLOAT (&(FS->NodeList[i]), bs, fs_file, ex);
3215 if (ex == EOF) {
3216 SUMA_SL_Err("Premature end of file!");
3217 SUMA_free(FS->NodeList); SUMA_free(FS->FaceSetList); FS->NodeList = NULL ; FS->FaceSetList = NULL;
3218 SUMA_RETURN(NOPE);
3219 }
3220 }
3221 for (i=0; i<FS->N_FaceSet * 3; ++i) {
3222 SUMA_READ_INT (&(FS->FaceSetList[i]), bs, fs_file, ex);
3223 if (ex == EOF) {
3224 SUMA_SL_Err("Premature end of file!");
3225 SUMA_free(FS->NodeList); SUMA_free(FS->FaceSetList); FS->NodeList = NULL ; FS->FaceSetList = NULL;
3226 SUMA_RETURN(NOPE);
3227 }
3228 }
3229
3230 fclose(fs_file);
3231 SUMA_LH("Returning");
3232 SUMA_RETURN(YUP);
3233 }
3234 /*!
3235 free memory allocated for FreeSurfer structure
3236 */
SUMA_Free_FreeSurfer(SUMA_FreeSurfer_struct * FS)3237 SUMA_Boolean SUMA_Free_FreeSurfer (SUMA_FreeSurfer_struct *FS)
3238 {
3239 static char FuncName[]={"SUMA_Free_FreeSurfer"};
3240
3241 SUMA_ENTRY;
3242
3243 if (FS->FaceSetList != NULL) SUMA_free(FS->FaceSetList);
3244 if (FS->NodeList != NULL) SUMA_free(FS->NodeList);
3245 if (FS->NodeId != NULL) SUMA_free(FS->NodeId);
3246 if (FS->FaceSetIndexInParent != NULL) SUMA_free(FS->FaceSetIndexInParent);
3247 if (FS != NULL) SUMA_free(FS);
3248 SUMA_RETURN (YUP);
3249 }
3250
3251 /*!
3252 Show elements of FreeSurfer structure
3253 */
SUMA_Show_FreeSurfer(SUMA_FreeSurfer_struct * FS,FILE * Out)3254 void SUMA_Show_FreeSurfer (SUMA_FreeSurfer_struct *FS, FILE *Out)
3255 {
3256 static char FuncName[]={"SUMA_Show_FreeSurfer"};
3257 int ND = 3, id, ip;
3258
3259 SUMA_ENTRY;
3260
3261 if (Out == NULL) Out = SUMA_STDOUT;
3262 if (FS->comment) fprintf (Out, "Comment: %s\n", FS->comment);
3263 else fprintf (Out, "Comment: NULL\n");
3264 fprintf (Out, "N_Node %d\n", FS->N_Node);
3265 if (FS->NodeId) {
3266 fprintf (Out, "First 2 points [id] X Y Z:\n\t[%d] %f %f %f\n\t[%d] %f %f %f\n", \
3267 FS->NodeId[0], FS->NodeList[0], FS->NodeList[1], FS->NodeList[2],
3268 FS->NodeId[1], FS->NodeList[3], FS->NodeList[4], FS->NodeList[5]);
3269 if (FS->N_Node > 2) {
3270 fprintf (Out, "Last 2 points [id] X Y Z:\n\t[%d] %f %f %f\n\t[%d] %f %f %f\n", \
3271 FS->NodeId[FS->N_Node-2], FS->NodeList[3*(FS->N_Node-2)], FS->NodeList[3*(FS->N_Node-2)+1], FS->NodeList[3*(FS->N_Node-2)+2],
3272 FS->NodeId[FS->N_Node-1], FS->NodeList[3*(FS->N_Node-1)], FS->NodeList[3*(FS->N_Node-1)+1], FS->NodeList[3*(FS->N_Node-1)+2]);
3273 }
3274 } else {
3275 fprintf (Out, "NULL NodeId\n");
3276 fprintf (Out, "First 2 points X Y Z:\n\t %f %f %f\n\t %f %f %f\n", \
3277 FS->NodeList[0], FS->NodeList[1], FS->NodeList[2],
3278 FS->NodeList[3], FS->NodeList[4], FS->NodeList[5]);
3279 if (FS->N_Node > 2) {
3280 fprintf (Out, "Last 2 points X Y Z:\n\t %f %f %f\n\t %f %f %f\n", \
3281 FS->NodeList[3*(FS->N_Node-2)], FS->NodeList[3*(FS->N_Node-2)+1], FS->NodeList[3*(FS->N_Node-2)+2],
3282 FS->NodeList[3*(FS->N_Node-1)], FS->NodeList[3*(FS->N_Node-1)+1], FS->NodeList[3*(FS->N_Node-1)+2]);
3283 }
3284 }
3285 fprintf (Out, "N_FaceSet %d\n", FS->N_FaceSet);
3286 if (!FS->isPatch) {
3287 if (FS->N_FaceSet > 2) {
3288 fprintf (Out, "First 2 polygons:\n\t%d %d %d\n\t%d %d %d\n", \
3289 FS->FaceSetList[0], FS->FaceSetList[1], FS->FaceSetList[2],
3290 FS->FaceSetList[3], FS->FaceSetList[4], FS->FaceSetList[5]);
3291 fprintf (Out, "Last 2 polygons:\n%d %d %d\n%d %d %d\n", \
3292 FS->FaceSetList[3 * (FS->N_FaceSet-2)], FS->FaceSetList[3 * (FS->N_FaceSet-2) + 1], FS->FaceSetList[3 * (FS->N_FaceSet-2) + 2],
3293 FS->FaceSetList[3 * (FS->N_FaceSet-1)], FS->FaceSetList[3 * (FS->N_FaceSet-1) + 1], FS->FaceSetList[3 * (FS->N_FaceSet-1) + 2]);
3294 }else {
3295 fprintf (Out, "First polygon:\n\t%d %d %d\n", \
3296 FS->FaceSetList[0], FS->FaceSetList[1], FS->FaceSetList[2]);
3297 }
3298 } else {
3299 if (FS->N_FaceSet > 2) {
3300 fprintf (Out, "First 2 polygons:\n\t[parent ID:%d] %d %d %d\n\t[parent ID:%d] %d %d %d\n", \
3301 FS->FaceSetIndexInParent[0], FS->FaceSetList[0], FS->FaceSetList[1], FS->FaceSetList[2],
3302 FS->FaceSetIndexInParent[1], FS->FaceSetList[3], FS->FaceSetList[4], FS->FaceSetList[5]);
3303 fprintf (Out, "Last 2 polygons:\n\t[parent ID:%d]%d %d %d\n\t[parent ID:%d]%d %d %d\n", \
3304 FS->FaceSetIndexInParent[FS->N_FaceSet-2], FS->FaceSetList[3 * (FS->N_FaceSet-2)], \
3305 FS->FaceSetList[3 * (FS->N_FaceSet-2) + 1], FS->FaceSetList[3 * (FS->N_FaceSet-2) + 2], \
3306 FS->FaceSetIndexInParent[FS->N_FaceSet-1], FS->FaceSetList[3 * (FS->N_FaceSet-1)], \
3307 FS->FaceSetList[3 * (FS->N_FaceSet-1) + 1], FS->FaceSetList[3 * (FS->N_FaceSet-1) + 2]);
3308 } else {
3309 fprintf (Out, "First polygon:\n\t[parent ID:%d] %d %d %d\n", \
3310 FS->FaceSetIndexInParent[0], FS->FaceSetList[0], FS->FaceSetList[1], FS->FaceSetList[2]);
3311 }
3312 }
3313 SUMA_RETURNe;
3314
3315 }
3316
3317 /*!
3318 \brief Change the face vector to a SUMA FaceSetList vector
3319 Polygons are automatically triangulated
3320
3321 \param face (long *) vector of ace indices. Faces are separated
3322 by -1 entries
3323 \param N (int *) to contain the number of faces is FaceSetList
3324 \SUMA_RETURN FaceSetList (int *) 3Nx1 vector of triangles making up mesh.
3325 */
3326
SUMA_BYU_PolyFaceToTriFace(int * face,int * N)3327 int * SUMA_BYU_PolyFaceToTriFace(int *face, int *N)
3328 {
3329 static char FuncName[]={"SUMA_BYU_PolyFaceToTriFace"};
3330 int i, k, N_alloc, iface, iface0, iFS3;
3331 int *FaceSetList=NULL;
3332 SUMA_Boolean LocalHead = NOPE;
3333
3334 SUMA_ENTRY;
3335
3336 /* Can't guess ahead of time, make sure you check down the line */
3337 N_alloc = *N*3;
3338 FaceSetList = (int *)SUMA_malloc(N_alloc*sizeof(int));
3339 if (!FaceSetList) {
3340 fprintf (SUMA_STDERR,"Error %s: Failed to reallocate.\n", FuncName);
3341 SUMA_RETURN(NULL);
3342 }
3343 iFS3 =0; /* index of triangulated facet */
3344 iface = 0;
3345 iface0 = 0;
3346 while (iface < *N) {
3347 iface0 = iface ; /* 1s node in polygon */
3348 if (iface0 < 0) {
3349 fprintf(SUMA_STDERR, "Error %s: Unexpected end flag", FuncName);
3350 SUMA_free(FaceSetList);
3351 SUMA_RETURN(NULL);
3352 }
3353 if (LocalHead) fprintf(SUMA_STDERR,
3354 "%s: iface0 = %d, face[%d] = %d: ",
3355 FuncName, iface0, iface0, (int)face[iface0]) ;
3356 do {
3357 if (iFS3+3 > N_alloc) {
3358 N_alloc = 2 * N_alloc;
3359 FaceSetList = (int *)realloc((void *)FaceSetList, N_alloc * sizeof(int));
3360 if (!FaceSetList) {
3361 fprintf (SUMA_STDERR,"Error %s: Failed to reallocate.\n", FuncName);
3362 SUMA_RETURN(NULL);
3363 }
3364 }
3365 FaceSetList[iFS3] = SUMA_ABS(face[iface0]); /* first node in polygon is first node of triangles forming polygon */
3366 if (FaceSetList[iFS3] < 0) {
3367 fprintf (SUMA_STDERR,"Negative index loaded (loc 0)\n");
3368 }
3369 if (LocalHead) fprintf(SUMA_STDERR,
3370 "t(%d, ", (int)face[iface0]);
3371 if (iface == iface0) ++iface;
3372 if (LocalHead) fprintf(SUMA_STDERR,
3373 "%d, ", (int)face[iface]);
3374 ++iFS3;
3375 FaceSetList[iFS3] = SUMA_ABS(face[iface]); /* node 2 */
3376 if (FaceSetList[iFS3] < 0) {
3377 fprintf (SUMA_STDERR,"Negative index loaded (loc 1)\n");
3378 }
3379 if (LocalHead) fprintf(SUMA_STDERR,
3380 "%d) ", (int)face[iface+1]);
3381 ++iFS3;
3382 FaceSetList[iFS3] = SUMA_ABS(face[iface+1]); /* node 3 */
3383 if (FaceSetList[iFS3] < 0) {
3384 fprintf (SUMA_STDERR,"Negative index loaded (loc 2)\n");
3385 }
3386 ++iFS3; ++iface;
3387 } while (face[iface] >= 0);
3388 if (LocalHead) fprintf(SUMA_STDERR," iFS3/N_alloc = %d/%d\n", iFS3, N_alloc);
3389 /* ++iface; skip -1 */
3390 ++iface; /* goto next */
3391 }
3392
3393 *N = iFS3 / 3;
3394
3395 /* reallocate */
3396
3397 if (LocalHead) {
3398 int tmpmin=-100, n3, itmp;
3399 n3 = 3 * *N;
3400 fprintf (SUMA_STDERR,"%s: N_FaceSet %d\n", FuncName, *N);
3401 SUMA_MIN_VEC (FaceSetList, n3, tmpmin);
3402 fprintf (SUMA_STDERR,"Minimum index is %d\n", tmpmin);
3403 if (tmpmin < 0) {
3404 fprintf (SUMA_STDERR,"Error %s: Bad ass pre-alloc negative number\n", FuncName);
3405 for (itmp=0; itmp<n3; ++itmp) {
3406 fprintf (SUMA_STDERR, "%d: %d\n", itmp, FaceSetList[itmp]);
3407 if (FaceSetList[itmp] < 0) {
3408 fprintf (SUMA_STDERR,"%s: Min of %d, at %d\n", FuncName, FaceSetList[itmp], itmp);
3409 }
3410 }
3411 }
3412 }
3413
3414 FaceSetList = (int *)SUMA_realloc((void *)FaceSetList, iFS3 * sizeof(int));
3415 if (LocalHead) {
3416 int tmpmin=-100, n3, itmp;
3417 n3 = 3 * *N;
3418 fprintf (SUMA_STDERR,"%s: N_FaceSet %d\n", FuncName, *N);
3419 SUMA_MIN_VEC (FaceSetList, n3, tmpmin);
3420 fprintf (SUMA_STDERR,"Minimum index is %d\n", tmpmin);
3421 if (tmpmin < 0) {
3422 fprintf (SUMA_STDERR,"Error %s: Bad post realloc ass negative number\n", FuncName);
3423 for (itmp=0; itmp<n3; ++itmp) {
3424 fprintf (SUMA_STDERR, "%d: %d\n", itmp, FaceSetList[itmp]);
3425 if (FaceSetList[itmp] < 0) {
3426 fprintf (SUMA_STDERR,"%s: Min of %d, at %d\n", FuncName, FaceSetList[itmp], itmp);
3427 }
3428 }
3429 }
3430 }
3431
3432
3433 if (LocalHead) fprintf(SUMA_STDERR,"%s: Returning (iFS3 = %d, N = %d...)\n", FuncName, iFS3, *N);
3434
3435 SUMA_RETURN(FaceSetList);
3436 }
3437
3438 /*! \brief Load a BYU surface model
3439
3440 */
SUMA_BYU_Read(char * f_name,SUMA_SurfaceObject * SO,int debug,byte hide_negcols)3441 SUMA_Boolean SUMA_BYU_Read(char *f_name, SUMA_SurfaceObject *SO,
3442 int debug, byte hide_negcols)
3443 {
3444 static char FuncName[]={"SUMA_BYU_Read"};
3445 int ok, nread, i, k, lessen=0, nodemin, nodemax,
3446 *face=NULL, n = -1, nalloc=-1;
3447 double dum;
3448 char *fl=NULL, *fli;
3449 SUMA_Boolean LocalHead = NOPE;
3450
3451 SUMA_ENTRY;
3452
3453 /* suck the file */
3454 fl = SUMA_file_suck( f_name , &nread );
3455 fli = fl;
3456 if (!fl) {
3457 SUMA_SL_Err("Failed to read file.");
3458 SUMA_RETURN(NOPE);
3459 }
3460
3461 ok = 0;
3462 SUMA_ADVANCE_PAST_NUM(fl, dum, ok);
3463 if (!ok) { SUMA_S_Err("Failed to read PART_NUM"); SUMA_free(fli); SUMA_RETURN(NOPE); }
3464 SUMA_LHv("PART_NUM %f\n", dum);
3465 if ((int)dum != 1) {
3466 SUMA_S_Warnv("Not ready to deal with PART_NUM > 1. Have %d\n", (int)dum);
3467 }
3468 SUMA_ADVANCE_PAST_NUM(fl, dum, ok);SO->N_Node = (int)dum;
3469 if (!ok) { SUMA_S_Err("Failed to read VERTEX_NUM"); SUMA_free(fli); SUMA_RETURN(NOPE); }
3470 SUMA_LHv("VERTEX_NUM %f\n", dum);
3471 SUMA_ADVANCE_PAST_NUM(fl, dum, ok);SO->N_FaceSet=(int)dum;
3472 if (!ok) { SUMA_S_Err("Failed to read POLY_NUM"); SUMA_free(fli); SUMA_RETURN(NOPE); }
3473 SUMA_LHv("POLY_NUM %f\n", dum);
3474 SUMA_ADVANCE_PAST_NUM(fl, dum, ok);
3475 if (!ok) { SUMA_S_Err("Failed to read EDGE_NUM"); SUMA_free(fli); SUMA_RETURN(NOPE); }
3476 SUMA_LHv("EDGE_NUM %f\n", dum);
3477 SUMA_ADVANCE_PAST_NUM(fl, dum, ok);
3478 if (!ok) { SUMA_S_Err("Failed to read POLY1"); SUMA_free(fli); SUMA_RETURN(NOPE); }
3479 SUMA_LHv("POLY1 %f\n", dum);
3480 SUMA_ADVANCE_PAST_NUM(fl, dum, ok);
3481 if (!ok) { SUMA_S_Err("Failed to read POLY2"); SUMA_free(fli); SUMA_RETURN(NOPE); }
3482 SUMA_LHv("POLY2 %f\n", dum);
3483
3484 /* Now allocate for node list */
3485 SO->NodeDim = 3;
3486 if (!(SO->NodeList = (float *)SUMA_malloc(SO->N_Node*sizeof(float)*SO->NodeDim))) {
3487 SUMA_S_Err("Failed to allocate for NodeList");
3488 SUMA_free(fli); SUMA_RETURN(NOPE);
3489 }
3490 for (i=0; i<SO->N_Node*SO->NodeDim; ++i) {
3491 SUMA_ADVANCE_PAST_NUM(fl, dum, ok);
3492 if (!ok) {
3493 SUMA_S_Err("Failed to read coordinate");
3494 SUMA_free(fli); SUMA_free(SO->NodeList); SO->NodeList = NULL;
3495 SUMA_RETURN(NOPE);
3496 }
3497 SO->NodeList[i] = (float)dum;
3498 SUMA_LHv("nodec %f\n", dum);
3499
3500 }
3501
3502 #if 1
3503 /* Now read all facesets (not triangles necessarily ) */
3504 nodemin = 1000; nodemax = -1;
3505 SUMA_ADVANCE_PAST_NUM(fl, dum, ok);
3506 nalloc = 0;
3507 n = 0;
3508 while(ok) {
3509 if (n+1 > nalloc) {
3510 face = (int *)SUMA_realloc(face, (nalloc+10000)*sizeof(int)); nalloc+=10000;
3511 }
3512 face[n] = (int) dum;
3513 nodemin = SUMA_MIN_PAIR(SUMA_ABS(face[n]), nodemin);
3514 nodemax = SUMA_MAX_PAIR(SUMA_ABS(face[n]), nodemax);
3515 ++n;
3516 SUMA_ADVANCE_PAST_NUM(fl, dum, ok);
3517 }
3518
3519 /* Now change the polyfaced things to triangles */
3520 SO->FaceSetDim = 3;
3521 SO->FaceSetList = SUMA_BYU_PolyFaceToTriFace(face, &n);
3522 SO->N_FaceSet = n;
3523 if (LocalHead) { SUMA_WRITE_ARRAY_1D(SO->FaceSetList, n*3, 3, "triangulated"); }
3524 SUMA_free(face); face = NULL;
3525 #else
3526 /* Now allocate for facesetlist list */
3527 SO->FaceSetDim = 3;
3528 if (!(SO->FaceSetList = (int *)SUMA_malloc(SO->N_FaceSet*sizeof(int)*SO->FaceSetDim))) {
3529 SUMA_S_Err("Failed to allocate for FaceSetList");
3530 SUMA_free(SO->NodeList); SO->NodeList = NULL;
3531 SUMA_free(fli); SUMA_RETURN(NOPE);
3532 }
3533 lessen = 0;
3534 nodemin = 1000; nodemax = -1;
3535 for (i=0; i<SO->N_FaceSet; ++i) {
3536 for (k=0; k<3;++k) {
3537 SUMA_ADVANCE_PAST_NUM(fl, dum, ok);
3538 if (!ok) {
3539 SUMA_S_Err("Failed to read polynode");
3540 SUMA_free(fli); SUMA_free(SO->NodeList); SO->NodeList = NULL;
3541 SUMA_free(SO->FaceSetList); SO->FaceSetList=NULL;
3542 SUMA_RETURN(NOPE);
3543 }
3544 SO->FaceSetList[3*i+k] = (int)dum;
3545 nodemin = SUMA_MIN_PAIR(SO->FaceSetList[3*i+k], nodemin);
3546 nodemax = SUMA_MAX_PAIR(SO->FaceSetList[3*i+k], nodemax);
3547 SUMA_LHv("facei %f\n", dum);
3548 }
3549 SUMA_ADVANCE_PAST_NUM(fl, dum, ok);
3550 if (!ok || dum > 0) {
3551 SUMA_S_Err("Failed to read closing negative node");
3552 SUMA_free(fli); SUMA_free(SO->NodeList); SO->NodeList = NULL;
3553 SUMA_free(SO->FaceSetList); SO->FaceSetList=NULL;
3554 SUMA_RETURN(NOPE);
3555 }
3556 }
3557 #endif
3558 if (LocalHead && nodemin > 0) { SUMA_S_Notev("Smallest node index in list is %d\n", nodemin); }
3559 if (LocalHead && nodemax >= SO->N_Node) { SUMA_S_Notev("Largest node index in list is %d\n", nodemax); }
3560 if (nodemin > 0 && nodemax == SO->N_Node) {
3561 SUMA_S_Note("FaceSetList is 1 based, changing to 0\n");
3562 lessen = 1;
3563 }
3564 if (nodemax > SO->N_Node || nodemin < 0) {
3565 SUMA_S_Errv("Node indices not strictly between [0, %d]\nhave [%d, %d]\n",
3566 SO->N_Node -1, nodemin, nodemax);
3567 SUMA_free(fli); SUMA_free(SO->NodeList); SO->NodeList = NULL;
3568 SUMA_free(SO->FaceSetList); SO->FaceSetList=NULL;
3569 SUMA_RETURN(NOPE);
3570 }
3571 if (lessen) {
3572 for (i=0; i<SO->FaceSetDim*SO->N_FaceSet; ++i) SO->FaceSetList[i] -= 1;
3573 }
3574 SO->FileType = SUMA_BYU;
3575 SO->Name = SUMA_StripPath(f_name);
3576 SO->FileFormat = SUMA_ASCII;
3577 if (LocalHead) SUMA_Print_Surface_Object(SO, NULL);
3578
3579 SUMA_LH("Done.");
3580
3581 SUMA_free(fli); fli=NULL;
3582
3583 SUMA_RETURN(YUP);
3584 }
3585
3586 /*!
3587 \brief Load a GIFTI surface from a .gii file
3588 */
SUMA_GIFTI_Read(char * f_name,SUMA_SurfaceObject * SO,int debug)3589 SUMA_Boolean SUMA_GIFTI_Read(char *f_name, SUMA_SurfaceObject *SO,
3590 int debug)
3591 {
3592 static char FuncName[]={"SUMA_GIFTI_Read"};
3593 NI_group *aSO=NULL;
3594 SUMA_Boolean LocalHead = NOPE;
3595
3596 SUMA_ENTRY;
3597
3598 if (SO->aSO) {
3599 SUMA_S_Err("SO has aSO already!");
3600 SUMA_RETURN(NOPE);
3601 }
3602
3603
3604 if (!(aSO = afni_open_gifti_surf(f_name,1))) {
3605 SUMA_RETURN(NOPE);
3606 }
3607
3608 SO->FileType = SUMA_GIFTI;
3609 SO->Name = SUMA_StripPath(f_name);
3610 SO->FileFormat = SUMA_XML_SURF;
3611
3612 if (!SUMA_MergeAfniSO_In_SumaSO(&aSO, SO)) {
3613 SUMA_S_Err("Failed to merge SOs");
3614 aSO = SUMA_FreeAfniSurfaceObject(aSO);
3615 SUMA_RETURN(NOPE);
3616 }
3617
3618
3619 if (LocalHead) SUMA_Print_Surface_Object (SO, NULL);
3620
3621 SUMA_RETURN(YUP);
3622 }
3623 /*!
3624 \brief Load a brain voyager surface model from a .srf file.
3625
3626 Thanks to Nikolaus Kriegeskorte for code snippets and help.
3627
3628 The following fields are set in SO:
3629 SO->NodeDim
3630 SO->FaceSetDim
3631 SO->NodeList
3632 SO->FaceSetList
3633 SO->N_Node;
3634 SO->N_FaceSet;
3635 SO->Name;
3636 SO->FileType;
3637 SO->FileFormat
3638
3639 see readsrf.m for more info
3640
3641 */
SUMA_BrainVoyager_Read(char * f_name,SUMA_SurfaceObject * SO,int debug,byte hide_negcols)3642 SUMA_Boolean SUMA_BrainVoyager_Read(char *f_name, SUMA_SurfaceObject *SO, int debug, byte hide_negcols)
3643 {
3644 static char FuncName[]={"SUMA_BrainVoyager_Read"};
3645 float FileVersion, cx, cy, cz, *fbuf = NULL;
3646 int i, ii, chnk, ex, surf_type, n_neighbors, bs, cnt_inmesh=0, *ibuf=NULL;
3647 char buffer[256];
3648 float fbuffer[256];
3649 FILE *fl=NULL;
3650 SUMA_Boolean LocalHead = NOPE;
3651
3652 SUMA_ENTRY;
3653
3654 /* check for existence */
3655 if (!SUMA_filexists(f_name)) {
3656 fprintf(SUMA_STDERR,"Error %s: File %s does not exist or cannot be read.\n", FuncName, f_name);
3657 SUMA_RETURN (NOPE);
3658 }else {
3659 if ( debug > 1) {
3660 fprintf(SUMA_STDERR,"%s: File %s exists and will be read.\n", FuncName, f_name);
3661 }
3662 }
3663
3664 fl = fopen(f_name, "r");
3665 if (!fl) {
3666 SUMA_SL_Err("Failed to open file for reading.\n");
3667 SUMA_RETURN(NOPE);
3668 }
3669
3670 SO->N_Node=0;
3671 SO->N_FaceSet=0;
3672
3673 /* read version, and number of nodes and facesets, assume no swapping for the moment */
3674 bs = 0;
3675 chnk = sizeof(float);
3676 ex = fread (&FileVersion, chnk, 1, fl);
3677 chnk = sizeof(int);
3678 ex = fread (&surf_type, chnk, 1, fl); /* must be 0, per website www.brainvoyager.com... */
3679 ex = fread (&(SO->N_Node), chnk, 1, fl);
3680 ex = fread (&(SO->N_FaceSet), chnk, 1, fl);
3681 if (FileVersion < 0 || FileVersion > 500000 || SO->N_Node < 0 || SO->N_FaceSet < 0) { /* trouble perhaps ? */
3682 SUMA_LH("Byte swapping needed...");
3683 bs = 1;
3684 }
3685 if (bs) {
3686 SUMA_SWAP_THIS(&FileVersion, sizeof(float));
3687 SUMA_SWAP_THIS(&surf_type, sizeof(int));
3688 SUMA_SWAP_THIS(&(SO->N_Node), sizeof(int));
3689 SUMA_SWAP_THIS(&(SO->N_FaceSet), sizeof(int));
3690 }
3691
3692 if (LocalHead) {
3693 fprintf (SUMA_STDERR,"%s:\nSurfType is %d\nN_Node = %d, N_FaceSet = %d\n",
3694 FuncName, surf_type, SO->N_Node, SO->N_FaceSet);
3695 }
3696
3697 if (FileVersion < 0 || FileVersion > 500000) { /* trouble perhaps ? */
3698 SUMA_SL_Err("Version number < 0 || > 500000 \nSeems like bad news to me, quitting...");
3699 fclose(fl);
3700 SUMA_RETURN(NOPE);
3701 }
3702
3703
3704 if (SO->N_Node < 0 || SO->N_FaceSet < 0) {
3705 SUMA_SL_Err("Negative values for N_Node and N_FaceSet.");
3706 fclose(fl);
3707 SUMA_RETURN(NOPE);
3708 }
3709
3710 SUMA_READ_FLOAT(&cx, bs, fl, ex);
3711 SUMA_READ_FLOAT(&cy, bs, fl, ex);
3712 SUMA_READ_FLOAT(&cz, bs, fl, ex);
3713 if (LocalHead) {
3714 fprintf (SUMA_STDERR,"%s:\ncenter = [%f, %f, %f]\n(Niko adds 30 to cy ...)\n", FuncName, cx, cy, cz);
3715 }
3716 SO->NodeDim = 3;
3717 SO->FaceSetDim = 3;
3718 fbuf = (float *)SUMA_malloc(SO->N_Node*sizeof(float));
3719 SO->NodeList = (float *)SUMA_malloc(SO->NodeDim*SO->N_Node*sizeof(float));
3720 SO->FaceSetList = (int *)SUMA_malloc(SO->FaceSetDim*SO->N_FaceSet*sizeof(int));
3721 ibuf = (int*)SUMA_malloc(SO->N_Node*sizeof(int));
3722 if (!ibuf || !fbuf || !SO->NodeList || !SO->FaceSetList) {
3723 SUMA_SL_Crit("Failed to allocate.");
3724 SUMA_RETURN(NOPE);
3725 }
3726
3727 /* read the coords */
3728 SUMA_LH("Reading coords...");
3729 ex = fread(fbuf, sizeof(float), SO->N_Node, fl);
3730 if (ex != SO->N_Node) { SUMA_SL_Warn("Failed to read all node X info"); }
3731 if (bs) SUMA_SWAP_VEC(fbuf,SO->N_Node,sizeof(float));
3732 for (i=0; i<SO->N_Node; ++i) SO->NodeList[3*i] = fbuf[i];
3733 ex = fread(fbuf, sizeof(float), SO->N_Node, fl);
3734 if (ex != SO->N_Node) { SUMA_SL_Warn("Failed to read all node Y info"); }
3735 if (bs) SUMA_SWAP_VEC(fbuf,SO->N_Node,sizeof(float));
3736 for (i=0; i<SO->N_Node; ++i) SO->NodeList[3*i+1] = fbuf[i];
3737 ex = fread(fbuf, sizeof(float), SO->N_Node, fl);
3738 if (ex != SO->N_Node) { SUMA_SL_Warn("Failed to read all node Z info"); }
3739 if (bs) SUMA_SWAP_VEC(fbuf,SO->N_Node,sizeof(float));
3740 for (i=0; i<SO->N_Node; ++i) SO->NodeList[3*i+2] = fbuf[i];
3741 /* no need for buffer anymore ... */
3742 SUMA_free(fbuf); fbuf = NULL;
3743 if (LocalHead) {
3744 char *sdbg = SUMA_ShowMeSome((void *)SO->NodeList, SUMA_float, SUMA_MIN_PAIR(20, SO->N_Node), 20, NULL);
3745 fprintf(SUMA_STDERR,"%s NodeList:\n%s\n", FuncName, sdbg);
3746 SUMA_free(sdbg);sdbg = NULL;
3747 }
3748 /* skip the node normals, which would be read much like the x y z coords*/
3749 fseek(fl, SO->N_Node*3*sizeof(float), SEEK_CUR);
3750
3751 /* skip the curvature color info */
3752 ex = fread(fbuffer, sizeof(float), 8, fl); /* colors of convex and concave stuff */
3753 if (bs) SUMA_SWAP_VEC(fbuffer,8, sizeof(float));
3754 if (LocalHead) {
3755 char *sdbg = SUMA_ShowMeSome((void *)fbuffer, SUMA_float, 8,8, NULL);
3756 fprintf(SUMA_STDERR,"%s colorstuff:\n%s\n", FuncName, sdbg);
3757 SUMA_free(sdbg);sdbg = NULL;
3758 }
3759 if (0) { /* don't skip mesh color, it is use to hide triangles ! */
3760 fseek(fl, SO->N_Node*sizeof(int), SEEK_CUR); /* jump over mesh color */
3761 cnt_inmesh = SO->N_Node;
3762 } else {
3763 if (!ibuf) {
3764 SUMA_SL_Crit("Failed to allocate.");
3765 SUMA_RETURN(NOPE);
3766 }
3767 /* read into buffer */
3768 ex = fread(ibuf, sizeof(int), SO->N_Node, fl);
3769 if (ex != SO->N_Node) { SUMA_SL_Warn("Failed to read all node color info"); }
3770 if (bs) SUMA_SWAP_VEC(ibuf,SO->N_Node,sizeof(int));
3771 /* Hide negative node indices (per info from Hester Breman*/
3772 cnt_inmesh = 0;
3773 for (i=0; i<SO->N_Node; ++i) {
3774 if (ibuf[i] >= 0) {
3775 ibuf[cnt_inmesh] = i;
3776 ++cnt_inmesh;
3777 }
3778 }
3779 }
3780
3781
3782 /* skip nearest neighbor info */
3783 for (i=0; i<SO->N_Node; ++i) {
3784 ex = fread(&n_neighbors, sizeof(int), 1, fl);
3785 if (bs) SUMA_SWAP_THIS(&n_neighbors, sizeof(int));
3786 fseek(fl, n_neighbors*sizeof(int), SEEK_CUR);
3787 }
3788
3789 /* read dems triangles */
3790 SUMA_LH("Reading FaceSets...");
3791 ex = fread(SO->FaceSetList, sizeof(int), SO->N_FaceSet * SO->FaceSetDim , fl);
3792 if (ex != SO->N_FaceSet * SO->FaceSetDim) {
3793 fprintf( SUMA_STDERR,
3794 "Error %s: Failed to read all faceset info.\n"
3795 "Read %d values, expected %d\n",
3796 FuncName, ex, SO->N_FaceSet * SO->FaceSetDim );
3797 SUMA_RETURN(NOPE);
3798 }
3799
3800 if (bs) SUMA_SWAP_VEC(SO->FaceSetList,
3801 (SO->N_FaceSet * SO->FaceSetDim),sizeof(int));
3802 if (LocalHead) {
3803 char *sdbg = SUMA_ShowMeSome((void *)SO->FaceSetList, SUMA_int,
3804 SUMA_MIN_PAIR(20, SO->N_FaceSet * SO->FaceSetDim),
3805 20, NULL);
3806 fprintf(SUMA_STDERR,"%s FaceSetList:\n%s\n", FuncName, sdbg);
3807 SUMA_free(sdbg);sdbg = NULL;
3808 }
3809 fclose(fl); fl = NULL;
3810
3811 /* decide on whether some nodes need to be hidden,
3812 flat maps in BV contain the entire mesh! */
3813 if (hide_negcols && cnt_inmesh < SO->N_Node) {
3814 SUMA_PATCH *patch=NULL;
3815 SUMA_MEMBER_FACE_SETS *Memb = NULL;
3816 fprintf(SUMA_STDERR,
3817 "%s: %d nodes have negative colors \n"
3818 "and have been removed from mesh %s\n",
3819 FuncName, SO->N_Node - cnt_inmesh, f_name);
3820 Memb = SUMA_MemberFaceSets (SO->N_Node,
3821 SO->FaceSetList, SO->N_FaceSet,
3822 SO->NodeDim, NULL);
3823 if (!Memb->NodeMemberOfFaceSet) {
3824 SUMA_SL_Crit("Failed to create Memb FaceSets!");
3825 SUMA_RETURN(NOPE);
3826 }
3827 SUMA_LH("Patchin");
3828 if (!(patch = SUMA_getPatch ( ibuf, cnt_inmesh,
3829 SO->N_Node, SO->FaceSetList, SO->N_FaceSet,
3830 Memb, SO->NodeDim, 0, 1))) {
3831
3832 SUMA_SL_Err("Failed to create patch, "
3833 "proceeding but mesh might be a mess.");
3834 } else {
3835 SUMA_LH("Switchin");
3836 if (SO->FaceSetList) SUMA_free(SO->FaceSetList); SO->FaceSetList = NULL;
3837 SO->FaceSetList = patch->FaceSetList; patch->FaceSetList = NULL;
3838 SO->N_FaceSet = patch->N_FaceSet;
3839 /* done with Memb */
3840 SUMA_Free_MemberFaceSets(Memb); Memb = NULL;
3841 /* done with patch */
3842 SUMA_freePatch(patch); patch = NULL;
3843 }
3844 /* Does this merit a warning?*/
3845 if (strstr(f_name, "FLAT") && debug) {
3846 SUMA_S_Note(
3847 "\n"
3848 "****************************************************************\n"
3849 "Viewing BrainVoyager's Flat Maps:\n"
3850 "---------------------------------\n"
3851 "BV, it seems, shows both flattened cortical surfaces\n"
3852 "using the same mesh. Each side of the flat surface \n"
3853 "represents another hemisphere.\n"
3854 "SUMA, which by default displays both backward and forward facing\n"
3855 "triangles, will display both sides simultaneously. To look at\n"
3856 "each side separately, set 'Backface Culling' to \n"
3857 "'cull the FrontFace'. Backface Culling modes are toggled\n"
3858 "with the 'B' button. Read SUMA's GUI help 'ctrl+h' for reminder.\n"
3859 "****************************************************************\n"
3860 "\n"
3861 );
3862 }
3863 } else {
3864 if (LocalHead) {
3865 fprintf(SUMA_STDERR,"%s: All nodes preserved in mesh.\n", FuncName);
3866 }
3867 }
3868
3869 if (ibuf) SUMA_free(ibuf); ibuf = NULL;
3870
3871
3872 SO->FileType = SUMA_BRAIN_VOYAGER;
3873 SO->Name = SUMA_StripPath(f_name);
3874 SO->FileFormat = SUMA_BINARY; /* files are likely all BINARY_LE, must take care of that at some point*/
3875
3876 SUMA_LH("Done.");
3877
3878 SUMA_RETURN(YUP);
3879 }
3880
3881 #define USE_PLY_VERTEX
3882
3883 /*** Code to read ply format data
3884 Ply functions are based on code by Greg Turk.
3885 ---------------------------------------------------------------
3886
3887 Copyright (c) 1994 The Board of Trustees of The Leland Stanford
3888 Junior University. All rights reserved.
3889
3890 Permission to use, copy, modify and distribute this software and its
3891 documentation for any purpose is hereby granted without fee, provided
3892 that the above copyright notice and this permission notice appear in
3893 all copies of this software and that you do not sell the software.
3894
3895 THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
3896 EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
3897 WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
3898
3899
3900 */
3901
3902 /* user's vertex and face definitions for a polygonal object */
3903
3904 typedef struct Vertex {
3905 float x,y,z; /* the usual 3-space position of a vertex */
3906 } Vertex;
3907
3908 typedef struct Face {
3909 unsigned char intensity; /* this user attaches intensity to faces */
3910 unsigned char nverts; /* number of vertex indices in list */
3911 int *verts; /* vertex index list */
3912 } Face;
3913
3914 /* information needed to describe the user's data to the PLY routines */
3915
3916 PlyProperty vert_props[] = { /* list of property information for a vertex */
3917 {"x", PLY_FLOAT, PLY_FLOAT, offsetof(Vertex,x), 0, 0, 0, 0},
3918 {"y", PLY_FLOAT, PLY_FLOAT, offsetof(Vertex,y), 0, 0, 0, 0},
3919 {"z", PLY_FLOAT, PLY_FLOAT, offsetof(Vertex,z), 0, 0, 0, 0},
3920 };
3921
3922 PlyProperty face_props[] = { /* list of property information for a vertex */
3923 {"intensity", PLY_UCHAR, PLY_UCHAR, offsetof(Face,intensity), 0, 0, 0, 0},
3924 {"vertex_indices", PLY_INT, PLY_INT, offsetof(Face,verts),
3925 1, PLY_UCHAR, PLY_UCHAR, offsetof(Face,nverts)},
3926 };
3927
3928
3929 /*!
3930 \brief Reads a Ply formatted file into a SUMA_SurfaceObject structure
3931 ans = SUMA_Ply_Read (f_name, SO);
3932
3933 \param f_name (char *) name (and path) of .ply file to read. Extension .ply is optional
3934 \param SO (SUMA_SurfaceObject *) pointer to a structure to return surface in f_name in
3935 \return ans (SUMA_Boolean) YUP/NOPE
3936
3937 The following fields are set in SO:
3938 SO->NodeDim
3939 SO->FaceSetDim
3940 SO->NodeList
3941 SO->FaceSetList
3942 SO->N_Node;
3943 SO->N_FaceSet;
3944 SO->Name;
3945 SO->FileType;
3946 SO->FileFormat
3947
3948 \sa SUMA_Ply_Write()
3949
3950 This function is a wrap around code by Greg Turk.
3951
3952 */
SUMA_Ply_Read(char * f_name,SUMA_SurfaceObject * SO)3953 SUMA_Boolean SUMA_Ply_Read (char * f_name, SUMA_SurfaceObject *SO)
3954 {
3955 static char FuncName[]={"SUMA_Ply_Read"};
3956 int i,j,k, j3, ji;
3957 PlyFile *ply = NULL;
3958 int nelems;
3959 char **elist = NULL;
3960 int file_type;
3961 float version;
3962 int nprops;
3963 int num_elems;
3964 PlyProperty **plist = NULL;
3965 Vertex vert;
3966 Face **flist = NULL;
3967 char *elem_name;
3968 int num_comments;
3969 char **comments = NULL;
3970 int num_obj_info;
3971 char **obj_info = NULL;
3972 SUMA_Boolean LocalHead = NOPE;
3973
3974 SUMA_ENTRY;
3975
3976 /* open a PLY file for reading */
3977 ply = ply_open_for_reading(f_name, &nelems, &elist, &file_type, &version);
3978 if (!ply) {
3979 fprintf (SUMA_STDERR,
3980 "Error %s: Failed to find/read %s.\n",
3981 FuncName, f_name);
3982 SUMA_RETURN (NOPE);
3983 }
3984
3985 /* print what we found out about the file */
3986 if (LocalHead) fprintf (SUMA_STDERR, "%s: version %f\n", FuncName, version);
3987 if (LocalHead) fprintf (SUMA_STDERR, "%s: type %d\n", FuncName, file_type);
3988
3989 /* go through each kind of element that we learned is in the file */
3990 /* and read them */
3991
3992 for (i = 0; i < nelems; i++) {
3993
3994 /* get the description of the first element */
3995 elem_name = elist[i];
3996 plist = ply_get_element_description (ply, elem_name, &num_elems, &nprops);
3997
3998 /* print the name of the element, for debugging */
3999 if (LocalHead)
4000 fprintf (SUMA_STDERR,
4001 "%s: element %s %d\n", FuncName, elem_name, num_elems);
4002
4003 /* if we're on vertex elements, read them in */
4004 if (equal_strings ("vertex", elem_name)) {
4005 SO->NodeList = (float *) SUMA_calloc (3*num_elems, sizeof(float));
4006 if (!SO->NodeList) {
4007 fprintf (SUMA_STDERR,
4008 "Error %s: Failed to allocate for SO->NodeList.\n",
4009 FuncName);
4010 SUMA_RETURN(NOPE);
4011 }
4012
4013 /* set up for getting vertex elements */
4014
4015 ply_get_property (ply, elem_name, &vert_props[0]);
4016 ply_get_property (ply, elem_name, &vert_props[1]);
4017 ply_get_property (ply, elem_name, &vert_props[2]);
4018
4019 SO->NodeDim = 3;
4020 SO->N_Node = num_elems;
4021 /* grab all the vertex elements */
4022 for (j = 0; j < num_elems; j++) {
4023 /* grab and element from the file */
4024 #ifdef USE_PLY_VERTEX
4025 ply_get_element (ply, (void *) (&vert));
4026 /* print out vertex x,y,z for debugging */
4027 SUMA_LH("vertex: %g %g %g",vert.x, vert.y, vert.z);
4028 /* copy to NodeList */
4029 j3 = SO->NodeDim*j;
4030 SO->NodeList[j3] = vert.x;
4031 SO->NodeList[j3+1] = vert.y;
4032 SO->NodeList[j3+2] = vert.z;
4033 #else
4034 j3 = SO->NodeDim*j;
4035 ply_get_element (ply, (void *) &(SO->NodeList[j3]));
4036 /* print out vertex x,y,z for debugging */
4037 if (LocalHead) fprintf (SUMA_STDERR, "%s vertex: %g %g %g\n", FuncName,
4038 SO->NodeList[j3], SO->NodeList[j3+1], SO->NodeList[j3+2]);
4039 #endif
4040
4041 }
4042 }
4043
4044 /* if we're on face elements, read them in */
4045 if (equal_strings ("face", elem_name)) {
4046
4047 /* create a list to hold all the face elements */
4048 flist = (Face **) SUMA_malloc (sizeof (Face *) * num_elems);
4049
4050 /* set up for getting face elements */
4051
4052 ply_get_property (ply, elem_name, &face_props[0]);
4053 ply_get_property (ply, elem_name, &face_props[1]);
4054
4055 /* grab all the face elements */
4056 for (j = 0; j < num_elems; j++) {
4057
4058 /* grab an element from the file */
4059 flist[j] = (Face *) SUMA_malloc (sizeof (Face));
4060 ply_get_element (ply, (void *) flist[j]);
4061
4062 /* print out face info, for debugging */
4063 if (LocalHead) {
4064 fprintf (SUMA_STDERR,"%s face: %d, list = ",
4065 FuncName, flist[j]->intensity);
4066 for (k = 0; k < flist[j]->nverts; k++)
4067 fprintf (SUMA_STDERR,"%d ", flist[j]->verts[k]);
4068 fprintf (SUMA_STDERR,"\n");
4069 }
4070
4071 }
4072 /* copy face elements to SO structure */
4073 SO->FaceSetDim = flist[0]->nverts;
4074 SO->N_FaceSet = num_elems;
4075 SO->FaceSetList = (int *) SUMA_calloc (SO->FaceSetDim * num_elems,
4076 sizeof(int));
4077 if (!SO->FaceSetList) {
4078 SUMA_S_Err("Failed to allocate for SO->NodeList.\n");
4079 if (SO->NodeList) SUMA_free(SO->NodeList);
4080 SUMA_RETURN(NOPE);
4081 }
4082
4083 for (j = 0; j < num_elems; j++) {
4084 if (flist[j]->nverts != SO->FaceSetDim) {
4085 SUMA_S_Err("All FaceSets must have the same dimension for SUMA.\n");
4086 if (SO->NodeList) SUMA_free(SO->NodeList);
4087 if (SO->FaceSetList) SUMA_free(SO->FaceSetList);
4088 SO->NodeList = NULL;
4089 SO->FaceSetList = NULL;
4090 SUMA_RETURN(NOPE);
4091 }
4092 ji = SO->FaceSetDim * j;
4093 for (k = 0; k < flist[j]->nverts; k++)
4094 SO->FaceSetList[ji+k] = flist[j]->verts[k];
4095 }
4096 }
4097
4098 /* fill up a few more fields */
4099 SO->FileType = SUMA_PLY;
4100 if (file_type == PLY_ASCII) SO->FileFormat = SUMA_ASCII;
4101 else if (file_type == PLY_BINARY_BE) SO->FileFormat = SUMA_BINARY_BE;
4102 else if (file_type == PLY_BINARY_LE) SO->FileFormat = SUMA_BINARY_LE;
4103 else {
4104 SUMA_S_Err("PLY_TYPE %d not recognized.\n", file_type);
4105 }
4106
4107 SO->Name = SUMA_StripPath(f_name);
4108
4109 /* print out the properties we got, for debugging */
4110 if (LocalHead) {
4111 for (j = 0; j < nprops; j++)
4112 fprintf (SUMA_STDERR, "%s property %s\n", FuncName, plist[j]->name);
4113 }
4114 }
4115
4116 /* grab and print out the comments in the file */
4117 comments = ply_get_comments (ply, &num_comments);
4118 if (LocalHead) {
4119 for (i = 0; i < num_comments; i++)
4120 fprintf (SUMA_STDERR, "%s comment = '%s'\n", FuncName, comments[i]);
4121 }
4122
4123 /* grab and print out the object information */
4124 obj_info = ply_get_obj_info (ply, &num_obj_info);
4125 if (LocalHead) {
4126 for (i = 0; i < num_obj_info; i++)
4127 fprintf (SUMA_STDERR, "%s obj_info = '%s'\n", FuncName, obj_info[i]);
4128 }
4129
4130 /* free the allocations necessary for vertex and facesetlists */
4131 for (j = 0; j < SO->N_FaceSet; j++) {
4132 SUMA_free(flist[j]);
4133 }
4134 SUMA_free(flist); flist = NULL;
4135
4136
4137 /* close the PLY file, ply structure is freed within*/
4138 ply_close (ply);
4139
4140 /* free plist */
4141 for (j = 0; j < nprops; j++) if (plist[j]) SUMA_free (plist[j]);
4142 if (plist) SUMA_free(plist);
4143
4144 /* free comments */
4145 for (i = 0; i < num_comments; i++) if (comments[i]) SUMA_free (comments[i]);
4146 if (comments) SUMA_free (comments);
4147
4148 /* free elist */
4149 for (i = 0; i < nelems; i++) if (elist[i]) SUMA_free (elist[i]);
4150 if (elist) SUMA_free (elist);
4151
4152 /* free obj_info */
4153 for (i = 0; i < num_obj_info; i++) if (obj_info[i]) SUMA_free (obj_info[i]);
4154 if (obj_info) SUMA_free (obj_info);
4155
4156 SUMA_RETURN(YUP);
4157 }
4158
4159 /*!
4160 \brief Writes an SO into a .ply file
4161 ans = SUMA_Ply_Write (f_name, SO);
4162 \param f_name (char *) name of .ply file. if .ply is not attached it will be added.
4163 \param SO (SUMA_SurfaceObject *) Surface object to write out.
4164 if SO->FileFormat = SUMA_BINARY_BE or SUMA_BINARY_LE the surface is written in binary ply format.
4165 SUMA_BINARY is set to SUMA_BINARY_BE
4166 \return ans (SUMA_Boolean) success flag.
4167
4168 In its current incarnation, the function does not overwrite a pre-existing file.
4169
4170 */
SUMA_Ply_Write(char * f_name_in,SUMA_SurfaceObject * SO)4171 SUMA_Boolean SUMA_Ply_Write (char * f_name_in, SUMA_SurfaceObject *SO)
4172 {
4173 static char FuncName[]={"SUMA_Ply_Write"};
4174 int i,j;
4175 PlyFile *ply = NULL;
4176 int nelems;
4177 int file_type;
4178 float version;
4179 int nverts ;
4180 int nfaces ;
4181 char *f_name, *f_name2, *elem_names[] = { "vertex", "face" };/* list of the kinds of elements in the user's object */
4182 int n_elem_names = 2;
4183 Vertex **verts = NULL;
4184 Face *faces = NULL;
4185 SUMA_Boolean LocalHead = NOPE;
4186
4187 SUMA_ENTRY;
4188
4189 if (!f_name_in) {
4190 fprintf (SUMA_STDERR, "Error %s: NULL filename\n", FuncName);
4191 SUMA_RETURN (NOPE);
4192 }
4193
4194 f_name = SUMA_Extension(f_name_in,".ply" , YUP);
4195 f_name2 = SUMA_append_string(f_name,".ply");
4196 if (!THD_ok_overwrite() && SUMA_filexists (f_name2)) {
4197 fprintf (SUMA_STDERR,
4198 "Error %s: file %s exists, will not overwrite.\n",
4199 FuncName, f_name2);
4200 SUMA_free(f_name2);f_name2 = NULL;
4201 SUMA_free(f_name);f_name = NULL;
4202 SUMA_RETURN (NOPE);
4203 }
4204 SUMA_free(f_name2); f_name2 = NULL;
4205
4206 nverts = SO->N_Node;
4207 nfaces = SO->N_FaceSet;
4208
4209 /* must have XYZ */
4210 if (SO->NodeDim != 3) {
4211 fprintf (SUMA_STDERR, "Error %s: SO->NodeDim != 3.\n", FuncName);
4212 SUMA_RETURN (NOPE);
4213 }
4214
4215 /* create the object in ply format */
4216 verts = (Vertex **) SUMA_malloc (nverts*sizeof(Vertex *));
4217 faces = (Face *) SUMA_malloc (nfaces*sizeof(Face));
4218 if (!verts || !faces) {
4219 fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
4220 if (verts) SUMA_free(verts);
4221 if (faces) SUMA_free(faces);
4222 SUMA_RETURN (NOPE);
4223 }
4224
4225 for (i = 0; i < nfaces; i++) {
4226 faces[i].intensity = '\001';
4227 faces[i].nverts = SO->FaceSetDim;
4228 faces[i].verts = &(SO->FaceSetList[SO->FaceSetDim*i]);
4229 }
4230
4231 /* open either a binary or ascii PLY file for writing */
4232 /* (the file will be called "test.ply" because the routines */
4233 /* enforce the .ply filename extension) */
4234
4235 switch (SO->FileFormat) {
4236 case SUMA_BINARY_BE:
4237 ply = ply_open_for_writing(f_name, n_elem_names, elem_names, PLY_BINARY_BE, &version);
4238 break;
4239
4240 case SUMA_BINARY_LE:
4241 ply = ply_open_for_writing(f_name, n_elem_names, elem_names,
4242 PLY_BINARY_LE, &version);
4243 break;
4244
4245 case SUMA_ASCII:
4246 ply = ply_open_for_writing(f_name, n_elem_names, elem_names,
4247 PLY_ASCII, &version);
4248 break;
4249
4250 case SUMA_BINARY:
4251 ply = ply_open_for_writing(f_name, n_elem_names, elem_names,
4252 PLY_BINARY_BE, &version);
4253 break;
4254
4255 case SUMA_FF_NOT_SPECIFIED:
4256 ply = ply_open_for_writing(f_name, n_elem_names, elem_names,
4257 PLY_ASCII, &version);
4258 break;
4259
4260 default:
4261 ply = ply_open_for_writing(f_name, n_elem_names, elem_names,
4262 PLY_ASCII, &version);
4263 break;
4264 }
4265
4266 if (!ply) {
4267 fprintf (SUMA_STDERR,"Error %s: Failed to create %s.ply\n",
4268 FuncName, f_name);
4269 if (verts) SUMA_free(verts);
4270 if (faces) SUMA_free(faces);
4271 SUMA_RETURN (NOPE);
4272 }
4273 /* describe what properties go into the vertex and face elements */
4274
4275 ply_element_count (ply, "vertex", nverts);
4276 ply_describe_property (ply, "vertex", &vert_props[0]);
4277 ply_describe_property (ply, "vertex", &vert_props[1]);
4278 ply_describe_property (ply, "vertex", &vert_props[2]);
4279
4280 ply_element_count (ply, "face", nfaces);
4281 ply_describe_property (ply, "face", &face_props[0]);
4282 ply_describe_property (ply, "face", &face_props[1]);
4283
4284 /* write a comment and an object information field */
4285 ply_put_comment (ply, "author: Greg Turk");
4286 ply_put_obj_info (ply, "random information");
4287
4288 /* we have described exactly what we will put in the file, so */
4289 /* we are now done with the header info */
4290 ply_header_complete (ply);
4291
4292 /* set up and write the vertex elements */
4293 ply_put_element_setup (ply, "vertex");
4294 for (i = 0; i < nverts; i++)
4295 ply_put_element (ply, (void *) &(SO->NodeList[SO->NodeDim*i]));
4296
4297 /* set up and write the face elements */
4298 ply_put_element_setup (ply, "face");
4299 for (i = 0; i < nfaces; i++)
4300 ply_put_element (ply, (void *) &faces[i]);
4301
4302 /* close the PLY file */
4303 ply_close (ply);
4304
4305 /* free */
4306 if (verts) SUMA_free(verts);
4307 if (faces) SUMA_free(faces);
4308 if (f_name) SUMA_free(f_name);
4309 SUMA_RETURN (YUP);
4310 }
4311
4312 /*!
4313 \brief Reads an STL formatted file into a SUMA_SurfaceObject structure
4314 ans = SUMA_STL_Read (f_name, SO);
4315
4316 \param f_name (char *) name (and path) of .stl file to read.
4317 Extension .stl is optional
4318 \param SO (SUMA_SurfaceObject *) pointer to a structure to return surface in f_name in
4319 \return ans (SUMA_Boolean) YUP/NOPE
4320
4321 The following fields are set in SO:
4322 SO->NodeDim
4323 SO->FaceSetDim
4324 SO->NodeList
4325 SO->FaceSetList
4326 SO->N_Node;
4327 SO->N_FaceSet;
4328 SO->Name;
4329 SO->FileType;
4330 SO->FileFormat
4331
4332 \sa SUMA_STL_Write()
4333
4334
4335 */
SUMA_STL_Read(char * f_name,SUMA_SurfaceObject * SO)4336 SUMA_Boolean SUMA_STL_Read (char * f_name, SUMA_SurfaceObject *SO)
4337 {
4338 static char FuncName[]={"SUMA_STL_Read"};
4339 int err=0, i, i3, nn, nfound, found, good,j[3],k, j3[3], nread, l;
4340 char head[126] = {""}, *bb=NULL, *fl, *op=NULL, *ope=NULL;
4341 double ff;
4342 FILE *fout = NULL;
4343 SUMA_Boolean LocalHead = NOPE;
4344
4345 SUMA_ENTRY;
4346
4347 /* open a STL file for reading */
4348 fout = fopen(f_name, "r");
4349 if (!fout) {
4350 fprintf (SUMA_STDERR,
4351 "Error %s: Failed to find/read %s.\n",
4352 FuncName, f_name);
4353 SUMA_RETURN (NOPE);
4354 }
4355
4356 /* Is this a binary or ascii file? Read 80 characters and check for 'solid'*/
4357 fread(head, sizeof(char), 80, fout);
4358 head[80] = '\0'; /* replace FreeBSD-specific strnstr() 11 Feb 2015 [rickr] */
4359 if ((bb=strstr(head, "solid"))) {
4360 if (bb - head > 3) {
4361 SUMA_S_Warn("term solid found but far from beginning of line..."
4362 "Still assuming it is ascii format");
4363 }
4364 SO->FileFormat = SUMA_ASCII;
4365 } else {
4366 SUMA_LH("Binary header: %s", head);
4367 SO->FileFormat = SUMA_BINARY_LE;
4368 }
4369 SO->FileType = SUMA_STL;
4370 SO->Name = SUMA_StripPath(f_name);
4371
4372 switch (SO->FileFormat) {
4373 case SUMA_BINARY_LE: {
4374 unsigned int ui;
4375 short ss;
4376 float fv[12];
4377
4378 SUMA_LH("Reading BINARY STL");
4379 /* We should be right at the number of triangles */
4380 fread(&ui, sizeof(unsigned int), 1, fout);
4381 SUMA_LH("%d facesets", ui);
4382 SO->N_FaceSet = ui;
4383 SO->FaceSetDim = 3;
4384 SO->NodeDim = 3;
4385 SO->FaceSetList = (int *) SUMA_calloc (SO->FaceSetDim * SO->N_FaceSet,
4386 sizeof(int));
4387 SO->FaceNormList = (float *)SUMA_calloc (SO->NodeDim * SO->N_FaceSet,
4388 sizeof(float));
4389 SO->N_Node = 3*SO->N_FaceSet;
4390 SO->NodeNormList = (float *)SUMA_calloc (SO->NodeDim * SO->N_Node,
4391 sizeof(float));
4392 SO->NodeList = (float *)SUMA_calloc (SO->NodeDim * SO->N_Node,
4393 sizeof(float));
4394 if (!SO->FaceSetList || !SO->NodeList ||
4395 !SO->NodeNormList || !SO->FaceNormList) {
4396 SUMA_S_Err("Failed to allocate for FaceSetList or NodeList...\n");
4397 SUMA_ifree(SO->FaceSetList); SUMA_ifree(SO->NodeList);
4398 SUMA_ifree(SO->NodeNormList); SUMA_ifree(SO->FaceNormList);
4399 SUMA_RETURN(NOPE);
4400 }
4401 /* Now fill up this stuff */
4402 for (nn=0,i=0; i<SO->N_FaceSet; ++i) {
4403 i3 = 3*i;
4404 nread = fread(fv, sizeof(float), 12, fout);
4405 SUMA_LH("Read %d vals at facet %d, nn=%d,"
4406 "ready for %d nodes, %d triangles",
4407 nread, i, nn, SO->N_Node, SO->N_FaceSet);
4408 SO->FaceNormList[i3 ] = fv[0];
4409 SO->FaceNormList[i3+1] = fv[1];
4410 SO->FaceNormList[i3+2] = fv[2];
4411 j[0] = nn; j3[0] = j[0]*3; ++nn;
4412 j[1] = nn; j3[1] = j[1]*3; ++nn;
4413 j[2] = nn; j3[2] = j[2]*3; ++nn;
4414 SO->FaceSetList[i3 ] = j[0];
4415 SO->FaceSetList[i3+1] = j[1];
4416 SO->FaceSetList[i3+2] = j[2];
4417
4418 SO->NodeList[j3[0] ] = fv[3];
4419 SO->NodeList[j3[0]+1] = fv[4];
4420 SO->NodeList[j3[0]+2] = fv[5];
4421 SO->NodeList[j3[1] ] = fv[6];
4422 SO->NodeList[j3[1]+1] = fv[7];
4423 SO->NodeList[j3[1]+2] = fv[8];
4424 SO->NodeList[j3[2] ] = fv[9];
4425 SO->NodeList[j3[2]+1] = fv[10];
4426 SO->NodeList[j3[2]+2] = fv[11];
4427
4428 /* and the redundant normals */
4429 SO->NodeNormList[j3[0] ] =
4430 SO->NodeNormList[j3[1] ] =
4431 SO->NodeNormList[j3[2] ] = SO->FaceNormList[i3 ];
4432 SO->NodeNormList[j3[0]+1] =
4433 SO->NodeNormList[j3[1]+1] =
4434 SO->NodeNormList[j3[2]+1] = SO->FaceNormList[i3+1];
4435 SO->NodeNormList[j3[0]+2] =
4436 SO->NodeNormList[j3[1]+2] =
4437 SO->NodeNormList[j3[2]+2] = SO->FaceNormList[i3+2];
4438 fread(&ss, sizeof(short), 1, fout);
4439 #if 0
4440 SUMA_LH( "Facet %d %d %d %d\n"
4441 "%f %f %f\n"
4442 "%f %f %f\n"
4443 "%f %f %f\n"
4444 "%d",
4445 i,
4446 SO->FaceSetList[i3],
4447 SO->FaceSetList[i3+1], SO->FaceSetList[i3+2],
4448 SO->NodeList[j3[0] ],
4449 SO->NodeList[j3[0]+1], SO->NodeList[j3[0]+2],
4450 SO->NodeList[j3[1] ],
4451 SO->NodeList[j3[1]+1], SO->NodeList[j3[1]+2],
4452 SO->NodeList[j3[2] ],
4453 SO->NodeList[j3[2]+1], SO->NodeList[j3[2]+2],
4454 ss);
4455 #endif
4456 }
4457 break; }
4458 case SUMA_ASCII:
4459 {
4460 SUMA_LH("Reading ASCII STL");
4461 if (fout) fclose(fout); fout = NULL;
4462 nread = SUMA_suck_file( f_name , &fl ) ;
4463 if (!fl) {
4464 SUMA_SL_Err("Failed to read file %s", f_name);
4465 SUMA_RETURN(NOPE);
4466 }
4467 SUMA_LH("Read in %d chars\n", nread);
4468 SO->NodeDim = SO->FaceSetDim = 3;
4469 /* You might need to track solid name for cases with nested
4470 objects... For now don't bother */
4471 op = fl;
4472 SUMA_ADVANCE_PAST(op, fl+nread, "solid", found, 1);
4473 ope = op;
4474 SUMA_ADVANCE_PAST(ope, fl+nread, "endsolid", found, 1);
4475 nn = 0;
4476 nfound = 0;
4477 do {
4478 /* Look for facet normal */
4479 SUMA_ADVANCE_PAST(op, ope, "facet normal", found, 1);
4480 if (found) {
4481 SUMA_LH("Found facet %d at offset %d", nfound, (int)(op-fl));
4482 /* SUMA_PRINT_STRING(op, op+30, NULL,"-->", "\n");*/
4483 if (SO->N_FaceSet <= nfound) {
4484 SO->N_FaceSet += SO->N_FaceSet+50000;
4485 SO->FaceSetList = (int *)SUMA_realloc(SO->FaceSetList,
4486 sizeof(int) * SO->FaceSetDim*SO->N_FaceSet);
4487 SO->FaceNormList = (float *)SUMA_realloc (SO->FaceNormList,
4488 SO->NodeDim * SO->N_FaceSet*sizeof(float));
4489 SO->N_Node = 3*SO->N_FaceSet;
4490 SO->NodeNormList = (float *)SUMA_realloc (SO->NodeNormList,
4491 SO->NodeDim * SO->N_Node * sizeof(float));
4492 SO->NodeList = (float *)SUMA_realloc (SO->NodeList,
4493 SO->NodeDim * SO->N_Node * sizeof(float));
4494 if (!SO->FaceSetList || !SO->NodeList ||
4495 !SO->NodeNormList || !SO->FaceNormList) {
4496 SUMA_S_Err("Failed to allocate for FaceSetList or"
4497 " NodeList...\n");
4498 SUMA_ifree(SO->FaceSetList);
4499 SUMA_ifree(SO->NodeList);
4500 SUMA_ifree(SO->NodeNormList);
4501 SUMA_ifree(SO->FaceNormList);
4502 SUMA_RETURN(NOPE);
4503 }
4504 }
4505 i3 = 3*nfound;
4506 /* Read normal */
4507 for (k=0;k<3;++k) {
4508 SUMA_ADVANCE_PAST_NUM(op, ff, good);
4509 if (good) SO->FaceNormList[i3+k] = ff;
4510 else {
4511 SO->FaceNormList[i3+k] = 0.0;
4512 ++err;
4513 }
4514 }
4515
4516 /* Pretend we have three new nodes */
4517 j[0] = nn; j3[0] = j[0]*3; ++nn;
4518 j[1] = nn; j3[1] = j[1]*3; ++nn;
4519 j[2] = nn; j3[2] = j[2]*3; ++nn;
4520 SO->FaceSetList[i3 ] = j[0];
4521 SO->FaceSetList[i3+1] = j[1];
4522 SO->FaceSetList[i3+2] = j[2];
4523
4524 for (l=0; l<3; ++l) {
4525 /* jump to vertex of node l*/
4526 SUMA_ADVANCE_PAST(op, op+nread, "vertex", found, 1);
4527 /* SUMA_PRINT_STRING(op, op+30, NULL,"-v->", "\n"); */
4528 if (!found) {
4529 SUMA_S_Err("Failed to find vertex!"); ++err;
4530 } else {
4531 /* get x y z */
4532 for (k=0; k<3; ++k) {
4533 SUMA_ADVANCE_PAST_NUM(op, ff, good);
4534 if (good) SO->NodeList[j3[l]+k] = ff;
4535 else {
4536 SO->NodeList[j3[l]+k] = 0.0;
4537 ++err;
4538 }
4539 }
4540 }
4541 }
4542
4543 /* and the redundant normals */
4544 SO->NodeNormList[j3[0] ] =
4545 SO->NodeNormList[j3[1] ] =
4546 SO->NodeNormList[j3[2] ] = SO->FaceNormList[i3 ];
4547 SO->NodeNormList[j3[0]+1] =
4548 SO->NodeNormList[j3[1]+1] =
4549 SO->NodeNormList[j3[2]+1] = SO->FaceNormList[i3+1];
4550 SO->NodeNormList[j3[0]+2] =
4551 SO->NodeNormList[j3[1]+2] =
4552 SO->NodeNormList[j3[2]+2] = SO->FaceNormList[i3+2];
4553
4554 SUMA_ADVANCE_PAST(op, ope, "endfacet", good, 1);
4555 if (!good) {
4556 SUMA_S_Warn("NO closing facet normal at triangle %d",
4557 nfound);
4558 }
4559 ++nfound;
4560 }
4561 } while (*op != '\0' && op < ope && found);
4562
4563 /* reallocate */
4564 SO->N_FaceSet = nfound;
4565 SO->FaceSetList = (int *)SUMA_realloc(SO->FaceSetList,
4566 sizeof(int) * SO->FaceSetDim*SO->N_FaceSet);
4567 SO->FaceNormList = (float *)SUMA_realloc (SO->FaceNormList,
4568 SO->NodeDim * SO->N_FaceSet*sizeof(float));
4569 SO->N_Node = 3*SO->N_FaceSet;
4570 SO->NodeNormList = (float *)SUMA_realloc (SO->NodeNormList,
4571 SO->NodeDim * SO->N_Node * sizeof(float));
4572 SO->NodeList = (float *)SUMA_realloc (SO->NodeList,
4573 SO->NodeDim * SO->N_Node * sizeof(float));
4574
4575 SUMA_ifree(fl);
4576 }
4577 break;
4578 default:
4579 SUMA_S_Err("Should not happen. Bad format");
4580 SUMA_RETURN(NOPE);
4581 break;
4582
4583 }
4584
4585 SUMA_LH("All done reading, %d triangles, %d nodes",
4586 SO->N_FaceSet, SO->N_Node);
4587 if (err) {
4588 SUMA_S_Warn("%d errs found, proceeding by the seat of the pants", err);
4589 }
4590
4591 SUMA_RETURN(YUP);
4592 }
4593
4594
4595 /*!
4596 \brief Writes an SO into a .stl file
4597 ans = SUMA_Stl_Write (f_name, SO);
4598 \param f_name (char *) name of .stl file. if .stl is not attached it
4599 will be added.
4600 \param SO (SUMA_SurfaceObject *) Surface object to write out.
4601 if SO->FileFormat = SUMA_BINARY_BE or SUMA_BINARY_LE the surface is
4602 written in binary stl format.
4603 SUMA_BINARY is set to SUMA_BINARY_BE
4604 \return ans (SUMA_Boolean) success flag.
4605
4606 In its current incarnation, the function does not overwrite a pre-existing file.
4607
4608 */
SUMA_STL_Write(char * f_name_in,SUMA_SurfaceObject * SO)4609 SUMA_Boolean SUMA_STL_Write (char * f_name_in, SUMA_SurfaceObject *SO)
4610 {
4611 static char FuncName[]={"SUMA_STL_Write"};
4612 int i, i3, j3[3];
4613 char *f_name, *f_name2;
4614 FILE *fout = NULL;
4615 SUMA_Boolean LocalHead = NOPE;
4616
4617 SUMA_ENTRY;
4618
4619 if (!f_name_in) {
4620 fprintf (SUMA_STDERR, "Error %s: NULL filename\n", FuncName);
4621 SUMA_RETURN (NOPE);
4622 }
4623
4624 f_name = SUMA_Extension(f_name_in,".stl" , YUP);
4625 f_name2 = SUMA_append_string(f_name,".stl");
4626 if (!THD_ok_overwrite() && SUMA_filexists (f_name2)) {
4627 fprintf (SUMA_STDERR,
4628 "Error %s: file %s exists, will not overwrite.\n",
4629 FuncName, f_name2);
4630 SUMA_free(f_name2);f_name2 = NULL;
4631 SUMA_free(f_name);f_name = NULL;
4632 SUMA_RETURN (NOPE);
4633 }
4634
4635
4636 /* must have XYZ */
4637 if (SO->NodeDim != 3) {
4638 fprintf (SUMA_STDERR, "Error %s: SO->NodeDim != 3.\n", FuncName);
4639 SUMA_RETURN (NOPE);
4640 }
4641
4642 fout = fopen(f_name2,"w");
4643 if (!fout) {
4644 SUMA_S_Err("Failed to open %s for writing", f_name2);
4645 SUMA_RETURN(NOPE);
4646 }
4647
4648 if (!SO->FaceNormList) SUMA_RECOMPUTE_NORMALS(SO);
4649
4650 /* open either a binary or ascii PLY file for writing */
4651 /* (the file will be called "test.ply" because the routines */
4652 /* enforce the .ply filename extension) */
4653
4654 switch (SO->FileFormat) {
4655 case SUMA_BINARY_BE:
4656 SUMA_S_Err("BINARY_BE not supported");
4657 SUMA_RETURN (NOPE);
4658 break;
4659
4660 case SUMA_BINARY_LE:
4661 case SUMA_BINARY:
4662 {
4663 short ds = 0;
4664 char dummy[80], dhead[81];
4665 snprintf(dummy,60,"SO Label: %s, Written by SUMA",
4666 CHECK_NULL_STR(SO->Label));
4667 snprintf(dhead,80,"%-80s",dummy);
4668 fwrite(dhead, sizeof(char), 80, fout);
4669 for (i=0; i<SO->N_FaceSet; ++i) {
4670 i3 = 3*i;
4671 fwrite(SO->FaceNormList+i3, sizeof(float), 3, fout);
4672 j3[0] = SO->NodeDim * SO->FaceSetList[i3 ];
4673 j3[1] = SO->NodeDim * SO->FaceSetList[i3+1];
4674 j3[2] = SO->NodeDim * SO->FaceSetList[i3+2];
4675 fwrite(SO->NodeList+j3[0], sizeof(float), 3, fout);
4676 fwrite(SO->NodeList+j3[1], sizeof(float), 3, fout);
4677 fwrite(SO->NodeList+j3[2], sizeof(float), 3, fout);
4678 fwrite(&ds, sizeof(short), 1, fout);
4679 }
4680 }
4681 break;
4682
4683 default:
4684 case SUMA_FF_NOT_SPECIFIED:
4685 case SUMA_ASCII:
4686 {
4687 fprintf(fout, "solid %s\n", CHECK_NULL_STR(SO->Label));
4688 for (i=0; i<SO->N_FaceSet; ++i) {
4689 i3 = 3*i;
4690 fprintf(fout, "facet normal %f %f %f\n",
4691 SO->FaceNormList[i3 ],
4692 SO->FaceNormList[i3+1],
4693 SO->FaceNormList[i3+2]);
4694 fprintf(fout, " outer loop\n");
4695 j3[0] = SO->NodeDim * SO->FaceSetList[i3 ];
4696 j3[1] = SO->NodeDim * SO->FaceSetList[i3+1];
4697 j3[2] = SO->NodeDim * SO->FaceSetList[i3+2];
4698 fprintf(fout, " vertex %f %f %f\n"
4699 " vertex %f %f %f\n"
4700 " vertex %f %f %f\n",
4701 SO->NodeList[j3[0] ],
4702 SO->NodeList[j3[0]+1], SO->NodeList[j3[0]+2],
4703 SO->NodeList[j3[1] ],
4704 SO->NodeList[j3[1]+1], SO->NodeList[j3[1]+2],
4705 SO->NodeList[j3[2] ],
4706 SO->NodeList[j3[2]+1], SO->NodeList[j3[2]+2]);
4707 fprintf(fout, " endloop\n");
4708 fprintf(fout, "endfacet\n");
4709 }
4710 fprintf(fout, "endsolid %s\n",CHECK_NULL_STR(SO->Label));
4711 }
4712 break;
4713 }
4714
4715 if (fout) fclose(fout); fout = NULL;
4716 if (f_name) SUMA_free(f_name);
4717 SUMA_free(f_name2); f_name2 = NULL;
4718 SUMA_RETURN (YUP);
4719 }
4720
4721
4722 /*!
4723 \brief Function to write a surface object to a FreeSurfer .asc file format
4724 ans = SUMA_Boolean SUMA_FS_Write (fileNm, SO, firstLine);
4725 \param fileNm (char *) name (and path) of file.
4726 \param SO (SUMA_SurfaceObject *) Surface Object
4727 \param firstLine (char *) string to place as comment (begins with #) in fileNm
4728 \return YUP/NOPE
4729
4730
4731 The function will not overwrite pre-existing.
4732 Written by Brenna Argall
4733 */
SUMA_FS_Write(char * fileNm,SUMA_SurfaceObject * SO,char * firstLine)4734 SUMA_Boolean SUMA_FS_Write (char *fileNm, SUMA_SurfaceObject *SO, char *firstLine)
4735 {
4736 static char FuncName[]={"SUMA_FS_Write"};
4737 int i, j;
4738 FILE *outFile = NULL;
4739
4740 SUMA_ENTRY;
4741
4742 if (!THD_ok_overwrite() && SUMA_filexists(fileNm)) {
4743 fprintf (SUMA_STDERR, "Error %s: file %s exists, will not overwrite.\n",FuncName, fileNm);
4744 SUMA_RETURN (NOPE);
4745 }
4746
4747 if (SO->NodeDim != 3 || SO->FaceSetDim != 3) {
4748 fprintf (SUMA_STDERR, "Error %s: Must have NodeDim and FaceSetDim = 3.\n",FuncName);
4749 SUMA_RETURN (NOPE);
4750 }
4751
4752 outFile = fopen(fileNm, "w");
4753 if (!outFile) {
4754 fprintf (SUMA_STDERR, "Error %s: Failed in opening %s for writing.\n",FuncName, fileNm);
4755 SUMA_RETURN (NOPE);
4756 }
4757
4758 if (firstLine) fprintf (outFile,"#%s\n", firstLine);
4759 else fprintf (outFile,"#!ascii version of FreeSurfer surface\n");
4760 fprintf (outFile, "%d %d\n", SO->N_Node, SO->N_FaceSet);
4761
4762 j=0;
4763 for (i=0; i<SO->N_Node; ++i) {
4764 j=SO->NodeDim * i;
4765 fprintf (outFile, "%f %f %f 0\n", SO->NodeList[j], SO->NodeList[j+1], SO->NodeList[j+2]);
4766 }
4767
4768 j=0;
4769 for (i=0; i<SO->N_FaceSet; ++i) {
4770 j = SO->FaceSetDim * i;
4771 fprintf (outFile, "%d %d %d 0\n", SO->FaceSetList[j], SO->FaceSetList[j+1], SO->FaceSetList[j+2]);
4772 }
4773
4774
4775 fclose(outFile);
4776
4777 SUMA_RETURN (YUP);
4778
4779 }
4780
SUMA_isSOinXformedSpace(SUMA_SurfaceObject * SO,NI_element ** nelp)4781 SUMA_Boolean SUMA_isSOinXformedSpace(SUMA_SurfaceObject *SO, NI_element **nelp)
4782 {
4783 static char FuncName[]={"SUMA_isSOinXformedSpace"};
4784 NI_element *nel=NULL;
4785
4786 SUMA_ENTRY;
4787
4788 if (nelp) *nelp = NULL;
4789
4790 if (!SO || !SO->aSO) {
4791 SUMA_S_Warn("Can't tell, returning NO");
4792 SUMA_RETURN(0);
4793 }
4794 nel = SUMA_FindNgrNamedElement(SO->aSO, "Node_XYZ");
4795 if (nelp) *nelp = nel;
4796 if (!nel) {
4797 SUMA_S_Warn("Can't tell, returning Nein");
4798 SUMA_RETURN(0);
4799 }
4800 SUMA_RETURN(NI_YES_ATTR(nel, "inxformspace"));
4801 }
4802
SUMA_GetSOCoordXform(SUMA_SurfaceObject * SO,double xform[4][4])4803 SUMA_Boolean SUMA_GetSOCoordXform(SUMA_SurfaceObject *SO, double xform[4][4])
4804 {
4805 static char FuncName[]={"SUMA_GetSOCoordXform"};
4806 NI_element *nel=NULL;
4807 double *x1d = NULL;
4808 int i=0,j=0,k=0;
4809 SUMA_ENTRY;
4810
4811 if (!SO || !SO->aSO) { SUMA_RETURN(0);}
4812
4813 if (!(nel = SUMA_FindNgrNamedElement(SO->aSO, "Coord_System"))) {
4814 SUMA_RETURN(0);
4815 }
4816
4817 x1d = (double *)nel->vec[0];
4818 k = 0;
4819 for (i=0; i<4;++i) {
4820 for (j=0; j<4; ++j) {
4821 xform[i][j] = x1d[k];
4822 ++k;
4823 }
4824 }
4825
4826 SUMA_RETURN(YUP);
4827 }
4828
SUMA_PutSOCoordXform(SUMA_SurfaceObject * SO,double xform[4][4])4829 SUMA_Boolean SUMA_PutSOCoordXform(SUMA_SurfaceObject *SO, double xform[4][4])
4830 {
4831 static char FuncName[]={"SUMA_PutSOCoordXform"};
4832 NI_element *nel=NULL;
4833 double *x1d = NULL;
4834 int i=0,j=0,k=0;
4835 SUMA_ENTRY;
4836
4837 if (!SO || !SO->aSO) { SUMA_RETURN(0);}
4838
4839 if (!(nel = SUMA_FindNgrNamedElement(SO->aSO, "Coord_System"))) {
4840 SUMA_RETURN(0);
4841 }
4842 if (nel->vec_num) x1d = (double *)nel->vec[0];
4843 else x1d = (double *)SUMA_calloc(16, sizeof(double));
4844 k = 0;
4845 for (i=0; i<4;++i) {
4846 for (j=0; j<4; ++j) {
4847 x1d[k] = xform[i][j];
4848 ++k;
4849 }
4850 }
4851 if (!nel->vec_num) {
4852 NI_add_column (nel, NI_DOUBLE, x1d);
4853 SUMA_free(x1d); x1d=NULL;
4854 }
4855 SUMA_RETURN(YUP);
4856 }
4857
SUMA_GIFTI_Write(char * fileNm,SUMA_SurfaceObject * SO,SUMA_SO_File_Format forceencode)4858 SUMA_Boolean SUMA_GIFTI_Write ( char *fileNm, SUMA_SurfaceObject *SO,
4859 SUMA_SO_File_Format forceencode)
4860 {
4861 static char FuncName[]={"SUMA_GIFTI_Write"};
4862 int i, j, gii_encode=-1;
4863 float *NodeList=NULL;
4864 double xform[4][4];
4865 NI_group *aSO=NULL;
4866 NI_element *nel=NULL;
4867 FILE *outFile = NULL;
4868 SUMA_Boolean suc = YUP;
4869 SUMA_Boolean LocalHead = NOPE;
4870
4871 SUMA_ENTRY;
4872
4873 suc = YUP;
4874
4875 if (!SO) {
4876 SUMA_S_Err("NULL input");
4877 SUMA_RETURN(NOPE);
4878 }
4879
4880 if (!THD_ok_overwrite() && SUMA_filexists(fileNm)) {
4881 fprintf (SUMA_STDERR,
4882 "Error %s: file %s exists, will not overwrite.\n",
4883 FuncName, fileNm);
4884 SUMA_RETURN (NOPE);
4885 }
4886
4887 if (!SO->aSO) {
4888 SUMA_LH("Adding aSO");
4889 SUMA_MergeAfniSO_In_SumaSO(NULL,SO);
4890 } else {
4891 SUMA_LH("Have aSO");
4892 }
4893
4894 SUMA_LH("Coordinate xform");
4895 /* Are the coordinates transformed? */
4896 if (SUMA_isSOinXformedSpace(SO, &nel)) { /* make copy of nodelist */
4897 SUMA_LH("Copying coords");
4898 NodeList = (float *)SUMA_malloc(sizeof(float)*SO->NodeDim*SO->N_Node);
4899 memcpy( (void *)NodeList,(void *)SO->NodeList,
4900 sizeof(float)*SO->NodeDim*SO->N_Node );
4901 /* undo the transform in coordinate copy*/
4902 if (!SUMA_GetSOCoordXform(SO, xform)) {
4903 SUMA_S_Err("Failed to get xform!");
4904 SUMA_free(NodeList); NodeList = NULL;
4905 SUMA_RETURN(NOPE);
4906 }
4907 if (!SUMA_Apply_Coord_xform(NodeList, SO->N_Node, SO->NodeDim,
4908 xform, 1, NULL)) {
4909 SUMA_S_Err("Failed to apply inverse xform!");
4910 SUMA_free(NodeList); NodeList = NULL;
4911 SUMA_RETURN(NOPE);
4912 }
4913 /* for normals, recomputing may need to be done if
4914 xform is not identity. Not sure what GIFTI definition
4915 is yet */
4916 if (!SUMA_IS_XFORM_IDENTITY(xform)) {
4917 SUMA_S_Warn("Normals are not be properly handled when,\n"
4918 "pointset xform is not identity matrix.");
4919 } else {
4920 SUMA_LH("Xform is identity");
4921 }
4922 } else {
4923 SUMA_LH("Copying coords pointer");
4924 NodeList = SO->NodeList;
4925 }
4926
4927 /* Now fill up aSO */
4928 SUMA_LH("Filling up aSO");
4929 nel = SUMA_FindNgrNamedElement(SO->aSO, "Node_XYZ");
4930 if (nel->vec_num) {
4931 SUMA_S_Crit("Unexpected non NULL coords pointer!");
4932 SUMA_RETURN(NOPE);
4933 }
4934 switch (SO->Side) {
4935 case SUMA_LEFT:
4936 NI_set_attribute(nel,"AnatomicalStructurePrimary", "CortexLeft");
4937 break;
4938 case SUMA_RIGHT:
4939 NI_set_attribute(nel,"AnatomicalStructurePrimary", "CortexRight");
4940 break;
4941 case SUMA_LR:
4942 NI_set_attribute(nel,"AnatomicalStructurePrimary","CortexRightAndLeft");
4943 break;
4944 case SUMA_SIDE_ERROR:
4945 case SUMA_NO_SIDE:
4946 break;
4947 }
4948
4949 /* Now put the Nodelist in the element.
4950 No pointer tricks here, keep niml separate */
4951
4952 NI_add_column(nel, NI_FLOAT, (void*)NodeList);
4953
4954 nel = SUMA_FindNgrNamedElement(SO->aSO, "Mesh_IJK");
4955 if (nel->vec_num) {
4956 SUMA_S_Crit("Unexpected non NULL mesh pointer!");
4957 SUMA_RETURN(NOPE);
4958 }
4959 NI_add_column(nel, NI_INT, (void*)SO->FaceSetList);
4960
4961 nel = SUMA_FindNgrNamedElement(SO->aSO, "Node_Normals");
4962 if (nel->vec_num) {
4963 SUMA_S_Crit("Unexpected non NULL node normals pointer!");
4964 SUMA_RETURN(NOPE);
4965 }
4966 if (SO->NodeNormList) NI_add_column(nel, NI_FLOAT, (void*)SO->NodeNormList);
4967
4968
4969 /* show me aSO */
4970 if (LocalHead) {
4971 SUMA_ShowAfniSurfaceObject( SO->aSO, NULL,
4972 1, "SUMA_GIFTI_Write Debug:\n");
4973 }
4974 /* write it out */
4975 /* gii_encode values set based on #define values in gifti_io.h */
4976 gii_encode = -1;
4977 if (forceencode == SUMA_XML_SURF) {
4978 gii_encode = 0; /* let gii function defaults rule */
4979 } else if (forceencode == SUMA_XML_B64_SURF) {
4980 gii_encode = 2;
4981 } else if (forceencode == SUMA_XML_B64GZ_SURF) {
4982 gii_encode = 3;
4983 } else if (forceencode == SUMA_XML_ASCII_SURF) {
4984 gii_encode = 1;
4985 }
4986
4987 if (!afni_write_gifti_surf(SO->aSO, fileNm, 1, gii_encode)) {
4988 SUMA_S_Errv("Failed to write SO to %s\n", fileNm);
4989 suc = NOPE;
4990 }
4991
4992 /* make sure all is back to initial state */
4993 nel = SUMA_FindNgrNamedElement(SO->aSO, "Node_XYZ");
4994 if (NodeList != SO->NodeList) {
4995 SUMA_free(NodeList); NodeList = NULL;
4996 }
4997 NI_remove_column(nel,0);
4998 nel = SUMA_FindNgrNamedElement(SO->aSO, "Mesh_IJK");
4999 NI_remove_column(nel,0);
5000 nel = SUMA_FindNgrNamedElement(SO->aSO, "Node_Normals");
5001 NI_remove_column(nel,0);
5002
5003 SUMA_RETURN(suc);
5004 }
5005 /*!
5006 \brief Function to write a surface object to a BYU file format
5007 ans = SUMA_Boolean SUMA_BYU_Write (fileNm, SO);
5008 \param fileNm (char *) name (and path) of file.
5009 \param SO (SUMA_SurfaceObject *) Surface Object
5010 \param base1 (int) if (base1) then 1st node is indexed 1 else it is 0
5011 \return YUP/NOPE
5012
5013
5014 The function will not overwrite pre-existing.
5015 Written by Brenna Argall
5016 */
SUMA_BYU_Write(char * fileNm,SUMA_SurfaceObject * SO,int base1)5017 SUMA_Boolean SUMA_BYU_Write (char *fileNm, SUMA_SurfaceObject *SO, int base1)
5018 {
5019 static char FuncName[]={"SUMA_BYU_Write"};
5020 int i, j;
5021 FILE *outFile = NULL;
5022
5023 SUMA_ENTRY;
5024
5025 if (!THD_ok_overwrite() && SUMA_filexists(fileNm)) {
5026 fprintf (SUMA_STDERR, "Error %s: file %s exists, will not overwrite.\n",FuncName, fileNm);
5027 SUMA_RETURN (NOPE);
5028 }
5029
5030 if (SO->NodeDim != 3 || SO->FaceSetDim != 3) {
5031 fprintf (SUMA_STDERR, "Error %s: Must have NodeDim and FaceSetDim = 3.\n",FuncName);
5032 SUMA_RETURN (NOPE);
5033 }
5034
5035 outFile = fopen(fileNm, "w");
5036 if (!outFile) {
5037 fprintf (SUMA_STDERR, "Error %s: Failed in opening %s for writing.\n",FuncName, fileNm);
5038 SUMA_RETURN (NOPE);
5039 }
5040 if (!base1) {
5041 SUMA_S_Warn("Not sure what to do when base1 is off.\n");
5042 }
5043 fprintf (outFile,
5044 "%7d %7d %7d %7d\n %7d %7d\n",
5045 1, SO->N_Node, SO->N_FaceSet,
5046 (SO->EL ? SO->EL->N_Distinct_Edges:-1), (base1 ? 1:0), (base1 ? SO->N_FaceSet:SO->N_FaceSet-1));
5047
5048 j=0;
5049 for (i=0; i<SO->N_Node; ++i) {
5050 j=SO->NodeDim * i;
5051 fprintf (outFile, "%e %e %e \n", SO->NodeList[j], SO->NodeList[j+1], SO->NodeList[j+2]);
5052 }
5053
5054 j=0;
5055 for (i=0; i<SO->N_FaceSet; ++i) {
5056 j = SO->FaceSetDim * i;
5057 if (!base1) {
5058 fprintf (outFile, "%7d %7d %7d\n",
5059 SO->FaceSetList[j], SO->FaceSetList[j+1], -SO->FaceSetList[j+2]);
5060 } else {
5061 fprintf (outFile, "%7d %7d %7d\n",
5062 SO->FaceSetList[j]+1, SO->FaceSetList[j+1]+1, -(SO->FaceSetList[j+2]+1));
5063 }
5064 }
5065
5066
5067 fclose(outFile);
5068
5069 SUMA_RETURN (YUP);
5070
5071 }
5072
5073 /*!
5074 \brief writes the NodeList and FaceSetList of SO to 2 ascii files
5075 ans = SUMA_Boolean SUMA_VEC_Write (SUMA_SFname *Fname, SUMA_SurfaceObject *SO);
5076 \param Fname (SUMA_SFname *) uses the SureFit filename structure to store
5077 the names (and paths) of the NodeList (name_coord)
5078 and the FaceSetList (name_topo) files.
5079 if (strlen(name_coord) == 0) no coord is written
5080 if (strlen(name_topo) == 0) no topo is written
5081 \param SO (SUMA_SurfaceObject *) pointer to SO structure.
5082 \return YUP/NOPE
5083
5084 \sa SUMA_VEC_Read
5085 The function will not overwrite pre-existing files.
5086
5087 */
SUMA_VEC_Write(SUMA_SFname * Fname,SUMA_SurfaceObject * SO)5088 SUMA_Boolean SUMA_VEC_Write (SUMA_SFname *Fname, SUMA_SurfaceObject *SO)
5089 {
5090
5091 static char FuncName[]={"SUMA_VEC_Write"};
5092 int i, j;
5093 FILE *outFile = NULL;
5094
5095 SUMA_ENTRY;
5096
5097 if (strlen(Fname->name_coord)) {
5098 if (!THD_ok_overwrite() && SUMA_filexists(Fname->name_coord)) {
5099 fprintf (SUMA_STDERR, "Error %s: file %s exists, will not overwrite.\n",FuncName, Fname->name_coord);
5100 SUMA_RETURN (NOPE);
5101 }
5102 }
5103 if (strlen(Fname->name_topo)) {
5104 if (!THD_ok_overwrite() && SUMA_filexists(Fname->name_topo)) {
5105 fprintf (SUMA_STDERR, "Error %s: file %s exists, will not overwrite.\n",FuncName, Fname->name_topo);
5106 SUMA_RETURN (NOPE);
5107 }
5108 }
5109 if (SO->NodeDim != 3 || SO->FaceSetDim != 3) {
5110 fprintf (SUMA_STDERR, "Error %s: Must have NodeDim and FaceSetDim = 3.\n",FuncName);
5111 SUMA_RETURN (NOPE);
5112 }
5113
5114 if (strlen(Fname->name_coord)) {
5115 outFile = fopen(Fname->name_coord, "w");
5116 if (!outFile) {
5117 fprintf (SUMA_STDERR, "Error %s: Failed in opening %s for writing.\n",FuncName, Fname->name_coord);
5118 SUMA_RETURN (NOPE);
5119 }
5120
5121 j=0;
5122 for (i=0; i<SO->N_Node; ++i) {
5123 j=SO->NodeDim * i;
5124 fprintf (outFile, "%f %f %f \n", SO->NodeList[j], SO->NodeList[j+1], SO->NodeList[j+2]);
5125 }
5126
5127 fclose (outFile);
5128 }
5129
5130 if (strlen(Fname->name_topo)) {
5131 outFile = fopen(Fname->name_topo, "w");
5132 if (!outFile) {
5133 fprintf (SUMA_STDERR, "Error %s: Failed in opening %s for writing.\n",FuncName, Fname->name_topo);
5134 SUMA_RETURN (NOPE);
5135 }
5136 j=0;
5137 for (i=0; i<SO->N_FaceSet; ++i) {
5138 j = SO->FaceSetDim * i;
5139 fprintf (outFile, "%d %d %d\n", SO->FaceSetList[j], SO->FaceSetList[j+1], SO->FaceSetList[j+2]);
5140 }
5141
5142 fclose (outFile);
5143 }
5144
5145 SUMA_RETURN (YUP);
5146
5147 }
5148
5149 /*!
5150 \brief function to read 1D (vec) format surfaces
5151 \sa SUMA_VEC_Write
5152 */
SUMA_VEC_Read(SUMA_SFname * Fname,SUMA_SurfaceObject * SO)5153 SUMA_Boolean SUMA_VEC_Read(SUMA_SFname *Fname, SUMA_SurfaceObject *SO)
5154 {
5155 static char FuncName[]={"SUMA_VEC_Read"};
5156 MRI_IMAGE *im = NULL;
5157 float *far=NULL;
5158 int icnt;
5159 SUMA_Boolean LocalHead = NOPE;
5160
5161 SUMA_ENTRY;
5162
5163 if (!SO || !Fname) {
5164 SUMA_SL_Err("NULL input");
5165 SUMA_RETURN(NOPE);
5166 }
5167 if (SO->NodeList || SO->FaceSetList) {
5168 SUMA_SL_Err("Non NULL SO->NodeList || SO->FaceSetList");
5169 SUMA_RETURN(NOPE);
5170 }
5171
5172 im = mri_read_1D (Fname->name_coord);
5173 if (!im) {
5174 SUMA_SLP_Err("Failed to read 1D file");
5175 SUMA_RETURN(NOPE);
5176 }
5177 far = MRI_FLOAT_PTR(im);
5178 SO->N_Node = im->nx;
5179 SO->NodeDim = im->ny;
5180 if (!SO->N_Node) {
5181 SUMA_SL_Err("Empty file");
5182 SUMA_RETURN(NOPE);
5183 }
5184 if (SO->NodeDim != 3 ) {
5185 SUMA_SL_Err("File must have\n"
5186 "3 columns.");
5187 mri_free(im); im = NULL; /* done with that baby */
5188 SUMA_RETURN(NOPE);
5189 }
5190
5191 SO->NodeList = (float *)SUMA_calloc (SO->N_Node*SO->NodeDim, sizeof(float));
5192 if (!SO->NodeList) {
5193 fprintf(SUMA_STDERR,"Error %s: Failed to allocate for NodeList.\n", FuncName);
5194 if (SO->NodeList) SUMA_free(SO->NodeList);
5195 if (SO->FaceSetList) SUMA_free(SO->FaceSetList);
5196 SUMA_RETURN (NOPE);
5197 }
5198
5199 for (icnt=0; icnt < SO->N_Node; ++icnt) {
5200 SO->NodeList[3*icnt] = far[icnt];
5201 SO->NodeList[3*icnt+1] = far[icnt+SO->N_Node];
5202 SO->NodeList[3*icnt+2] = far[icnt+2*SO->N_Node];
5203 }
5204 #if 0
5205 if (LocalHead) {
5206 fprintf (SUMA_STDERR,"%s: SO->NodeList\n Node 0: %f, %f, %f \n Node %d: %f, %f, %f \n",
5207 FuncName,
5208 SO->NodeList[0], SO->NodeList[1], SO->NodeList[2], SO->N_Node -1,
5209 SO->NodeList[3*(SO->N_Node-1)], SO->NodeList[3*(SO->N_Node-1)+1], SO->NodeList[3*(SO->N_Node-1)+2]);
5210 }
5211 #endif
5212 mri_free(im); im = NULL;
5213
5214 im = mri_read_1D (Fname->name_topo);
5215 if (!im) {
5216 SUMA_SL_Err("Failed to read 1D file");
5217 SUMA_RETURN(NOPE);
5218 }
5219 far = MRI_FLOAT_PTR(im);
5220 SO->N_FaceSet = im->nx;
5221 SO->FaceSetDim = im->ny;
5222 if (!SO->N_FaceSet) {
5223 SUMA_SL_Err("Empty file");
5224 SUMA_RETURN(NOPE);
5225 }
5226 if (SO->FaceSetDim != 3 ) {
5227 SUMA_SL_Err("File must have\n"
5228 "3 columns.");
5229 mri_free(im); im = NULL; /* done with that baby */
5230 SUMA_RETURN(NOPE);
5231 }
5232
5233 SO->FaceSetList = (int *)SUMA_calloc (SO->N_FaceSet*SO->FaceSetDim, sizeof(int));
5234 if (!SO->FaceSetList) {
5235 fprintf(SUMA_STDERR,"Error %s: Failed to allocate for FaceSetList.\n", FuncName);
5236 if (SO->NodeList) SUMA_free(SO->NodeList);
5237 if (SO->FaceSetList) SUMA_free(SO->FaceSetList);
5238 SUMA_RETURN (NOPE);
5239 }
5240
5241 for (icnt=0; icnt < SO->N_FaceSet; ++icnt) {
5242 SO->FaceSetList[3*icnt] = (int)far[icnt];
5243 SO->FaceSetList[3*icnt+1] = (int)far[icnt+SO->N_FaceSet];
5244 SO->FaceSetList[3*icnt+2] = (int)far[icnt+2*SO->N_FaceSet];
5245 }
5246
5247 if (LocalHead) {
5248 fprintf (SUMA_STDERR,"%s: SO->FaceSetList\n Node 0: %d, %d, %d \n Node %d: %d, %d, %d \n",
5249 FuncName,
5250 SO->FaceSetList[0], SO->FaceSetList[1], SO->FaceSetList[2], SO->N_FaceSet -1,
5251 SO->FaceSetList[3*(SO->N_FaceSet-1)], SO->FaceSetList[3*(SO->N_FaceSet-1)+1], SO->FaceSetList[3*(SO->N_FaceSet-1)+2]);
5252 }
5253 mri_free(im); im = NULL;
5254
5255 SUMA_RETURN(YUP);
5256 }
5257
5258 /*!
5259 \brief A function to write a Surface Object into a Surefit ascii format
5260 \param F_prefix (char *) Prefix of surace filenames. Output will be of the form:
5261 Prefix.N_NODE.topo
5262 Prefix.N_NODE.coord where N_Node is the number of nodes making up the surface.
5263 \param SO (SUMA_SurfaceObject *) surface object
5264 \return YUP/NOPE
5265
5266 */
5267
5268
5269
5270 /*!
5271 \brief Handles opening an ROI file
5272 \param filename (char *)
5273 \param data(void *)
5274
5275 - results are placed in SUMAg_DOv
5276
5277 */
SUMA_OpenDrawnROI(char * filename,void * data)5278 void SUMA_OpenDrawnROI (char *filename, void *data)
5279 {
5280 static char FuncName[]={"SUMA_OpenDrawnROI"};
5281 DList *list=NULL;
5282 SUMA_DRAWN_ROI **ROIv=NULL;
5283 int i, N_ROI;
5284 SUMA_SurfaceObject *SO=NULL, *SOp=NULL;
5285 SUMA_OVERLAYS *over=NULL;
5286 SUMA_SurfaceViewer *sv = (SUMA_SurfaceViewer *)data;
5287 SUMA_Boolean LocalHead = NOPE;
5288
5289 SUMA_ENTRY;
5290
5291 SUMA_LH("Called");
5292
5293 if (!sv) sv = &(SUMAg_SVv[0]);
5294
5295 /* check for type ... */
5296
5297 if (SUMA_isExtension(filename, ".niml.roi")) {
5298 /* load niml ROI */
5299 if (!( ROIv = SUMA_OpenDrawnROI_NIML (filename, &N_ROI, YUP, sv))) {
5300 SUMA_SLP_Err("Failed to read NIML ROI.");
5301 SUMA_RETURNe;
5302 }
5303 }else if (SUMA_isExtension(filename, ".1D.roi")) {
5304 /* load 1D ROI */
5305 /* You need to select a parent surface */
5306 SUMA_SLP_Warn("Assuming parent surface.");
5307 if ((SO = SUMA_SV_Focus_SO(sv))) {
5308 if (SO->N_patchNode < SO->N_Node || SO->patchNodeMask) {
5309 SUMA_S_Note("Assigning ROI to domain parent");
5310 if (!(SOp = SUMA_findSOp_inDOv(SO->LocalDomainParentID,
5311 SUMAg_DOv, SUMAg_N_DOv))) {
5312 SUMA_S_Note("Failed to find LDP, sticking with initial surf");
5313 /* continue ...*/
5314 }else {
5315 SO = SOp;
5316 }
5317 }
5318 if (!( ROIv = SUMA_OpenDrawnROI_1D (filename, SO->idcode_str,
5319 &N_ROI, YUP))) {
5320 SUMA_SLP_Err("Failed to read NIML ROI.");
5321 SUMA_RETURNe;
5322 }
5323 } else {
5324 SUMA_SLP_Err("Have no surface in focus. Can't load ROI\n"
5325 "Select a surface and try again.");
5326 SUMA_RETURNe;
5327 }
5328 }else {
5329 SUMA_SLP_Err( "Failed to recognize\n"
5330 "ROI type from filename.");
5331 SUMA_RETURNe;
5332 }
5333
5334 /* put those ROIs in SUMAg_DOv */
5335 for (i=0; i < N_ROI; ++i) {
5336 /* add ROI to DO list */
5337 if (!SUMA_AddDO ( SUMAg_DOv, &SUMAg_N_DOv,
5338 (void *)ROIv[i], ROIdO_type, SUMA_WORLD)) {
5339 fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AddDO.\n", FuncName);
5340 }
5341 }
5342 /* free ROIv */
5343 if (ROIv) SUMA_free(ROIv); ROIv = NULL;
5344
5345 /* if there are no currentROIs selected, set currentROI to the
5346 first in the list */
5347 if (!SUMAg_CF->X->DrawROI->curDrawnROI) {
5348 i = 0;
5349 do {
5350 if (SUMAg_DOv[i].ObjectType == ROIdO_type)
5351 SUMAg_CF->X->DrawROI->curDrawnROI =
5352 (SUMA_DRAWN_ROI *)SUMAg_DOv[i].OP;
5353 ++i;
5354 } while (i < SUMAg_N_DOv && !SUMAg_CF->X->DrawROI->curDrawnROI);
5355 }
5356
5357 if (SUMAg_CF->X->DrawROI->curDrawnROI) {
5358 SUMA_InitializeDrawROIWindow(SUMAg_CF->X->DrawROI->curDrawnROI);
5359 }
5360
5361 /* Now update the Paint job on the ROI plane */
5362 SO = SUMA_findSOp_inDOv(
5363 SUMAg_CF->X->DrawROI->curDrawnROI->Parent_idcode_str,
5364 SUMAg_DOv, SUMAg_N_DOv);
5365 if (!SUMA_Paint_SO_ROIplanes_w (SO, SUMAg_DOv, SUMAg_N_DOv)) {
5366 SUMA_SLP_Err("Failed in SUMA_Paint_SO_ROIplanes_w.");
5367 SUMA_RETURNe;
5368 }
5369
5370 /* find the overlay plane */
5371 over = SUMA_Fetch_OverlayPointer(
5372 (SUMA_ALL_DO *)SO,
5373 SUMAg_CF->X->DrawROI->curDrawnROI->ColPlaneName,
5374 &i);
5375 if (over) SUMA_InitializeColPlaneShell((SUMA_ALL_DO *)SO, over);
5376
5377 /* put a nice redisplay here */
5378 if (!list) list = SUMA_CreateList ();
5379 SUMA_REGISTER_TAIL_COMMAND_NO_DATA( list, SE_Redisplay_AllVisible,
5380 SES_Suma, NULL);
5381 if (!SUMA_Engine(&list)) {
5382 SUMA_SLP_Err("Failed to redisplay.");
5383 SUMA_RETURNe;
5384 }
5385
5386
5387 SUMA_RETURNe;
5388 }
5389
5390 /*!
5391 Since parent information does not exist in ROI 1D files,
5392 you need to specify the parent surface.
5393
5394 ans = SUMA_OpenDrawnROI_1D (filename, Parent_idcode_str);
5395
5396 \param filename (char *) name of 1D file (see below for formats)
5397 \param Parent_idcode_str (char *) idcode of parent surface
5398 \param N_ROI (int *) will contain the number of ROIs read in
5399 \param ForDisplay (SUMA_Boolean) YUP: prepares ROI for display
5400 \return ans (SUMA_Boolean) YUP for good NOPE for not good.
5401
5402 - The ROI is added to SUMAg_DOv
5403
5404 - The 1D file can have multiple formats. Some are particularly
5405 inefficient and should not be used. But we aim to please so
5406 anything goes. You can have a varying number of columns which
5407 are i, l, r, g, b. These columns stand for index, label, red,
5408 green and blue, respectively.
5409 * format 1: i
5410 Only a bunch of node (int) indices are supplied. Label of all nodes
5411 defaults to 0 and a default color is given
5412 * format 2: i l
5413 Each node carries a label (int) with it. This way you can
5414 have multiple ROIs specified in one 1D file. The same
5415 color is assigned to each of the ROIs.
5416 * format 3: i r g b
5417 A bunch of nodes with r g b (float) triplet specifying the nodes'
5418 colors. Obviously, since all nodes belong to the same ROI,
5419 the specification of an r g b for each node is redundant since
5420 all nodes in the same ROI have the same color. Use the
5421 niml format if that sounds crazy to you. If you want a different
5422 color for each node then you should not load the data as an ROI
5423 but as a node color file.
5424 * format 4: i l r g b
5425 A bunch of nodes with labels and r g b .
5426 Like format 2 but with the possibility of specifying the colors of
5427 each ROI.
5428
5429 */
SUMA_OpenDrawnROI_1D(char * filename,char * Parent_idcode_str,int * N_ROI,SUMA_Boolean ForDisplay)5430 SUMA_DRAWN_ROI ** SUMA_OpenDrawnROI_1D (char *filename, char *Parent_idcode_str,
5431 int *N_ROI, SUMA_Boolean ForDisplay)
5432 {
5433 static char FuncName[]={"SUMA_OpenDrawnROI_1D"};
5434 MRI_IMAGE *im = NULL;
5435 int ncol, nrow ;
5436 float *far=NULL;
5437 SUMA_DRAWN_ROI **ROIv=NULL;
5438 SUMA_Boolean LocalHead = NOPE;
5439
5440 SUMA_ENTRY;
5441
5442 SUMA_LH("Called");
5443
5444 *N_ROI = 0;
5445
5446 im = mri_read_1D (filename);
5447
5448 if (!im) {
5449 SUMA_SLP_Err("Failed to read 1D file");
5450 SUMA_RETURN(NULL);
5451 }
5452
5453 far = MRI_FLOAT_PTR(im);
5454 ncol = im->nx;
5455 nrow = im->ny;
5456
5457 if (!ncol) {
5458 SUMA_SL_Err("Empty file");
5459 SUMA_RETURN(NULL);
5460 }
5461 if (nrow != 1 && nrow != 2 && nrow != 4 && nrow != 5) {
5462 SUMA_SL_Err("File must have\n"
5463 " 1,2,4 or 5 columns.");
5464 mri_free(im); im = NULL; /* done with that baby */
5465 SUMA_RETURN(NULL);
5466 }
5467
5468 if (0 && LocalHead) {
5469 SUMA_disp_vect(far, ncol*nrow);
5470 }
5471
5472 switch (nrow) {
5473 case 1:
5474 /* Node index only*/
5475 ROIv= SUMA_MultiColumnsToDrawnROI(ncol,
5476 (void*)far, SUMA_float,
5477 (void*)NULL, SUMA_float,
5478 (void*)NULL, SUMA_float,
5479 (void*)NULL, SUMA_float,
5480 (void*)NULL, SUMA_float,
5481 NULL, 0, filename,
5482 Parent_idcode_str, N_ROI, ForDisplay, 0);
5483 break;
5484 case 2:
5485 /* Node index & Node Label */
5486 ROIv= SUMA_MultiColumnsToDrawnROI(ncol,
5487 (void*)far, SUMA_float,
5488 (void*)(far+ncol), SUMA_float,
5489 (void*)NULL, SUMA_float,
5490 (void*)NULL, SUMA_float,
5491 (void*)NULL, SUMA_float,
5492 NULL, 0, filename,
5493 Parent_idcode_str, N_ROI, ForDisplay, 0);
5494 break;
5495 case 4:
5496 /* Node index & R G B */
5497 ROIv= SUMA_MultiColumnsToDrawnROI(ncol,
5498 (void*)far, SUMA_float,
5499 (void*)(far+ncol), SUMA_float,
5500 (void*)(far+2*ncol), SUMA_float,
5501 (void*)(far+3*ncol), SUMA_float,
5502 (void*)NULL, SUMA_float,
5503 NULL, 0, filename,
5504 Parent_idcode_str, N_ROI, ForDisplay, 0);
5505 break;
5506 case 5:
5507 /* Node index, Node Label, R G B */
5508 ROIv= SUMA_MultiColumnsToDrawnROI(ncol,
5509 (void*)far, SUMA_float,
5510 (void*)(far+ncol), SUMA_float,
5511 (void*)(far+2*ncol), SUMA_float,
5512 (void*)(far+3*ncol), SUMA_float,
5513 (void*)(far+4*ncol), SUMA_float,
5514 NULL, 0, filename,
5515 Parent_idcode_str, N_ROI, ForDisplay, 0);
5516 break;
5517 default:
5518 SUMA_S_Errv("Bad number of columns (%d) in %s\n"
5519 "Only 1, 2, 4, and 5 allowed\n",
5520 nrow, filename);
5521 break;
5522 }
5523 mri_free(im); im = NULL; /* done with that baby */
5524 SUMA_RETURN(ROIv);
5525 }
5526 /*! \brief, given a set of vectors, turn them into a drawn ROI
5527 The manner is which the columns are interpreted is detailed
5528 in the help for SUMA_OpenDrawnROI_1D
5529
5530 N_Nodes (int) Number of nodes in ind
5531
5532 ind (void *) Node indices. A mandatory vector containing the
5533 indices of nodes to include in the ROI
5534 ind_type (SUMA_VARTYPE) SUMA_int or SUMA_float. This is used
5535 to type cast ind
5536
5537 col0 (void *) Label attached to each node in ind
5538 col0_type (SUMA_VARTYPE) type of col0
5539
5540 col1 (void *)
5541 col1_type
5542
5543 ...
5544
5545 col3 (void *)
5546 col3_type
5547
5548 if all of col* are NULL, then this is like a one column 1D file
5549 input to SUMA_OpenDrawnROI_1D
5550 if only col0 is set, then this is like a 2 column 1D file
5551 if only col3 is NULL then this is like a 4 column 1D file
5552 if none are NULL then that is the 5 column 1D file
5553 */
5554
SUMA_MultiColumnsToDrawnROI(int N_Nodes,void * ind,SUMA_VARTYPE ind_type,void * col0,SUMA_VARTYPE col0_type,void * col1,SUMA_VARTYPE col1_type,void * col2,SUMA_VARTYPE col2_type,void * col3,SUMA_VARTYPE col3_type,SUMA_COLOR_MAP * cmap,int edges_only,char * name,char * Parent_idcode_str,int * N_ROI,SUMA_Boolean ForDisplay,SUMA_Boolean LabelIsCmapIndex)5555 SUMA_DRAWN_ROI **SUMA_MultiColumnsToDrawnROI(
5556 int N_Nodes,
5557 void *ind, SUMA_VARTYPE ind_type,
5558 void *col0, SUMA_VARTYPE col0_type,
5559 void *col1, SUMA_VARTYPE col1_type,
5560 void *col2, SUMA_VARTYPE col2_type,
5561 void *col3, SUMA_VARTYPE col3_type,
5562 SUMA_COLOR_MAP *cmap,
5563 int edges_only,
5564 char *name, char *Parent_idcode_str,
5565 int *N_ROI, SUMA_Boolean ForDisplay,
5566 SUMA_Boolean LabelIsCmapIndex)
5567
5568 {
5569 static char FuncName[]={"SUMA_MultiColumnsToDrawnROI"};
5570 char smapflag[32];
5571 int *iv=NULL;
5572 float *fv=NULL;
5573 int ncol=0, nc;
5574 int nrow=0;
5575 int *iLabel=NULL, *iNode = NULL, *isort=NULL,
5576 i, N_Labels = 0, *iStart=NULL, *iStop=NULL,
5577 cnt = 0, ilmax = 0;
5578 float *r=NULL, *g=NULL, *b=NULL, *RGB=NULL, acol[4]={1.0, 0.0, 0.0, 1.0};
5579 SUMA_DRAWN_ROI **ROIv=NULL;
5580 SUMA_Boolean LocalHead = NOPE;
5581
5582 SUMA_ENTRY;
5583
5584 if (ind) ++nrow;
5585 if (col0) ++nrow;
5586 if (col1) ++nrow;
5587 if (col2) ++nrow;
5588 if (col3) ++nrow;
5589 ncol = N_Nodes;
5590
5591 if (!ind || !N_Nodes) {
5592 SUMA_S_Err("NULL index, or no nodes");
5593 SUMA_RETURN(NULL);
5594 }
5595 if ( (ind_type != SUMA_float && ind_type != SUMA_int) ) {
5596 SUMA_S_Err("Bad index type");
5597 SUMA_RETURN(NULL);
5598 }
5599 if ( (col0 && col0_type != SUMA_float && col0_type != SUMA_int) ) {
5600 SUMA_S_Err("Bad col0 type");
5601 SUMA_RETURN(NULL);
5602 }
5603 if ( (col1 && col1_type != SUMA_float && col1_type != SUMA_int) ) {
5604 SUMA_S_Err("Bad col1 type");
5605 SUMA_RETURN(NULL);
5606 }
5607 if ( (col2 && col2_type != SUMA_float && col2_type != SUMA_int) ) {
5608 SUMA_S_Err("Bad col2 type");
5609 SUMA_RETURN(NULL);
5610 }
5611 if ( (col3 && col3_type != SUMA_float && col3_type != SUMA_int) ) {
5612 SUMA_S_Err("Bad col3 type");
5613 SUMA_RETURN(NULL);
5614 }
5615 if (nrow != 1 && nrow != 2 && nrow != 4 && nrow != 5) {
5616 SUMA_S_Err("Bad number of input columns");
5617 SUMA_RETURN(NULL);
5618 }
5619
5620 switch (nrow) {
5621 case 1:
5622 /* Node index only*/
5623 SUMA_LH ("1D format: i");
5624 iNode = (int *)SUMA_malloc(ncol*sizeof(int));
5625 iLabel = (int *)SUMA_malloc(1*sizeof(int));
5626 if (!iNode ||!iLabel) {
5627 SUMA_SL_Err("Failed to allocate");
5628 SUMA_RETURN(NULL);
5629 }
5630 if (ind_type == SUMA_float) {
5631 fv = (float *)ind;
5632 for (i=0; i < ncol; ++i) iNode[i] = (int)fv[i];
5633 } else if (ind_type == SUMA_int) {
5634 iv = (int *)ind;
5635 for (i=0; i < ncol; ++i) iNode[i] = iv[i];
5636 }
5637
5638 iLabel[0] = 0;
5639 N_Labels = 1;
5640 iStart = (int *)SUMA_malloc(1*sizeof(int));
5641 iStop = (int *)SUMA_malloc(1*sizeof(int));
5642 RGB = (float *)SUMA_malloc(3*1*sizeof(float));
5643 iStart[0] = 0;
5644 iStop[0] = ncol-1;
5645 RGB[0] = 1.0; RGB[1] = 1.0; RGB[2] = 0;
5646 break;
5647 case 2:
5648 /* Node index & Node Label */
5649 SUMA_LH("1D format: i l");
5650 /* copy the node indices and labels for cleanliness */
5651 iLabel = (int *)SUMA_malloc(ncol*sizeof(int));
5652 iNode = (int *)SUMA_malloc(ncol*sizeof(int));
5653 if (!iNode || !iLabel) {
5654 SUMA_SL_Err("Failed to allocate");
5655 SUMA_RETURN(NULL);
5656 }
5657 if (col0_type == SUMA_float) {
5658 fv = (float*)col0;
5659 for (i=0; i < ncol; ++i) iLabel[i] = (int)fv[i];
5660 } else if (col0_type == SUMA_int) {
5661 iv = (int *)col0;
5662 for (i=0; i < ncol; ++i) iLabel[i] = (int)iv[i];
5663 }
5664 /* sort the Labels and the iNode accordingly */
5665 isort = SUMA_z_dqsort( iLabel, ncol);
5666 if (ind_type == SUMA_float) {
5667 fv = (float *)ind;
5668 for (i=0; i < ncol; ++i) iNode[i] = (int)fv[isort[i]];
5669 } else if (ind_type == SUMA_int) {
5670 iv = (int *)ind;
5671 for (i=0; i < ncol; ++i) iNode[i] = iv[isort[i]];
5672 }
5673
5674 /* Count the number of distinct labels */
5675 N_Labels = 1;
5676 for (i=1; i < ncol; ++i) if (iLabel[i] != iLabel[i-1]) ++N_Labels;
5677 sprintf(smapflag, "%d", N_Labels);
5678 /* store where each label begins and ends */
5679 iStart = (int *)SUMA_malloc(N_Labels*sizeof(int));
5680 iStop = (int *)SUMA_malloc(N_Labels*sizeof(int));
5681 RGB = (float *)SUMA_malloc(3*N_Labels*sizeof(float));
5682 if (!iStart || !iStop) {
5683 SUMA_SL_Err("Failed to allocate");
5684 SUMA_RETURN(NULL);
5685 }
5686 cnt = 0;
5687 iStart[cnt] = 0;
5688 iStop[cnt] = ncol -1;
5689 if (cmap) {
5690 ilmax = cmap->N_M[0]-1;
5691 if (!LabelIsCmapIndex) {
5692 nc = SUMA_ColMapKeyIndex(iLabel[0],cmap);
5693 } else {
5694 nc = SUMA_MIN_PAIR(iLabel[0], ilmax);
5695 }
5696 if (nc < 0) {
5697 RGB[3*cnt] = -1.0; RGB[3*cnt+1] = -1.0; RGB[3*cnt+2] = -1.0;
5698 } else {
5699 RGB[3*cnt] = cmap->M[nc][0];
5700 RGB[3*cnt+1] = cmap->M[nc][1];
5701 RGB[3*cnt+2] = cmap->M[nc][2];
5702 }
5703 SUMA_LHv("cmap %p chd %p (%s), %d, ilabel %d at node %d, \n"
5704 " col %f %f %f\n",
5705 cmap, cmap->chd, cmap->Name,
5706 cnt, iLabel[0], iNode[0],
5707 RGB[3*cnt], RGB[3*cnt+1], RGB[3*cnt+2]);
5708 } else {
5709 SUMA_a_good_col(smapflag,iLabel[0], acol);
5710 RGB[3*cnt] = acol[0]; RGB[3*cnt+1] = acol[1]; RGB[3*cnt+2] = acol[2];
5711 }
5712 for (i=1; i < ncol; ++i) {
5713 if (iLabel[i] != iLabel[i-1]) {
5714 iStop[cnt] = i-1;
5715 ++cnt;
5716 iStart[cnt] = i;
5717 iStop[cnt] = ncol -1;
5718 if (cmap) {
5719 if (!LabelIsCmapIndex) {
5720 nc = SUMA_ColMapKeyIndex(iLabel[i],cmap);
5721 } else {
5722 nc = SUMA_MIN_PAIR(iLabel[i], ilmax);
5723 }
5724 if ((nc) >= 0) {
5725 RGB[3*cnt] = cmap->M[nc][0];
5726 RGB[3*cnt+1] = cmap->M[nc][1];
5727 RGB[3*cnt+2] = cmap->M[nc][2];
5728 } else {
5729 RGB[3*cnt] = -1.0; RGB[3*cnt+1] = -1.0; RGB[3*cnt+2] = -1.0;
5730 }
5731 } else {
5732 SUMA_a_good_col(smapflag, iLabel[i], acol);
5733 RGB[3*cnt] = acol[0]; RGB[3*cnt+1] = acol[1];
5734 RGB[3*cnt+2] = acol[2];
5735
5736 }
5737 }
5738 }
5739 break;
5740 case 4:
5741 /* Node index, R G B */
5742 SUMA_LH("1D format: i R G B");
5743 iNode = (int *)SUMA_malloc(ncol*sizeof(int));
5744 iLabel = (int *)SUMA_malloc(1*sizeof(int));
5745 r = (float *)SUMA_malloc(ncol*sizeof(float));
5746 g = (float *)SUMA_malloc(ncol*sizeof(float));
5747 b = (float *)SUMA_malloc(ncol*sizeof(float));
5748 if (!iNode || !iLabel || !r || !g || !b) {
5749 SUMA_SL_Err("Failed to allocate");
5750 SUMA_RETURN(NULL);
5751 }
5752
5753 if (ind_type == SUMA_float) {
5754 fv = (float *)ind;
5755 for (i=0; i < ncol; ++i) iNode[i] = (int)fv[i];
5756 } else if (ind_type == SUMA_int) {
5757 iv = (int *)ind;
5758 for (i=0; i < ncol; ++i) iNode[i] = iv[i];
5759 }
5760 if (col0_type == SUMA_float) {
5761 fv = (float *)col0;
5762 for (i=0; i < ncol; ++i) r[i] = fv[i];
5763 } else {
5764 iv = (int *)col0;
5765 for (i=0; i < ncol; ++i) r[i] = (float)iv[i];
5766 }
5767 if (col1_type == SUMA_float) {
5768 fv = (float *)col1;
5769 for (i=0; i < ncol; ++i) g[i] = fv[i];
5770 } else {
5771 iv = (int *)col1;
5772 for (i=0; i < ncol; ++i) g[i] = (float)iv[i];
5773 }
5774 if (col2_type == SUMA_float) {
5775 fv = (float *)col2;
5776 for (i=0; i < ncol; ++i) b[i] = fv[i];
5777 } else {
5778 iv = (int *)col2;
5779 for (i=0; i < ncol; ++i) b[i] = (float)iv[i];
5780 }
5781
5782
5783 iLabel[0] = 0;
5784 N_Labels = 1;
5785 iStart = (int *)SUMA_malloc(1*sizeof(int));
5786 iStop = (int *)SUMA_malloc(1*sizeof(int));
5787 RGB = (float *)SUMA_malloc(3*1*sizeof(float));
5788
5789 iStart[0] = 0;
5790 iStop[0] = ncol-1;
5791 RGB[0] = r[0]; RGB[1] = g[0]; RGB[2] = b[0];
5792 break;
5793 case 5:
5794 /* Node index, Node Label, R G B */
5795 SUMA_LH("1D format: i l R G B");
5796 /* copy the node indices and labels for cleanliness */
5797 iLabel = (int *)SUMA_malloc(ncol*sizeof(int));
5798 iNode = (int *)SUMA_malloc(ncol*sizeof(int));
5799 r = (float *)SUMA_malloc(ncol*sizeof(float));
5800 g = (float *)SUMA_malloc(ncol*sizeof(float));
5801 b = (float *)SUMA_malloc(ncol*sizeof(float));
5802 if (!iNode || !iLabel || !r || !g || !b) {
5803 SUMA_SL_Err("Failed to allocate");
5804 SUMA_RETURN(NULL);
5805 }
5806
5807
5808 if (col0_type == SUMA_float) {
5809 fv = (float*)col0;
5810 for (i=0; i < ncol; ++i) iLabel[i] = (int)fv[i];
5811 } else if (col0_type == SUMA_int) {
5812 iv = (int *)col0;
5813 for (i=0; i < ncol; ++i) iLabel[i] = (int)iv[i];
5814 }
5815 /* sort the Labels and the iNode accordingly */
5816 isort = SUMA_z_dqsort( iLabel, ncol);
5817 if (ind_type == SUMA_float) {
5818 fv = (float *)ind;
5819 for (i=0; i < ncol; ++i) iNode[i] = (int)fv[isort[i]];
5820 } else if (ind_type == SUMA_int) {
5821 iv = (int *)ind;
5822 for (i=0; i < ncol; ++i) iNode[i] = iv[isort[i]];
5823 }
5824
5825
5826 if (col1_type == SUMA_float) {
5827 fv = (float *)col1;
5828 for (i=0; i < ncol; ++i) r[i] = fv[isort[i]];
5829 } else {
5830 iv = (int *)col1;
5831 for (i=0; i < ncol; ++i) r[i] = (float)iv[isort[i]];
5832 }
5833 if (col2_type == SUMA_float) {
5834 fv = (float *)col2;
5835 for (i=0; i < ncol; ++i) g[i] = fv[isort[i]];
5836 } else {
5837 iv = (int *)col2;
5838 for (i=0; i < ncol; ++i) g[i] = (float)iv[isort[i]];
5839 }
5840 if (col3_type == SUMA_float) {
5841 fv = (float *)col3;
5842 for (i=0; i < ncol; ++i) b[i] = fv[isort[i]];
5843 } else {
5844 iv = (int *)col3;
5845 for (i=0; i < ncol; ++i) b[i] = (float)iv[isort[i]];
5846 }
5847
5848
5849 /* Count the number of distinct labels */
5850 N_Labels = 1;
5851 for (i=1; i < ncol; ++i) if (iLabel[i] != iLabel[i-1]) ++N_Labels;
5852 /* store where each label begins and ends */
5853 iStart = (int *)SUMA_malloc(N_Labels*sizeof(int));
5854 iStop = (int *)SUMA_malloc(N_Labels*sizeof(int));
5855 RGB = (float *)SUMA_malloc(3*N_Labels*sizeof(float));
5856 if (!iStart || !iStop || !RGB) {
5857 SUMA_SL_Err("Failed to allocate");
5858 SUMA_RETURN(NULL);
5859 }
5860 cnt = 0;
5861 iStart[cnt] = 0;
5862 iStop[cnt] = ncol -1;
5863 RGB[3*cnt] = r[0]; RGB[3*cnt+1] = g[0]; RGB[3*cnt+2] = b[0];
5864 for (i=1; i < ncol; ++i) {
5865 if (iLabel[i] != iLabel[i-1]) {
5866 iStop[cnt] = i-1;
5867 ++cnt;
5868 iStart[cnt] = i;
5869 iStop[cnt] = ncol -1;
5870 RGB[3*cnt] = r[i]; RGB[3*cnt+1] = g[i]; RGB[3*cnt+2] = b[i];
5871 }
5872 }
5873 break;
5874 default:
5875 SUMA_S_Err("Bad function input. Have cols\n"
5876 "Accepting only 1, 2, 4, and 5\n");
5877 break;
5878 }
5879
5880
5881 ROIv = (SUMA_DRAWN_ROI **)SUMA_calloc(N_Labels,sizeof(SUMA_DRAWN_ROI*));
5882
5883 for (i=0; i < N_Labels; ++i) {
5884 int Value, N_Node, *Node=NULL;
5885 float fillcolor[3], edgecolor[3];
5886 int edgethickness;
5887 char stmp[20], *Label=NULL;
5888 SUMA_PARSED_NAME *NewName=NULL;
5889
5890 edgethickness = 3;
5891 fillcolor[0] = RGB[3*i];
5892 fillcolor[1] = RGB[3*i+1];
5893 fillcolor[2] = RGB[3*i+2];
5894 edgecolor[0] = 0; edgecolor[1] = 0; edgecolor[2] = 1;
5895 Value = iLabel[iStart[i]]; /* the index label of this ROI */
5896 N_Node = iStop[i] - iStart[i] + 1; /* Number of Nodes in this ROI */
5897 Node = &(iNode[iStart[i]]);
5898 /* pointer to location of first index in this ROI */
5899 /* prepare a label for these ROIs */
5900 NewName = SUMA_ParseFname (name, NULL);
5901 if (!NewName) {
5902 Label = SUMA_copy_string("BadLabel");
5903 }else {
5904 sprintf(stmp,"(%d)", Value);
5905 Label = SUMA_append_string(stmp,NewName->FileName_NoExt);
5906 }
5907 /* SUMA_LH("Transforming to Drawn ROIs..."); */
5908 if (!(ROIv[i] = SUMA_1DROI_to_DrawnROI( Node, N_Node ,
5909 Value, Parent_idcode_str,
5910 Label, NULL,
5911 fillcolor, edgecolor, edgethickness,
5912 SUMAg_DOv, SUMAg_N_DOv,
5913 ForDisplay))) {
5914 int kkk = 0;
5915 SUMA_SL_Err("Failed to transform to Drawn ROI");
5916 for (kkk=0; kkk<i; ++kkk) {
5917 if (ROIv[kkk]) SUMA_freeDrawnROI(ROIv[kkk]);
5918 }
5919 SUMA_free(ROIv);ROIv=NULL;
5920 SUMA_RETURN(NULL);
5921 }
5922 if (edges_only) { /* remove blob collection for less memory waste */
5923 if (ROIv[i]->ROIstrokelist)
5924 SUMA_EmptyDestroyList(ROIv[i]->ROIstrokelist);
5925 ROIv[i]->ROIstrokelist = NULL;
5926 if (ROIv[i]->ActionStack)
5927 SUMA_EmptyDestroyActionStack(ROIv[i]->ActionStack);
5928 ROIv[i]->ActionStack = NULL;
5929 }
5930 if (nrow == 5 || nrow == 4) {
5931 SUMA_LH("Marking as color by fillcolor");
5932 ROIv[i]->ColorByLabel = NOPE;
5933 }
5934 if (Label) SUMA_free(Label); Label = NULL;
5935 if (NewName) SUMA_Free_Parsed_Name(NewName); NewName = NULL;
5936 if (0 && LocalHead)
5937 fprintf (SUMA_STDERR, "%s: ROI->Parent_idcode_str %s\n",
5938 FuncName, ROIv[i]->Parent_idcode_str);
5939
5940 }
5941
5942 SUMA_LH("Freeing...");
5943
5944 if (iLabel) SUMA_free(iLabel); iLabel = NULL;
5945 if (isort) SUMA_free(isort); isort = NULL;
5946 if (iNode) SUMA_free(iNode); iNode = NULL;
5947 if (iStart) SUMA_free(iStart); iStart = NULL;
5948 if (iStop) SUMA_free(iStop); iStop = NULL;
5949 if (r) SUMA_free(r); r = NULL;
5950 if (g) SUMA_free(g); g = NULL;
5951 if (b) SUMA_free(b); b = NULL;
5952 if (RGB) SUMA_free(RGB); RGB = NULL;
5953
5954 *N_ROI = N_Labels;
5955 SUMA_RETURN(ROIv);
5956
5957 }
5958
5959 /*!
5960 \brief Loads a niml ROI
5961
5962 \param ForDisplay (SUMA_Boolean)
5963 YUP: Performs checks to see if ROI with similar idcode already
5964 exists and if parent surface is loaded.
5965 NOPE: Does not check for above conditions.
5966 */
SUMA_OpenDrawnROI_NIML(char * filename,int * N_ROI,SUMA_Boolean ForDisplay,SUMA_SurfaceViewer * sv)5967 SUMA_DRAWN_ROI ** SUMA_OpenDrawnROI_NIML (char *filename,
5968 int *N_ROI,
5969 SUMA_Boolean ForDisplay,
5970 SUMA_SurfaceViewer *sv)
5971 { /* begin embedded function */
5972 static char FuncName[]={"SUMA_OpenDrawnROI_NIML"};
5973 char stmp[SUMA_MAX_NAME_LENGTH+100], *nel_idcode, *att=NULL;
5974 NI_element *nel = NULL;
5975 NI_element **nelv=NULL;
5976 NI_stream ns ;
5977 int n_read=0, idat, answer, inel, iDO, N_nel, iwarn=0, ir=0, sd=0;
5978 SUMA_NIML_ROI_DATUM *niml_ROI_datum_buff=NULL;
5979 SUMA_NIML_DRAWN_ROI * nimlROI=NULL;
5980 SUMA_DRAWN_ROI **ROIv=NULL;
5981 SUMA_SurfaceObject *SO=NULL;
5982 SUMA_Boolean found = YUP, AddNel = YUP,
5983 AlwaysReplace = NOPE, NeverReplace = NOPE;
5984 SUMA_Boolean LocalHead = NOPE;
5985
5986 SUMA_ENTRY;
5987
5988 if (!sv) { sv = SUMA_LAST_VIEWER;}
5989
5990 if (!sv) sv = &(SUMAg_SVv[0]);
5991
5992 *N_ROI = 0;
5993
5994 if (SUMAg_CF->nimlROI_Datum_type < 0) {
5995 SUMA_SL_Err("Bad niml type code");
5996 SUMA_RETURN(NULL);
5997 }
5998 if (LocalHead)
5999 fprintf( SUMA_STDERR, "%s: roi_type code = %d\n",
6000 FuncName, SUMAg_CF->nimlROI_Datum_type) ;
6001
6002 sprintf(stmp,"file:%s", filename);
6003 ns = NI_stream_open( stmp , "r" ) ;
6004 if( ns == NULL ){
6005 SUMA_SL_Err("Can't open ROI file");
6006 SUMA_RETURN(NULL);
6007 }
6008
6009 nelv = (NI_element **)
6010 SUMA_calloc(SUMA_MAX_DISPLAYABLE_OBJECTS, sizeof(NI_element *));
6011 if (!nelv) {
6012 SUMA_SLP_Crit("Failed to allocate");
6013 SUMA_RETURN(NULL);
6014 }
6015
6016 NeverReplace = NOPE;
6017 AlwaysReplace = NOPE;
6018 inel = 0;
6019 do {
6020 SUMA_LH("Calling NI_read_element");
6021 nel = NI_read_element(ns,1) ;
6022
6023 if (nel && nel->vec_num) { /* Must check for ROIs that are empty.
6024 They cause a crash that was meticulously
6025 reported by Mike Arcaro.
6026 Empty ROIs can be created if one
6027 starts a new ROI then undo drawing operations
6028 and save all ROIs to niml format. */
6029 found = YUP;
6030 SUMA_LH("Have nel, will travel");
6031 if (LocalHead && 0) SUMA_nel_stdout (nel);
6032
6033 if (strcmp(nel->name,SUMA_Dset_Type_Name(SUMA_NODE_ROI))) {
6034 SUMA_SLP_Err ( "ni element not of the \n"
6035 "Node ROI variety.\n"
6036 "Element discarded.");
6037 NI_free_element(nel) ; nel = NULL;
6038 SUMA_RETURN(NULL);
6039 }
6040 SUMA_LH("Type check redux");
6041 /* somewhat redundant test */
6042 if (nel->vec_typ[0] != SUMAg_CF->nimlROI_Datum_type) {
6043 SUMA_SLP_Err ("Datum type mismatch.");
6044 NI_free_element(nel) ; nel = NULL;
6045 SUMA_RETURN(NULL);
6046 }
6047
6048 SUMA_LH("IDs please");
6049 /* make sure id is set properly (the curse of old versions) */
6050 att = NI_get_attribute( nel , "self_idcode");
6051 if (!att) { /* try old way */
6052 if ((att = NI_get_attribute( nel , "idcode_str"))) {
6053 NI_set_attribute(nel, "self_idcode", att);
6054 NI_kill_attribute (nel,"idcode_str");
6055 att = NI_get_attribute( nel , "self_idcode");
6056 } else if ((att = NI_get_attribute( nel , "Object_ID"))) {
6057 NI_set_attribute(nel, "self_idcode", att);
6058 NI_kill_attribute (nel,"Object_ID");
6059 att = NI_get_attribute( nel , "self_idcode");
6060 }
6061 }
6062 if (att) {
6063 nel_idcode = att;
6064 } else { /* put one in, anything is fine */
6065 att = (char*)SUMA_calloc(SUMA_IDCODE_LENGTH,
6066 sizeof(char));
6067 UNIQ_idcode_fill(att);
6068 NI_set_attribute(nel,"self_idcode",att);
6069 SUMA_free(att); att = NULL;
6070 nel_idcode = NI_get_attribute(nel,"self_idcode");
6071 }
6072
6073 if (ForDisplay) {
6074 /* find out if a displayable object exists
6075 with the same idcode_str */
6076 SUMA_LH("Checking for self id...");
6077 if (!nel_idcode) {
6078 SUMA_S_Err("Must have id by now!");
6079 SUMA_RETURN(NULL);
6080 }
6081 if (SUMA_existDO(nel_idcode, SUMAg_DOv, SUMAg_N_DOv)) {
6082 if (AlwaysReplace) {
6083 AddNel = YUP;
6084 }
6085 if (NeverReplace) {
6086 AddNel = NOPE;
6087 }
6088 if (!AlwaysReplace && !NeverReplace) { /* ASk */
6089 sprintf(stmp, "Found duplicate ROIs.\n"
6090 "Replace ROI %s (%s) by\n"
6091 "version in file ?",
6092 NI_get_attribute( nel , "Label"), nel_idcode);
6093
6094 answer = SUMA_ForceUser_YesNo (sv->X->TOPLEVEL,
6095 stmp,
6096 0, SWP_DONT_CARE);
6097 if (LocalHead)
6098 fprintf (SUMA_STDERR,
6099 "%s: Got %d, You ?\n", FuncName, answer);
6100 switch (answer) {
6101 case SUMA_YES:
6102 SUMA_LH("YES");
6103 AddNel = YUP;
6104 break;
6105
6106 case SUMA_NO:
6107 SUMA_LH("NO");
6108 /* don't add this one */
6109 AddNel = NOPE;
6110 break;
6111
6112 case SUMA_YES_ALL:
6113 SUMA_LH("YES ALL");
6114 /* cancel Check_Prior */
6115 AddNel = YUP;
6116 AlwaysReplace = YUP;
6117 break;
6118
6119 case SUMA_NO_ALL:
6120 SUMA_LH("NO ALL");
6121 /* don't add this one and set flag to
6122 ignore the doubles */
6123 AddNel = NOPE;
6124 NeverReplace = YUP;
6125 break;
6126
6127 default:
6128 SUMA_SLP_Crit(
6129 "Don't know what to do with this button.");
6130 SUMA_RETURN(NULL);
6131 break;
6132 }
6133 }
6134 } else {
6135 AddNel = YUP;
6136 }
6137
6138 /* make sure element's parent exists */
6139 if (AddNel) {
6140 SUMA_LH("Checking for Parent surface...");
6141 att = NI_get_attribute( nel , "domain_parent_idcode");
6142 if (!att) { /* try old way */
6143 if ((att = NI_get_attribute( nel , "Parent_idcode_str"))) {
6144 NI_set_attribute(nel, "domain_parent_idcode", att);
6145 NI_kill_attribute (nel,"Parent_idcode_str");
6146 att = NI_get_attribute(nel,"domain_parent_idcode");
6147 } else if ((att = NI_get_attribute( nel , "Parent_ID"))) {
6148 NI_set_attribute(nel, "domain_parent_idcode", att);
6149 NI_kill_attribute (nel,"Parent_ID");
6150 att = NI_get_attribute(nel,"domain_parent_idcode");
6151 }
6152 }
6153 iDO = -1;
6154 if (att) {
6155 iDO = SUMA_whichDO( att,
6156 SUMAg_DOv, SUMAg_N_DOv);
6157 }
6158
6159 if (iDO < 0) {
6160 if (!iwarn && !LocalHead) {
6161 SUMA_S_Warnv(
6162 "ROI's parent surface not loaded, or ROI is\n"
6163 "unparented. Looking for adoptive parents...\n"
6164 "(Message muted for remainder of ROIs in:\n"
6165 " %s )\n"
6166 , filename );
6167 ++iwarn;
6168 }
6169
6170 sd=SUMA_SideType(NI_get_attribute(nel,"Parent_side"));
6171 /* assume user has selected the proper surface first */
6172 if (iDO < 0 && (SO = SUMA_SV_Focus_SO(sv))) {
6173 /* Use selection and side match ?*/
6174 if (SUMA_isSurfaceOfSide(SO,sd)) {
6175 iDO = SUMA_findSO_inDOv(SO->LocalDomainParentID,
6176 SUMAg_DOv, SUMAg_N_DOv);
6177 SUMA_LHv("User SO selection (%d) ?\n", iDO);
6178 }
6179 }
6180 if (iDO < 0) {
6181 /* How about a big LDP with side match ? */
6182 if (sd == SUMA_LEFT || sd == SUMA_RIGHT || sd == SUMA_LR) {
6183 iDO = SUMA_BiggestLocalDomainParent_Side(SUMAg_DOv,
6184 SUMAg_N_DOv,
6185 sd);
6186 SUMA_LHv("Got big one (%d) of same side?\n", iDO);
6187 }
6188 }
6189 /* forget the side now */
6190 if (iDO < 0 && (SO = SUMA_SV_Focus_SO(sv))) {
6191 /* user selection, who cares about sid */
6192 iDO = SUMA_findSO_inDOv(SO->LocalDomainParentID,
6193 SUMAg_DOv, SUMAg_N_DOv);
6194 SUMA_LHv("User SO selection (%d) no side check ?\n",
6195 iDO);
6196 }
6197 if (iDO < 0) { /* try one last time */
6198 /* Damnit, Janet, get anything */
6199 iDO = SUMA_BiggestLocalDomainParent(SUMAg_DOv,
6200 SUMAg_N_DOv);
6201 SUMA_LHv("Got big one (%d) of any side?\n", iDO);
6202 }
6203 if (iDO < 0) {
6204 SUMA_S_Err("Can't find adoptive surface\n"
6205 "Try selecting adoptive surface before\n"
6206 "opening ROI");
6207 AddNel = NOPE;
6208 } else {
6209 SO = (SUMA_SurfaceObject *)SUMAg_DOv[iDO].OP;
6210 SUMA_LHv("Found LDP in %s\n", SO->Label);
6211 NI_set_attribute(nel,
6212 "domain_parent_idcode",
6213 SO->idcode_str);
6214 AddNel = YUP;
6215 }
6216 }
6217 }
6218 } else {
6219 AddNel = YUP; /* ignore checks */
6220 }
6221
6222 if (AddNel) {
6223 SUMA_LHv("Adding Nel %d\n", inel);
6224 nelv[inel] = nel;
6225 ++inel;
6226 }else {
6227 SUMA_LHv("Skipping Nel %d\n", inel);
6228 }
6229
6230 ++n_read;
6231 }else {
6232 SUMA_LH("NULL nel, to the spruce goose");
6233 found = NOPE;
6234 }
6235
6236 } while (found);
6237
6238 NI_stream_close(ns) ;
6239 N_nel = inel;
6240
6241 if( !n_read){
6242 SUMA_SL_Err("Found no elements in file!");
6243 SUMA_free(nelv);
6244 SUMA_RETURN(NULL);
6245 }
6246 if (!N_nel) {
6247 SUMA_free(nelv);
6248 SUMA_RETURN(NULL);
6249 }
6250 /* Now turn those nel into ROIS */
6251 ROIv = (SUMA_DRAWN_ROI **) SUMA_calloc(N_nel, sizeof(SUMA_DRAWN_ROI*));
6252 for (inel=0; inel < N_nel; ++inel) {
6253 if (LocalHead)
6254 fprintf (SUMA_STDERR,
6255 "%s: Processing nel %d/%d...\n", FuncName, inel, N_nel);
6256 nel = nelv[inel];
6257 nel_idcode = NI_get_attribute( nel , "self_idcode");
6258 if (!nel_idcode) {
6259 SUMA_S_Err("An id must be present by now!\n");
6260 SUMA_RETURN(NULL);
6261 }
6262 /* store nel in nimlROI struct */
6263
6264 /* allocate for nimlROI */
6265 nimlROI = (SUMA_NIML_DRAWN_ROI *)
6266 SUMA_calloc(1,sizeof(SUMA_NIML_DRAWN_ROI));
6267 nimlROI->Type = (int)strtod(NI_get_attribute( nel , "Type"), NULL);
6268 nimlROI->idcode_str =
6269 SUMA_copy_string(NI_get_attribute( nel , "self_idcode"));
6270 nimlROI->Parent_idcode_str =
6271 SUMA_copy_string(NI_get_attribute( nel , "domain_parent_idcode"));
6272 nimlROI->Label = SUMA_copy_string(NI_get_attribute( nel , "Label"));
6273 nimlROI->iLabel = (int)strtod(NI_get_attribute( nel , "iLabel"), NULL);
6274 nimlROI->N_ROI_datum = nel->vec_len;
6275 nimlROI->ColPlaneName =
6276 SUMA_copy_string(NI_get_attribute( nel , "ColPlaneName"));
6277
6278 ir = SUMA_StringToNum (NI_get_attribute( nel , "FillColor"),
6279 (void*)nimlROI->FillColor, 3,1);
6280 nimlROI->FillColor[3] = 1.0;
6281 if (ir < 3) {
6282 SUMA_SLP_Err("Failed in reading FillColor.");
6283 SUMA_free(nelv);
6284 SUMA_RETURN(NULL);
6285 }else if (ir == 4) {
6286 SUMA_StringToNum (NI_get_attribute( nel , "FillColor"),
6287 (void*)nimlROI->FillColor, 4,1);
6288 }
6289
6290 ir = SUMA_StringToNum (NI_get_attribute( nel , "EdgeColor"),
6291 (void*)nimlROI->EdgeColor, 3,1);
6292 nimlROI->EdgeColor[3] = 1.0;
6293
6294 if (ir < 3) {
6295 SUMA_SLP_Err("Failed in reading EdgeColor.");
6296 SUMA_free(nelv);
6297 SUMA_RETURN(NULL);
6298 }else if (ir == 4) {
6299 SUMA_StringToNum (NI_get_attribute( nel , "EdgeColor"),
6300 (void*)nimlROI->EdgeColor, 4,1);
6301 }
6302
6303 nimlROI->EdgeThickness =
6304 (int)strtod(NI_get_attribute( nel , "EdgeThickness"), NULL);
6305
6306 if (LocalHead) {
6307 fprintf (SUMA_STDERR,"%s: vec_type[0] = %d (%d)\n",
6308 FuncName, nel->vec_typ[0], SUMAg_CF->nimlROI_Datum_type) ;
6309 fprintf (SUMA_STDERR,
6310 "%s: vec_len =%d\tvec_num = %d\n"
6311 "idcode_str %s, Parent_idcode_str %s\n",
6312 FuncName, nel->vec_len, nel->vec_num,
6313 nimlROI->idcode_str, nimlROI->Parent_idcode_str);
6314 }
6315
6316 nimlROI->ROI_datum =
6317 (SUMA_NIML_ROI_DATUM *)
6318 SUMA_calloc(nimlROI->N_ROI_datum,sizeof(SUMA_NIML_ROI_DATUM));
6319
6320 /* DO NOT use niml_ROI_datum_buff = (SUMA_NIML_ROI_DATUM *)nel->vec[idat];
6321 inside the loop.
6322 For the SUMA_NIML_DRAWN_ROI you have one column of (SUMA_NIML_ROI_DATUM *)
6323 ni_type = "SUMA_NIML_ROI_DATUM". If you had for type:
6324 "SUMA_NIML_ROI_DATUM, int" then you'd have two columns with the second
6325 column being a vector of ints. The only caveat is that the second column
6326 must be of equal length to the first. */
6327 niml_ROI_datum_buff = (SUMA_NIML_ROI_DATUM *)nel->vec[0];
6328 /* now fill the ROI_datum structures */
6329 SUMA_LH("Filling ROI datum structures...");
6330 for (idat=0; idat< nimlROI->N_ROI_datum ; ++idat) {
6331 if (LocalHead) fprintf (SUMA_STDERR,"%s: i=%d\n", FuncName, idat);
6332 nimlROI->ROI_datum[idat].action = niml_ROI_datum_buff[idat].action;
6333 nimlROI->ROI_datum[idat].Type = niml_ROI_datum_buff[idat].Type;
6334 nimlROI->ROI_datum[idat].N_n = niml_ROI_datum_buff[idat].N_n;
6335 if (nimlROI->ROI_datum[idat].N_n > 0) {
6336 if (LocalHead)
6337 fprintf (SUMA_STDERR,
6338 "%s: Copying nPath, %d values\n",
6339 FuncName, nimlROI->ROI_datum[idat].N_n);
6340 nimlROI->ROI_datum[idat].nPath =
6341 (int *)SUMA_malloc(sizeof(int)*nimlROI->ROI_datum[idat].N_n);
6342 memcpy( nimlROI->ROI_datum[idat].nPath,
6343 niml_ROI_datum_buff[idat].nPath,
6344 sizeof(int)*nimlROI->ROI_datum[idat].N_n);
6345 } else {
6346 SUMA_LH("Null nPath");
6347 nimlROI->ROI_datum[idat].nPath = NULL;
6348 }
6349 if (LocalHead) {
6350 fprintf (SUMA_STDERR,"%s: Segment %d\tType %d\tN_n %d\taction %d\n",
6351 FuncName, idat, nimlROI->ROI_datum[idat].Type,
6352 nimlROI->ROI_datum[idat].N_n,nimlROI->ROI_datum[idat].action);
6353 }
6354 }
6355
6356 /* Does ROI already exist with the same idcode_str ?*/
6357
6358 SUMA_LH("Checking for duplicates...");
6359 if ((iDO = SUMA_whichDO(nel_idcode, SUMAg_DOv, SUMAg_N_DOv)) >= 0) {
6360 SUMA_LH("Duplicate found ... Deleteing old one...");
6361 /* ROI already exists delete it */
6362 if (!SUMA_DeleteROI ((SUMA_DRAWN_ROI *)SUMAg_DOv[iDO].OP)) {
6363 SUMA_SLP_Err("Failed to delete ROI");
6364 SUMA_RETURN(NULL);
6365 }
6366 }
6367
6368 /* transfom nimlROI to a series of drawing actions */
6369 SUMA_LH("Transforming ROI to a series of actions...");
6370 ROIv[inel] = SUMA_NIMLDrawnROI_to_DrawnROI (nimlROI, ForDisplay);
6371 if (LocalHead)
6372 fprintf (SUMA_STDERR, "%s: ROI->Parent_idcode_str %s\n",
6373 FuncName, ROIv[inel]->Parent_idcode_str);
6374
6375 /* manually free nimlROI fields that received copies
6376 of allocated space as opposed to pointer copies */
6377 if (nimlROI->idcode_str) SUMA_free(nimlROI->idcode_str);
6378 if (nimlROI->Parent_idcode_str) SUMA_free(nimlROI->Parent_idcode_str);
6379 if (nimlROI->Label) SUMA_free(nimlROI->Label);
6380 if (nimlROI->ColPlaneName) SUMA_free(nimlROI->ColPlaneName);
6381
6382
6383 /* free nimlROI */
6384 nimlROI = SUMA_Free_NIMLDrawROI(nimlROI);
6385
6386 /* free nel and get it ready for the next load */
6387 NI_free_element(nel) ; nel = NULL;
6388
6389 }
6390
6391 /* free nelv */
6392 SUMA_free(nelv);
6393
6394 *N_ROI = N_nel;
6395 SUMA_RETURN(ROIv);
6396 }
6397
6398 /*!
6399 \brief turns a bunch of ROIs into a NI dataset
6400 A new version of SUMA_ROIv2dataset that allows
6401 the use of dsets as groups
6402 \param ROIv (SUMA_DRAWN_ROI**) vector of ROI structures
6403 \param N_ROIv (int) number of ROI structures
6404 \param Parent_idcode_str (char *) idcode of parent surface
6405 \param Pad_to (int) create Dset that has a full node listing
6406 from node 0 to node Pad_to (a total of Pad_to + 1 nodes)
6407 Use -1 to turn off padding.
6408 \param Pad_val (int) use this value (usually 0) to label a node being padded
6409 as oppsed to a node being a part of an ROI. This option
6410 is only useful with Pad_to
6411 \param cmp (SUMA_COLOR_MAP **) if cmp, them the colormap for these ROIs is
6412 returned in *cmp
6413 \return nel (NI_element *) structure to data set
6414 NULL if failed
6415 */
SUMA_ROIv2Grpdataset(SUMA_DRAWN_ROI ** ROIv,int N_ROIv,char * Parent_idcode_str,int Pad_to,int Pad_val,SUMA_COLOR_MAP ** cmp)6416 SUMA_DSET *SUMA_ROIv2Grpdataset (SUMA_DRAWN_ROI** ROIv, int N_ROIv,
6417 char *Parent_idcode_str,
6418 int Pad_to, int Pad_val,
6419 SUMA_COLOR_MAP **cmp)
6420 {
6421 static char FuncName[]={"SUMA_ROIv2Grpdataset"};
6422 int ii, i, nn, cnt, N_NodesTotal = 0, MaxIndex = 0,
6423 *ip=NULL, *NodesTotal=NULL, *LabelsTotal=NULL,
6424 *NodesTotal_p=NULL, *LabelsTotal_p=NULL,
6425 iicol=0, new_col = 0;
6426 SUMA_DSET *dset =NULL;
6427 SUMA_COLOR_MAP_HASH_DATUM *hd=NULL;
6428 SUMA_COLOR_MAP *cm = NULL;
6429 SUMA_Boolean LocalHead = NOPE;
6430
6431 SUMA_ENTRY;
6432
6433 /* Now you have the ROIs, concatenate all NodesInROI vectors into 1*/
6434 /* count the total number of nodes */
6435 N_NodesTotal = 0;
6436 for (ii=0; ii < N_ROIv; ++ii) {
6437 SUMA_ROI_CRUDE_COUNT_NODES(ROIv[ii], cnt);
6438 if (LocalHead) {
6439 fprintf (SUMA_STDERR,"%s: ROI #%d: %d nodes\n", FuncName, ii, cnt);
6440 }
6441 N_NodesTotal += cnt;
6442 }
6443 if (LocalHead)
6444 fprintf (SUMA_STDERR,"%s: %d nodes total.\n", FuncName, N_NodesTotal);
6445
6446 NodesTotal = (int *)SUMA_calloc(N_NodesTotal, sizeof(int));
6447 LabelsTotal = (int *)SUMA_calloc(N_NodesTotal, sizeof(int));
6448
6449 if (!NodesTotal || !LabelsTotal) {
6450 SUMA_S_Err("Failed to allocate.");
6451 SUMA_RETURN(dset);
6452 }
6453
6454 /* allocate for a colormap */
6455 if (cmp) {
6456 cm = (SUMA_COLOR_MAP*) SUMA_calloc(1,sizeof(SUMA_COLOR_MAP));
6457 cm->top_frac = 0.0f;
6458 cm->SO = NULL;
6459 cm->N_M[0] = N_ROIv; cm->N_M[1] = 4;
6460 cm->idvec = (int *)SUMA_calloc(cm->N_M[0], sizeof(int));;
6461 cm->cname = (char **)SUMA_calloc(cm->N_M[0], sizeof(char*));
6462 cm->M = (float**)SUMA_allocate2D (cm->N_M[0], cm->N_M[1], sizeof(float));
6463 cm->Name = SUMA_copy_string("Funkhouser");
6464 cm->Sgn = 0;
6465 cm->frac = NULL;
6466 iicol = 0;
6467 } else {
6468 cm = NULL;
6469 }
6470
6471 cnt = 0;
6472 N_NodesTotal = 0;
6473 MaxIndex = -1;
6474 for (ii=0; ii < N_ROIv; ++ii) {
6475 SUMA_LH("Appending ROI");
6476 /* You do not need the Unique operation in SUMA_NodesInROI,
6477 but it is nice to have so that you can report the nodes that
6478 were part of more than one ROI. If you do not Set the Unique
6479 flag in SUMA_NodesInROI you will likely get node duplication
6480 but these nodes are in the same ROI and therefore are not
6481 duplicates to be removed....*/
6482 ip = SUMA_NodesInROI (ROIv[ii], &nn, YUP);
6483 if (LocalHead) {
6484 fprintf (SUMA_STDERR,"%s: Nodes in ROI #%d\n", FuncName, ii);
6485 SUMA_disp_dvect (ip, nn);
6486 }
6487
6488 /* stick the color, label and key into a colormap */
6489 if (cm) {
6490 new_col = 0;
6491 if (!ii) {
6492 new_col = 1;
6493 } else {
6494 HASH_FIND_INT(cm->chd, &(ROIv[ii]->iLabel), hd);
6495 if (hd) {
6496 new_col = 0; /* exists already, do not add */
6497 } else new_col = 1;
6498 }
6499 if (new_col) { /* add details */
6500 hd = (SUMA_COLOR_MAP_HASH_DATUM *)
6501 SUMA_calloc(1, sizeof(SUMA_COLOR_MAP_HASH_DATUM));
6502 hd->id = ROIv[ii]->iLabel;
6503 hd->colmapindex = iicol;
6504 HASH_ADD_INT(cm->chd, id, hd);
6505
6506 cm->M[iicol][0] = ROIv[ii]->FillColor[0];
6507 cm->M[iicol][1] = ROIv[ii]->FillColor[1];
6508 cm->M[iicol][2] = ROIv[ii]->FillColor[2];
6509 cm->M[iicol][3] = ROIv[ii]->FillColor[3];
6510 cm->idvec[iicol] = ROIv[ii]->iLabel;
6511 cm->cname[iicol] = SUMA_copy_string(ROIv[ii]->Label);
6512 ++iicol;
6513 }
6514 }
6515
6516 for (i=0; i < nn; ++i) {
6517 NodesTotal[cnt] = ip[i];
6518 LabelsTotal[cnt] = ROIv[ii]->iLabel;
6519 if (ip[i] > MaxIndex) MaxIndex = ip[i];
6520 ++cnt;
6521 }
6522 N_NodesTotal += nn;
6523 SUMA_freeDrawnROI (ROIv[ii]); ROIv[ii] = NULL; /* free the Drawn ROI */
6524 SUMA_free(ip);ip=NULL;
6525 }
6526
6527 if (cm) {
6528 SUMA_S_Notev("Have %d/%d new entries in colormap\n", iicol, N_ROIv);
6529 /* now trim cm */
6530 if (iicol < cm->N_M[0]) {
6531 SUMA_LH("Trimming excess");
6532 cm->idvec = (int *)SUMA_realloc(cm->idvec, iicol*sizeof(int));;
6533 cm->cname = (char **)SUMA_realloc(cm->cname, iicol * sizeof(char*));
6534 /* reallocating M is a pain in the behind */
6535 pause_mcw_malloc();
6536 for (i=iicol; i<cm->N_M[0]; ++i) {
6537 if (cm->M[i]) free(cm->M[i]); cm->M[i]=NULL;
6538 }
6539 cm->M = (float **)SUMA_realloc(cm->M, iicol * sizeof(float*));
6540 resume_mcw_malloc();
6541 cm->N_M[0] = iicol;
6542 }
6543 *cmp = cm; cm = NULL;
6544 }
6545
6546 if (0 && LocalHead) {
6547 SUMA_disp_dvect (NodesTotal, N_NodesTotal);
6548 }
6549
6550 /* Now you want to make sure that no two nodes are listed twice */
6551 /* sort NodesTotal and rearrange LabelsTotal accordingly */
6552 { int *isort = NULL, *LabelsTotal_r = NULL,
6553 *NodesTotal_u = NULL, N_NodesTotal_u, *iu = NULL;
6554 char report[200];
6555
6556 isort = SUMA_z_dqsort(NodesTotal, N_NodesTotal);
6557 LabelsTotal_r = SUMA_reorder (LabelsTotal, isort, N_NodesTotal);
6558 SUMA_free(LabelsTotal);
6559 LabelsTotal = LabelsTotal_r; LabelsTotal_r = NULL;
6560 SUMA_free(isort); isort = NULL;
6561
6562 /* now get the unique set of nodes */
6563 NodesTotal_u = SUMA_UniqueInt_ind (NodesTotal, N_NodesTotal,
6564 &N_NodesTotal_u, &iu);
6565 /* reorder LabelsTotal to contain data from the nodes
6566 left in NodesTotal_u */
6567 LabelsTotal_r = SUMA_reorder (LabelsTotal, iu, N_NodesTotal_u);
6568 SUMA_free(NodesTotal); NodesTotal = NULL;
6569 SUMA_free(LabelsTotal); LabelsTotal = NULL;
6570 SUMA_free(iu); iu = NULL;
6571 NodesTotal = NodesTotal_u; NodesTotal_u = NULL;
6572 LabelsTotal = LabelsTotal_r; LabelsTotal_r = NULL;
6573
6574 if (N_NodesTotal - N_NodesTotal_u) {
6575 snprintf(report, 199,
6576 "%d/%d nodes had duplicate entries.\n"
6577 "(ie same node part of more than 1 ROI)\n"
6578 "Duplicate entries were eliminated.",
6579 N_NodesTotal - N_NodesTotal_u , N_NodesTotal);
6580
6581 N_NodesTotal = N_NodesTotal_u; N_NodesTotal_u = 0;
6582 SUMA_SLP_Warn("%s", report);
6583 }
6584 }
6585
6586 if (Pad_to > 0) {
6587 SUMA_LH("Padding to desired length");
6588 if (Pad_to < MaxIndex) {
6589 SUMA_SL_Err("ROI contains node index > padding limit\n"
6590 "No padding done.");
6591 if (NodesTotal) SUMA_free(NodesTotal); NodesTotal = NULL;
6592 if (LabelsTotal) SUMA_free(LabelsTotal); LabelsTotal = NULL;
6593 SUMA_RETURN(NULL);
6594 }else {
6595 NodesTotal_p = (int *)SUMA_calloc(Pad_to+1, sizeof(int));
6596 LabelsTotal_p = (int *)SUMA_calloc(Pad_to+1, sizeof(int));
6597 if (!NodesTotal_p || !LabelsTotal_p) {
6598 SUMA_SL_Crit("Failed to allocate for NodesTotal_p || "
6599 "LabelsTotal_p");
6600 if (NodesTotal) SUMA_free(NodesTotal); NodesTotal = NULL;
6601 if (LabelsTotal) SUMA_free(LabelsTotal); LabelsTotal = NULL;
6602 SUMA_RETURN(NULL);
6603 }
6604 if (Pad_val) for(i=0; i<=Pad_to; ++i) LabelsTotal_p[i] = Pad_val;
6605 for(i=0; i<=Pad_to; ++i) NodesTotal_p[i] = i;
6606 for(i=0; i<N_NodesTotal; ++i) {
6607 LabelsTotal_p[NodesTotal[i]] = LabelsTotal[i];
6608 }
6609 SUMA_free(NodesTotal);
6610 NodesTotal = NodesTotal_p; NodesTotal_p = NULL;
6611 SUMA_free(LabelsTotal);
6612 LabelsTotal = LabelsTotal_p; LabelsTotal_p = NULL;
6613 N_NodesTotal = Pad_to + 1;
6614 }
6615 }
6616 if (LocalHead) {
6617 fprintf( SUMA_STDERR,
6618 "%s: N_NodesTotal = %d\nCreating dset\n",
6619 FuncName, N_NodesTotal);
6620 }
6621 /* construct a NIML data set for the output */
6622 dset = SUMA_CreateDsetPointer(
6623 NULL, /* usually the filename */
6624 SUMA_NODE_ROI, /* mix and match */
6625 NULL, /* no idcode, let the function create one from the filename*/
6626 Parent_idcode_str, /* no domain str specified */
6627 N_NodesTotal /* Number of nodes allocated for */
6628 ); /* DO NOT free dset, it is store in DsetList */
6629
6630
6631
6632 if (!dset) {
6633 SUMA_SL_Err("Failed in SUMA_CreateDsetPointer");
6634 SUMA_RETURN(NULL);
6635 }
6636
6637 /* Add the index column */
6638 SUMA_LH("Adding index column...");
6639 if (!SUMA_AddDsetNelCol ( dset, "node index",
6640 SUMA_NODE_INDEX, (void *)NodesTotal, NULL, 1)) {
6641 SUMA_SL_Err("Failed in SUMA_AddNelCol");
6642 SUMA_RETURN(dset);
6643 }
6644
6645 /* Add the label column */
6646 SUMA_LH("Adding label column...");
6647 if (!SUMA_AddDsetNelCol (dset, "integer label",
6648 SUMA_NODE_ILABEL, (void *)LabelsTotal, NULL, 1)) {
6649 SUMA_SL_Err("Failed in SUMA_AddNelCol");
6650 SUMA_RETURN(dset);
6651 }
6652
6653 /* make it easy */
6654 dset->dnel = SUMA_FindDsetDataElement(dset);
6655 dset->inel = SUMA_FindSDsetNodeIndexElement(dset);
6656
6657 SUMA_LH("cleanup ...");
6658 if (NodesTotal) SUMA_free(NodesTotal); NodesTotal = NULL;
6659 if (LabelsTotal) SUMA_free(LabelsTotal); LabelsTotal = NULL;
6660
6661 SUMA_RETURN(dset);
6662 }
6663
6664 /*!
6665 \brief turns a bunch of ROIs into a list of node vectors
6666 Each list is for a particular ROI.
6667 The ordering of the node indices is preserved as
6668 it appears in the ROI
6669 \param ROIv (SUMA_DRAWN_ROI**) vector of ROI structures
6670 \param N_ROIv (int) number of ROI structures
6671 \return nl (DList *) linked list of node indices for each ROI
6672 NULL if failed
6673 */
6674
SUMA_free_ROI_Extract(void * dd)6675 void SUMA_free_ROI_Extract(void *dd)
6676 {
6677 SUMA_ROI_EXTRACT *ddd=(SUMA_ROI_EXTRACT *)dd;
6678 if (ddd) {
6679 if (ddd->vals) SUMA_free(ddd->vals);
6680 if (ddd->name) SUMA_free(ddd->name);
6681 SUMA_free(ddd);
6682 }
6683 return;
6684 }
6685
SUMA_GetROIExtractLabeled(DList * ddl,int i)6686 SUMA_ROI_EXTRACT *SUMA_GetROIExtractLabeled(DList *ddl, int i)
6687 {
6688 static char FuncName[]={"SUMA_GetROIExtractLabeled"};
6689 DListElmt *el=NULL;
6690 SUMA_ROI_EXTRACT *dd=NULL;
6691
6692 SUMA_ENTRY;
6693
6694 if (!ddl) SUMA_RETURN(NULL);
6695
6696 el=dlist_head(ddl);
6697 while (el) {
6698 dd = (SUMA_ROI_EXTRACT *)el->data;
6699 if (dd->label == i) SUMA_RETURN(dd);
6700 el = dlist_next(el);
6701 }
6702
6703 SUMA_RETURN(NULL);
6704 }
6705
SUMA_ROIv2NodeLists(SUMA_DRAWN_ROI ** ROIv,int N_ROIv,int purgedups)6706 DList *SUMA_ROIv2NodeLists (SUMA_DRAWN_ROI** ROIv, int N_ROIv, int purgedups)
6707 {
6708 static char FuncName[]={"SUMA_ROIv2NodeLists"};
6709 int ii, i, nn, cnt, nodemin=9999999, nodemax=-1, MaxNodeIndex=-1,
6710 N_NodesMax=0;
6711 byte *visited=NULL;
6712 SUMA_DSET *dset =NULL;
6713 DList *ddl=NULL;
6714 DListElmt *Elm=NULL, *eldd=NULL;
6715 SUMA_ROI_EXTRACT *dd=NULL;
6716 SUMA_ROI_DATUM *ROI_Datum=NULL;
6717 SUMA_Boolean LocalHead = NOPE;
6718
6719 SUMA_ENTRY;
6720
6721 /* Now you have the ROIs, concatenate all NodesInROI vectors into 1*/
6722 /* count the total number of nodes */
6723 ddl = (DList *)SUMA_calloc(1, sizeof(DList));
6724 dlist_init(ddl, SUMA_free_ROI_Extract);
6725 N_NodesMax = 0; nodemin=100000; nodemax=0, MaxNodeIndex=0;
6726 for (ii=0; ii < N_ROIv; ++ii) {
6727 if ((cnt=SUMA_NodeRange_DrawnROI (ROIv[ii], &nodemin, &nodemax)) >= 0) {
6728 if (LocalHead) {
6729 fprintf (SUMA_STDERR,"%s: ROI #%d: %d nodes,%d/%d min/max nodes\n",
6730 FuncName, ii, cnt, nodemin, nodemax);
6731 }
6732 /* is this a new label ? */
6733 dd = SUMA_GetROIExtractLabeled(ddl, ROIv[ii]->iLabel);
6734 if (!dd) {
6735 dd = (SUMA_ROI_EXTRACT*)SUMA_calloc(1,sizeof(SUMA_ROI_EXTRACT));
6736 dd->label = ROIv[ii]->iLabel;
6737 dd->name = SUMA_copy_string(ROIv[ii]->Label);
6738 dd->N_alloc = cnt;
6739 dd->vals = (int *)SUMA_calloc(dd->N_alloc, sizeof(int));
6740 dd->N_vals = 0;
6741 dlist_ins_next(ddl,dlist_tail(ddl),dd);
6742 } else { /* This allows for multiple ROI of the same label
6743 to be combined */
6744 dd->N_alloc += cnt;
6745 dd->vals = (int *)SUMA_realloc(dd->vals, dd->N_alloc*sizeof(int));
6746 }
6747 if (MaxNodeIndex < nodemax) MaxNodeIndex = nodemax;
6748 } else {
6749 SUMA_S_Err( "Cannot handle failure in NodeRange function\n"
6750 "Must have as many elements in ddl as in ROIv");
6751 SUMA_RETURN(NULL);
6752 }
6753 }
6754
6755
6756 /* allocate a vector to keep track of visited nodes */
6757 SUMA_LHv("Ready to fill up, MaxNodeIndex %d\n", MaxNodeIndex);
6758 {
6759 if (purgedups)
6760 visited = (byte *)SUMA_malloc(sizeof(byte)*(MaxNodeIndex+1));
6761 else visited = NULL;
6762 eldd = dlist_head(ddl);
6763 while(eldd) {
6764 dd = (SUMA_ROI_EXTRACT *)eldd->data;
6765 if (visited) memset((void*)visited, 0, sizeof(byte)*(MaxNodeIndex+1));
6766 for (ii=0; ii < N_ROIv; ++ii) {
6767 if (ROIv[ii]->iLabel == dd->label) {
6768 Elm = dlist_head(ROIv[ii]->ROIstrokelist);
6769 while (Elm && Elm->data) {
6770 ROI_Datum = (SUMA_ROI_DATUM *)Elm->data;
6771 SUMA_LHv("Will check on %d nodes, label %d, (%d)\n",
6772 ROI_Datum->N_n, dd->label, ROIv[ii]->iLabel);
6773 for (i=0; i < ROI_Datum->N_n; ++i) {
6774 if (!visited || !visited[ROI_Datum->nPath[i]]) {
6775 dd->vals[dd->N_vals] = ROI_Datum->nPath[i];
6776 if (visited) visited[ROI_Datum->nPath[i]]=1;
6777 ++dd->N_vals;
6778 }
6779 }
6780 Elm = dlist_next(Elm);
6781 }
6782 } /* add ROI's of this label */
6783 } /* ii */
6784 eldd = dlist_next(eldd);
6785 }
6786 }
6787
6788 if (visited) SUMA_free(visited); visited = NULL;
6789
6790
6791 SUMA_RETURN(ddl);
6792 }
6793
6794 /*!
6795 From ROIs, create a dataset with one column for each ROI value.
6796 For each ROI value, use Pad_val at nodes not occupied
6797 */
SUMA_ROIv2MultiDset(SUMA_DRAWN_ROI ** ROIv,int N_ROIv,char * Parent_idcode_str,int Pad_to,int Pad_val,SUMA_COLOR_MAP ** cmp)6798 SUMA_DSET *SUMA_ROIv2MultiDset (SUMA_DRAWN_ROI** ROIv, int N_ROIv,
6799 char *Parent_idcode_str,
6800 int Pad_to, int Pad_val,
6801 SUMA_COLOR_MAP **cmp)
6802 {
6803 static char FuncName[]={"SUMA_ROIv2MultiDset"};
6804 int ii, i, nn, cnt, nodemin=9999999, nodemax=-1, MaxIndex=-1,
6805 N_NodesMax=0, iicol, new_col = 0, icol = 0, rnode=-1;
6806 int *ivec=NULL, *NodesTotal=NULL, N_NodesTotal;
6807 SUMA_DSET *dset =NULL;
6808 DList *ddl=NULL;
6809 DListElmt *Elm=NULL, *eldd=NULL;
6810 SUMA_ROI_EXTRACT *dd=NULL;
6811 SUMA_ROI_DATUM *ROI_Datum=NULL;
6812 SUMA_COLOR_MAP_HASH_DATUM *hd=NULL;
6813 SUMA_COLOR_MAP *cm = NULL;
6814 SUMA_Boolean LocalHead = NOPE;
6815
6816 SUMA_ENTRY;
6817
6818 /* get list of values to work with */
6819 ddl = (DList *)SUMA_calloc(1, sizeof(DList));
6820 dlist_init(ddl, SUMA_free_ROI_Extract);
6821 N_NodesMax = 0; nodemin=100000; nodemax=0, MaxIndex=0;
6822 for (ii=0; ii < N_ROIv; ++ii) {
6823 if ((cnt=SUMA_NodeRange_DrawnROI (ROIv[ii], &nodemin, &nodemax)) >= 0) {
6824 if (LocalHead) {
6825 fprintf (SUMA_STDERR,"%s: ROI #%d: %d nodes,%d/%d min/max nodes\n",
6826 FuncName, ii, cnt, nodemin, nodemax);
6827 }
6828 /* is this a new label ? */
6829 dd = SUMA_GetROIExtractLabeled(ddl, ROIv[ii]->iLabel);
6830 if (!dd) {
6831 dd = (SUMA_ROI_EXTRACT*)SUMA_calloc(1,sizeof(SUMA_ROI_EXTRACT));
6832 dd->label = ROIv[ii]->iLabel;
6833 dd->name = SUMA_copy_string(ROIv[ii]->Label);
6834 dd->N_alloc = 0;
6835 dd->vals = NULL; /* don't bother with storage */
6836 dd->N_vals = 0;
6837 dlist_ins_next(ddl,dlist_tail(ddl),dd);
6838 }
6839 if (MaxIndex < nodemax) MaxIndex = nodemax;
6840 } else {
6841 SUMA_S_Err( "Cannot handle failure in NodeRange function\n"
6842 "Must have as many elements in ddl as in ROIv");
6843 SUMA_RETURN(NULL);
6844 }
6845 }
6846
6847 /* Now get a unique list of the nodes involved,
6848 much like the 1st steps in SUMA_ROIv2Grpdataset */
6849 /* Now you have the ROIs, concatenate all NodesInROI vectors into 1*/
6850 /* count the total number of nodes */
6851 N_NodesTotal = 0;
6852 for (ii=0; ii < N_ROIv; ++ii) {
6853 SUMA_ROI_CRUDE_COUNT_NODES(ROIv[ii], cnt);
6854 if (LocalHead) {
6855 fprintf (SUMA_STDERR,"%s: ROI #%d: %d nodes\n", FuncName, ii, cnt);
6856 }
6857 N_NodesTotal += cnt;
6858 }
6859 if (LocalHead)
6860 fprintf (SUMA_STDERR,"%s: %d nodes total.\n", FuncName, N_NodesTotal);
6861
6862 NodesTotal = (int *)SUMA_calloc(N_NodesTotal, sizeof(int));
6863
6864 if (!NodesTotal) {
6865 SUMA_S_Err("Failed to allocate.");
6866 SUMA_RETURN(dset);
6867 }
6868
6869 /* allocate for a colormap */
6870 if (cmp) {
6871 cm = (SUMA_COLOR_MAP*) SUMA_calloc(1,sizeof(SUMA_COLOR_MAP));
6872 cm->top_frac = 0.0f;
6873 cm->SO = NULL;
6874 cm->N_M[0] = N_ROIv+1; cm->N_M[1] = 4;
6875 cm->idvec = (int *)SUMA_calloc(cm->N_M[0], sizeof(int));;
6876 cm->cname = (char **)SUMA_calloc(cm->N_M[0], sizeof(char*));
6877 cm->M = (float**)SUMA_allocate2D (cm->N_M[0], cm->N_M[1], sizeof(float));
6878 cm->Name = SUMA_copy_string("Funkhouser");
6879 cm->Sgn = 0;
6880 cm->frac = NULL;
6881 iicol = 0;
6882 } else {
6883 cm = NULL;
6884 }
6885
6886 cnt = 0;
6887 N_NodesTotal = 0;
6888 for (ii=0; ii < N_ROIv; ++ii) {
6889 SUMA_LH("Appending ROI");
6890 /* You do not need the Unique operation in SUMA_NodesInROI,
6891 but it is nice to have so that you can report the nodes that
6892 were part of more than one ROI. If you do not Set the Unique
6893 flag in SUMA_NodesInROI you will likely get node duplication
6894 but these nodes are in the same ROI and therefore are not
6895 duplicates to be removed....*/
6896 ivec = SUMA_NodesInROI (ROIv[ii], &nn, YUP);
6897 if (LocalHead) {
6898 fprintf (SUMA_STDERR,"%s: Nodes in ROI #%d\n", FuncName, ii);
6899 SUMA_disp_dvect (ivec, nn);
6900 }
6901
6902 /* stick the color, label and key into a colormap */
6903 if (cm) {
6904 new_col = 0;
6905 if (!ii) {
6906 new_col = 1;
6907 } else {
6908 HASH_FIND_INT(cm->chd, &(ROIv[ii]->iLabel), hd);
6909 if (hd) {
6910 new_col = 0; /* exists already, do not add */
6911 } else new_col = 1;
6912 }
6913 if (new_col) { /* add details */
6914 hd = (SUMA_COLOR_MAP_HASH_DATUM *)
6915 SUMA_calloc(1, sizeof(SUMA_COLOR_MAP_HASH_DATUM));
6916 hd->id = ROIv[ii]->iLabel;
6917 hd->colmapindex = iicol;
6918 HASH_ADD_INT(cm->chd, id, hd);
6919
6920 cm->M[iicol][0] = ROIv[ii]->FillColor[0];
6921 cm->M[iicol][1] = ROIv[ii]->FillColor[1];
6922 cm->M[iicol][2] = ROIv[ii]->FillColor[2];
6923 cm->M[iicol][3] = ROIv[ii]->FillColor[3];
6924 cm->idvec[iicol] = ROIv[ii]->iLabel;
6925 cm->cname[iicol] = SUMA_copy_string(ROIv[ii]->Label);
6926 ++iicol;
6927 }
6928 }
6929
6930 for (i=0; i < nn; ++i) {
6931 NodesTotal[cnt] = ivec[i];
6932 ++cnt;
6933 }
6934 N_NodesTotal += nn;
6935 SUMA_free(ivec);ivec=NULL;
6936
6937 }
6938
6939
6940 if (cm) {
6941 /* Now add the not labeled color */
6942 hd = (SUMA_COLOR_MAP_HASH_DATUM *)
6943 SUMA_calloc(1, sizeof(SUMA_COLOR_MAP_HASH_DATUM));
6944 hd->id = Pad_val;
6945 hd->colmapindex = iicol;
6946 HASH_ADD_INT(cm->chd, id, hd);
6947
6948 cm->M[iicol][0] = 0.0;
6949 cm->M[iicol][1] = 0.0;
6950 cm->M[iicol][2] = 0.0;
6951 cm->M[iicol][3] = 0.0;
6952 cm->idvec[iicol] = Pad_val;
6953 cm->cname[iicol] = SUMA_copy_string("NothingHere");
6954 ++iicol;
6955
6956 SUMA_S_Notev("Have %d/%d new entries in colormap\n", iicol, N_ROIv);
6957 /* now trim cm */
6958 if (iicol < cm->N_M[0]) {
6959 SUMA_LH("Trimming excess");
6960 cm->idvec = (int *)SUMA_realloc(cm->idvec, iicol*sizeof(int));;
6961 cm->cname = (char **)SUMA_realloc(cm->cname, iicol * sizeof(char*));
6962 /* reallocating M is a pain in the behind */
6963 pause_mcw_malloc();
6964 for (i=iicol; i<cm->N_M[0]; ++i) {
6965 if (cm->M[i]) free(cm->M[i]); cm->M[i]=NULL;
6966 }
6967 cm->M = (float **)SUMA_realloc(cm->M, iicol * sizeof(float*));
6968 resume_mcw_malloc();
6969 cm->N_M[0] = iicol;
6970 }
6971 *cmp = cm; cm = NULL;
6972 }
6973
6974 if (Pad_to < 0) {
6975 /* Now get the unique set of nodes */
6976 ivec = SUMA_UniqueInt(NodesTotal, N_NodesTotal,
6977 &cnt, 0);
6978 SUMA_free(NodesTotal); NodesTotal = ivec; ivec=NULL;
6979 N_NodesTotal = cnt;
6980 } else {
6981 /* recreate NodesTotal (it was not needed, but that is OK)*/
6982 if (NodesTotal) SUMA_free(NodesTotal); NodesTotal = NULL;
6983 N_NodesTotal = Pad_to+1;
6984 NodesTotal = (int *)SUMA_calloc(N_NodesTotal, sizeof(int));
6985 for (i=0; i<N_NodesTotal; ++i) NodesTotal[i]=i;
6986 }
6987
6988 if (0 && LocalHead) {
6989 SUMA_disp_dvect (NodesTotal, N_NodesTotal);
6990 }
6991
6992 /* Create a datset to store all that stuff */
6993 SUMA_LHv("Ready to fill up %d nodes with %d (%d cols if cmp) values\n",
6994 N_NodesTotal, dlist_size(ddl), cmp ? (*cmp)->N_M[0] : -1);
6995 /* construct a NIML data set for the output */
6996 dset = SUMA_CreateDsetPointer(
6997 NULL,
6998 SUMA_NODE_ROI,
6999 NULL,
7000 Parent_idcode_str,
7001 N_NodesTotal
7002 ); /* DO NOT free dset, it is store in DsetList */
7003
7004
7005
7006 if (!dset) {
7007 SUMA_SL_Err("Failed in SUMA_CreateDsetPointer");
7008 SUMA_RETURN(NULL);
7009 }
7010
7011 /* Add the index column */
7012 SUMA_LH("Adding index column...");
7013 if (!SUMA_AddDsetNelCol ( dset, "node index",
7014 SUMA_NODE_INDEX, (void *)NodesTotal, NULL, 1)) {
7015 SUMA_SL_Err("Failed in SUMA_AddNelCol");
7016 SUMA_RETURN(dset);
7017 }
7018
7019 /* For each label value add a column */
7020 {
7021 icol = 0;
7022 eldd = dlist_head(ddl);
7023 while(eldd) {
7024 dd = (SUMA_ROI_EXTRACT *)eldd->data;
7025 SUMA_LH("Adding label column...");
7026 if (!SUMA_AddDsetNelCol (dset, dd->name,
7027 SUMA_NODE_ILABEL, NULL, NULL, 1)) {
7028 SUMA_SL_Err("Failed in SUMA_AddNelCol");
7029 SUMA_RETURN(dset);
7030 }
7031 ivec = (int *)SDSET_VEC(dset,SDSET_VECNUM(dset)-1);
7032 if (Pad_val) { for (ii=0; ii < N_NodesTotal; ++ii) ivec[ii]=Pad_val; }
7033 for (ii=0; ii < N_ROIv; ++ii) {
7034 SUMA_LHv("Filling label column for label %d from ROI %d...",
7035 dd->label, ROIv[ii]->iLabel);
7036 if (ROIv[ii]->iLabel == dd->label) {
7037 Elm = dlist_head(ROIv[ii]->ROIstrokelist);
7038 while (Elm && Elm->data) {
7039 ROI_Datum = (SUMA_ROI_DATUM *)Elm->data;
7040 SUMA_LHv("Will add %d nodes, label %d, (%d)\n",
7041 ROI_Datum->N_n, dd->label, ROIv[ii]->iLabel);
7042 for (i=0; i < ROI_Datum->N_n; ++i) {
7043 if ((rnode = SUMA_GetNodeRow_FromNodeIndex_s(dset,
7044 ROI_Datum->nPath[i], -1)) < 0) {
7045 SUMA_S_Errv("Failed to get row for node %d\n",
7046 ROI_Datum->nPath[i]);
7047 SUMA_RETURN(NULL); /*leaky return, should not happen */
7048 }
7049 ivec[rnode] = dd->label;
7050 }
7051 Elm = dlist_next(Elm);
7052 }
7053 } /* add ROI's of this label */
7054 } /* ii */
7055 eldd = dlist_next(eldd);
7056 ++icol;
7057 }
7058 }
7059
7060 /* make it easy */
7061 dset->dnel = SUMA_FindDsetDataElement(dset);
7062 dset->inel = SUMA_FindSDsetNodeIndexElement(dset);
7063
7064 /* Set all column ranges, they don't get set when you add columns with NULL */
7065 SUMA_UpdateDsetColRange(dset, -1);
7066
7067 SUMA_LH("cleanup ...");
7068 for (ii=0; ii < N_ROIv; ++ii) {/* free the Drawn ROIs */
7069 if (ROIv[ii]) SUMA_freeDrawnROI (ROIv[ii]); ROIv[ii] = NULL;
7070 }
7071 if (NodesTotal) SUMA_free(NodesTotal); NodesTotal = NULL;
7072 if (ddl) SUMA_free(ddl);
7073
7074
7075 SUMA_RETURN(dset);
7076 }
7077
7078 /*!
7079 \brief turns a bunch of ROIs into a NI dataset
7080
7081 \param ROIv (SUMA_DRAWN_ROI**) vector of ROI structures
7082 \param N_ROIv (int) number of ROI structures
7083 \param Parent_idcode_str (char *) idcode of parent surface
7084 \param Pad_to (int) create Dset that has a full node listing
7085 from node 0 to node Pad_to (a total of Pad_to + 1 nodes)
7086 Use -1 to turn off padding.
7087 \param Pad_val (int) use this value (usually 0) to label a node being padded
7088 as oppsed to a node being a part of an ROI. This option
7089 is only useful with Pad_to
7090 \return nel (NI_element *) structure to data set
7091 NULL if failed
7092 */
SUMA_ROIv2dataset(SUMA_DRAWN_ROI ** ROIv,int N_ROIv,char * Parent_idcode_str,int Pad_to,int Pad_val)7093 NI_element *SUMA_ROIv2dataset (SUMA_DRAWN_ROI** ROIv, int N_ROIv,
7094 char *Parent_idcode_str, int Pad_to, int Pad_val)
7095 {
7096 static char FuncName[]={"SUMA_ROIv2dataset"};
7097 int ii, i, nn, cnt, N_NodesTotal = 0, MaxIndex = 0,
7098 *ip=NULL, *NodesTotal=NULL, *LabelsTotal=NULL,
7099 *NodesTotal_p=NULL, *LabelsTotal_p=NULL;
7100 NI_element *nel=NULL;
7101 SUMA_Boolean LocalHead = NOPE;
7102
7103 SUMA_ENTRY;
7104
7105 SUMA_SL_Err("Obsolete, use SUMA_ROIv2Grpdataset");
7106 SUMA_RETURN(NULL);
7107
7108 /* Now you have the ROIs, concatenate all NodesInROI vectors into 1*/
7109 /* count the total number of nodes */
7110 N_NodesTotal = 0;
7111 for (ii=0; ii < N_ROIv; ++ii) {
7112 SUMA_ROI_CRUDE_COUNT_NODES(ROIv[ii], cnt);
7113 if (LocalHead) {
7114 fprintf (SUMA_STDERR,"%s: ROI #%d: %d nodes\n", FuncName, ii, cnt);
7115 }
7116 N_NodesTotal += cnt;
7117 }
7118 if (LocalHead)
7119 fprintf (SUMA_STDERR,"%s: %d nodes total.\n", FuncName, N_NodesTotal);
7120
7121 NodesTotal = (int *)SUMA_calloc(N_NodesTotal, sizeof(int));
7122 LabelsTotal = (int *)SUMA_calloc(N_NodesTotal, sizeof(int));
7123
7124 if (!NodesTotal || !LabelsTotal) {
7125 SUMA_S_Err("Failed to allocate.");
7126 SUMA_RETURN(nel);
7127 }
7128
7129 cnt = 0;
7130 N_NodesTotal = 0;
7131 MaxIndex = -1;
7132 for (ii=0; ii < N_ROIv; ++ii) {
7133 SUMA_LH("Appending ROI");
7134 /* You do not need the Unique operation in SUMA_NodesInROI,
7135 but it is nice to have so that you can report the nodes that
7136 were part of more than one ROI. If you do not Set the Unique
7137 flag in SUMA_NodesInROI you will likely get node duplication
7138 but these nodes are in the same ROI and therefore are not
7139 duplicates to be removed....*/
7140 ip = SUMA_NodesInROI (ROIv[ii], &nn, YUP);
7141 if (LocalHead) {
7142 fprintf (SUMA_STDERR,"%s: Nodes in ROI #%d\n", FuncName, ii);
7143 SUMA_disp_dvect (ip, nn);
7144 }
7145 for (i=0; i < nn; ++i) {
7146 NodesTotal[cnt] = ip[i];
7147 LabelsTotal[cnt] = ROIv[ii]->iLabel;
7148 if (ip[i] > MaxIndex) MaxIndex = ip[i];
7149 ++cnt;
7150 }
7151 N_NodesTotal += nn;
7152 SUMA_freeDrawnROI (ROIv[ii]); ROIv[ii] = NULL; /* free the Drawn ROI */
7153 SUMA_free(ip);ip=NULL;
7154 }
7155
7156 if (LocalHead) {
7157 SUMA_disp_dvect (NodesTotal, N_NodesTotal);
7158 }
7159
7160 /* Now you want to make sure that no two nodes are listed twice */
7161 /* sort NodesTotal and rearrange LabelsTotal accordingly */
7162 { int *isort = NULL, *LabelsTotal_r = NULL,
7163 *NodesTotal_u = NULL, N_NodesTotal_u, *iu = NULL;
7164 char report[100];
7165
7166 isort = SUMA_z_dqsort(NodesTotal, N_NodesTotal);
7167 LabelsTotal_r = SUMA_reorder (LabelsTotal, isort, N_NodesTotal);
7168 SUMA_free(LabelsTotal);
7169 LabelsTotal = LabelsTotal_r; LabelsTotal_r = NULL;
7170 SUMA_free(isort); isort = NULL;
7171
7172 /* now get the unique set of nodes */
7173 NodesTotal_u = SUMA_UniqueInt_ind (NodesTotal, N_NodesTotal, &N_NodesTotal_u, &iu);
7174 /* reorder LabelsTotal to contain data from the nodes left in NodesTotal_u */
7175 LabelsTotal_r = SUMA_reorder (LabelsTotal, iu, N_NodesTotal_u);
7176 SUMA_free(NodesTotal); NodesTotal = NULL;
7177 SUMA_free(LabelsTotal); LabelsTotal = NULL;
7178 SUMA_free(iu); iu = NULL;
7179 NodesTotal = NodesTotal_u; NodesTotal_u = NULL;
7180 LabelsTotal = LabelsTotal_r; LabelsTotal_r = NULL;
7181
7182 if (N_NodesTotal - N_NodesTotal_u) {
7183 sprintf(report, "%d/%d nodes had duplicate entries.\n"
7184 "(ie same node part of more than 1 ROI)\n"
7185 "Duplicate entries were eliminated.",
7186 N_NodesTotal - N_NodesTotal_u , N_NodesTotal);
7187
7188 N_NodesTotal = N_NodesTotal_u; N_NodesTotal_u = 0;
7189 SUMA_SLP_Warn("%s",report);
7190 }
7191 }
7192
7193 if (Pad_to > 0) {
7194 SUMA_LH("Padding to desired length");
7195 if (Pad_to < MaxIndex) {
7196 SUMA_SL_Err("ROI contains node index > padding limit\n"
7197 "No padding done.");
7198 if (NodesTotal) SUMA_free(NodesTotal); NodesTotal = NULL;
7199 if (LabelsTotal) SUMA_free(LabelsTotal); LabelsTotal = NULL;
7200 SUMA_RETURN(NULL);
7201 }else {
7202 NodesTotal_p = (int *)SUMA_calloc(Pad_to+1, sizeof(int));
7203 LabelsTotal_p = (int *)SUMA_calloc(Pad_to+1, sizeof(int));
7204 if (!NodesTotal_p || !LabelsTotal_p) {
7205 SUMA_SL_Crit("Failed to allocate for NodesTotal_p || LabelsTotal_p");
7206 if (NodesTotal) SUMA_free(NodesTotal); NodesTotal = NULL;
7207 if (LabelsTotal) SUMA_free(LabelsTotal); LabelsTotal = NULL;
7208 SUMA_RETURN(NULL);
7209 }
7210 if (Pad_val) for(i=0; i<=Pad_to; ++i) LabelsTotal_p[i] = Pad_val;
7211 for(i=0; i<=Pad_to; ++i) NodesTotal_p[i] = i;
7212 for(i=0; i<N_NodesTotal; ++i) {
7213 LabelsTotal_p[NodesTotal[i]] = LabelsTotal[i];
7214 }
7215 SUMA_free(NodesTotal); NodesTotal = NodesTotal_p; NodesTotal_p = NULL;
7216 SUMA_free(LabelsTotal); LabelsTotal = LabelsTotal_p; LabelsTotal_p = NULL;
7217 N_NodesTotal = Pad_to + 1;
7218 }
7219 }
7220
7221 /* construct a NIML data set for the output */
7222 SUMA_LH("Creating nel ");
7223 nel = SUMA_NewNel ( SUMA_NODE_ROI, /* one of SUMA_DSET_TYPE */
7224 Parent_idcode_str, /* idcode of Domain Parent */
7225 NULL, /* idcode of geometry parent, not useful here*/
7226 N_NodesTotal,/* Number of elements */
7227 NULL,
7228 NULL);
7229
7230 if (!nel) {
7231 SUMA_SL_Err("Failed in SUMA_NewNel");
7232 SUMA_RETURN(nel);
7233 }
7234
7235 /* Add the index column */
7236 SUMA_LH("Adding index column...");
7237 if (!SUMA_AddNelCol (nel, "node index", SUMA_NODE_INDEX, (void *)NodesTotal, NULL, 1)) {
7238 SUMA_SL_Err("Failed in SUMA_AddNelCol");
7239 SUMA_RETURN(nel);
7240 }
7241
7242 /* Add the label column */
7243 SUMA_LH("Adding label column...");
7244 if (!SUMA_AddNelCol (nel, "integer label", SUMA_NODE_ILABEL, (void *)LabelsTotal, NULL, 1)) {
7245 SUMA_SL_Err("Failed in SUMA_AddNelCol");
7246 SUMA_RETURN(nel);
7247 }
7248
7249 SUMA_LH("cleanup ...");
7250 if (NodesTotal) SUMA_free(NodesTotal); NodesTotal = NULL;
7251 if (LabelsTotal) SUMA_free(LabelsTotal); LabelsTotal = NULL;
7252
7253 SUMA_RETURN(nel);
7254 }
7255
7256
7257 /*!
7258 \brief handles savinf SO to ascii filename
7259
7260 \param filename (char *)
7261 \param data(void *) pointer to SUMA_SAVESO_STRUCT containing sv and SO be saved
7262
7263 - This function frees the SUMA_SAVESO_STRUCT before returning
7264 */
SUMA_SaveSOascii(char * filename,void * data)7265 void SUMA_SaveSOascii (char *filename, void *data)
7266 {
7267 static char FuncName[]={"SUMA_SaveSOascii"};
7268 char *newname = NULL, *newprefix = NULL, *tmp1= NULL, *tmp2= NULL;
7269 FILE *Fout = NULL;
7270 static int answer;
7271 int ND=-1, NP=-1, ii=-1, id=-1,ip=-1;
7272 GLfloat *glar_ColorList = NULL;
7273 SUMA_SAVESO_STRUCT *SaveSO_data = NULL;
7274 SUMA_Boolean LocalHead = NOPE;
7275
7276 SUMA_ENTRY;
7277
7278 SUMA_LH("Called");
7279
7280 if (!data) {
7281 SUMA_SLP_Err("NULL data");
7282 SUMA_RETURNe;
7283 }
7284
7285 SaveSO_data = (SUMA_SAVESO_STRUCT *)data;
7286 if (!SaveSO_data->SO || !SaveSO_data->sv) {
7287 SUMA_SLP_Err("Null SO or Null sv");
7288 if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
7289 SUMA_RETURNe;
7290 }
7291
7292 /* remove any of the extensions to be used */
7293 tmp1 = SUMA_Extension(filename, ".1D.xyz", YUP);
7294 tmp2 = SUMA_Extension(tmp1, ".1D.tri", YUP);
7295 newprefix = SUMA_Extension(tmp2, ".1D.col", YUP);
7296 if (tmp1) SUMA_free(tmp1); tmp1 = NULL;
7297 if (tmp2) SUMA_free(tmp2); tmp2 = NULL;
7298
7299 /* add a .xyz extension */
7300 if (newname) SUMA_free(newname); newname = NULL;
7301 newname = SUMA_Extension(newprefix, ".1D.xyz", NOPE);
7302 if (!newname) {
7303 SUMA_SL_Err("Invalid filename");
7304 if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
7305 SUMA_RETURNe;
7306 }
7307 SUMA_LH("%s", newname);
7308 /* check for filename existence */
7309 if (SUMA_filexists (newname)) {
7310 answer = SUMA_ForceUser_YesNo (SUMAg_SVv[0].X->TOPLEVEL,
7311 "Prefix exists, overwrite?",
7312 SUMA_NO, SWP_DONT_CARE);
7313 if (answer == SUMA_NO ||answer == SUMA_NO_ALL) {
7314 if (newname) SUMA_free(newname); newname = NULL;
7315 if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
7316 SUMA_RETURNe;
7317 }
7318 }
7319
7320 /* add a .tri extension */
7321 if (answer != SUMA_YES_ALL && answer != SUMA_YES) {
7322 if (newname) SUMA_free(newname);newname = NULL;
7323 newname = SUMA_Extension(newprefix, ".1D.tri", NOPE);
7324 if (!newname) {
7325 SUMA_SL_Err("Invalid filename");
7326 if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
7327 SUMA_RETURNe;
7328 }
7329 SUMA_LH("%s",newname);
7330 /* check for filename existence */
7331 if (SUMA_filexists (newname)) {
7332 answer = SUMA_ForceUser_YesNo (SUMAg_SVv[0].X->TOPLEVEL,
7333 "Prefix exists, overwrite?",
7334 SUMA_NO, SWP_DONT_CARE);
7335 if (answer == SUMA_NO ||answer == SUMA_NO_ALL) {
7336 if (newname) SUMA_free(newname);newname = NULL;
7337 if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
7338 SUMA_RETURNe;
7339 }
7340 }
7341 }
7342
7343 /* add a .col extension */
7344 if (answer != SUMA_YES_ALL && answer != SUMA_YES) {
7345 if (newname) SUMA_free(newname); newname = NULL;
7346 newname = SUMA_Extension(newprefix, ".1D.col", NOPE);
7347 if (!newname) {
7348 SUMA_SL_Err("Invalid filename");
7349 if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
7350 SUMA_RETURNe;
7351 }
7352 SUMA_LH("%s", newname);
7353 /* check for filename existence */
7354 if (SUMA_filexists (newname)) {
7355 answer = SUMA_ForceUser_YesNo (SUMAg_SVv[0].X->TOPLEVEL,
7356 "Prefix exists, overwrite?",
7357 SUMA_NO, SWP_DONT_CARE);
7358 if (answer == SUMA_NO ||answer == SUMA_NO_ALL) {
7359 if (newname) SUMA_free(newname);newname = NULL;
7360 if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
7361 SUMA_RETURNe;
7362 }
7363 }
7364 }
7365
7366 /* OK, names are acceptable, proceed */
7367 ND = SaveSO_data->SO->NodeDim;
7368 NP = SaveSO_data->SO->FaceSetDim;
7369
7370 if (newname) SUMA_free(newname);newname = NULL;
7371 newname = SUMA_Extension(newprefix, ".1D.xyz", NOPE);
7372 SUMA_LH("Preparing to write .1D.xyz %s.\n", newname);
7373 Fout = fopen(newname, "w");
7374 if (Fout == NULL) {
7375 SUMA_S_Err("Could not open file %s for writing.\n", newname);
7376 if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
7377 SUMA_RETURNe;
7378 }
7379
7380 fprintf(Fout, "#FileContents = Node coordinates\n"
7381 "#RowFormat = X Y Z\n"
7382 "#N_Nodes = %d\n"
7383 "#Source = SUMA, surface %s (idcode: %s)\n",
7384 SaveSO_data->SO->N_Node,
7385 SaveSO_data->SO->Label, SaveSO_data->SO->idcode_str);
7386 for (ii=0; ii < SaveSO_data->SO->N_Node; ++ii) {
7387 id = ND * ii;
7388 fprintf(Fout, "%f\t%f\t%f\n",
7389 SaveSO_data->SO->NodeList[id],
7390 SaveSO_data->SO->NodeList[id+1],SaveSO_data->SO->NodeList[id+2]);
7391 }
7392 fclose (Fout);
7393
7394 if (newname) SUMA_free(newname);newname = NULL;
7395 newname = SUMA_Extension(newprefix, ".1D.tri", NOPE);
7396 SUMA_LH("Preparing to write .1D.tri %s.\n", newname);
7397 Fout = fopen(newname, "w");
7398 if (Fout == NULL) {
7399 SUMA_S_Err("Could not open file %s for writing.\n", newname);
7400 if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
7401 SUMA_RETURNe;
7402 }
7403
7404 fprintf(Fout, "#FileContents = Triangles\n"
7405 "#RowFormat = n1 n2 n3\n"
7406 "#N_Tri = %d\n"
7407 "#Source = SUMA, surface %s (idcode: %s)\n",
7408 SaveSO_data->SO->N_FaceSet, SaveSO_data->SO->Label,
7409 SaveSO_data->SO->idcode_str);
7410 for (ii=0; ii < SaveSO_data->SO->N_FaceSet; ++ii) {
7411 ip = NP * ii;
7412 fprintf(Fout, "%d\t%d\t%d\n",
7413 SaveSO_data->SO->FaceSetList[ip],
7414 SaveSO_data->SO->FaceSetList[ip+1],SaveSO_data->SO->FaceSetList[ip+2]);
7415 }
7416 fclose (Fout);
7417
7418 if (newname) SUMA_free(newname);newname = NULL;
7419 newname = SUMA_Extension(newprefix, ".1D.col", NOPE);
7420 SUMA_LH("Preparing to write .1D.col %s.\n", newname);
7421 Fout = fopen(newname, "w");
7422 if (Fout == NULL) {
7423 SUMA_S_Err("Could not open file %s for writing.\n", newname);
7424 if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
7425 SUMA_RETURNe;
7426 }
7427 glar_ColorList =
7428 SUMA_GetColorList (SaveSO_data->sv, SaveSO_data->SO->idcode_str);
7429 if (!glar_ColorList) {
7430 fprintf(SUMA_STDERR, "Error %s: NULL glar_ColorList. BAD.\n", FuncName);
7431 if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
7432 SUMA_RETURNe;
7433 }
7434 fprintf(Fout, "#FileContents = Node Colors\n"
7435 "#RowFormat = n R G B\n"
7436 "#N_Nodes = %d\n"
7437 "#Source = SUMA, surface %s (idcode: %s)\n",
7438 SaveSO_data->SO->N_Node, SaveSO_data->SO->Label,
7439 SaveSO_data->SO->idcode_str);
7440 for (ii=0; ii < SaveSO_data->SO->N_Node; ++ii) {
7441 ip = 4 * ii;
7442 fprintf(Fout, "%d\t%f\t%f\t%f\n",
7443 ii, glar_ColorList[ip], glar_ColorList[ip+1], glar_ColorList[ip+2]);
7444 }
7445 fclose (Fout);
7446
7447 if (LocalHead) fprintf(SUMA_STDERR, "%s: Wrote files to disk.\n",
7448 FuncName);
7449
7450 if (newname) SUMA_free(newname);newname = NULL;
7451 if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
7452 if (newprefix) SUMA_free(newprefix);
7453 SUMA_RETURNe;
7454 }
7455 /*!
7456 \brief handles saving xform opts to filename.
7457
7458 \param filename (char *)
7459 \param data(void *) pointer to SUMA_XFORM stucture to be saved.
7460 */
SUMA_SaveXformOpts(char * filename,void * data)7461 void SUMA_SaveXformOpts (char *filename, void *data)
7462 {
7463 static char FuncName[]={"SUMA_SaveXformOpts"};
7464 SUMA_XFORM *xf=(SUMA_XFORM *)data;
7465 char *fn=NULL;
7466 int suc;
7467 NI_element *dotopts=NULL;
7468 SUMA_Boolean LocalHead = NOPE;
7469
7470 SUMA_ENTRY;
7471
7472 SUMA_LH("Called");
7473 if (!data) {
7474 SUMA_S_Err("NULL input");
7475 SUMA_RETURNe;
7476 }
7477
7478 SUMA_LHv("Xform %s, filename %s\n", xf->name, filename);
7479
7480 if (!strcmp(xf->name,"Dot")) {
7481 if (!(dotopts = SUMA_FindNgrNamedElement(xf->XformOpts, "dotopts"))) {
7482 SUMA_S_Err("No dotopts");
7483 SUMA_RETURNe;
7484 }
7485 fn = SUMA_Extension(filename, ".niml.xfopts", NOPE);
7486 fn = SUMA_append_replace_string("file:",fn,"",2);
7487 NEL_WRITE_1D(dotopts, fn, suc);
7488 SUMA_free(fn);
7489 } else {
7490 fn = SUMA_Extension(filename, ".niml.xfopts", NOPE);
7491 fn = SUMA_append_replace_string("file:",fn,"",2);
7492 NEL_WRITE_TXH(xf->XformOpts, fn, suc);
7493 }
7494
7495 SUMA_RETURNe;
7496 }
7497
7498 /*!
7499 \brief handles saving ROI to filename.
7500
7501 \param filename (char *)
7502 \param data(void *) pointer to DrawnROI stucture to be saved.
7503 If you pass null then SUMAg_CF->X->DrawROI->curDrawnROI is used.
7504 */
SUMA_SaveDrawnROI(char * filename,void * data)7505 void SUMA_SaveDrawnROI (char *filename, void *data)
7506 {
7507 static char FuncName[]={"SUMA_SaveDrawnROI"};
7508 SUMA_DRAWN_ROI *DrawnROI=NULL;
7509 SUMA_SurfaceObject *SO= NULL;
7510 SUMA_Boolean LocalHead = NOPE;
7511
7512 SUMA_ENTRY;
7513
7514 SUMA_LH("Called");
7515 if (!data) {
7516 DrawnROI = SUMAg_CF->X->DrawROI->curDrawnROI;
7517 } else {
7518 DrawnROI = (SUMA_DRAWN_ROI *)data;
7519 }
7520
7521 /* is there a DrawnROI to work with ? */
7522 if (!DrawnROI) {
7523 SUMA_SLP_Err("No ROI selected.");
7524 SUMA_RETURNe;
7525 }
7526
7527 /* Find the parent SO of that ROI */
7528 SO = SUMA_findSOp_inDOv(DrawnROI->Parent_idcode_str, SUMAg_DOv, SUMAg_N_DOv);
7529 if (!SO) {
7530 SUMA_SLP_Err("No Parent surface found.");
7531 SUMA_RETURNe;
7532 }
7533
7534 /* switch the type of saving */
7535 switch (SUMAg_CF->X->DrawROI->SaveMode) {
7536 case SW_DrawROI_SaveMode1D:
7537 if (!SUMA_SaveDrawnROI_1D (filename, SO, DrawnROI,
7538 SUMAg_CF->X->DrawROI->SaveWhat)) {
7539 SUMA_SLP_Err("Failed to save ROI to disk");
7540 SUMA_RETURNe;
7541 }
7542 break;
7543 case SW_DrawROI_SaveModeNIML:
7544 if (!SUMA_SaveDrawnROINIML (filename, SO, DrawnROI,
7545 SUMAg_CF->X->DrawROI->SaveWhat, SUMA_ASCII)) {
7546 SUMA_SLP_Err("Failed to save ROI to disk");
7547 SUMA_RETURNe;
7548 }
7549 break;
7550 case SW_DrawROI_SaveMode:
7551 case SW_N_DrawROI_SaveMode:
7552 default:
7553 SUMA_SL_Err("WhatYouTalkinAbout?");
7554 SUMA_RETURNe;
7555 break;
7556 }
7557
7558 SUMA_RETURNe;
7559 }
7560
SUMA_SaveDrawnROI_1D(char * filename,SUMA_SurfaceObject * SO,SUMA_DRAWN_ROI * DrawnROI,int SaveWhat)7561 SUMA_Boolean SUMA_SaveDrawnROI_1D (char *filename, SUMA_SurfaceObject *SO,
7562 SUMA_DRAWN_ROI *DrawnROI, int SaveWhat)
7563 {
7564 static char FuncName[]={"SUMA_SaveDrawnROI_1D"};
7565 char stmp[SUMA_MAX_NAME_LENGTH+20];
7566 SUMA_DRAWN_ROI **ROIv = NULL;
7567 int N_ROI=0;
7568 SUMA_Boolean LocalHead = NOPE;
7569
7570 SUMA_ENTRY;
7571 SUMA_LH("Called");
7572
7573 if (SaveWhat == SW_DrawROI_SaveWhatThis) {
7574 if (!SUMA_Write_DrawnROI_1D (&DrawnROI, 1, filename)) {
7575 sprintf(stmp,"Failed to write %s", filename);
7576 SUMA_SLP_Err("%s",stmp);
7577 SUMA_RETURN(NOPE);
7578 }
7579 }else if (SaveWhat == SW_DrawROI_SaveWhatRelated){
7580 /* get the pointers to the ROIs that are related to SO*/
7581 if (!(ROIv = SUMA_Find_ROIrelatedtoSO (SO, SUMAg_DOv, SUMAg_N_DOv,
7582 &N_ROI))) {
7583 SUMA_SLP_Err("Failed to write ROIs related to SO.");
7584 SUMA_RETURN(NOPE);
7585 }
7586 if (!SUMA_Write_DrawnROI_1D (ROIv, N_ROI, filename)) {
7587 sprintf(stmp,"Failed to write %s", filename);
7588 SUMA_SLP_Err("%s",stmp);
7589 SUMA_RETURN(NOPE);
7590 }
7591
7592 if (ROIv) SUMA_free(ROIv);
7593 } else {
7594 SUMA_SLP_Err("SaveWhat option not nderstood");
7595 SUMA_RETURN(NOPE);
7596 }
7597
7598
7599
7600 SUMA_RETURN(YUP);
7601 }
7602
SUMA_SaveDrawnROINIML(char * filename,SUMA_SurfaceObject * SO,SUMA_DRAWN_ROI * DrawnROI,int SaveWhat,int Format)7603 SUMA_Boolean SUMA_SaveDrawnROINIML (char *filename, SUMA_SurfaceObject *SO,
7604 SUMA_DRAWN_ROI *DrawnROI, int SaveWhat,
7605 int Format)
7606 {
7607 static char FuncName[]={"SaveDrawnROINIML"};
7608 char stmp[SUMA_MAX_NAME_LENGTH+20];
7609 SUMA_DRAWN_ROI **ROIv = NULL;
7610 int N_ROI=0;
7611 SUMA_Boolean LocalHead = NOPE;
7612
7613 SUMA_ENTRY;
7614 SUMA_LH("Called");
7615
7616 if (SaveWhat == SW_DrawROI_SaveWhatThis) {
7617 if (!SUMA_Write_DrawnROI_NIML (&DrawnROI, 1, filename, Format)) {
7618 sprintf(stmp,"Failed to write %s", filename);
7619 SUMA_SLP_Err("%s",stmp);
7620 SUMA_RETURN(NOPE);
7621 }
7622 }else if (SaveWhat == SW_DrawROI_SaveWhatRelated){
7623 /* get the pointers to the ROIs that are related to SO*/
7624 if (!(ROIv = SUMA_Find_ROIrelatedtoSO (SO, SUMAg_DOv, SUMAg_N_DOv,
7625 &N_ROI))) {
7626 SUMA_SLP_Err("Failed to write ROIs related to SO.");
7627 SUMA_RETURN(NOPE);
7628 }
7629 if (!SUMA_Write_DrawnROI_NIML (ROIv, N_ROI, filename, Format)) {
7630 sprintf(stmp,"Failed to write %s", filename);
7631 SUMA_SLP_Err("%s",stmp);
7632 SUMA_RETURN(NOPE);
7633 }
7634
7635 if (ROIv) SUMA_free(ROIv);
7636 } else {
7637 SUMA_SLP_Err("SaveWhat option not nderstood");
7638 SUMA_RETURN(NOPE);
7639 }
7640
7641 SUMA_RETURN(YUP);
7642 }
7643
7644 /*!
7645 \brief writes a vector of SUMA_DRAWN_ROI * to disk in NIML format
7646 */
7647
SUMA_Write_DrawnROI_NIML(SUMA_DRAWN_ROI ** ROIv,int N_ROI,char * filename,int Format)7648 SUMA_Boolean SUMA_Write_DrawnROI_NIML (SUMA_DRAWN_ROI **ROIv, int N_ROI,
7649 char *filename, int Format)
7650 {
7651 static char FuncName[]={"SUMA_Write_DrawnROI_NIML"};
7652 char stmp[SUMA_MAX_NAME_LENGTH+20];
7653 char *newname=NULL;
7654 int i;
7655 NI_element *nel ;
7656 NI_stream ns ;
7657 SUMA_NIML_DRAWN_ROI *niml_ROI = NULL;
7658 SUMA_DRAWN_ROI *ROI = NULL;
7659 SUMA_Boolean WriteBin = NOPE, LocalHead = NOPE;
7660
7661 SUMA_ENTRY;
7662
7663 if (Format == SUMA_ASCII) WriteBin = NOPE;
7664 else if (Format == SUMA_BINARY) WriteBin = YUP;
7665 else {
7666 SUMA_SL_Err("Wrong format");
7667 SUMA_RETURN(NOPE);
7668 }
7669
7670 if (SUMAg_CF->nimlROI_Datum_type < 0) {
7671 SUMA_SL_Err("Bad niml type code");
7672 SUMA_RETURN(NOPE);
7673 }
7674 if (LocalHead) fprintf(SUMA_STDERR, "%s: roi_type code = %d\n",
7675 FuncName, SUMAg_CF->nimlROI_Datum_type) ;
7676
7677 /* add a .niml.roi extension */
7678 if (strlen(filename) >= SUMA_MAX_NAME_LENGTH-20) {
7679 SUMA_SLP_Err("Give me a break, what kind of a filename is this ?");
7680 SUMA_RETURN(NOPE);
7681 }
7682
7683 sprintf(stmp,"file:%s", filename);
7684 newname = SUMA_Extension(stmp, ".niml.roi", NOPE);
7685 SUMA_LH("%s",newname);
7686 ns = NI_stream_open( newname , "w" ) ;
7687
7688 /* write the various ROIs */
7689 for (i=0; i < N_ROI; ++i) {
7690 ROI = ROIv[i];
7691 if (!ROI) {
7692 SUMA_SL_Err("NULL ROI!");
7693 NI_stream_close( ns ) ;
7694 SUMA_RETURN(NOPE);
7695 }
7696 /* Transform the ROI to niml friendly structure */
7697 if (!(niml_ROI = SUMA_DrawnROI_to_NIMLDrawnROI (ROI))) {
7698 SUMA_SL_Err("NULL niml_ROI!");
7699 NI_stream_close( ns ) ;
7700 SUMA_RETURN(NOPE);
7701 }
7702
7703 /* Now create a ni element */
7704 if (LocalHead)
7705 fprintf( SUMA_STDERR,
7706 "%s: Creating new element of %d segments\n",
7707 FuncName, niml_ROI->N_ROI_datum);
7708 nel = NI_new_data_element( SUMA_Dset_Type_Name(SUMA_NODE_ROI),
7709 niml_ROI->N_ROI_datum);
7710
7711 SUMA_LH("Adding column...");
7712 NI_add_column( nel , SUMAg_CF->nimlROI_Datum_type, niml_ROI->ROI_datum );
7713
7714 SUMA_LH("Setting attributes...");
7715 NI_set_attribute (nel, "self_idcode", niml_ROI->idcode_str);
7716 NI_set_attribute (nel, "domain_parent_idcode",
7717 niml_ROI->Parent_idcode_str);
7718 NI_set_attribute (nel, "Parent_side",
7719 SUMA_SideName(niml_ROI->Parent_side));
7720 NI_set_attribute (nel, "Label", niml_ROI->Label);
7721 sprintf(stmp,"%d", niml_ROI->iLabel);
7722 NI_set_attribute (nel, "iLabel", stmp);
7723 sprintf(stmp,"%d", niml_ROI->Type);
7724 NI_set_attribute (nel, "Type", stmp);
7725 NI_set_attribute (nel, "ColPlaneName", niml_ROI->ColPlaneName);
7726 sprintf(stmp,"%f %f %f %f", niml_ROI->FillColor[0], niml_ROI->FillColor[1],
7727 niml_ROI->FillColor[2], niml_ROI->FillColor[3]);
7728 NI_set_attribute (nel, "FillColor",stmp);
7729 sprintf(stmp,"%f %f %f %f", niml_ROI->EdgeColor[0], niml_ROI->EdgeColor[1],
7730 niml_ROI->EdgeColor[2], niml_ROI->EdgeColor[3]);
7731 NI_set_attribute (nel, "EdgeColor",stmp);
7732 sprintf(stmp,"%d", niml_ROI->EdgeThickness);
7733 NI_set_attribute (nel, "EdgeThickness", stmp);
7734
7735 if (LocalHead) SUMA_nel_stdout (nel);
7736
7737 if (!WriteBin) {
7738 SUMA_LH ("Writing element, Text mode.");
7739 if (NI_write_element( ns , nel ,
7740 NI_TEXT_MODE | NI_HEADERSHARP_FLAG ) < 0) {
7741 SUMA_SL_Err("Badness, failed to write nel");
7742 NI_stream_close( ns ) ;
7743 SUMA_RETURN(NOPE);
7744 }
7745 } else {
7746 SUMA_LH ("Writing element, Binary mode.");
7747 if (NI_write_element( ns , nel , NI_BINARY_MODE) < 0) {
7748 SUMA_SL_Err("Badness, failed to write nel");
7749 NI_stream_close( ns ) ;
7750 SUMA_RETURN(NOPE);
7751 }
7752 }
7753
7754 /* free nel */
7755 NI_free_element(nel) ; nel = NULL;
7756
7757 /* free the niml_ROI structure */
7758 niml_ROI = SUMA_Free_NIMLDrawROI (niml_ROI); niml_ROI = NULL;
7759
7760 }
7761
7762 NI_stream_close( ns ) ;
7763
7764 if (newname) SUMA_free(newname);
7765
7766 SUMA_RETURN(YUP);
7767 }
7768
7769
7770 /*!
7771 \brief A function to take a SUMA_DRAWN_ROI struct and return an equivalent
7772 SUMA_1D_DRAWN_ROI struct.
7773
7774 - Do not free SUMA_1D_DRAWN_ROI manually, many of its fields are
7775 pointer copies of values in SUMA_DRAWN_ROI.
7776
7777 \sa SUMA_Free_1DDrawROI
7778 */
SUMA_DrawnROI_to_1DDrawROI(SUMA_DRAWN_ROI * ROI)7779 SUMA_1D_DRAWN_ROI * SUMA_DrawnROI_to_1DDrawROI (SUMA_DRAWN_ROI *ROI)
7780 {
7781 static char FuncName[]={"SUMA_DrawnROI_to_1DDrawROI"};
7782 SUMA_1D_DRAWN_ROI *ROI_1D=NULL;
7783 SUMA_ROI_DATUM *ROI_Datum=NULL;
7784 DListElmt *Elm = NULL;
7785 int i = -1, cnt = 0, *isort=NULL, *iLabel=NULL, *iNode=NULL;
7786 SUMA_Boolean LocalHead = NOPE;
7787
7788 SUMA_ENTRY;
7789
7790 if (!ROI) {
7791 SUMA_SL_Err("Null ROI");
7792 SUMA_RETURN(NULL);
7793 }
7794
7795 /* count the total number of nodes in ROI */
7796
7797 /* allocate for nimlROI */
7798 ROI_1D = (SUMA_1D_DRAWN_ROI *)SUMA_calloc(1,sizeof(SUMA_1D_DRAWN_ROI));
7799 Elm = NULL;
7800 ROI_1D->N = 0;
7801 do {
7802 if (!Elm) Elm = dlist_head(ROI->ROIstrokelist);
7803 else Elm = Elm->next;
7804 ROI_Datum = (SUMA_ROI_DATUM *)Elm->data;
7805 ROI_1D->N += ROI_Datum->N_n;
7806 } while (Elm != dlist_tail(ROI->ROIstrokelist));
7807
7808 ROI_1D->Type = (int)ROI->Type;
7809 ROI_1D->idcode_str = ROI->idcode_str;
7810 ROI_1D->Parent_idcode_str = ROI->Parent_idcode_str;
7811 ROI_1D->Parent_side = ROI->Parent_side;
7812 ROI_1D->Label = ROI->Label;
7813 ROI_1D->iNode = NULL;
7814 ROI_1D->iLabel = NULL;
7815 iNode = (int *) SUMA_calloc(ROI_1D->N, sizeof(int));
7816 iLabel = (int *) SUMA_calloc(ROI_1D->N, sizeof(int));
7817 if (!iNode || !iLabel) {
7818 SUMA_SL_Err("Failed to allocate");
7819 SUMA_RETURN(NULL);
7820 }
7821
7822 /* now fill the node indices and the node values */
7823 Elm = NULL;
7824 cnt = 0;
7825 do {
7826 if (!Elm) Elm = dlist_head(ROI->ROIstrokelist);
7827 else Elm = Elm->next;
7828 ROI_Datum = (SUMA_ROI_DATUM *)Elm->data;
7829 for (i=0; i < ROI_Datum->N_n; ++i) {
7830 iNode[cnt] = ROI_Datum->nPath[i];
7831 iLabel[cnt] = ROI->iLabel;
7832 ++cnt;
7833 }
7834 } while (Elm != dlist_tail(ROI->ROIstrokelist));
7835
7836 /* some node entries are redundant, clear those up */
7837 /* first sort iNode */
7838 isort = SUMA_z_dqsort( iNode, ROI_1D->N);
7839
7840 /* Now sort the labels accordingly */
7841 ROI_1D->iLabel = (int *) SUMA_calloc(ROI_1D->N, sizeof(int));
7842 ROI_1D->iNode = (int *) SUMA_calloc(ROI_1D->N, sizeof(int));
7843 if (!ROI_1D->iNode || !ROI_1D->iLabel) {
7844 SUMA_SL_Err("Failed to allocate");
7845 SUMA_RETURN(NULL);
7846 }
7847
7848 for (i=0; i < ROI_1D->N; ++i) {
7849 ROI_1D->iLabel[i] = iLabel[isort[i]];
7850 }
7851 if (iLabel) SUMA_free(iLabel); iLabel = NULL; /* done with unsorted version of iLabel */
7852
7853 /* Now remove redundant entries */
7854 cnt = 0;
7855 ROI_1D->iNode[cnt] = iNode[0];
7856 ROI_1D->iLabel[cnt] = ROI_1D->iLabel[0];
7857 ++cnt;
7858 for (i=1;i<ROI_1D->N;++i)
7859 {
7860 if ((iNode[i] != iNode[i- 1]))
7861 {
7862 ROI_1D->iNode[cnt] = iNode[i];
7863 ROI_1D->iLabel[cnt] = ROI_1D->iLabel[i];
7864 ++cnt;
7865 }
7866 }
7867
7868
7869 /* you would reallocate here, because cnt is always <= ROI_1D->N,
7870 but it is not worth the effort because cnt is only slightly
7871 less than ROI_1D->N */
7872
7873 /* just update ROI_1D->N */
7874 ROI_1D->N = cnt;
7875
7876 if (isort) SUMA_free(isort); isort = NULL;
7877 if (iNode) SUMA_free(iNode); iNode = NULL;
7878
7879 SUMA_RETURN(ROI_1D);
7880 }
7881 /*!
7882 \brief A function to find the range of node values in an ROI
7883 \returns the maximum number of nodes in this ROI.
7884
7885 */
SUMA_NodeRange_DrawnROI(SUMA_DRAWN_ROI * ROI,int * min,int * max)7886 int SUMA_NodeRange_DrawnROI (SUMA_DRAWN_ROI *ROI, int *min, int *max)
7887 {
7888 static char FuncName[]={"SUMA_NodeRange_DrawnROI"};
7889
7890 SUMA_ROI_DATUM *ROI_Datum=NULL;
7891 DListElmt *Elm = NULL;
7892 int i = -1, cnt = 0;
7893 SUMA_Boolean LocalHead = NOPE;
7894
7895 SUMA_ENTRY;
7896
7897 if (!ROI || !min || !max) {
7898 SUMA_SL_Err("Null ROI");
7899 SUMA_RETURN(-1);
7900 }
7901
7902 /* count the total number of nodes in ROI */
7903
7904
7905 /* now fill the node indices and the node values */
7906 Elm = NULL;
7907 *min = -1;
7908 *max = -1;
7909 cnt = 0;
7910 do {
7911 if (!Elm) Elm = dlist_head(ROI->ROIstrokelist);
7912 else Elm = Elm->next;
7913 ROI_Datum = (SUMA_ROI_DATUM *)Elm->data;
7914 for (i=0; i < ROI_Datum->N_n; ++i) {
7915 if (*min < 0) *min = ROI_Datum->nPath[i];
7916 else if (*min > ROI_Datum->nPath[i]) *min = ROI_Datum->nPath[i];
7917
7918 if (*max < ROI_Datum->nPath[i]) *max = ROI_Datum->nPath[i];
7919 ++cnt;
7920 }
7921 } while (Elm != dlist_tail(ROI->ROIstrokelist));
7922
7923 SUMA_RETURN(cnt);
7924 }
7925
7926
7927 /*!
7928 \brief frees a ROI_1D structure. These structures are created by
7929 the likes of SUMA_DrawnROI_to_1DDrawROI
7930
7931 \sa SUMA_DrawnROI_to_1DDrawROI
7932 */
SUMA_Free_1DDrawROI(SUMA_1D_DRAWN_ROI * ROI_1D)7933 SUMA_1D_DRAWN_ROI * SUMA_Free_1DDrawROI (SUMA_1D_DRAWN_ROI *ROI_1D)
7934 {
7935 static char FuncName[]={"SUMA_Free_1DDrawROI"};
7936 SUMA_Boolean LocalHead = NOPE;
7937
7938 SUMA_ENTRY;
7939
7940 if (!ROI_1D) SUMA_RETURN(NULL);
7941
7942 if (ROI_1D->iLabel) SUMA_free(ROI_1D->iLabel);
7943 if (ROI_1D->iNode) SUMA_free(ROI_1D->iNode);
7944
7945 SUMA_free(ROI_1D);
7946
7947 SUMA_RETURN(NULL);
7948 }
7949
7950
7951 /*!
7952 \brief writes a vector of SUMA_DRAWN_ROI * to disk in afni's 1D ascii format
7953 */
7954
SUMA_Write_DrawnROI_1D(SUMA_DRAWN_ROI ** ROIv,int N_ROI,char * filename)7955 SUMA_Boolean SUMA_Write_DrawnROI_1D (SUMA_DRAWN_ROI **ROIv, int N_ROI,
7956 char *filename)
7957 {
7958 static char FuncName[]={"SUMA_Write_DrawnROI_1D"};
7959 char *newname=NULL;
7960 int i,j;
7961 SUMA_1D_DRAWN_ROI *ROI_1D = NULL;
7962 SUMA_DRAWN_ROI *ROI = NULL;
7963 FILE *fout=NULL;
7964 SUMA_Boolean LocalHead = NOPE;
7965
7966 SUMA_ENTRY;
7967
7968 /* add a .1D.roi extension */
7969 newname = SUMA_Extension(filename, ".1D.roi", NOPE);
7970 if (!newname) {
7971 SUMA_SL_Err("Invalid filename");
7972 SUMA_RETURN(NOPE);
7973 }
7974
7975 SUMA_LH("%s",newname);
7976
7977 fout = fopen(newname,"w");
7978 if (!fout) {
7979 SUMA_SL_Err("Failed to open file for writing.");
7980 SUMA_RETURN(NOPE);
7981 }
7982
7983 /* write the various ROIs */
7984 for (i=0; i < N_ROI; ++i) {
7985 ROI = ROIv[i];
7986 if (!ROI) {
7987 SUMA_SL_Err("NULL ROI!");
7988 fclose(fout);
7989 SUMA_RETURN(NOPE);
7990 }
7991 /* Transform the ROI to niml friendly structure */
7992 if (!(ROI_1D = SUMA_DrawnROI_to_1DDrawROI (ROI))) {
7993 SUMA_SL_Err("NULL niml_ROI!");
7994 fclose(fout);
7995 SUMA_RETURN(NOPE);
7996 }
7997
7998 /* write it out in a NIML friendly format */
7999 /* begin with attributes */
8000 fprintf (fout,"# %s\n", SUMA_Dset_Type_Name(SUMA_NODE_ROI));
8001 fprintf (fout,"# ni_type = \"SUMA_1D_ROI_DATUMorint,int?\"\n");
8002 fprintf (fout,"# ni_dimen = \"%d\"\n", ROI_1D->N);
8003 fprintf (fout,"# ni_datasize = \"???\"\n");
8004 fprintf (fout,"# idcode_str = \"%s\"\n", ROI_1D->idcode_str);
8005 fprintf (fout,"# Parent_idcode_str = \"%s\"\n",
8006 ROI_1D->Parent_idcode_str);
8007 fprintf (fout,"# Parent_side = \"%s\"\n",
8008 SUMA_SideName(ROI_1D->Parent_side));
8009 fprintf (fout,"# Label = \"%s\"\n", ROI_1D->Label);
8010 fprintf (fout,"# >\n");
8011 for (j=0; j < ROI_1D->N; ++j)
8012 fprintf (fout," %d %d\n", ROI_1D->iNode[j], ROI_1D->iLabel[j]);
8013 fprintf (fout,"# </%s>\n", SUMA_Dset_Type_Name(SUMA_NODE_ROI));
8014 fprintf (fout,"\n");
8015
8016 /* free the ROI_1D structure */
8017 ROI_1D = SUMA_Free_1DDrawROI (ROI_1D); ROI_1D = NULL;
8018 }
8019
8020 fclose(fout) ;
8021 if (newname) SUMA_free(newname);
8022
8023 SUMA_RETURN(YUP);
8024 }
8025
8026
SUMA_New_FormAfniDset_Opt(void)8027 SUMA_FORM_AFNI_DSET_STRUCT *SUMA_New_FormAfniDset_Opt(void)
8028 {
8029 static char FuncName[]={"SUMA_New_FormAfniDset_Opt"};
8030 SUMA_FORM_AFNI_DSET_STRUCT *Opt=NULL;
8031
8032 SUMA_ENTRY;
8033
8034 Opt = (SUMA_FORM_AFNI_DSET_STRUCT*)
8035 SUMA_calloc(1,sizeof(SUMA_FORM_AFNI_DSET_STRUCT));
8036
8037 Opt->master = NULL;
8038 Opt->mset = NULL;
8039 Opt->mask = NULL;
8040 Opt->prefix = NULL;
8041 Opt->prefix_path = NULL;
8042 Opt->orcode = NULL;
8043 Opt->do_ijk = 1;
8044 Opt->dimen_ii=0;
8045 Opt->dimen_jj=0;
8046 Opt->dimen_kk=0;
8047 Opt->datum=MRI_short;
8048 Opt->dval=1.0;
8049 Opt->fval=0.0;
8050 Opt->mmask=NULL;
8051 Opt->full_list = 0;
8052 Opt->exists = -1;
8053 Opt->coorder_xyz = 1; /* 0 if xyz are in dicom, 1 if in dataset order */
8054 SUMA_RETURN(Opt);
8055 }
8056
SUMA_Free_FormAfniDset_Opt(SUMA_FORM_AFNI_DSET_STRUCT * Opt)8057 SUMA_FORM_AFNI_DSET_STRUCT *SUMA_Free_FormAfniDset_Opt(SUMA_FORM_AFNI_DSET_STRUCT *Opt)
8058 {
8059 static char FuncName[]={"SUMA_Free_FormAfniDset_Opt"};
8060 SUMA_ENTRY;
8061
8062 if (!Opt) SUMA_RETURN(NULL);
8063
8064 if (Opt->master) SUMA_free(Opt->master);
8065 if (Opt->mask) SUMA_free(Opt->mask);
8066 if (Opt->mset) {
8067 SUMA_SL_Warn("mset is not freed in this function.\nMake sure it is not a lost pointer.\nSet mset to NULL to avoid seeing this message");
8068 }
8069 if (Opt->prefix) SUMA_free(Opt->prefix);
8070 if (Opt->prefix_path) SUMA_free(Opt->prefix_path);
8071 if (Opt->mmask) SUMA_free(Opt->mmask);
8072 if (Opt->orcode) SUMA_free(Opt->orcode);
8073 SUMA_free(Opt);
8074
8075 SUMA_RETURN(NULL);
8076 }
8077
8078 /*!
8079 (stolen from 3dUndump)
8080 \param NodeList (float *) (3*N_valsx1) XYZ or IJK coordinates.
8081 Can be NULL if Opt->full_list = 1.
8082 &(NodeList[3*n]) is the pointer for the coordinates of entry ni
8083 \param vals (float *) (N_valsx1) vector of values. Can be NULL, in which case the
8084 default value in Opt is used.
8085 \param N_vals (int) number of values. If Opt->full_list then N_vals must be equal to the
8086 number of voxels in the data set (dimen_ii*dimen_jj*dimen_kk)
8087 as specified by Opt's fields or the master set.
8088 \param Opt (SUMA_FORM_AFNI_DSET_STRUCT *) The famed options structure:
8089 master: Name of master dset. NULL if none
8090 mask: Name of mask dset. NULL if none.
8091 prefix: Prefix of output. Must have.
8092 orcode: Orientation string. NULL if none, like RAI, LPI, etc.
8093 do_ijk: 1 = coordinates in NodeList are voxel indices (i j k)
8094 0 = coordinates in NodeList are voxel dicomm coordinates (x y z)
8095 dimen_ii(_jj, _kk): Number of voxels in ii (jj, kk) directions.
8096 Do not use with master option
8097 Must use either master or dimen options.
8098 datum: output data type: MRI_short(default), MRI_byte, MRI_float only.
8099 dval: Default data value (default 1). Used if vals is NULL
8100 fval: Default fill value (default 0).
8101 mmask: (byte *) mask of (dimen_ii*dimen_jj*dimen_kk x 1) values always.
8102 This can be used to pass a predefined mask. NULL if not
8103 interested in it. Cannot specify it along with mask
8104 option above. If both NodeList and Vals are null, then
8105 mmask is used as data, replaces vals in a way. If mmask points
8106 to non NULL, the memory at that pointer is freed when Opt is freed.
8107 full_list: 1 = full list, coordinates are inferred from 1D index of array.
8108 N_vals == dimen_ii*dimen_jj*dimen_kk. Requires NodeList == NULL
8109 0 = not a full list NodeList != NULL
8110 exists: A flag that indicates upon returning from this function whether the
8111 dset's name exists already or not.
8112 -1: untested
8113 1: exists
8114 0: Does not exist
8115 - See SUMA_Free_FormAfniDset_Opt for freeing Opt and its contents
8116
8117 \return dset (THD_3dim_dataset *) output dset.
8118 Write it to disk with : DSET_write(dset) ;
8119 Delete it with: DSET_delete(dset); dset = NULL;
8120
8121 - FUNCTION NOT FULLY TESTED for all options, USE WITH CARE : Feb 08 05
8122 */
SUMA_FormAfnidset(float * NodeList,float * vals,int N_vals,SUMA_FORM_AFNI_DSET_STRUCT * Opt)8123 THD_3dim_dataset *SUMA_FormAfnidset (float *NodeList, float *vals,
8124 int N_vals, SUMA_FORM_AFNI_DSET_STRUCT *Opt)
8125 {
8126 static char FuncName[]={"SUMA_FormAfnidset"};
8127 THD_coorder cord;
8128 int ii=0,jj=0,kk=0,ll=0,ijk=0 , nx=0,ny=0,nz=0 , nxyz=0 ;
8129 float xx,yy,zz,vv=0.0 , dx,dy,dz;
8130 short sv=0 ;
8131 byte bv=0 ;
8132 float *fbr=NULL, fval_float, dval_float;
8133 byte *bbr=NULL, *mmask=NULL, fval_byte, dval_byte;
8134 short *sbr=NULL, fval_short, dval_short;
8135 char *orcode=NULL;
8136 float xxdown =0.0,xxup=0.0 , yydown=0.0,yyup=0.0 , zzdown=0.0,zzup=0.0 ;
8137 SUMA_Boolean LocalHead = NOPE;
8138 THD_3dim_dataset *dset=NULL, *mset=NULL, *maskset=NULL;
8139
8140 SUMA_ENTRY;
8141
8142 /* check for badiosity */
8143 if( Opt->do_ijk == 0 && (!Opt->master && !Opt->mset) ) {
8144 SUMA_SL_Err("Can't use mm coords without master.") ;
8145 SUMA_RETURN(NULL);
8146 }
8147 if( (Opt->master == NULL && Opt->mset == NULL) && Opt->dimen_ii < 2 ) {
8148 SUMA_SL_Err("Must use exactly one of Opt->master or Opt->dimen options");
8149 SUMA_RETURN(NULL);
8150 }
8151 if (Opt->master && Opt->mset) {
8152 SUMA_SL_Err("Cannot use Opt->master and Opt->mset");
8153 SUMA_RETURN(NULL);
8154 }
8155
8156 fval_byte = (byte)Opt->fval;
8157 fval_short = (short)Opt->fval;
8158 fval_float = (float)Opt->fval;
8159 dval_byte = (byte)Opt->dval;
8160 dval_short = (short)Opt->dval;
8161 dval_float = (float)Opt->dval;
8162
8163 if( (Opt->datum == MRI_short && dval_short == fval_short) ||
8164 (Opt->datum == MRI_float && dval_float == fval_float) ||
8165 (Opt->datum == MRI_byte && dval_byte == fval_byte ) ){
8166
8167 SUMA_SL_Warn("dval and fval are the same!") ;
8168 }
8169
8170 if (Opt->full_list && NodeList) {
8171 SUMA_SL_Err("Opt->full_list && NodeList");
8172 SUMA_RETURN(NULL);
8173 }
8174 if (!Opt->full_list && !NodeList &&!Opt->mmask) {
8175 SUMA_SL_Err("!Opt->full_list && !NodeList && !Opt->mmask");
8176 SUMA_RETURN(NULL);
8177 }
8178
8179 if (!Opt->prefix || !Opt->prefix_path) {
8180 SUMA_SL_Err("Need a prefix and a prefix_path Joe.");
8181 SUMA_RETURN(NULL);
8182 }
8183
8184 if (!NodeList && !vals && !Opt->mmask) {
8185 SUMA_SL_Warn("Creating a dataset of constants. "
8186 "(!NodeList && !vals && !Opt->mmask)");
8187 }
8188
8189 if (Opt->master) {
8190 mset = THD_open_dataset(Opt->master);
8191 if( mset == NULL ) {
8192 SUMA_SL_Err("-master: can't open dataset" ) ;
8193 SUMA_RETURN(dset);
8194 }
8195 }
8196 if (Opt->mset) mset = Opt->mset;
8197
8198 if ((Opt->master || Opt->mset) && Opt->orcode) {
8199 SUMA_SL_Err("Cannot have bothpt->master && Opt->orcode");
8200 SUMA_RETURN(dset);
8201 }
8202
8203 if (Opt->mask && Opt->mmask) {
8204 SUMA_SL_Err("Cannot have both Opt->mask && Opt->mmask");
8205 SUMA_RETURN(dset);
8206 }
8207
8208 if (Opt->mask) {
8209 maskset = THD_open_dataset( Opt->mask) ;
8210 if( maskset == NULL ) {
8211 SUMA_SL_Err("-mask: can't open dataset" ) ;
8212 if (mset) { DSET_delete(mset); mset = NULL; }
8213 SUMA_RETURN(dset);
8214 }
8215 }
8216
8217
8218 /*-- set orcode to value from -master, if this is needed --*/
8219
8220 if( mset != NULL ){
8221 orcode = malloc(4) ;
8222 orcode[0] = ORIENT_typestr[mset->daxes->xxorient][0] ;
8223 orcode[1] = ORIENT_typestr[mset->daxes->yyorient][0] ;
8224 orcode[2] = ORIENT_typestr[mset->daxes->zzorient][0] ;
8225 orcode[3] = '\0' ;
8226 } else if (Opt->orcode) {
8227 orcode = malloc(6) ; orcode = strcpy(orcode, Opt->orcode);
8228 } else {
8229 SUMA_SL_Err("Huh?");
8230 if (mset) { DSET_delete(mset); mset = NULL; }
8231 if (maskset) { DSET_delete(maskset); maskset = NULL; }
8232 SUMA_RETURN(dset);
8233 }
8234
8235 THD_coorder_fill( orcode , &cord ) ; /* setup coordinate order */
8236
8237 /*-- make empty dataset --*/
8238 if( mset != NULL ){ /* from -master */
8239
8240 dset = EDIT_empty_copy( mset ) ;
8241 EDIT_dset_items( dset ,
8242 ADN_prefix , Opt->prefix ,
8243 ADN_datum_all , Opt->datum ,
8244 ADN_nvals , 1 ,
8245 ADN_ntt , 0 ,
8246 ADN_func_type , ISANAT(mset) ? mset->func_type
8247 : FUNC_FIM_TYPE ,
8248
8249 ADN_directory_name , Opt->prefix_path ,
8250 ADN_none ) ;
8251
8252 } else { /* from nothing */
8253 THD_ivec3 iv_nxyz , iv_xyzorient ;
8254 THD_fvec3 fv_xyzorg , fv_xyzdel ;
8255
8256 LOAD_IVEC3( iv_nxyz , Opt->dimen_ii , Opt->dimen_jj , Opt->dimen_kk ) ;
8257 LOAD_IVEC3( iv_xyzorient , cord.xxor , cord.yyor , cord.zzor ) ;
8258 LOAD_FVEC3( fv_xyzdel ,
8259 ORIENT_sign[iv_xyzorient.ijk[0]]=='+' ? 1.0 : -1.0 ,
8260 ORIENT_sign[iv_xyzorient.ijk[1]]=='+' ? 1.0 : -1.0 ,
8261 ORIENT_sign[iv_xyzorient.ijk[2]]=='+' ? 1.0 : -1.0 ) ;
8262 LOAD_FVEC3( fv_xyzorg ,
8263 ORIENT_sign[iv_xyzorient.ijk[0]]=='+' ? -0.5*Opt->dimen_ii : 0.5*Opt->dimen_ii,
8264 ORIENT_sign[iv_xyzorient.ijk[1]]=='+' ? -0.5*Opt->dimen_jj : 0.5*Opt->dimen_jj,
8265 ORIENT_sign[iv_xyzorient.ijk[2]]=='+' ? -0.5*Opt->dimen_kk : 0.5*Opt->dimen_kk ) ;
8266
8267 dset = EDIT_empty_copy( NULL ) ;
8268
8269 EDIT_dset_items( dset ,
8270 ADN_nxyz , iv_nxyz ,
8271 ADN_xyzdel , fv_xyzdel ,
8272 ADN_xyzorg , fv_xyzorg ,
8273 ADN_xyzorient , iv_xyzorient ,
8274 ADN_prefix , Opt->prefix ,
8275 ADN_datum_all , Opt->datum ,
8276 ADN_nvals , 1 ,
8277 ADN_ntt , 0 ,
8278 ADN_type , HEAD_FUNC_TYPE ,
8279 ADN_func_type , FUNC_FIM_TYPE ,
8280 ADN_directory_name , Opt->prefix_path ,
8281 ADN_none ) ;
8282
8283 }
8284
8285 if( THD_is_file(DSET_HEADNAME(dset)) ) {
8286 SUMA_LHv("Note Output dataset %s already exists \n", DSET_HEADNAME(dset)) ;
8287 Opt->exists = 1;
8288 } else {
8289 Opt->exists = 0;
8290 }
8291
8292 /*-- make empty brick array for dataset --*/
8293
8294 EDIT_substitute_brick( dset , 0 , Opt->datum , NULL ) ; /* will make array */
8295
8296 nx = DSET_NX(dset); ny = DSET_NY(dset); nz = DSET_NZ(dset); nxyz = nx*ny*nz;
8297
8298 if (Opt->full_list && N_vals != nxyz) {
8299 SUMA_SL_Err("Opt->full_list && N_vals != nx*ny*nz");
8300 SUMA_RETURN(NULL);
8301 }
8302 /* 19 Feb 2004: check and make mask if desired */
8303
8304 if( maskset != NULL &&
8305 ( DSET_NX(maskset) != nx ||
8306 DSET_NY(maskset) != ny ||
8307 DSET_NZ(maskset) != nz ) ) {
8308 SUMA_SL_Err("mask dataset doesn't match dimension of output dataset") ;
8309 if (mset) { DSET_delete(mset); mset = NULL; }
8310 if (maskset) { DSET_delete(maskset); maskset = NULL; }
8311 DSET_delete(dset); dset = NULL;
8312 SUMA_RETURN(NULL);
8313 }
8314
8315 if( maskset != NULL ){
8316 mmask = THD_makemask( maskset , 0 , 1.0,-1.0 ) ;
8317 SUMA_SL_Warn("can't create mask for some reason!") ;
8318 DSET_delete(maskset) ;
8319 } else mmask = Opt->mmask;
8320
8321 if( mmask == NULL ){
8322 } else {
8323 int nmask = THD_countmask( nxyz , mmask ) ;
8324 if( nmask == 0 ){
8325 SUMA_SL_Warn("0 voxels in mask -- ignoring it!") ;
8326 if (!Opt->mmask) free((void *)mmask) ; mmask = NULL ;
8327 } else {
8328 fprintf(SUMA_STDERR,"%s:++ %d voxels found in mask\n", FuncName, nmask) ;
8329 }
8330 }
8331
8332 /*-- fill new dataset brick with the -fval value --*/
8333 switch( Opt->datum ){
8334 case MRI_short:
8335 if (0)
8336 fprintf(SUMA_STDERR,"%s: Filling with %d\n", FuncName, fval_short);
8337 sbr = (short *) DSET_BRICK_ARRAY(dset,0) ;
8338 for( ii=0 ; ii < nxyz ; ii++ ) sbr[ii] = fval_short ;
8339 break ;
8340
8341 case MRI_float:
8342 fbr = (float *) DSET_BRICK_ARRAY(dset,0) ;
8343 for( ii=0 ; ii < nxyz ; ii++ ) fbr[ii] = fval_float ;
8344 break ;
8345
8346 case MRI_byte:
8347 bbr = (byte *) DSET_BRICK_ARRAY(dset,0) ;
8348 for( ii=0 ; ii < nxyz ; ii++ ) bbr[ii] = fval_byte ;
8349 break ;
8350 }
8351
8352 /* 24 Nov 2000: get the bounding box for the dataset */
8353
8354 dx = fabs(dset->daxes->xxdel) ; if( dx <= 0.0 ) dx = 1.0 ;
8355 dy = fabs(dset->daxes->yydel) ; if( dy <= 0.0 ) dy = 1.0 ;
8356 dz = fabs(dset->daxes->zzdel) ; if( dz <= 0.0 ) dz = 1.0 ;
8357
8358 if( !Opt->do_ijk ){
8359 #ifndef EXTEND_BBOX
8360 xxdown = dset->daxes->xxmin - 0.501 * dx ;
8361 xxup = dset->daxes->xxmax + 0.501 * dx ;
8362 yydown = dset->daxes->yymin - 0.501 * dy ;
8363 yyup = dset->daxes->yymax + 0.501 * dy ;
8364 zzdown = dset->daxes->zzmin - 0.501 * dz ;
8365 zzup = dset->daxes->zzmax + 0.501 * dz ;
8366 #else
8367 xxdown = dset->daxes->xxmin ;
8368 xxup = dset->daxes->xxmax ;
8369 yydown = dset->daxes->yymin ;
8370 yyup = dset->daxes->yymax ;
8371 zzdown = dset->daxes->zzmin ;
8372 zzup = dset->daxes->zzmax ;
8373 #endif
8374 }
8375
8376 for (ll=0; ll<N_vals; ++ll) {
8377 /* stick 'em in */
8378 if (!Opt->full_list) {
8379 xx = NodeList[3*ll]; yy = NodeList[3*ll+1]; zz = NodeList[3*ll+2];
8380 if (Opt->do_ijk) {
8381 ii = (int) rint(xx) ; jj = (int) rint(yy) ; kk = (int) rint(zz) ;
8382 if( ii < 0 || ii >= nx ){
8383 fprintf(stderr,
8384 "Warning %s: entry %d: i index=%d is invalid, ignoring...\n",
8385 FuncName,ll,ii) ;
8386 continue ;
8387 }
8388 if( jj < 0 || jj >= ny ){
8389 fprintf(stderr,
8390 "Warning %s: entry %d: j index=%d is invalid, ignoring...\n",
8391 FuncName, ll,jj) ;
8392 continue ;
8393 }
8394 if( kk < 0 || kk >= nz ){
8395 fprintf(stderr,
8396 "Warning %s: entry %d: k index=%d is invalid\n",
8397 FuncName,ll,kk) ;
8398 continue ;
8399 }
8400 } else { /* inputs are coordinates => must convert to index */
8401
8402 THD_fvec3 mv , dv ; /* temp vectors */
8403 THD_ivec3 iv ;
8404
8405 if (Opt->coorder_xyz) {
8406 THD_coorder_to_dicom( &cord , &xx,&yy,&zz ) ; /* to Dicom order */
8407 }
8408 LOAD_FVEC3( dv , xx,yy,zz ) ;
8409 mv = THD_dicomm_to_3dmm( dset , dv ) ; /* to Dataset order */
8410
8411 /* 24 Nov 2000: check (xx,yy,zz) for being inside the box */
8412
8413 if( mv.xyz[0] < xxdown || mv.xyz[0] > xxup ){
8414 fprintf(stderr,
8415 "+++ Warning %s: line %d: x coord=%g is outside %g .. %g\n" ,
8416 FuncName,ll,mv.xyz[0] , xxdown,xxup ) ;
8417 continue ;
8418 }
8419 if( mv.xyz[1] < yydown || mv.xyz[1] > yyup ){
8420 fprintf(stderr,
8421 "+++ Warning %s: line %d: y coord=%g is outside %g .. %g\n" ,
8422 FuncName,ll,mv.xyz[1] , yydown , yyup ) ;
8423 continue ;
8424 }
8425 if( mv.xyz[2] < zzdown || mv.xyz[2] > zzup ){
8426 fprintf(stderr,
8427 "+++ Warning %s: line %d: z coord=%g is outside %g .. %g\n" ,
8428 FuncName,ll,mv.xyz[2] , zzdown , zzup ) ;
8429 continue ;
8430 }
8431
8432 iv = THD_3dmm_to_3dind( dset , mv ) ; /* to Dataset index */
8433 ii = iv.ijk[0]; jj = iv.ijk[1]; kk = iv.ijk[2]; /* save */
8434 }
8435
8436 ijk = ii + jj*nx + kk*nx*ny ;
8437 } else {
8438 ijk = ll;
8439 }
8440
8441 if (vals) vv = vals[ll];
8442 else vv = dval_float ;
8443
8444 if( mmask == NULL || mmask[ijk] ){
8445 switch( Opt->datum ){
8446 case MRI_float:{
8447 if( fbr[ijk] != fval_float && fbr[ijk] != vv )
8448 fprintf(stderr,"Overwrite voxel %d %d %d\n",ii,jj,kk) ;
8449 fbr[ijk] = vv ;
8450 }
8451 break ;
8452 case MRI_short:{
8453 sv = SHORTIZE(vv) ;
8454 if( sbr[ijk] != fval_short && sbr[ijk] != sv )
8455 fprintf(stderr,"Overwrite voxel %d %d %d\n",ii,jj,kk) ;
8456 sbr[ijk] = sv ;
8457 }
8458 break ;
8459 case MRI_byte:{
8460 bv = BYTEIZE(vv) ;
8461 if( bbr[ijk] != fval_byte && bbr[ijk] != bv )
8462 fprintf(stderr,"Overwrite voxel %d %d %d\n",ii,jj,kk) ;
8463 bbr[ijk] = bv ;
8464 }
8465 break ;
8466 }
8467 }
8468
8469 }
8470
8471 if (orcode) free(orcode); orcode = NULL;
8472 if (mmask && !Opt->mmask) free(mmask); mmask = NULL;
8473 if (mset && !Opt->mset) DSET_delete(mset); mset = NULL;
8474
8475 SUMA_RETURN(dset);
8476 }
8477
8478 /*!
8479 \brief A function to change a SurfaceObject to niml format
8480 \param SO (SUMA_SurfaceObject *)
8481 \param optlist (char *) string indicating what parts of SO to put in ngr
8482 choose any combination of: NodeList, FaceSetList,
8483 EdgeList, MemberFace, NodeNeighb, VolPar, facenormals,
8484 NodeNormals, PolyArea,
8485 \param No_LinksExternalElements (int) 1: Do not include IDs of elements not
8486 created inside this group, i.e. not mentioned in optlist
8487 0: So include IDs of elements that may reside
8488 on disk.
8489 \return ngr (NI_group *) a NI group element formed from SO.
8490 NOTE: That element has the SAME ID as SO!
8491 \sa SUMA_nimlSO2SO
8492 */
SUMA_SO2nimlSO(SUMA_SurfaceObject * SO,char * optlist,int nlee)8493 NI_group *SUMA_SO2nimlSO(SUMA_SurfaceObject *SO, char *optlist, int nlee)
8494 {
8495 static char FuncName[]={"SUMA_SO2nimlSO"};
8496 NI_group *ngr = NULL;
8497 NI_element *nel = NULL;
8498 char stmp[500];
8499 SUMA_Boolean LocalHead = NOPE;
8500
8501 SUMA_ENTRY;
8502
8503 if (!SO) {
8504 SUMA_SL_Err("Null SO"); SUMA_RETURN(ngr);
8505 }
8506
8507 /* create group and name it */
8508 ngr = NI_new_group_element();
8509 NI_rename_group(ngr, "SurfaceObject");
8510
8511 /** BEGIN ATTRIBUTES COMMON TO ALL OBJECTS **/
8512
8513 /* set the object type attribute */
8514 switch (SO->FaceSetDim) {
8515 case 3:
8516 NI_set_attribute(ngr, "Object_Type", "Triangulated_Surface");
8517 break;
8518 default:
8519 NI_set_attribute(ngr, "Object_Type", SUMA_EMPTY_ATTR);
8520 SUMA_SL_Warn("FaceSetDim not supported");
8521 break;
8522 }
8523
8524 /* set the object ID */
8525 if (SO->idcode_str) {
8526 NI_set_attribute(ngr, "self_idcode", SO->idcode_str);
8527 } else {
8528 NI_set_attribute(ngr, "self_idcode", SUMA_EMPTY_ATTR);
8529 }
8530
8531 /* set the object Label */
8532 if (SO->Label) {
8533 NI_set_attribute(ngr, "Object_Label", SO->Label);
8534 } else {
8535 NI_set_attribute(ngr, "Object_Label", SUMA_EMPTY_ATTR);
8536 }
8537
8538
8539 /* set the parent ID */
8540 if (SO->LocalDomainParentID) {
8541 NI_set_attribute(ngr, "domain_parent_idcode", SO->LocalDomainParentID);
8542 } else {
8543 NI_set_attribute(ngr, "domain_parent_idcode", SUMA_EMPTY_ATTR);
8544 }
8545
8546 /* set the grand parent ID */
8547 if (SO->DomainGrandParentID) {
8548 NI_set_attribute(ngr, "Grand_domain_parent_idcode",
8549 SO->DomainGrandParentID);
8550 } else {
8551 NI_set_attribute(ngr, "Grand_domain_parent_idcode", SUMA_EMPTY_ATTR);
8552 }
8553
8554 /** END ATTRIBUTES COMMON TO ALL OBJECTS **/
8555
8556 /** BEGIN ATTRIBUTES specific to Surfaces**/
8557 if (SO->Group_idcode_str) {
8558 NI_set_attribute(ngr, "Subject_ID", SO->Group_idcode_str);
8559 } else {
8560 NI_set_attribute(ngr, "Subject_ID", SUMA_EMPTY_ATTR);
8561 }
8562
8563 if (SO->Group) {
8564 NI_set_attribute(ngr, "Subject_Label", SO->Group);
8565 } else {
8566 NI_set_attribute(ngr, "Subject_Label", SUMA_EMPTY_ATTR);
8567 }
8568
8569 if (SO->OriginatorID) {
8570 NI_set_attribute(ngr, "Instance_ID", SO->OriginatorID);
8571 } else {
8572 NI_set_attribute(ngr, "Instance_ID", SUMA_EMPTY_ATTR);
8573 }
8574
8575 if (SO->OriginatorLabel) {
8576 NI_set_attribute(ngr, "Instance_Label", SO->OriginatorLabel);
8577 } else {
8578 NI_set_attribute(ngr, "Instance_Label", SUMA_EMPTY_ATTR);
8579 }
8580
8581 NI_SET_INT(ngr, "do_type", SO->do_type);
8582
8583 switch (SO->Side) {
8584 case SUMA_NO_SIDE:
8585 NI_set_attribute(ngr, "Side", "none");
8586 break;
8587 case SUMA_LEFT:
8588 NI_set_attribute(ngr, "Side", "left");
8589 break;
8590 case SUMA_RIGHT:
8591 NI_set_attribute(ngr, "Side", "right");
8592 break;
8593 case SUMA_LR:
8594 NI_set_attribute(ngr, "Side", "lr");
8595 break;
8596 default:
8597 NI_set_attribute(ngr, "Side", SUMA_EMPTY_ATTR);
8598 break;
8599 }
8600
8601 if (SO->State) {
8602 NI_set_attribute(ngr, "Layer_Name", SO->State);
8603 } else {
8604 NI_set_attribute(ngr, "Layer_Name", SUMA_EMPTY_ATTR);
8605 }
8606
8607 if (SO->AnatCorrect) {
8608 NI_set_attribute(ngr, "Anatomically_Correct", "yes");
8609 } else {
8610 NI_set_attribute(ngr, "Anatomically_Correct", "no");
8611 }
8612
8613 sprintf(stmp,"%d", SO->EmbedDim);
8614 NI_set_attribute(ngr, "Embedding_Dimension", stmp);
8615
8616 if (SO->FileType >=0) {
8617 sprintf(stmp,"%s", SUMA_SurfaceTypeString(SO->FileType));
8618 NI_set_attribute(ngr, "Surface_Creation_Software", stmp);
8619 } else {
8620 NI_set_attribute(ngr, "Surface_Creation_Software", SUMA_EMPTY_ATTR);
8621 }
8622
8623 NI_set_attribute(ngr, "Surface_Creation_History", SUMA_EMPTY_ATTR);
8624
8625
8626 sprintf(stmp,"%d", SO->normdir);
8627 NI_set_attribute(ngr, "Node_Normal_Direction", stmp);
8628
8629 if (!nlee || SUMA_iswordin(optlist,"FaceSetList")) {
8630 if (SO->facesetlist_idcode_str) {
8631 NI_set_attribute(ngr, "Mesh_Element_ID", SO->facesetlist_idcode_str);
8632 } else {
8633 if (SO->idcode_str) {
8634 sprintf(stmp, "facesetlist_idcode_str_%s", SO->idcode_str);
8635 SUMA_NEW_ID(SO->facesetlist_idcode_str, stmp);
8636 NI_set_attribute(ngr, "Mesh_Element_ID", SO->facesetlist_idcode_str);
8637 } else {
8638 NI_set_attribute(ngr, "Mesh_Element_ID", SUMA_EMPTY_ATTR);
8639 }
8640 }
8641 }
8642
8643 if (!nlee || SUMA_iswordin(optlist,"NodeList")) {
8644 if (SO->nodelist_idcode_str) {
8645 NI_set_attribute(ngr, "NodeList_Element_ID", SO->nodelist_idcode_str);
8646 } else {
8647 if (SO->idcode_str) {
8648 sprintf(stmp, "nodelist_idcode_str_%s", SO->idcode_str);
8649 SUMA_NEW_ID(SO->nodelist_idcode_str, stmp);
8650 NI_set_attribute(ngr, "NodeList_Element_ID",
8651 SO->nodelist_idcode_str);
8652 } else {
8653 NI_set_attribute(ngr, "NodeList_Element_ID", SUMA_EMPTY_ATTR);
8654 }
8655 }
8656 }
8657 if (!nlee || SUMA_iswordin(optlist,"facenormals")) {
8658 if (SO->facenormals_idcode_str) {
8659 NI_set_attribute(ngr, "Polygon_Normals_Element_ID",
8660 SO->facenormals_idcode_str);
8661 } else {
8662 if (SO->idcode_str) {
8663 sprintf(stmp, "facenormals_idcode_str_%s", SO->idcode_str);
8664 SUMA_NEW_ID(SO->facenormals_idcode_str, stmp);
8665 NI_set_attribute(ngr, "Polygon_Normals_Element_ID",
8666 SO->facenormals_idcode_str);
8667 } else {
8668 NI_set_attribute(ngr, "Polygon_Normals_Element_ID", SUMA_EMPTY_ATTR);
8669 }
8670 }
8671 }
8672
8673 if (!nlee || SUMA_iswordin(optlist,"NodeNormals")) {
8674 if (SO->nodenormals_idcode_str) {
8675 NI_set_attribute(ngr, "Node_Normals_Element_ID",
8676 SO->nodenormals_idcode_str);
8677 } else {
8678 if (SO->idcode_str) {
8679 sprintf(stmp, "nodenormals_idcode_str_%s", SO->idcode_str);
8680 SUMA_NEW_ID(SO->nodenormals_idcode_str, stmp);
8681 NI_set_attribute(ngr, "Node_Normals_Element_ID",
8682 SO->nodenormals_idcode_str);
8683 } else {
8684 NI_set_attribute(ngr, "Node_Normals_Element_ID", SUMA_EMPTY_ATTR);
8685 }
8686 }
8687 }
8688
8689 if (!nlee || SUMA_iswordin(optlist,"PolyArea")) {
8690 if (SO->polyarea_idcode_str) {
8691 NI_set_attribute(ngr, "Polygon_Area_Element_ID",
8692 SO->polyarea_idcode_str);
8693 } else {
8694 if (SO->idcode_str) {
8695 sprintf(stmp, "polyarea_idcode_str_%s", SO->idcode_str);
8696 SUMA_NEW_ID(SO->polyarea_idcode_str, stmp);
8697 NI_set_attribute(ngr, "Polygon_Area_Element_ID",
8698 SO->polyarea_idcode_str);
8699 } else {
8700 NI_set_attribute(ngr, "Polygon_Area_Element_ID", SUMA_EMPTY_ATTR);
8701 }
8702 }
8703 }
8704
8705 if (!nlee || SUMA_iswordin(optlist,"EdgeList")) {
8706 /* add here the edge list, the node neighbor list
8707 and the face neighbor list IDs*/
8708 if (SO->EL && SO->EL->idcode_str) {
8709 NI_set_attribute(ngr, "SUMA_Edge_List_Element_ID", SO->EL->idcode_str);
8710 } else {
8711 NI_set_attribute(ngr, "SUMA_Edge_List_Element_ID", SUMA_EMPTY_ATTR);
8712 }
8713 }
8714
8715 if (!nlee || SUMA_iswordin(optlist,"MemberFace")) {
8716 if (SO->MF && SO->MF->idcode_str) {
8717 NI_set_attribute(ngr, "SUMA_Node_Face_Member_Element_ID",
8718 SO->MF->idcode_str);
8719 } else {
8720 NI_set_attribute(ngr, "SUMA_Node_Face_Member_Element_ID",
8721 SUMA_EMPTY_ATTR);
8722 }
8723 }
8724
8725 if (!nlee || SUMA_iswordin(optlist,"NodeNeighb")) {
8726 if (SO->FN && SO->FN->idcode_str) {
8727 NI_set_attribute(ngr, "SUMA_Node_First_Neighb_Element_ID",
8728 SO->FN->idcode_str);
8729 } else {
8730 NI_set_attribute(ngr, "SUMA_Node_First_Neighb_Element_ID",
8731 SUMA_EMPTY_ATTR);
8732 }
8733 }
8734
8735 if (!nlee) {
8736 /* add the parent volume (SurfVol, NOT SurfVol_AlndExp) IDcode if present.
8737 That ID does not usually refer to the volume from which VolPar
8738 is created. Except in the case
8739 where you are viewing the surfaces on the orignal volume (SurfVol) then
8740 this field and SurfVol (afni dset *) ->idcode.str and
8741 VolPar->vol_idcode_str should be identical */
8742 if (SO->parent_vol_idcode_str) {
8743 NI_set_attribute(ngr, "SUMA_Afni_Parent_Vol_ID",
8744 SO->parent_vol_idcode_str);
8745 } else {
8746 NI_set_attribute(ngr, "SUMA_Afni_Parent_Vol_ID", SUMA_EMPTY_ATTR);
8747 }
8748 }
8749
8750 /** END ATTRIBUTES specific to Surfaces**/
8751
8752 /** BEGIN Adding data elements **/
8753
8754 /* add the node list */
8755 if (SUMA_iswordin(optlist,"NodeList")) {
8756 SUMA_LH("Adding Nodelist nel...");
8757 nel = SUMA_NodeXYZ2NodeXYZ_nel (SO, SO->NodeList, 0, SUMA_NEW_NODE_XYZ);
8758 if (!nel) { SUMA_SL_Err("Failed to create nel"); NI_free_element(ngr); SUMA_RETURN(NULL); }
8759 NI_add_to_group( ngr, nel);
8760 }
8761
8762 /* add the faceset list */
8763 if (SUMA_iswordin(optlist,"FaceSetList")) {
8764 SUMA_LH("Adding Nodelist nel...");
8765 nel = SUMA_Mesh_IJK2Mesh_IJK_nel (SO, SO->FaceSetList, 0, SUMA_NEW_MESH_IJK);
8766 if (!nel) { SUMA_SL_Err("Failed to create nel"); NI_free_element(ngr); SUMA_RETURN(NULL); }
8767 NI_add_to_group( ngr, nel);
8768 }
8769
8770 /* add the edge list */
8771 if (SUMA_iswordin(optlist,"EdgeList")) {
8772 SUMA_LH("Adding EdgeList nel...");
8773 SUMA_SL_Warn("Option not implemented yet.");
8774 if (SO->EL) {
8775 /* if (!nel) { SUMA_SL_Err("Failed to create nel"); NI_free_element(ngr); SUMA_RETURN(NULL); }
8776 NI_add_to_group( ngr, nel); */
8777 }
8778 }
8779
8780 /* add the member face list */
8781 if (SUMA_iswordin(optlist,"MemberFace")) {
8782 SUMA_LH("Adding Member of FaceSet nel...");
8783 SUMA_SL_Warn("Option not implemented yet.");
8784 if (SO->MF) {
8785 /* if (!nel) { SUMA_SL_Err("Failed to create nel"); NI_free_element(ngr); SUMA_RETURN(NULL); }
8786 NI_add_to_group( ngr, nel); */
8787 }
8788 }
8789
8790 /* add the node neighbor list */
8791 if (SUMA_iswordin(optlist,"NodeNeighb")) {
8792 SUMA_LH("Adding node neighbors nel...");
8793 SUMA_SL_Warn("Option not implemented yet.");
8794 if (SO->FN) {
8795 /* if (!nel) { SUMA_SL_Err("Failed to create nel"); NI_free_element(ngr); SUMA_RETURN(NULL); }
8796 NI_add_to_group( ngr, nel); */
8797 }
8798 }
8799
8800 /* add the VolPar element */
8801 if (SUMA_iswordin(optlist,"VolPar")) {
8802 SUMA_LH("Adding VolPar nel ...");
8803 if (SO->VolPar) {
8804 nel = SUMA_SOVolPar2VolPar_nel (SO, SO->VolPar, SUMA_SURFACE_VOLUME_PARENT);
8805 if (!nel) { SUMA_SL_Err("Failed to create nel"); NI_free_element(ngr); SUMA_RETURN(NULL); }
8806 NI_add_to_group( ngr, nel);
8807 }
8808 }
8809
8810 /** END Adding data elements **/
8811 if (LocalHead) {
8812 int suc;
8813 SUMA_SL_Warn("writing SO group to DISK!");
8814 NEL_WRITE_TX(ngr, "file:Test_SO2NIML_write_asc_1D", suc);
8815 }
8816
8817 SUMA_RETURN(ngr);
8818 }
8819
SUMA_isnimlSO(NI_group * ngr)8820 SUMA_Boolean SUMA_isnimlSO(NI_group *ngr)
8821 {
8822 static char FuncName[]={"SUMA_isnimlSO"};
8823
8824 SUMA_ENTRY;
8825 if (!ngr || !ngr->name || strcmp(ngr->name, "SurfaceObject")) {
8826 SUMA_RETURN(NOPE);
8827 }
8828 SUMA_RETURN(YUP);
8829 }
8830
SUMA_nimlSO2SO(NI_group * ngr)8831 SUMA_SurfaceObject *SUMA_nimlSO2SO(NI_group *ngr)
8832 {
8833 static char FuncName[]={"SUMA_nimlSO2SO"};
8834 NI_element *nel = NULL;
8835 char stmp[500], *tmp;
8836 int ip;
8837 SUMA_SurfaceObject *SO=NULL;
8838 SUMA_Boolean LocalHead = NOPE;
8839
8840 SUMA_ENTRY;
8841
8842 if (!ngr) { SUMA_SL_Err("Null ngr"); SUMA_RETURN(SO); }
8843
8844 if (!SUMA_isnimlSO(ngr)) {
8845 fprintf (SUMA_STDERR,
8846 "Error %s: group name (%s) is not (SUMA_SurfaceObject)\n"
8847 "Object does not appear to be a surface.",
8848 FuncName, ngr->name);
8849 }
8850
8851 /* a new surface */
8852 SO = SUMA_Alloc_SurfObject_Struct(1);
8853 if (!SO) { SUMA_SL_Err("Failed to create SO."); SUMA_RETURN(SO); }
8854
8855 /** BEGIN ATTRIBUTES COMMON TO ALL OBJECTS **/
8856 tmp = SUMA_copy_string(NI_get_attribute(ngr,"self_idcode"));
8857 if (SUMA_IS_EMPTY_STR_ATTR(tmp)) {
8858 SUMA_SL_Warn( "No ID in nel.\n"
8859 "That's not cool yall.\n"
8860 "I'll be adding a new one now.");
8861 SUMA_NEW_ID(SO->idcode_str, NULL);
8862 NI_set_attribute(ngr, "Group_ID", SO->idcode_str);
8863 } else SO->idcode_str = SUMA_copy_string(tmp);
8864
8865 tmp = NI_get_attribute(ngr, "Object_Type");
8866 if (SUMA_IS_EMPTY_STR_ATTR(tmp)) {
8867 SUMA_SL_Err("Missing Object Type.");
8868 SUMA_Free_Surface_Object(SO);
8869 SO = NULL;
8870 SUMA_RETURN(SO);
8871 }
8872 if (!strcmp(tmp, "Triangulated_Surface")) SO->FaceSetDim = 3;
8873 else {
8874 fprintf (SUMA_STDERR,
8875 "Error %s: Object_Type %s not recognized.\n", FuncName, tmp);
8876 SUMA_Free_Surface_Object(SO); SO = NULL; SUMA_RETURN(SO);
8877 }
8878
8879 NI_GET_INT(ngr, "do_type", SO->do_type);
8880
8881 tmp = NI_get_attribute(ngr, "Object_Label");
8882 if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->Label = SUMA_copy_string(tmp);
8883
8884 /* set the parent ID */
8885 tmp = NI_get_attribute(ngr, "domain_parent_idcode");
8886 if (!SUMA_IS_EMPTY_STR_ATTR(tmp))
8887 SO->LocalDomainParentID = SUMA_copy_string(tmp);
8888
8889
8890 /* set the grand parent ID */
8891 tmp = NI_get_attribute(ngr, "Grand_domain_parent_idcode");
8892 if (!SUMA_IS_EMPTY_STR_ATTR(tmp))
8893 SO->DomainGrandParentID = SUMA_copy_string(tmp);
8894
8895
8896 /** END ATTRIBUTES COMMON TO ALL OBJECTS **/
8897
8898 /** BEGIN ATTRIBUTES specific to Surfaces**/
8899 tmp = NI_get_attribute(ngr, "Subject_ID");
8900 if (!SUMA_IS_EMPTY_STR_ATTR(tmp))
8901 SO->Group_idcode_str = SUMA_copy_string(tmp);
8902
8903 tmp = NI_get_attribute(ngr, "Subject_Label");
8904 if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->Group = SUMA_copy_string(tmp);
8905
8906 tmp = NI_get_attribute(ngr, "Instance_ID");
8907 if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->OriginatorID = SUMA_copy_string(tmp);
8908
8909 tmp = NI_get_attribute(ngr, "Instance_Label");
8910 if (!SUMA_IS_EMPTY_STR_ATTR(tmp))
8911 SO->OriginatorLabel = SUMA_copy_string(tmp);
8912
8913
8914 tmp = NI_get_attribute(ngr, "Side");
8915 if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) {
8916 if (!strcmp(tmp,"none")) SO->Side = SUMA_NO_SIDE;
8917 else if (!strcmp(tmp,"left")) SO->Side = SUMA_LEFT;
8918 else if (!strcmp(tmp,"right")) SO->Side = SUMA_RIGHT;
8919 else if (!strcmp(tmp,"lr")) SO->Side = SUMA_LR;
8920 }
8921
8922 tmp = NI_get_attribute(ngr, "Layer_Name");
8923 if (!SUMA_IS_EMPTY_STR_ATTR(tmp))
8924 SO->State = SUMA_copy_string(tmp);
8925
8926 tmp = NI_get_attribute(ngr, "Anatomically_Correct");
8927 if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) {
8928 if (!strcmp(tmp,"yes")) SO->AnatCorrect = 1;
8929 else SO->AnatCorrect = 0;
8930 }
8931
8932 tmp = NI_get_attribute(ngr, "Embedding_Dimension");
8933 if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->EmbedDim = atoi(tmp);
8934
8935 tmp = NI_get_attribute(ngr, "Surface_Creation_Software");
8936 if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->FileType = SUMA_SurfaceTypeCode(tmp);
8937
8938 tmp = NI_get_attribute(ngr, "SUMA_Afni_Parent_Vol_ID");
8939 if (!SUMA_IS_EMPTY_STR_ATTR(tmp))
8940 SO->parent_vol_idcode_str = SUMA_copy_string(tmp);
8941
8942 tmp = NI_get_attribute(ngr, "Node_Normal_Direction");
8943 if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->normdir = atoi(tmp);
8944
8945 /** END ATTRIBUTES specific to Surfaces**/
8946
8947 /* now read the elements in this group */
8948 for( ip=0 ; ip < ngr->part_num ; ip++ ){
8949 /* do not free elements as you process them, free with group at end */
8950 switch( ngr->part_typ[ip] ){
8951 /*-- a sub-group ==> recursion! --*/
8952 case NI_GROUP_TYPE:
8953 SUMA_SL_Err("Not ready from groups inside surface group.\n"
8954 " Group ignored");
8955 break ;
8956 case NI_ELEMENT_TYPE:
8957 nel = (NI_element *)ngr->part[ip] ;
8958 if (LocalHead) {
8959 fprintf(SUMA_STDERR,
8960 "%s: name=%s \n"
8961 "vec_len=%d vec_filled=%d, vec_num=%d\n",
8962 FuncName, nel->name,
8963 nel->vec_len, nel->vec_filled, nel->vec_num );
8964 }
8965
8966 /*--- NodeList ---*/
8967 if( strcmp(nel->name,"Node_XYZ") == 0 ||
8968 strcmp(nel->name,"NewNode_XYZ") == 0) { /* Get Da NodeList */
8969 if (LocalHead)
8970 fprintf (SUMA_STDERR,
8971 "%s:\nGetting NodeList...\n", FuncName);
8972 if (!SUMA_NodeXYZ_nel2NodeXYZ(SO, nel)) {
8973 SUMA_SL_Err("Failed in SUMA_NodeXYZ_nel2NodeXYZ");
8974 SUMA_Free_Surface_Object(SO); SO = NULL; SUMA_RETURN(SO);
8975 }
8976 } else if ( strcmp(nel->name,"Mesh_IJK") == 0 ||
8977 strcmp(nel->name,"NewMesh_IJK") == 0) {
8978 /* Get Da FaceSetList */
8979 if (LocalHead)
8980 fprintf (SUMA_STDERR,"%s:\nGetting FaceSetList...\n",
8981 FuncName);
8982 if (!SUMA_Mesh_IJK_nel2Mesh_IJK(SO, nel)) {
8983 SUMA_SL_Err("Failed in SUMA_Mesh_IJK_nel2Mesh_IJK");
8984 SUMA_Free_Surface_Object(SO); SO = NULL; SUMA_RETURN(SO);
8985 }
8986 } else if ( strcmp(nel->name,"SurfaceVolumeParent") == 0) {
8987 /* Get Da FaceSetList */
8988 if (LocalHead) fprintf (SUMA_STDERR,"%s:\nGetting VolPar...\n",
8989 FuncName);
8990 if (!SUMA_VolPar_nel2SOVolPar(SO, nel)) {
8991 SUMA_SL_Err("Failed in SUMA_VolPar_nel2SOVolPar");
8992 SUMA_Free_Surface_Object(SO); SO = NULL; SUMA_RETURN(SO);
8993 }
8994 } else {
8995 fprintf (SUMA_STDERR,
8996 "Warning %s:\n nel (%s) unknown, ignoring it.\n",
8997 FuncName, nel->name);
8998 }
8999 break;
9000 default:
9001 SUMA_SL_Err("Don't know what to make of this "
9002 "group element, ignoring.");
9003 break;
9004 }
9005 }
9006
9007 if (!SO->NodeList || !SO->FaceSetList) {
9008 /* perhaps you'll remove this condition in the future ...*/
9009 SUMA_SL_Err("Looks like NodeList and/or FaceSetList "
9010 "not in group. Balking.\n");
9011 SUMA_Free_Surface_Object(SO); SO = NULL; SUMA_RETURN(SO);
9012 }
9013
9014 /* check on all elements that need to be loaded */
9015 tmp = NI_get_attribute(ngr, "Mesh_Element_ID");
9016 if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) {
9017 if (!SO->FaceSetList) { /* element was not part of this group, usually recover from other files on disk, for the moment, warning */
9018 fprintf (SUMA_STDERR,"Warning %s:\n group %s called for FaceSetList element_ID %s which was not found.\n", FuncName, ngr->name, tmp);
9019 /*
9020 in the future, try to load from separate file
9021 nel = SUMA_Find_nel_File(tmp); (for example) SUMA_Mesh_IJK_nel2Mesh_IJK(SO, nel) ; NI_free_nel(nel); nel = NULL;
9022 */
9023 }
9024 }
9025
9026 tmp = NI_get_attribute(ngr, "NodeList_Element_ID");
9027 if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) {
9028 if (!SO->NodeList) { /* element was not part of this group, usually recover from other files on disk, for the moment, warning */
9029 fprintf (SUMA_STDERR,"Warning %s:\n group %s called for NodeList element_ID %s which was not found.\n", FuncName, ngr->name, tmp);
9030 /*
9031 in the future, try to load from separate file
9032 nel = SUMA_Find_nel_File(tmp); (for example) SUMA_NodeXYZ_nel2NodeXYZ(SO, nel) ; NI_free_nel(nel); nel = NULL;
9033 */
9034 }
9035 }
9036
9037 tmp = NI_get_attribute(ngr, "facenormals_idcode_str");
9038 if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) {
9039 if (!SO->FaceNormList) { /* element was not part of this group, usually recover from other files on disk, for the moment, warning */
9040 fprintf (SUMA_STDERR,"Warning %s:\n group %s called for facenormals element_ID %s which was not found.\n", FuncName, ngr->name, tmp);
9041 /*
9042 in the future, try to load from separate file
9043 nel = SUMA_Find_nel_File(tmp); (for example) xxxxxx(SO, nel) ; NI_free_nel(nel); nel = NULL;
9044 */
9045 }
9046 }
9047
9048 tmp = NI_get_attribute(ngr, "Node_Normals_Element_ID");
9049 if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) {
9050 if (!SO->NodeNormList) { /* element was not part of this group, usually recover from other files on disk, for the moment, warning */
9051 fprintf (SUMA_STDERR,"Warning %s:\n group %s called for Node_Normals element_ID %s which was not found.\n", FuncName, ngr->name, tmp);
9052 /*
9053 in the future, try to load from separate file
9054 nel = SUMA_Find_nel_File(tmp); (for example) xxxxxx(SO, nel) ; NI_free_nel(nel); nel = NULL;
9055 */
9056 }
9057 }
9058
9059 tmp = NI_get_attribute(ngr, "Polygon_Area_Element_ID");
9060 if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) {
9061 if (!SO->PolyArea) { /* element was not part of this group, usually recover from other files on disk, for the moment, warning */
9062 fprintf (SUMA_STDERR,"Warning %s:\n group %s called for Polygon_Area element_ID %s which was not found.\n", FuncName, ngr->name, tmp);
9063 /*
9064 in the future, try to load from separate file
9065 nel = SUMA_Find_nel_File(tmp); (for example) xxxxxx(SO, nel) ; NI_free_nel(nel); nel = NULL;
9066 */
9067 }
9068 }
9069
9070 tmp = NI_get_attribute(ngr, "SUMA_Edge_List_Element_ID");
9071 if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) {
9072 if (!SO->EL) { /* element was not part of this group, usually recover from other files on disk, for the moment, warning */
9073 fprintf (SUMA_STDERR,"Warning %s:\n group %s called for Edge_List element_ID %s which was not found.\n", FuncName, ngr->name, tmp);
9074 /*
9075 in the future, try to load from separate file
9076 nel = SUMA_Find_nel_File(tmp); (for example) xxxxxx(SO, nel) ; NI_free_nel(nel); nel = NULL;
9077 */
9078 }
9079 }
9080
9081 tmp = NI_get_attribute(ngr, "SUMA_Node_Face_Member_Element_ID");
9082 if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) {
9083 if (!SO->MF) { /* element was not part of this group, usually recover from other files on disk, for the moment, warning */
9084 fprintf (SUMA_STDERR,"Warning %s:\n group %s called for Node_Face_Member element_ID %s which was not found.\n", FuncName, ngr->name, tmp);
9085 /*
9086 in the future, try to load from separate file
9087 nel = SUMA_Find_nel_File(tmp); (for example) xxxxxx(SO, nel) ; NI_free_nel(nel); nel = NULL;
9088 */
9089 }
9090 }
9091
9092 tmp = NI_get_attribute(ngr, "SUMA_Node_First_Neighb_Element_ID");
9093 if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) {
9094 if (!SO->FN) { /* element was not part of this group, usually recover from other files on disk, for the moment, warning */
9095 fprintf (SUMA_STDERR,"Warning %s:\n group %s called for Node_First_Neighb element_ID %s which was not found.\n", FuncName, ngr->name, tmp);
9096 /*
9097 in the future, try to load from separate file
9098 nel = SUMA_Find_nel_File(tmp); (for example) xxxxxx(SO, nel) ; NI_free_nel(nel); nel = NULL;
9099 */
9100 }
9101 }
9102
9103
9104 if (SO->MF && SO->MF->idcode_str) {
9105 NI_set_attribute(ngr, "SUMA_Node_Face_Member_Element_ID", SO->MF->idcode_str);
9106 } else {
9107 NI_set_attribute(ngr, "SUMA_Node_Face_Member_Element_ID", SUMA_EMPTY_ATTR);
9108 }
9109
9110 if (SO->FN && SO->FN->idcode_str) {
9111 NI_set_attribute(ngr, "SUMA_Node_First_Neighb_Element_ID", SO->FN->idcode_str);
9112 } else {
9113 NI_set_attribute(ngr, "SUMA_Node_First_Neighb_Element_ID", SUMA_EMPTY_ATTR);
9114 }
9115
9116
9117
9118 SUMA_RETURN(SO);
9119 }
9120
9121 /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Begin OpenDX functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
9122
9123
SUMA_Free_OpenDX_StructVec(SUMA_OPEN_DX_STRUCT ** dxv,int nobj)9124 SUMA_OPEN_DX_STRUCT ** SUMA_Free_OpenDX_StructVec(SUMA_OPEN_DX_STRUCT **dxv, int nobj)
9125 {
9126 static char FuncName[]={"SUMA_Free_OpenDX_StructVec"};
9127 int i;
9128
9129 SUMA_ENTRY;
9130
9131 if (!dxv) SUMA_RETURN(NULL);
9132 for (i=0; i<nobj; ++i) {
9133 dxv[i] = SUMA_Free_OpenDX_Struct(dxv[i]);
9134 }
9135 SUMA_free(dxv);
9136 SUMA_RETURN(NULL);
9137 }
9138
9139
SUMA_OpenDX_Write(char * fname,SUMA_SurfaceObject * SO)9140 SUMA_Boolean SUMA_OpenDX_Write(char *fname, SUMA_SurfaceObject *SO)
9141 {
9142 static char FuncName[]={"SUMA_OpenDX_Write"};
9143
9144 SUMA_ENTRY;
9145
9146 SUMA_SL_Err("Not supported yet");
9147
9148 SUMA_RETURN(NOPE);
9149 }
9150
9151
9152
9153
9154
9155 /*!
9156 \brief returns structure containing object of a certain name in dxv
9157 do not free returned structure since it is a copy of pointer in dxv
9158 */
SUMA_Find_OpenDX_Object_Name(SUMA_OPEN_DX_STRUCT ** dxv,int iop,char * nm,int * nf)9159 SUMA_OPEN_DX_STRUCT *SUMA_Find_OpenDX_Object_Name(SUMA_OPEN_DX_STRUCT **dxv, int iop, char *nm, int *nf)
9160 {
9161 static char FuncName[]={"SUMA_Find_OpenDX_Object_Name"};
9162 int i;
9163 SUMA_OPEN_DX_STRUCT *dx = NULL;
9164 SUMA_Boolean LocalHead = NOPE;
9165
9166 SUMA_ENTRY;
9167
9168 *nf = 0;
9169 for (i=0; i<iop; ++i) {
9170 if (strstr(dxv[i]->object, nm)) {
9171 if (!dx) dx = dxv[i];
9172 ++ (*nf);
9173 }
9174 }
9175
9176 if (LocalHead) fprintf(SUMA_STDERR,"%s: Found %d objects\n", FuncName, *nf);
9177 SUMA_RETURN(dx);
9178 }
9179 /*!
9180 \brief returns structure containing object of a certain class in dxv
9181 do not free returned structure since it is a copy of pointer in dxv
9182 */
SUMA_Find_OpenDX_Object_Class(SUMA_OPEN_DX_STRUCT ** dxv,int iop,char * nm,int * nf)9183 SUMA_OPEN_DX_STRUCT *SUMA_Find_OpenDX_Object_Class(SUMA_OPEN_DX_STRUCT **dxv, int iop, char *nm, int *nf)
9184 {
9185 static char FuncName[]={"SUMA_Find_OpenDX_Object_Class"};
9186 int i;
9187 SUMA_OPEN_DX_STRUCT *dx = NULL;
9188 SUMA_Boolean LocalHead = NOPE;
9189
9190 SUMA_ENTRY;
9191
9192 *nf = 0;
9193 for (i=0; i<iop; ++i) {
9194 if (strstr(dxv[i]->class, nm)) {
9195 if (!dx) dx = dxv[i];
9196 ++ (*nf);
9197 }
9198 }
9199
9200 if (LocalHead) fprintf(SUMA_STDERR,"%s: Found %d objects\n", FuncName, *nf);
9201 SUMA_RETURN(dx);
9202 }
9203
9204
SUMA_OpenDX_Read_CruiseVolHead(char * fname,THD_3dim_dataset * dset,int LoadData)9205 char * SUMA_OpenDX_Read_CruiseVolHead(char *fname, THD_3dim_dataset *dset, int LoadData)
9206 {
9207 static char FuncName[]={"SUMA_OpenDX_Read_CruiseVolHead"};
9208 int i = 0, nf, iop, chunk, End, bs, doff, data_type=SUMA_notypeset;
9209 THD_ivec3 iv3;
9210 THD_mat33 m33;
9211 THD_ivec3 orixyz , nxyz ;
9212 THD_fvec3 dxyz , orgxyz ;
9213 float ep[3], sp[3];
9214 char *scom=NULL, form[10], swp[10], orstr[10], xfov[100], yfov[100], zfov[100], *prefix = NULL, *dsetheadname = NULL;
9215 SUMA_OPEN_DX_STRUCT **dxv=NULL, *dxp=NULL, *dxc=NULL, *dxf=NULL, *dxa=NULL;
9216 SUMA_Boolean LocalHead = NOPE;
9217
9218 SUMA_ENTRY;
9219
9220 if (!dset || !fname) {
9221 SUMA_SL_Err("NULL fname || NULL dset!");
9222 SUMA_RETURN(NOPE);
9223 }
9224
9225 prefix = SUMA_AfniPrefix(fname, NULL, NULL, NULL);
9226 if( !THD_filename_ok(prefix) ) {
9227 SUMA_SL_Err("Bad prefix");
9228 SUMA_RETURN(NOPE);
9229 }
9230 dsetheadname = SUMA_append_string(prefix,"+orig.HEAD");
9231 if (SUMA_filexists(dsetheadname)) {
9232 SUMA_SL_Err("Bad prefix, output dset exists");
9233 SUMA_RETURN(NOPE);
9234 }
9235 SUMA_free(dsetheadname); dsetheadname = NULL;
9236
9237 SUMA_LH("Reading objects");
9238 dxv = SUMA_OpenDX_Read(fname, &iop);
9239 if (!dxv) {
9240 SUMA_SL_Err("Failed to read DX file.");
9241 SUMA_RETURN(NOPE);
9242 }
9243
9244 SUMA_LH("Checking for field object");
9245 dxf = SUMA_Find_OpenDX_Object_Class(dxv, iop, "field", &nf);
9246 if (!dxf || nf != 1) { SUMA_SL_Err("Failed to find one and only one field object"); goto CLEAN_EXIT; }
9247 dxp = dxc = NULL;
9248 for (i=0; i<dxf->n_comp; ++i) {
9249 if (strstr(dxf->comp_name[i],"positions")) {
9250 dxp = SUMA_Find_OpenDX_Object_Name(dxv, iop, dxf->comp_value[i], &nf);
9251 if (!dxp || nf != 1) { SUMA_SL_Err("Failed to find one and only one positions object"); goto CLEAN_EXIT; }
9252 }
9253 if (strstr(dxf->comp_name[i],"connections")) {
9254 dxc = SUMA_Find_OpenDX_Object_Name(dxv, iop, dxf->comp_value[i], &nf);
9255 if (!dxc || nf != 1) { SUMA_SL_Err("Failed to find one and only one connections object"); goto CLEAN_EXIT; }
9256 }
9257 if (strstr(dxf->comp_name[i],"data")) {
9258 dxa = SUMA_Find_OpenDX_Object_Name(dxv, iop, dxf->comp_value[i], &nf);
9259 if (!dxa || nf != 1) { SUMA_SL_Err("Failed to find one and only one data object"); goto CLEAN_EXIT; }
9260 }
9261 }
9262
9263 if (!dxp || !dxv || !dxa) {
9264 SUMA_SL_Err("Failed to find necessary objects"); SUMA_RETURN(NOPE);
9265 }
9266
9267 /* sanity */
9268 SUMA_LH("Sanity checks");
9269 if (!dxa->data_format) {
9270 SUMA_SL_Err("Not a binary data file!");
9271 goto CLEAN_EXIT;
9272 }
9273 if (!dxa->data) {
9274 SUMA_SL_Err("No data file!");
9275 goto CLEAN_EXIT;
9276 }
9277 if (dxp->n_counts != 3) {
9278 SUMA_SL_Err("counts field must have 3 values");
9279 goto CLEAN_EXIT;
9280 }
9281 if (dxp->n_delta != 9) {
9282 SUMA_SL_Err("delta must contain 9 elements!");
9283 goto CLEAN_EXIT;
9284 }
9285
9286 /* form the command */
9287 SUMA_LH("Forming command");
9288 /* 3d what? */
9289 chunk = 0;
9290 form[0] = '\0';
9291 data_type = SUMA_CTypeName2VarType(dxa->type);
9292 switch (data_type) {
9293 case SUMA_float:
9294 sprintf(form,"3Df");
9295 chunk = sizeof(float);
9296 break;
9297 case SUMA_double:
9298 sprintf(form,"3Dd");
9299 chunk = sizeof(double);
9300 break;
9301 case SUMA_int:
9302 sprintf(form,"3Di");
9303 chunk = sizeof(int);
9304 break;
9305 case SUMA_short:
9306 sprintf(form,"3Ds");
9307 chunk = sizeof(short);
9308 break;
9309 case SUMA_byte:
9310 sprintf(form,"3Db");
9311 chunk = sizeof(byte);
9312 break;
9313 default:
9314 SUMA_SL_Err("No support for this type");
9315 goto CLEAN_EXIT;
9316 break;
9317 }
9318 /* byte ordering */
9319 SUMA_WHAT_ENDIAN(End);
9320 bs = 0;
9321 swp[0] = '\0';
9322 if (End != dxa->data_format) {
9323 SUMA_LH("swapping needed");
9324 bs = 1;
9325 switch (chunk) {
9326 case 1:
9327 break;
9328 case 2:
9329 sprintf(swp,"-2swap");
9330 break;
9331 case 4:
9332 sprintf(swp,"-4swap");
9333 break;
9334 case 8:
9335 sprintf(swp,"-8swap");
9336 break;
9337 default:
9338 SUMA_SL_Err("Patchunk!");
9339 break;
9340 }
9341 }
9342 if (dxa->data_off) doff = (int)strtol(dxa->data_off,NULL, 10);
9343 else doff = 0;
9344
9345 /* direction that varies the fastest (x) is in the last delta
9346 count is ordered like delta. I do not know about origin yet,
9347 I assume that origin follows the ordering of count
9348 see http://opendx.npaci.edu/docs/html/pages/usrgu068.htm
9349 for reference, someday....*/
9350
9351 /* number of voxels */
9352 LOAD_IVEC3( nxyz , dxp->counts[2] , dxp->counts[1] , dxp->counts[0] ) ;
9353
9354 /* orientation */
9355 /* find closest orientation in RAI, delta matrix does allow for
9356 obliqueness (non diagonal matrix) but we ignore it */
9357 LOAD_MAT(m33,
9358 dxp->delta[6], dxp->delta[7], dxp->delta[8],
9359 dxp->delta[3], dxp->delta[4], dxp->delta[5],
9360 dxp->delta[0], dxp->delta[1], dxp->delta[2] );
9361 orixyz = THD_matrix_to_orientation( m33 );
9362
9363 /* dimensions */
9364 {
9365 float fb[3];
9366 SUMA_NORM_VEC((&(dxp->delta[6])),3, fb[0]);
9367 SUMA_NORM_VEC((&(dxp->delta[3])),3, fb[1]);
9368 SUMA_NORM_VEC((&(dxp->delta[0])),3, fb[2]);
9369 LOAD_FVEC3( dxyz , fb[0] , fb[1] , fb[2] ) ;
9370 SUMA_sizeto3d_2_deltaHEAD(orixyz, &dxyz);
9371 }
9372
9373 /* origin , assumed to be center of first voxel*/
9374 LOAD_FVEC3( orgxyz , dxp->origin[2] , dxp->origin[1] , dxp->origin[0] ) ;
9375 SUMA_originto3d_2_originHEAD(orixyz, &orgxyz);
9376
9377 /* start point (edge of origin voxel) and end point (opposite to start ) */
9378 sp[0] = dxp->origin[2] + SUMA_ABS(dxyz.xyz[0]) / 2.0;
9379 sp[1] = dxp->origin[1] + SUMA_ABS(dxyz.xyz[1]) / 2.0;
9380 sp[2] = dxp->origin[0] + SUMA_ABS(dxyz.xyz[2]) / 2.0;
9381 ep[0] = dxp->origin[2] + (nxyz.ijk[0] - 0.5) * SUMA_ABS(dxyz.xyz[0]);
9382 ep[1] = dxp->origin[1] + (nxyz.ijk[1] - 0.5) * SUMA_ABS(dxyz.xyz[1]);
9383 ep[2] = dxp->origin[0] + (nxyz.ijk[2] - 0.5) * SUMA_ABS(dxyz.xyz[2]);
9384 SUMA_orcode_to_orstring (orixyz.ijk[0], orixyz.ijk[1], orixyz.ijk[2], orstr);
9385 sprintf(xfov," -xFOV %.2f%c-%.2f%c", sp[0], orstr[0], ep[0], orstr[3]);
9386 sprintf(yfov," -yFOV %.2f%c-%.2f%c", sp[1], orstr[1], ep[1], orstr[4]);
9387 sprintf(zfov," -zFOV %.2f%c-%.2f%c", sp[2], orstr[2], ep[2], orstr[5]);
9388
9389
9390 scom = (char *)SUMA_calloc((strlen(dxa->data)+500), sizeof(char));
9391 sprintf(scom,"to3d %s %s %s %s -prefix %s %s:%d:0:%d:%d:%d:%s ", swp, xfov, yfov, zfov, prefix, form, doff, dxp->counts[2], dxp->counts[1], dxp->counts[0], dxa->data);
9392
9393
9394 if (dset) { /* form the dset header */
9395 int nvals_read = 0;
9396 EDIT_dset_items( dset ,
9397 ADN_prefix , prefix ,
9398 ADN_datum_all , data_type ,
9399 ADN_nxyz , nxyz ,
9400 ADN_xyzdel , dxyz ,
9401 ADN_xyzorg , orgxyz ,
9402 ADN_xyzorient , orixyz ,
9403 ADN_malloc_type , DATABLOCK_MEM_MALLOC ,
9404 ADN_view_type , VIEW_ORIGINAL_TYPE ,
9405 ADN_type , HEAD_ANAT_TYPE ,
9406 ADN_func_type , ANAT_BUCK_TYPE ,
9407 ADN_none ) ;
9408
9409 if (LoadData) {
9410 void *vec=NULL;
9411 if (!(vec = SUMA_BinarySuck(dxa->data, data_type, dxa->data_format, doff, -1, &nvals_read))) {
9412 SUMA_SL_Err("Failed to read data file"); goto CLEAN_EXIT;
9413 }
9414 EDIT_substitute_brick( dset , 0 , data_type , vec) ;
9415 if (LocalHead) fprintf(SUMA_STDERR,"%s: Read %d values from file.\n", FuncName, nvals_read);
9416 /* DSET_write(dset) ; */
9417 }
9418 }
9419
9420
9421
9422 CLEAN_EXIT:
9423 dxv = SUMA_Free_OpenDX_StructVec(dxv, iop);
9424 if (prefix) SUMA_free(prefix); prefix = NULL;
9425
9426 SUMA_RETURN(scom);
9427 }
9428
9429 /*!
9430 \brief reads an OpenDX surface. Sample surfaces provided by Aaron Carass
9431
9432 The following fields are set in SO:
9433 SO->NodeDim
9434 SO->FaceSetDim
9435 SO->NodeList
9436 SO->FaceSetList
9437 SO->N_Node;
9438 SO->N_FaceSet;
9439 SO->Name;
9440 SO->FileType;
9441 SO->FileFormat
9442
9443 */
SUMA_OpenDX_Read_SO(char * fname,SUMA_SurfaceObject * SO)9444 SUMA_Boolean SUMA_OpenDX_Read_SO(char *fname, SUMA_SurfaceObject *SO)
9445 {
9446 static char FuncName[]={"SUMA_OpenDX_Read_SO"};
9447 int i = 0, nf, iop;
9448 SUMA_OPEN_DX_STRUCT **dxv=NULL, *dxp=NULL, *dxc = NULL, *dxf = NULL,
9449 *dxo = NULL;
9450 SUMA_Boolean ans = NOPE;
9451 SUMA_Boolean LocalHead = NOPE;
9452
9453 SUMA_ENTRY;
9454
9455 if (!SO || !fname) {
9456 SUMA_SL_Err("NULL fname || NULL SO!");
9457 SUMA_RETURN(NOPE);
9458 }
9459
9460 SUMA_LH("Reading objects");
9461 dxv = SUMA_OpenDX_Read(fname, &iop);
9462 if (!dxv) {
9463 SUMA_SL_Err("Failed to read DX file.");
9464 SUMA_RETURN(NOPE);
9465 }
9466
9467
9468 SUMA_LH("Checking for field object");
9469 dxf = SUMA_Find_OpenDX_Object_Class(dxv, iop, "field", &nf);
9470 if (!dxf || nf != 1) {
9471 SUMA_SL_Err("Failed to find one and only one field object");
9472 goto CLEAN_EXIT; }
9473 /* get names of objects that contain positions and connections */
9474 dxp = dxc = dxo = NULL;
9475 for (i=0; i<dxf->n_comp; ++i) {
9476 if (strstr(dxf->comp_name[i],"positions")) {
9477 dxp = SUMA_Find_OpenDX_Object_Name(dxv, iop, dxf->comp_value[i], &nf);
9478 if (!dxp || nf != 1) {
9479 SUMA_SL_Err("Failed to find one and only one positions object");
9480 goto CLEAN_EXIT;
9481 }
9482 }
9483 if (strstr(dxf->comp_name[i],"connections")) {
9484 dxc = SUMA_Find_OpenDX_Object_Name(dxv, iop, dxf->comp_value[i], &nf);
9485 if (!dxc || nf != 1) {
9486 SUMA_SL_Err("Failed to find one and only one connections object");
9487 goto CLEAN_EXIT;
9488 }
9489 }
9490 if (strstr(dxf->comp_name[i],"origin")) {
9491 dxo = SUMA_Find_OpenDX_Object_Name(dxv, iop, dxf->comp_value[i], &nf);
9492 if (!dxo || nf != 1) {
9493 SUMA_SL_Err("Failed to find one and only one origin object.\n"
9494 "Origin ignored");
9495 }
9496 }
9497 }
9498
9499 if (!dxp || !dxv) {
9500 SUMA_SL_Err("Failed to find necessary objects"); goto CLEAN_EXIT;
9501 }
9502
9503 SUMA_LH("checking...");
9504 if (SUMA_CTypeName2VarType (dxp->type) != SUMA_float) {
9505 SUMA_SL_Err("Expected floats for positions"); goto CLEAN_EXIT;
9506 }
9507 if (dxp->bad_data) {
9508 SUMA_SL_Err("Problem reading data for positions"); goto CLEAN_EXIT;
9509 }
9510 if (dxp->rank != 1) {
9511 SUMA_SL_Err("Expected rank of 1 for positions"); goto CLEAN_EXIT;
9512 }
9513 if (dxp->shape != 3) {
9514 SUMA_SL_Err("Expected rank of 3 for positions"); goto CLEAN_EXIT;
9515 }
9516 if (SUMA_CTypeName2VarType (dxc->type) != SUMA_int) {
9517 SUMA_SL_Err("Expected ints for connections"); goto CLEAN_EXIT;
9518 }
9519 if (dxc->bad_data) {
9520 SUMA_SL_Err("Problem reading data for connections"); goto CLEAN_EXIT;
9521 }
9522 if (dxc->rank != 1) {
9523 SUMA_SL_Err("Expected rank of 1 for connections"); goto CLEAN_EXIT;
9524 }
9525 if (dxc->shape != 3) {
9526 SUMA_SL_Err("Expected rank of 3 for connections"); goto CLEAN_EXIT;
9527 }
9528 /* if dxo */
9529 if (dxo) {
9530 if (SUMA_CTypeName2VarType (dxo->type) != SUMA_float) {
9531 SUMA_SL_Err("Expected floats for origin.\nOrigin ignored"); dxo = NULL;
9532 }
9533 if (!dxo->datap || dxo->shape * dxo->items != 3) {
9534 SUMA_SL_Err("Unknown origin format, ignoring origin"); dxo = NULL;
9535 }
9536 }
9537
9538 SUMA_LH("Take the gold");
9539 SO->FileType = SUMA_OPENDX_MESH;
9540 SO->FileFormat = SUMA_ASCII;
9541
9542 SO->NodeDim = dxp->shape;
9543 SO->NodeList = (float *)dxp->datap; dxp->datap = NULL;
9544 SO->N_Node = dxp->items;
9545
9546 SO->FaceSetDim = dxc->shape;
9547 SO->FaceSetList = (int *)dxc->datap; dxc->datap = NULL;
9548 SO->N_FaceSet = dxc->items;;
9549 SO->Name = SUMA_StripPath(fname);
9550
9551 if (dxo) {
9552 float *fvec=(float*)dxo->datap;
9553 SUMA_LH("Adding origin");
9554 i = 0;
9555 while (i < dxp->items*dxp->shape) {
9556 SO->NodeList[i] += fvec[0]; ++i;
9557 SO->NodeList[i] += fvec[1]; ++i;
9558 SO->NodeList[i] += fvec[2]; ++i;
9559 }
9560 }
9561
9562 /* all is well here */
9563 ans = YUP;
9564
9565 CLEAN_EXIT:
9566 SUMA_LH("Frenching dxv");
9567 for (i=0; i<iop; ++i) {
9568 dxv[i] = SUMA_Free_OpenDX_Struct(dxv[i]);
9569 }
9570 if (dxv) SUMA_free(dxv); dxv = NULL;
9571 SUMA_RETURN(YUP);
9572 }
9573 /* >>>>>>>>>>>>>>> END OpenDX functions <<<<<<<<<<<<<<<<<<<<< */
9574
9575 /* >>>>>>>>>>>>>>> Begin OBJ functions <<<<<<<<<<<<<<<<<<<<< */
9576
9577
SUMA_Free_OBJ(SUMA_OBJ_STRUCT * obj)9578 SUMA_OBJ_STRUCT *SUMA_Free_OBJ(SUMA_OBJ_STRUCT *obj)
9579 {
9580 static char FuncName[]={"SUMA_Free_OBJ"};
9581
9582 SUMA_ENTRY;
9583
9584 if (!obj) SUMA_RETURN(NULL);
9585 SUMA_ifree(obj->Vert);
9586 SUMA_ifree(obj->Face);
9587 SUMA_ifree(obj->Point);
9588 SUMA_free(obj);
9589
9590 SUMA_RETURN(NULL);
9591 }
9592
9593 /*!
9594 \sa http://en.wikipedia.org/wiki/Wavefront_.obj_file
9595 */
SUMA_OBJ_Read(char * fname)9596 SUMA_OBJ_STRUCT *SUMA_OBJ_Read(char *fname)
9597 {
9598 static char FuncName[]={"SUMA_OBJ_Read"};
9599 int nread = 0, i = 0, good=0;
9600 int nwarn_face=0;
9601 char *fl=NULL, *op = NULL,sbuf[256]={""},
9602 *oc, *op2;
9603 SUMA_OBJ_STRUCT *obj=NULL;
9604 double num=0.0;
9605 SUMA_Boolean LocalHead = NOPE;
9606
9607 SUMA_ENTRY;
9608
9609 SUMA_LH("Sucking file");
9610 nread = SUMA_suck_file( fname , &fl ) ;
9611 if (!fl) {
9612 SUMA_SL_Err("Failed to read file.");
9613 SUMA_RETURN(obj);
9614 }
9615
9616 if (LocalHead) fprintf(SUMA_STDERR,"%s: Read in %d chars\n", FuncName, nread);
9617
9618 obj = (SUMA_OBJ_STRUCT *)SUMA_calloc(1, sizeof(SUMA_OBJ_STRUCT));
9619
9620 op = fl;
9621 do {
9622 SUMA_IS_COMMENT_LINE(op, NULL, '#', good);
9623 if (good) {
9624 oc = op;
9625 SUMA_SKIP_LINE(op, NULL);
9626 if (LocalHead && op > oc) {
9627 SUMA_PRINT_STRING(oc, op, NULL,"Comment Line:", "\n");
9628 fprintf(SUMA_STDERR,"\n");
9629 }
9630 continue;
9631 }
9632 SUMA_SKIP_BLANK(op,NULL);
9633 /* SUMA_NPRINT_STRING(op, NULL, NULL, 10, "\nTop:", "\n"); */
9634 SUMA_GET_BETWEEN_BLANKS(op, NULL, op2);
9635 /* SUMA_NPRINT_STRING(op2, NULL, NULL, 10, "\nAfter 1st word:", "\n"); */
9636 oc = op;
9637 if (op2 > op) {
9638 if (!strncmp(op, "v ", 2)) {
9639 if (!obj->N_Vert) SUMA_LH("Have vert");
9640 if (obj->N_Vert >= obj->N_Vert_alloc) {
9641 obj->N_Vert_alloc += 1000;
9642 obj->Vert = (float *)SUMA_realloc(obj->Vert,
9643 sizeof(float)*3*obj->N_Vert_alloc);
9644 }
9645 op = op2;
9646 SUMA_SKIP_LINE(op2, NULL); /* op2 is now at next line */
9647 SUMA_ADVANCE_PAST_NUM(op, num, good);
9648 if (good) {
9649 obj->Vert[3*obj->N_Vert ] = (float)num;
9650 } else {
9651 SUMA_NFILL_STRING(oc, NULL, sbuf, 100);
9652 SUMA_S_Err("Failed to get X coord at %s ...", sbuf);
9653 SUMA_RETURN(SUMA_Free_OBJ(obj));
9654 }
9655 SUMA_ADVANCE_PAST_NUM(op, num, good);
9656 if (good) {
9657 obj->Vert[3*obj->N_Vert+1] = (float)num;
9658 } else {
9659 SUMA_NFILL_STRING(oc, NULL, sbuf, 100);
9660 SUMA_S_Err("Failed to get Y coord at %s ...", sbuf);
9661 SUMA_RETURN(SUMA_Free_OBJ(obj));
9662 }
9663 SUMA_ADVANCE_PAST_NUM(op, num, good);
9664 if (good) {
9665 obj->Vert[3*obj->N_Vert+2] = (float)num;
9666 } else {
9667 SUMA_NFILL_STRING(oc, NULL, sbuf, 100);
9668 SUMA_S_Err("Failed to get Z coord at %s ...", sbuf);
9669 SUMA_RETURN(SUMA_Free_OBJ(obj));
9670 }
9671 ++obj->N_Vert;
9672 SUMA_SKIP_PURE_BLANK(op, NULL);
9673 if (!SUMA_IS_EOL(*op)) {
9674 SUMA_NFILL_STRING(oc, NULL, sbuf, 100);
9675 SUMA_S_Err("Unexplained jibberish on line %s ...", sbuf);
9676 SUMA_RETURN(SUMA_Free_OBJ(obj));
9677 }
9678 } else if (!strncmp(op,"f ",2)) {
9679 if (!obj->N_Face) SUMA_LH("Have face");
9680 if (obj->N_Face >= obj->N_Face_alloc) {
9681 obj->N_Face_alloc += 1000;
9682 obj->Face = (int *)SUMA_realloc(obj->Face,
9683 sizeof(int)*3*obj->N_Face_alloc);
9684 }
9685 op = op2;
9686 SUMA_SKIP_LINE(op2, NULL); /* op2 is now at next line */
9687 SUMA_ADVANCE_PAST_NUM(op, num, good);
9688 if (good) {
9689 obj->Face[3*obj->N_Face ] = (int)num;
9690 } else {
9691 SUMA_NFILL_STRING(oc, NULL, sbuf, 100);
9692 SUMA_S_Err("Failed to get node 1 at %s ...", sbuf);
9693 SUMA_RETURN(SUMA_Free_OBJ(obj));
9694 }
9695 if (*op == '/') {
9696 if (!nwarn_face) {
9697 SUMA_S_Warn("Ignoring additional face parameters");
9698 }
9699 ++nwarn_face;
9700 SUMA_SKIP_TO_NEXT_BLANK(op, NULL);
9701 }
9702 SUMA_ADVANCE_PAST_NUM(op, num, good);
9703 if (good) {
9704 obj->Face[3*obj->N_Face+1] = (int)num;
9705 } else {
9706 SUMA_NFILL_STRING(oc, NULL, sbuf, 100);
9707 SUMA_S_Err("Failed to get node 2 at %s ...", sbuf);
9708 SUMA_RETURN(SUMA_Free_OBJ(obj));
9709 }
9710 if (*op == '/') {
9711 if (!nwarn_face) {
9712 SUMA_S_Warn("Ignoring additional face parameters");
9713 }
9714 ++nwarn_face;
9715 SUMA_SKIP_TO_NEXT_BLANK(op, NULL);
9716 }
9717 SUMA_ADVANCE_PAST_NUM(op, num, good);
9718 if (good) {
9719 obj->Face[3*obj->N_Face+2] = (int)num;
9720 } else {
9721 SUMA_NFILL_STRING(oc, NULL, sbuf, 100);
9722 SUMA_S_Err("Failed to get node 3 at %s ...", sbuf);
9723 SUMA_RETURN(SUMA_Free_OBJ(obj));
9724 }
9725 if (*op == '/') {
9726 if (!nwarn_face) {
9727 SUMA_S_Warn("Ignoring additional face parameters");
9728 }
9729 ++nwarn_face;
9730 SUMA_SKIP_TO_NEXT_BLANK(op, NULL);
9731 }
9732 SUMA_SKIP_PURE_BLANK(op, NULL);
9733 if (!SUMA_IS_EOL(*op)) {
9734 SUMA_NFILL_STRING(oc, NULL, sbuf, 100);
9735 SUMA_S_Err("Face is not for triangle %s ...", sbuf);
9736 SUMA_RETURN(SUMA_Free_OBJ(obj));
9737 }
9738 ++obj->N_Face;
9739 } else if (!strncmp(op, "p ", 2)) {
9740 if (!obj->N_Point) SUMA_LH("Have point");
9741 if (obj->N_Point >= obj->N_Point_alloc) {
9742 obj->N_Point_alloc += 1000;
9743 obj->Point = (int *)SUMA_realloc(obj->Point,
9744 sizeof(int)*obj->N_Point_alloc);
9745 }
9746 op = op2;
9747 SUMA_SKIP_LINE(op2, NULL); /* op2 is now at next line */
9748 SUMA_ADVANCE_PAST_NUM(op, num, good);
9749 if (good) {
9750 obj->Point[obj->N_Point ] = (int)num;
9751 } else {
9752 SUMA_NFILL_STRING(oc, NULL, sbuf, 100);
9753 SUMA_S_Err("Failed to get point index at %s ...", sbuf);
9754 SUMA_RETURN(SUMA_Free_OBJ(obj));
9755 }
9756 ++obj->N_Point;
9757 SUMA_SKIP_PURE_BLANK(op, NULL);
9758 if (!SUMA_IS_EOL(*op)) {
9759 SUMA_NFILL_STRING(oc, NULL, sbuf, 100);
9760 SUMA_S_Err("Unexplained jibberish on line %s ...", sbuf);
9761 SUMA_RETURN(SUMA_Free_OBJ(obj));
9762 }
9763 } else {
9764 if (LocalHead) {
9765 SUMA_NFILL_STRING(oc, NULL, sbuf, 100);
9766 SUMA_LH("Ignoring entry %s (%ld)", sbuf, fl-op);
9767 }
9768 }
9769 op = op2;
9770 }
9771 } while (*op != '\0');
9772
9773 if (obj) {
9774 if (obj->N_Vert && obj->N_Vert != obj->N_Vert_alloc) {
9775 obj->Vert = (float *)SUMA_realloc(obj->Vert,
9776 3*obj->N_Vert*sizeof(float));
9777 obj->N_Vert_alloc = obj->N_Vert;
9778 }
9779 if (obj->N_Face && obj->N_Face != obj->N_Face_alloc) {
9780 obj->Face = (int *)SUMA_realloc(obj->Face,
9781 3*obj->N_Face*sizeof(int));
9782 obj->N_Face_alloc = obj->N_Face;
9783 }
9784 if (obj->N_Point && obj->N_Point != obj->N_Point_alloc) {
9785 obj->Point = (int *)SUMA_realloc(obj->Point,
9786 obj->N_Point*sizeof(int));
9787 obj->N_Point_alloc = obj->N_Point;
9788 }
9789 }
9790 SUMA_RETURN(obj);
9791 }
9792
SUMA_OBJ_2_SO(SUMA_OBJ_STRUCT * obj)9793 SUMA_SurfaceObject *SUMA_OBJ_2_SO(SUMA_OBJ_STRUCT *obj)
9794 {
9795 static char FuncName[]={"SUMA_OBJ_2_SO"};
9796 SUMA_SurfaceObject *SO = NULL;
9797
9798 SUMA_ENTRY;
9799
9800 if (!obj) SUMA_RETURN(SO);
9801 if (!(SO = SUMA_NewSO ( &(obj->Vert), obj->N_Vert,
9802 &(obj->Face), obj->N_Face,
9803 NULL))) {
9804 SUMA_S_Err("Failed to get new SO");
9805 SUMA_RETURN(SO);
9806 }
9807 SO->FileType = SUMA_OBJ_MESH;
9808 SO->FileFormat = SUMA_ASCII;
9809
9810 SUMA_RETURN(SO);
9811 }
9812
SUMA_OBJ_Read_SO(char * fname,SUMA_SurfaceObject * SO,SUMA_SphereDO ** sphdo)9813 SUMA_Boolean SUMA_OBJ_Read_SO(char *fname, SUMA_SurfaceObject *SO,
9814 SUMA_SphereDO **sphdo)
9815 {
9816 static char FuncName[]={"SUMA_OBJ_Read_SO"};
9817 SUMA_OBJ_STRUCT *obj=NULL;
9818 int i;
9819 SUMA_Boolean LocalHead=NOPE;
9820 SUMA_ENTRY;
9821
9822 if (!fname || !SO) SUMA_RETURN(NOPE);
9823 if (sphdo && *sphdo) {
9824 SUMA_S_Err("*sphdo must be NULL at input");
9825 SUMA_RETURN(NOPE);
9826 }
9827 if (!(obj = SUMA_OBJ_Read(fname))) {
9828 SUMA_S_Err("Failed in SUMA_OBJ_Read");
9829 SUMA_RETURN(NOPE);
9830 }
9831 if (LocalHead) SUMA_Show_OBJ(obj, "OBJ read", 0, NULL);
9832
9833 SO->FileType = SUMA_OBJ_MESH;
9834 SO->FileFormat = SUMA_ASCII;
9835
9836 SO->NodeDim = 3;
9837 SO->NodeList = obj->Vert;
9838 SO->N_Node = obj->N_Vert;
9839
9840 SO->FaceSetDim = 3;
9841 SO->FaceSetList = obj->Face;
9842 SO->N_FaceSet = obj->N_Face;
9843 for (i=0; i<3*SO->N_FaceSet; ++i) {
9844 SO->FaceSetList[i] -= 1;
9845 }
9846
9847 SO->Name = SUMA_StripPath(fname);
9848 SUMA_NEW_ID(SO->idcode_str,fname);
9849
9850 if (obj->N_Point) {
9851 char sbuf[1024]={""};
9852 SUMA_DO *DO = NULL;
9853 for (i=0; i<obj->N_Point; ++i) obj->Point[i] -= 1;
9854 DO = (SUMA_DO *)SUMA_calloc(1,sizeof(SUMA_DO));
9855 snprintf(sbuf, 1023, "<nido_head coord_type = 'mobile'\n"
9856 "default_SO_label = '%s'\n"
9857 "bond = 'surface'\n"
9858 "idcode_str = '%s' />\n"
9859 "<S rad = '0.1' col = '0.9 0.1 0.61' />",
9860 SO->Label, SO->idcode_str);
9861 if (!(DO->OP = (void *)SUMA_ReadNIDO(sbuf, SO->idcode_str))) {
9862 SUMA_S_Err("Failed to create ball datum");
9863
9864 } else {
9865 DO->ObjectType = NIDO_type;
9866 DO->CoordType = SUMA_WORLD;
9867 SO->NodeNIDOObjects =
9868 SUMA_Multiply_NodeNIDOObjects( SO, DO, obj->Point, obj->N_Point);
9869 }
9870 SUMA_Free_Displayable_Object(DO); DO = NULL;
9871 if (LocalHead) {
9872 int ip3;
9873 FILE *fout=fopen("junk.1D.do", "w");
9874 if (fout) {
9875 SUMA_LH("Writing SCALED junk.1D.do");
9876 fprintf(fout, "#spheres\n");
9877 i = 0;
9878 while (i < obj->N_Point) {
9879 ip3 = obj->Point[i]*3;
9880 fprintf(fout, "%f %f %f\n",
9881 SO->NodeList[ip3 ]/319.7,
9882 SO->NodeList[ip3+1]/319.7,
9883 SO->NodeList[ip3+2]/319.7);
9884 ++i;
9885 }
9886 fclose(fout); fout=NULL;
9887 }
9888 }
9889 if (sphdo) {
9890 SUMA_SphereDO *SDO=NULL;
9891 int ip3 = 0, i3 = 0;
9892
9893 SUMA_S_Warn("Loosing link of points to node ids here");
9894 SDO = SUMA_Alloc_SphereDO ( obj->N_Point, fname,
9895 NULL, SP_type);
9896 i = 0;
9897 while (i < SDO->N_n) {
9898 ip3 = obj->Point[i]*3;
9899 i3 = 3*i;
9900 SDO->cxyz[i3] = SO->NodeList[ip3];
9901 SDO->cxyz[i3+1] = SO->NodeList[ip3+1];
9902 SDO->cxyz[i3+2] = SO->NodeList[ip3+2];
9903 ++i;
9904 }
9905 *sphdo = SDO; SDO=NULL;
9906 }
9907 }
9908
9909
9910 obj->Vert = NULL; /* pointer copied into SO above */
9911 obj->Face = NULL; /* pointer copied into SO above */
9912 obj = SUMA_Free_OBJ(obj);
9913
9914 SUMA_RETURN(YUP);
9915 }
9916
SUMA_OBJ_Info(SUMA_OBJ_STRUCT * obj,char * Header,int level)9917 char *SUMA_OBJ_Info(SUMA_OBJ_STRUCT *obj, char *Header, int level)
9918 {
9919 static char FuncName[]={"SUMA_OBJ_Info"};
9920 SUMA_STRING *SS=NULL;
9921 char *s=NULL;
9922
9923 SUMA_ENTRY;
9924
9925 SS = SUMA_StringAppend (NULL, NULL);
9926
9927 if (Header) SS = SUMA_StringAppend_va(SS,"%s\n", Header);
9928
9929 if (!obj) SS = SUMA_StringAppend(SS,"NULL obj");
9930 else {
9931 SS = SUMA_StringAppend_va(SS, "%d vertices at %p (%d alloc)\n",
9932 obj->N_Vert, obj->Vert, obj->N_Vert_alloc);
9933 SS = SUMA_StringAppend_va(SS, "%d faces at %p (%d alloc)\n",
9934 obj->N_Face, obj->Face, obj->N_Face_alloc);
9935 SS = SUMA_StringAppend_va(SS, "%d points at %p (%d alloc)\n",
9936 obj->N_Point, obj->Point, obj->N_Point_alloc);
9937 }
9938
9939 SS = SUMA_StringAppend(SS,NULL);
9940 s = SS->s;
9941 SUMA_free(SS);
9942
9943 SUMA_RETURN(s);
9944 }
9945
SUMA_Show_OBJ(SUMA_OBJ_STRUCT * obj,char * Header,int level,FILE * out)9946 void SUMA_Show_OBJ(SUMA_OBJ_STRUCT *obj, char *Header, int level, FILE *out)
9947 {
9948 static char FuncName[]={"SUMA_Show_OBJ"};
9949 char *s = NULL;
9950
9951 SUMA_ENTRY;
9952
9953 if (!out) out = SUMA_STDERR;
9954
9955 s = SUMA_OBJ_Info(obj, Header, level);
9956 fprintf(out, "%s", s);
9957 SUMA_free(s); s = NULL;
9958
9959 SUMA_RETURNe;
9960 }
9961
9962 /* >>>>>>>>>>>>>>> End OBJ functions <<<<<<<<<<<<<<<<<<<<< */
9963