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