Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

SUMA_Surface_IO.c

Go to the documentation of this file.
00001 
00002 #include "SUMA_suma.h"
00003 #include "PLY/ply.h"
00004 
00005 #undef STAND_ALONE
00006 
00007 #if defined SUMA_SureFit_STAND_ALONE
00008 #define STAND_ALONE 
00009 #elif defined SUMA_FreeSurfer_STAND_ALONE
00010 #define STAND_ALONE
00011 #elif defined SUMA_Ply_Read_STAND_ALONE
00012 #define STAND_ALONE
00013 #elif defined SUMA_ConvertSurface_STAND_ALONE
00014 #define STAND_ALONE
00015 #elif defined SUMA_ROI2dataset_STAND_ALONE
00016 #define STAND_ALONE
00017 #elif defined SUMA_FScurv_to_1D_STAND_ALONE
00018 #define STAND_ALONE
00019 #elif defined SUMA_FSread_annot_STAND_ALONE
00020 #define STAND_ALONE
00021 #endif
00022 
00023 #ifdef STAND_ALONE
00024 /* these global variables must be declared even if they will not be used by this main */
00025 SUMA_SurfaceViewer *SUMAg_cSV = NULL; /*!< Global pointer to current Surface Viewer structure*/
00026 SUMA_SurfaceViewer *SUMAg_SVv = NULL; /*!< Global pointer to the vector containing the various Surface Viewer Structures 
00027                                     SUMAg_SVv contains SUMA_MAX_SURF_VIEWERS structures */
00028 int SUMAg_N_SVv = 0; /*!< Number of SVs realized by X */
00029 SUMA_DO *SUMAg_DOv = NULL;   /*!< Global pointer to Displayable Object structure vector*/
00030 int SUMAg_N_DOv = 0; /*!< Number of DOs stored in DOv */
00031 SUMA_CommonFields *SUMAg_CF = NULL; /*!< Global pointer to structure containing info common to all viewers */
00032 #else
00033 extern SUMA_CommonFields *SUMAg_CF;
00034 extern SUMA_DO *SUMAg_DOv;
00035 extern SUMA_SurfaceViewer *SUMAg_SVv;
00036 extern int SUMAg_N_SVv; 
00037 extern int SUMAg_N_DOv;  
00038 #endif
00039    
00040 
00041 
00042 /*!
00043    \brief a function to simplify loading surfaces the old way
00044    The only difference with SUMA_Load_Surface_Object_eng is that it 
00045    takes the file names needed in the first three character pointers
00046    usually: if_name1: (char *) name of entire surface file or the coordinates file
00047             if_name2: (char *) name of triangulation file
00048             vp_name: (char *) name of volume parent file, just for SureFit surfaces.
00049 */
00050 SUMA_SurfaceObject *SUMA_Load_Surface_Object_Wrapper ( char *if_name, char *if_name2, char *vp_name, 
00051                                                    SUMA_SO_File_Type SO_FT, SUMA_SO_File_Format SO_FF, char *sv_name, int debug)
00052 {
00053    static char FuncName[]={"SUMA_Load_Surface_Object_Wrapper"};
00054    SUMA_SurfaceObject *SO=NULL;
00055    void *SO_name=NULL;
00056    SUMA_SFname *SF_name = NULL;
00057    SUMA_Boolean LocalHead = NOPE;
00058 
00059    SUMA_ENTRY;
00060 
00061    switch (SO_FT) {
00062       case SUMA_SUREFIT:
00063          SF_name = (SUMA_SFname *) SUMA_malloc(sizeof(SUMA_SFname));
00064          sprintf(SF_name->name_coord,"%s", if_name);
00065          sprintf(SF_name->name_topo,"%s", if_name2); 
00066          if (!vp_name) { /* initialize to empty string */
00067             SF_name->name_param[0] = '\0'; 
00068          }
00069          else {
00070             sprintf(SF_name->name_param,"%s", vp_name);
00071          }
00072          SO_name = (void *)SF_name;
00073          if (debug > 0) fprintf (SUMA_STDOUT,"Reading %s and %s...\n", SF_name->name_coord, SF_name->name_topo);
00074          SO = SUMA_Load_Surface_Object (SO_name, SUMA_SUREFIT, SUMA_ASCII, sv_name);
00075          break;
00076       case SUMA_VEC:
00077          SF_name = (SUMA_SFname *) SUMA_malloc(sizeof(SUMA_SFname));
00078          sprintf(SF_name->name_coord,"%s", if_name);
00079          sprintf(SF_name->name_topo,"%s", if_name2); 
00080          SO_name = (void *)SF_name;
00081          fprintf (SUMA_STDOUT,"Reading %s and %s...\n", SF_name->name_coord, SF_name->name_topo);
00082          SO = SUMA_Load_Surface_Object (SO_name, SUMA_VEC, SUMA_ASCII, sv_name);
00083          break;
00084       case SUMA_FREE_SURFER:
00085       case SUMA_FREE_SURFER_PATCH:
00086          SO_name = (void *)if_name; 
00087          fprintf (SUMA_STDOUT,"Reading %s ...\n",if_name);
00088          if (SUMA_isExtension(SO_name, ".asc")) 
00089             SO = SUMA_Load_Surface_Object (SO_name, SUMA_FREE_SURFER, SUMA_ASCII, sv_name);
00090          else
00091             SO = SUMA_Load_Surface_Object_eng (SO_name, SUMA_FREE_SURFER, SUMA_BINARY_BE, sv_name, 0);
00092          break;  
00093       case SUMA_OPENDX_MESH:
00094          SO_name = (void *)if_name; 
00095          fprintf (SUMA_STDOUT,"Reading %s ...\n",if_name);
00096          SO = SUMA_Load_Surface_Object (SO_name, SUMA_OPENDX_MESH, SUMA_ASCII, sv_name);
00097          break;  
00098       case SUMA_PLY:
00099          SO_name = (void *)if_name; 
00100          fprintf (SUMA_STDOUT,"Reading %s ...\n",if_name);
00101          SO = SUMA_Load_Surface_Object (SO_name, SUMA_PLY, SUMA_FF_NOT_SPECIFIED, sv_name);
00102          break;  
00103       case SUMA_BRAIN_VOYAGER:
00104          SO_name = (void *)if_name; 
00105          fprintf (SUMA_STDOUT,"Reading %s ...\n",if_name);
00106          SO = SUMA_Load_Surface_Object (SO_name, SUMA_BRAIN_VOYAGER, SUMA_BINARY, sv_name);
00107          break;  
00108       default:
00109          fprintf (SUMA_STDERR,"Error %s: Bad format.\n", FuncName);
00110          exit(1);
00111    }
00112 
00113    if (SF_name) SUMA_free(SF_name); SF_name = NULL;
00114    SUMA_RETURN(SO);
00115 }
00116 
00117 /*!
00118    \brief Removes the standard extension from a dataset filename
00119    \param Name (char *) name 
00120    \param form SUMA_DSET_FORMAT
00121    \return (char *) no_extension (you have to free that one with SUMA_free)
00122 */
00123 
00124 char *SUMA_RemoveSurfNameExtension (char*Name, SUMA_SO_File_Type oType)
00125 {
00126    static char FuncName[]={"SUMA_RemoveSurfNameExtension"};
00127    char *noex = NULL, *tmp = NULL;
00128    
00129    SUMA_ENTRY;
00130    
00131    if (!Name) { SUMA_SL_Err("NULL Name"); SUMA_RETURN(NULL); }
00132   
00133    switch (oType) {
00134       case SUMA_SUREFIT:
00135          tmp  =  SUMA_Extension(Name, ".coord", YUP);
00136          noex  =  SUMA_Extension(tmp, ".topo", YUP); SUMA_free(tmp); tmp = NULL;
00137          break;
00138       case SUMA_VEC:
00139          tmp  =  SUMA_Extension(Name, ".1D.coord", YUP);
00140          noex  =  SUMA_Extension(tmp, ".1D.topo", YUP); SUMA_free(tmp); tmp = NULL;
00141          break;
00142       case SUMA_FREE_SURFER:
00143       case SUMA_FREE_SURFER_PATCH:
00144          noex  =  SUMA_Extension(Name, ".asc", YUP);
00145          break;  
00146       case SUMA_PLY:
00147          noex  =  SUMA_Extension(Name,".ply" , YUP); 
00148          break;  
00149       case SUMA_OPENDX_MESH:
00150          noex  =  SUMA_Extension(Name,".dx" , YUP); 
00151          break;  
00152       case SUMA_INVENTOR_GENERIC:
00153          noex  =  SUMA_Extension(Name,".iv" , YUP); 
00154          break;
00155       case SUMA_BRAIN_VOYAGER:
00156          noex  =  SUMA_Extension(Name,".srf" , YUP); 
00157          break;
00158       default:
00159          /* do nothing, get back fprintf (SUMA_STDERR,"Warning %s: Bad format.\n", FuncName); */
00160          noex = SUMA_copy_string(Name);
00161          break;
00162    }
00163    
00164    SUMA_RETURN(noex);
00165 }
00166 
00167 /*!
00168    \brief much like SUMA_Prefix2SurfaceName, but handles the case where namecoord and nametopo are not the same
00169    consider it a more general version of SUMA_Prefix2SurfaceName
00170 */
00171 void * SUMA_2Prefix2SurfaceName (char *namecoord, char *nametopo, char *path, char *vp_name, SUMA_SO_File_Type oType, SUMA_Boolean *exists)
00172 {
00173    static char FuncName[]={"SUMA_2Prefix2SurfaceName"};
00174    SUMA_Boolean exist1, exist2;
00175    SUMA_SFname *SF_name1 = NULL, *SF_name2 = NULL;
00176    
00177    SUMA_ENTRY;
00178    
00179    if (!nametopo && !namecoord) { SUMA_RETURN(NULL); }
00180    
00181    if (!nametopo) SUMA_RETURN(SUMA_Prefix2SurfaceName (namecoord, path, vp_name, oType, exists));
00182    if (!namecoord) SUMA_RETURN(SUMA_Prefix2SurfaceName (nametopo, path, vp_name, oType, exists));
00183    
00184    if (strcmp(namecoord, nametopo) == 0) SUMA_RETURN(SUMA_Prefix2SurfaceName (nametopo, path, vp_name, oType, exists));
00185    if (oType != SUMA_SUREFIT && oType != SUMA_VEC) {
00186       SUMA_SL_Err("Wrong usage of function, namecoord and nametopo are different but surface type is neither SUMA_SUREFIT nor SUMA_VEC");
00187       SUMA_RETURN(NULL);
00188    }
00189    
00190    /* the pain in the behind case */
00191    SF_name1 = SUMA_Prefix2SurfaceName (namecoord, path, vp_name, oType, &exist1);
00192    if (!SF_name1) {
00193       SUMA_SL_Err("Failed to create name");
00194       SUMA_RETURN(NULL);
00195    }
00196    SF_name2 = SUMA_Prefix2SurfaceName (nametopo, path, vp_name, oType, &exist2);
00197    if (!SF_name2) {
00198       SUMA_free(SF_name1); SF_name1= NULL;
00199       SUMA_SL_Err("Failed to create name");
00200       SUMA_RETURN(NULL);
00201    }
00202    
00203    if (exist1 || exist2) *exists = YUP;
00204    
00205    sprintf(SF_name1->name_topo, "%s", SF_name2->name_topo);
00206    SUMA_free(SF_name2); SF_name2= NULL;
00207    
00208    SUMA_RETURN(SF_name1);
00209 }  
00210 /*!
00211    \brief A function to take a prefix (or name) and turn it into the structure needed
00212           by SUMA_Save_Surface_Object   
00213    also sets *exists = YUP if completed filename exists on disk. For surfaces requiring
00214             two files, *exists = YUP if any of the files exists       
00215    - free returned pointer with SUMA_free
00216    
00217    \sa SUMA_2Prefix2SurfaceName if you have a surface with different names for coord and topo )
00218 */
00219 
00220 void * SUMA_Prefix2SurfaceName (char *prefix_in, char *path, char *vp_name, SUMA_SO_File_Type oType, SUMA_Boolean *exists)
00221 {
00222    static char FuncName[]={"SUMA_Prefix2SurfaceName"};
00223    SUMA_SFname *SF_name = NULL;
00224    char *ppref = NULL, *prefix=NULL;
00225    void *SO_name = NULL;
00226    
00227    SUMA_ENTRY;
00228    
00229    if (!prefix_in) {
00230       fprintf (SUMA_STDERR,"Error %s: NULL name input\n", FuncName);
00231       SUMA_RETURN(NULL);
00232    }
00233    /* trim the prefix if necessary */
00234    if (!(prefix = SUMA_RemoveSurfNameExtension (prefix_in, oType))) {
00235       fprintf (SUMA_STDERR,"Error %s: Failed to remove extension\n", FuncName);
00236       SUMA_RETURN(NULL);
00237    }
00238    
00239    if (path) {
00240       if (path[strlen(path)-1] == '/') {
00241          ppref = SUMA_append_replace_string(path, prefix, "", 0);
00242       } else {
00243          ppref = SUMA_append_replace_string(path, prefix, "/", 0);
00244       }
00245    } else {
00246       ppref = SUMA_copy_string(prefix);
00247    }
00248    
00249    switch (oType) {
00250       case SUMA_SUREFIT:
00251          SF_name = (SUMA_SFname *) SUMA_malloc(sizeof(SUMA_SFname));
00252          snprintf(SF_name->name_coord, (SUMA_MAX_DIR_LENGTH+SUMA_MAX_NAME_LENGTH+1)*sizeof(char),
00253                    "%s.coord", ppref);
00254          snprintf(SF_name->name_topo, (SUMA_MAX_DIR_LENGTH+SUMA_MAX_NAME_LENGTH+1)*sizeof(char),
00255                    "%s.topo", ppref); 
00256          if (SUMA_filexists(SF_name->name_topo) || SUMA_filexists(SF_name->name_coord)) *exists = YUP;
00257          else *exists = NOPE;
00258          if (!vp_name) { /* initialize to empty string */
00259             SF_name->name_param[0] = '\0'; 
00260          }
00261          else {
00262             snprintf(SF_name->name_param, (SUMA_MAX_DIR_LENGTH+SUMA_MAX_NAME_LENGTH+1)*sizeof(char),
00263                    "%s", vp_name);
00264          }
00265          SO_name = (void *)SF_name;
00266          break;
00267       case SUMA_VEC:
00268          if (SF_name) SUMA_free(SF_name);
00269          SF_name = (SUMA_SFname *) SUMA_malloc(sizeof(SUMA_SFname));
00270          snprintf(SF_name->name_coord, (SUMA_MAX_DIR_LENGTH+SUMA_MAX_NAME_LENGTH+1)*sizeof(char),
00271                    "%s.1D.coord", ppref);
00272          snprintf(SF_name->name_topo, (SUMA_MAX_DIR_LENGTH+SUMA_MAX_NAME_LENGTH+1)*sizeof(char),
00273                    "%s.1D.topo", ppref); 
00274          if (SUMA_filexists(SF_name->name_topo) || SUMA_filexists(SF_name->name_coord)) *exists = YUP;
00275          else *exists = NOPE;
00276          SO_name = (void *)SF_name;
00277          break;
00278       case SUMA_FREE_SURFER:
00279       case SUMA_FREE_SURFER_PATCH:
00280          SO_name = (void *)SUMA_append_string(ppref,".asc"); 
00281          if (SUMA_filexists((char*)SO_name)) *exists = YUP;
00282          else *exists = NOPE;
00283          break;  
00284       case SUMA_OPENDX_MESH:
00285          SO_name = (void *)SUMA_append_string(ppref,".dx"); 
00286          if (SUMA_filexists((char*)SO_name)) *exists = YUP;
00287          else *exists = NOPE;
00288          break;  
00289       case SUMA_PLY:
00290          SO_name = (void *)SUMA_append_string(ppref,".ply"); 
00291          if (SUMA_filexists((char*)SO_name)) *exists = YUP;
00292          else *exists = NOPE;
00293          break;  
00294       case SUMA_BRAIN_VOYAGER:
00295          SO_name = (void *)SUMA_append_string(ppref,".srf"); 
00296          if (SUMA_filexists((char*)SO_name)) *exists = YUP;
00297          else *exists = NOPE;
00298          break;
00299       case SUMA_INVENTOR_GENERIC:
00300          SO_name = (void *)SUMA_append_string(ppref,".iv"); 
00301          if (SUMA_filexists((char*)SO_name)) *exists = YUP;
00302          else *exists = NOPE;
00303          break;
00304       default:
00305          fprintf (SUMA_STDERR,"Error %s: Unknown format.\n", FuncName);
00306          SO_name = (void *)SUMA_copy_string(ppref);
00307          if (SUMA_filexists((char*)SO_name)) *exists = YUP;
00308          else *exists = NOPE;
00309          break;
00310    }
00311    
00312    if (ppref) SUMA_free(ppref);
00313    if (prefix) SUMA_free(prefix); 
00314    
00315    SUMA_RETURN(SO_name);
00316 }
00317    
00318 /*!**  
00319 Function: SUMA_SureFit_Read_Coord 
00320 Usage : 
00321 Ret = SUMA_SureFit_Read_Coord (coordname, SureFit)
00322    
00323    
00324 Input paramters : 
00325 \param coordname (char *) name of .coord file
00326 \param SureFit (SUMA_SureFit_struct *) pointer to the SureFit structure
00327    
00328 Returns : 
00329 \return  (SUMA_Boolean) YUP/NOPE for success/failure
00330    
00331 Support : 
00332 \sa   
00333 \sa   
00334    
00335 Side effects : 
00336    
00337    
00338    
00339 ***/
00340 SUMA_Boolean SUMA_SureFit_Read_Coord (char * f_name, SUMA_SureFit_struct *SF)
00341 {/*SUMA_SureFit_Read_Coord*/
00342    static char FuncName[]={"SUMA_SureFit_Read_Coord"}; 
00343    FILE *sf_file;
00344         int ex, EndHead, FoundHead, evl, cnt, skp, ND, id;
00345         char stmp[100], head_strt[100], head_end[100], s[1000], delimstr[] = {' ', '\0'}, *st;
00346         
00347         SUMA_ENTRY;
00348         
00349         ND = 3;
00350         
00351         /* check for existence */
00352         if (!SUMA_filexists(f_name)) {
00353                 fprintf(SUMA_STDERR,"File %s does not exist or cannot be read.\n", f_name);
00354                 SUMA_RETURN (NOPE);
00355         }
00356         
00357         sprintf(SF->name_coord, "%s", f_name);
00358         
00359         /* start reading */
00360         sf_file = fopen (f_name,"r");
00361         if (sf_file == NULL)
00362                 {
00363                         SUMA_error_message (FuncName,"Could not open input file ",0);
00364                         SUMA_RETURN (NOPE);
00365                 }
00366 
00367         /* read until you reach the begin header BeginHeader */
00368         ex = 1;
00369         FoundHead = 0;
00370         sprintf(head_strt,"BeginHeader");
00371         while (ex != EOF && !FoundHead)
00372         {
00373                 ex = fscanf (sf_file,"%s",s);
00374                 if (strlen (s) >= strlen(head_strt)) 
00375                         {
00376                                 evl = SUMA_iswordin (s,head_strt);
00377                                 if (evl == 1) FoundHead = 1;
00378                         }
00379         }
00380         
00381         if (!FoundHead) {
00382                 fprintf(SUMA_STDERR,"Error %s: BeginHeader not found in %s.\nPerhaps you are using old versions of Caret/SureFit files.\n", FuncName, f_name);
00383                 SUMA_RETURN (NOPE);
00384         }
00385         EndHead = 0;
00386         sprintf(head_end,"EndHeader");
00387         sprintf(delimstr," ");
00388         
00389         while (ex != EOF && !EndHead)   {
00390                 ex = fscanf (sf_file,"%s",s);
00391                 /*fprintf(stdout,"%s\n", s);*/
00392                 if (strlen (s) >= strlen(head_end)) 
00393                         {
00394                                 evl = SUMA_iswordin (s,head_end);
00395                                 if (evl == 1) EndHead = 1;
00396                         }
00397                 /* look for some tokens */
00398                 skp = 0;
00399                 if (!EndHead) {
00400                         st = strtok(s, delimstr);
00401                         sprintf(stmp,"encoding");
00402                         if (!skp && SUMA_iswordin (st, stmp) == 1) {
00403                                 /*fprintf(stdout,"Found encoding\n");*/
00404                                 ex = fscanf (sf_file,"%s",(SF->encoding_coord));
00405                                 skp = 1;
00406                         }
00407                         
00408                         sprintf(stmp,"configuration_id");
00409                         if (!skp && SUMA_iswordin (st, stmp) == 1) {
00410                                 /*fprintf(stdout,"Found configuration_id\n");*/
00411                                 ex = fscanf (sf_file,"%s",(SF->configuration_id));
00412                                 skp = 1;
00413                         }
00414                         
00415                         sprintf(stmp,"coordframe_id");
00416                         if (!skp && SUMA_iswordin (st, stmp) == 1) {
00417                                 /*fprintf(stdout,"Found configuration_id\n");*/
00418                                 ex = fscanf (sf_file,"%s",(SF->coordframe_id));
00419                                 skp = 1;
00420                         }
00421 
00422                 }
00423         }
00424         /* Now read the Number of Nodes */
00425         fscanf(sf_file, "%d", &SF->N_Node);
00426         /*fprintf (stdout,"Expecting %d nodes.\n", SF->N_Node);*/
00427         
00428         /* allocate space */
00429         SF->NodeList = (float *)SUMA_calloc(SF->N_Node * ND, sizeof(float));
00430         SF->NodeId = (int *)SUMA_calloc (SF->N_Node, sizeof(int));
00431         
00432         if (SF->NodeList == NULL || SF->NodeId == NULL) {
00433                 fprintf(SUMA_STDERR, "Error %s: Could not allocate space for NodeList &/| NodeId.\n", FuncName);
00434                 SUMA_RETURN (NOPE);
00435         }
00436         
00437         /* Now read the nodes until the end of the file */
00438                 cnt = 0;
00439                 while (ex != EOF && cnt < SF->N_Node)   {
00440                         id = cnt * ND;
00441                         ex = fscanf (sf_file,"%d %f %f %f",&(SF->NodeId[cnt]), \
00442                                         &(SF->NodeList[id]), &(SF->NodeList[id+1]), &(SF->NodeList[id+2]));
00443                         ++cnt;
00444                 }
00445         if (cnt != SF->N_Node) {
00446                 fprintf(SUMA_STDERR, "Error %s: Expecting %d Nodes, read %d.\n", FuncName, SF->N_Node, cnt);
00447                 SUMA_RETURN (NOPE);
00448         }
00449         fclose (sf_file);
00450         SUMA_RETURN (YUP); 
00451 }/*SUMA_SureFit_Read_Coord*/
00452 
00453 SUMA_Boolean SUMA_SureFit_Read_Topo (char * f_name, SUMA_SureFit_struct *SF)
00454 {/*SUMA_SureFit_Read_Topo*/
00455         static char FuncName[]={"SUMA_SureFit_Read_Topo"}; 
00456    FILE *sf_file;
00457         int ex, EndHead, FoundHead, evl, cnt, skp, jnk, i, ip, NP;
00458         char stmp[100], head_strt[100], head_end[100], s[1000], delimstr[] = {' ', '\0'}, *st;
00459         
00460         SUMA_ENTRY;
00461 
00462         /* check for existence */
00463         if (!SUMA_filexists(f_name)) {
00464                 fprintf(SUMA_STDERR,"File %s does not exist or cannot be read.\n", f_name);
00465                 SUMA_RETURN (NOPE);
00466         }
00467         
00468         sprintf(SF->name_topo, "%s", f_name);
00469         
00470         /* start reading */
00471         sf_file = fopen (f_name,"r");
00472         if (sf_file == NULL)
00473                 {
00474                         SUMA_error_message (FuncName,"Could not open input file ",0);
00475                         SUMA_RETURN (NOPE);
00476                 }
00477 
00478         /* read until you reach the begin header BeginHeader */
00479         ex = 1;
00480         FoundHead = 0;
00481         sprintf(head_strt,"BeginHeader");
00482         while (ex != EOF && !FoundHead)
00483         {
00484                 ex = fscanf (sf_file,"%s",s);
00485                 if (strlen (s) >= strlen(head_strt)) 
00486                         {
00487                                 evl = SUMA_iswordin (s,head_strt);
00488                                 if (evl == 1) FoundHead = 1;
00489                         }
00490         }
00491         if (!FoundHead) {
00492                 fprintf(SUMA_STDERR,"Error %s: BeginHeader not found in %s.\nPerhaps you are using old versions of Caret/SureFit files.\n", FuncName, f_name);
00493                 SUMA_RETURN (NOPE);
00494         }
00495         EndHead = 0;
00496         sprintf(head_end,"EndHeader");
00497         sprintf(delimstr," ");
00498         
00499         while (ex != EOF && !EndHead)   {
00500                 ex = fscanf (sf_file,"%s",s);
00501                 /*fprintf(stdout,"%s\n", s);*/
00502                 if (strlen (s) >= strlen(head_end)) 
00503                         {
00504                                 evl = SUMA_iswordin (s,head_end);
00505                                 if (evl == 1) EndHead = 1;
00506                         }
00507                 /* look for some tokens */
00508                 skp = 0;
00509                 if (!EndHead) {
00510                         st = strtok(s, delimstr);
00511                         sprintf(stmp,"encoding");
00512                         if (!skp && SUMA_iswordin (st, stmp) == 1) {
00513                                 /*fprintf(stdout,"Found encoding\n");*/
00514                                 ex = fscanf (sf_file,"%s",(SF->encoding_topo));
00515                                 skp = 1;
00516                         }
00517                         
00518                         sprintf(stmp,"perimeter_id");
00519                         if (!skp && SUMA_iswordin (st, stmp) == 1) {
00520                                 /*fprintf(stdout,"Found perimeter_id\n");*/
00521                                 ex = fscanf (sf_file,"%s",(SF->perimeter_id));
00522                                 skp = 1;
00523                         }
00524                         
00525                         sprintf(stmp,"date");
00526                         if (!skp && SUMA_iswordin (st, stmp) == 1) {
00527                                 /*fprintf(stdout,"Found date\n");*/
00528                                 ex = fscanf (sf_file,"%s\n",(SF->date));
00529                                 skp = 1;
00530                         }
00531 
00532                 }
00533         }
00534         /* Now read the Number of Nodes Specs */
00535         fscanf(sf_file, "%d", &SF->N_Node_Specs);
00536         /*fprintf (stdout,"Expecting %d Node_Specs.\n", SF->N_Node_Specs);*/
00537         
00538         SF->FN.N_Node = SF->N_Node_Specs;
00539         SF->FN.N_Neighb_max = 0;
00540 
00541         /* allocate for Node Specs Matrix and First_Neighb structure*/
00542         SF->Specs_mat = (int **) SUMA_allocate2D(SF->N_Node_Specs, 6, sizeof(int));
00543         /*assume maximum number of neighbors is SUMA_MAX_NUMBER_NODE_NEIGHB */
00544         SF->FN.FirstNeighb = (int **) SUMA_allocate2D(SF->FN.N_Node, SUMA_MAX_NUMBER_NODE_NEIGHB, sizeof (int));
00545         SF->FN.N_Neighb = (int *) SUMA_calloc (SF->FN.N_Node, sizeof(int));
00546         SF->FN.NodeId = (int *) SUMA_calloc (SF->FN.N_Node, sizeof(int));
00547         
00548         if (SF->Specs_mat == NULL || SF->FN.FirstNeighb == NULL || SF->FN.N_Neighb == NULL || SF->FN.NodeId == NULL ){
00549                 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);
00550                 SUMA_RETURN (NOPE);
00551         } 
00552         
00553         /* Now read the node specs */
00554         /*fprintf (stdout,"About to read specs\n");*/
00555         cnt = 0;
00556         while (ex != EOF && cnt < SF->N_Node_Specs)     {
00557                 ex = fscanf (sf_file,"%d %d %d %d %d %d",&(SF->Specs_mat[cnt][0]), &(SF->Specs_mat[cnt][1]), \
00558                                 &(SF->Specs_mat[cnt][2]), &(SF->Specs_mat[cnt][3]), &(SF->Specs_mat[cnt][4]), &(SF->Specs_mat[cnt][5]));
00559                 SF->FN.NodeId[cnt] = SF->Specs_mat[cnt][0];
00560                 SF->FN.N_Neighb[cnt] = SF->Specs_mat[cnt][1];
00561                 if (SF->FN.N_Neighb[cnt] > SUMA_MAX_NUMBER_NODE_NEIGHB-1) {
00562                         fprintf (SUMA_STDERR,"Error %s: Node %d has more neighbors (%d) than the maximum allowed (%d)\n", \
00563                                 FuncName, SF->FN.NodeId[cnt], SF->FN.N_Neighb[cnt], SUMA_MAX_NUMBER_NODE_NEIGHB-1);
00564                         SUMA_RETURN (NOPE);
00565                 }
00566                 if (SF->FN.N_Neighb[cnt] > SF->FN.N_Neighb_max) SF->FN.N_Neighb_max = SF->FN.N_Neighb[cnt];
00567                 
00568                 /* Now Read in the Neighbors info */
00569                 for (i=0; i < SF->FN.N_Neighb[cnt]; ++ i) {
00570                         ex = fscanf (sf_file,"%d %d", &jnk, &(SF->FN.FirstNeighb[cnt][i]));
00571                 }
00572                 /* seal with -1 */
00573                 SF->FN.FirstNeighb[cnt][SF->FN.N_Neighb[cnt]] = -1;
00574                 
00575                 ++cnt;
00576         }
00577         if (cnt != SF->N_Node_Specs) {
00578                 fprintf(SUMA_STDERR, "Error %s: Expecting %d NodeSpecs, read %d.\n", FuncName, SF->N_Node_Specs, cnt);
00579                 SUMA_RETURN (NOPE);
00580         }
00581         /*fprintf (stdout, "Done with Node Specs.\n");*/
00582         ex = fscanf (sf_file,"%d", &(SF->N_FaceSet));
00583         /*fprintf (stdout, "Expecting to read %d facesets.\n", SF->N_FaceSet);*/
00584         
00585         NP = 3;
00586         SF->FaceSetList = (int *) SUMA_calloc(SF->N_FaceSet * 3, sizeof(int));
00587         if (SF->FaceSetList == NULL){
00588                 fprintf(SUMA_STDERR, "Error %s: Could not allocate space for SF->FaceSetList.\n", FuncName);
00589                 SUMA_RETURN (NOPE);
00590         } 
00591         
00592         /*fprintf (stdout,"About to read FaceSets\n");*/
00593         cnt = 0;
00594         while (ex != EOF && cnt < SF->N_FaceSet)        {
00595                 ip = NP * cnt;
00596                 ex = fscanf (sf_file,"%d %d %d ",&(SF->FaceSetList[ip]), &(SF->FaceSetList[ip+1]), \
00597                                 &(SF->FaceSetList[ip+2]));
00598                 ++cnt;
00599         }
00600         if (cnt != SF->N_FaceSet) {
00601                 fprintf(SUMA_STDERR, "Error %s: Expecting %d FaceSets, read %d.\n", FuncName, SF->N_FaceSet, cnt);
00602                 SUMA_RETURN (NOPE);
00603         }
00604         fclose (sf_file);
00605         
00606 SUMA_RETURN (YUP);
00607 }/*SUMA_SureFit_Read_Topo*/
00608 
00609 /*!
00610 Show data structure containing SureFit surface object
00611 */
00612 void SUMA_Show_SureFit (SUMA_SureFit_struct *SF, FILE *Out)
00613 {       int cnt, id, ND, NP;
00614         static char FuncName[]={"SUMA_Show_SureFit"};
00615         
00616         SUMA_ENTRY;
00617 
00618         ND = 3;
00619         NP = 3;
00620         if (Out == NULL) Out = SUMA_STDOUT;
00621         fprintf (Out, "\n%s: Coord Info\n", SF->name_coord);
00622         fprintf (Out, "N_Node %d\n", SF->N_Node);
00623         fprintf (Out, "encoding_coord: %s\nconfiguration id: %s, coordframe_id: %s\n", SF->encoding_coord,SF->configuration_id, SF->coordframe_id);
00624         fprintf (Out, "First 2 points [id] X Y Z:\n\t[%d] %f %f %f\n\t[%d] %f %f %f\n", \
00625                 SF->NodeId[0], SF->NodeList[0], SF->NodeList[1], SF->NodeList[2],
00626                 SF->NodeId[1], SF->NodeList[3], SF->NodeList[4], SF->NodeList[5]);
00627         if (SF->N_Node > 2) {
00628       fprintf (Out, "Last 2 points [id] X Y Z:\n\t[%d] %f %f %f\n\t[%d] %f %f %f\n", \
00629                    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],
00630                    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]);
00631         }
00632    fprintf (Out, "\n%s: Topo Info\n", SF->name_topo);
00633         fprintf (Out, "N_Node_Specs %d\n", SF->N_Node_Specs);
00634         fprintf (Out, "ecnoding_topo: %s, date %s\n",  SF->encoding_topo, SF->date);
00635         fprintf (Out, "N_FaceSet %d\n", SF->N_FaceSet);
00636         if (SF->N_FaceSet > 2) {
00637            fprintf (Out, "First 2 polygons:\n\t%d %d %d\n\t%d %d %d\n", \
00638                    SF->FaceSetList[0], SF->FaceSetList[1], SF->FaceSetList[2],
00639                    SF->FaceSetList[3], SF->FaceSetList[4], SF->FaceSetList[5]);
00640       fprintf (Out, "Last 2 polygons:\n\t%d %d %d\n\t%d %d %d\n", \
00641                    SF->FaceSetList[NP*(SF->N_FaceSet-2)], SF->FaceSetList[NP*(SF->N_FaceSet-2) + 1], SF->FaceSetList[NP*(SF->N_FaceSet-2) + 2],
00642                    SF->FaceSetList[NP*(SF->N_FaceSet-1)], SF->FaceSetList[NP*(SF->N_FaceSet-1) + 1], SF->FaceSetList[NP*(SF->N_FaceSet-1) + 2]);
00643         } else {
00644       fprintf (Out, "First polygon:\n\t%d %d %d\n", \
00645                    SF->FaceSetList[0], SF->FaceSetList[1], SF->FaceSetList[2] );
00646    }
00647    fprintf (Out, "\nNode Specs (%d):\n", SF->N_Node_Specs);
00648         fprintf (Out, "First Entry: \t%d %d %d %d %d %d\n", \
00649         SF->Specs_mat[0][0], SF->Specs_mat[0][1],SF->Specs_mat[0][2], SF->Specs_mat[0][3],SF->Specs_mat[0][4], SF->Specs_mat[0][5]);
00650         cnt = 0;
00651         while (cnt < SF->FN.N_Neighb[0]) {
00652                 fprintf (Out, "\t%d %d\n", cnt, SF->FN.FirstNeighb[0][cnt]); 
00653                 ++cnt;
00654         }
00655         fprintf (Out, "Last Entry: \t%d %d %d %d %d %d\n", \
00656                 SF->Specs_mat[SF->N_Node_Specs-1][0], SF->Specs_mat[SF->N_Node_Specs-1][1],SF->Specs_mat[SF->N_Node_Specs-1][2],\
00657                 SF->Specs_mat[SF->N_Node_Specs-1][3],SF->Specs_mat[SF->N_Node_Specs-1][4], SF->Specs_mat[SF->N_Node_Specs-1][5]);
00658         cnt = 0;
00659         while (cnt < SF->FN.N_Neighb[SF->N_Node_Specs-1]) {
00660                 fprintf (Out, "\t%d %d\n", cnt, SF->FN.FirstNeighb[SF->N_Node_Specs-1][cnt]); 
00661                 ++cnt;
00662         }
00663 
00664         SUMA_RETURNe;
00665 }
00666 
00667 /*!
00668    \brief writes a surface in SureFit format
00669    ans = SUMA_SureFit_Write (Fname,SO);
00670    
00671    \param  Fname (SUMA_SFname *) uses the SureFit filename structure to store
00672                                  the names (and paths) of the NodeList (name_coord)
00673                                  and the FaceSetList (name_topo) files.
00674                                  If strlen(name_coord) == 0 then the coord file is not
00675                                  written out. 
00676                                  If strlen(name_topo) == 0 then topo file is not written out
00677    \param SO (SUMA_SurfaceObject *) pointer to SO structure.
00678    \return YUP/NOPE
00679    
00680    \sa SUMA_SureFit_Read_Topo() 
00681    \sa SUMA_SureFit_Read_Coord() 
00682    
00683    The function will not overwrite pre-existing files.
00684    
00685 
00686 NOTE: Header info is incomplete. 
00687 for .coord:
00688 BeginHeader
00689 configuration_id NA
00690 coordframe_id NA
00691 encoding ASCII
00692 EndHeader
00693 
00694 for .topo:
00695 BeginHeader
00696 date NA
00697 encoding ASCII
00698 perimeter_id NA
00699 EndHeader
00700 
00701 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.
00702 
00703 The naming convention of SureFit surfaces is not enforced.
00704 
00705 */  
00706 SUMA_Boolean SUMA_SureFit_Write (SUMA_SFname *Fname, SUMA_SurfaceObject *SO)
00707 {
00708    
00709    static char FuncName[]={"SUMA_SureFit_Write"};
00710    int i, j;
00711    FILE *outFile = NULL;
00712    
00713    SUMA_ENTRY;
00714 
00715    if (strlen(Fname->name_coord)) {
00716       if (SUMA_filexists(Fname->name_coord)) {
00717          fprintf (SUMA_STDERR, "Error %s: file %s exists, will not overwrite.\n",FuncName, Fname->name_coord);
00718          SUMA_RETURN (NOPE);
00719       }
00720    }
00721    
00722    if (strlen(Fname->name_topo)) {
00723       if (SUMA_filexists(Fname->name_topo)) {
00724          fprintf (SUMA_STDERR, "Error %s: file %s exists, will not overwrite.\n",FuncName, Fname->name_topo);
00725          SUMA_RETURN (NOPE);
00726       }
00727    }
00728    
00729    if (SO->NodeDim != 3 || SO->FaceSetDim != 3) {
00730       fprintf (SUMA_STDERR, "Error %s: Must have NodeDim and FaceSetDim = 3.\n",FuncName);
00731       SUMA_RETURN (NOPE);
00732    }
00733    
00734    if (strlen(Fname->name_coord)) {
00735       outFile = fopen(Fname->name_coord, "w");
00736       if (!outFile) {
00737          fprintf (SUMA_STDERR, "Error %s: Failed in opening %s for writing.\n",FuncName, Fname->name_coord);
00738          SUMA_RETURN (NOPE);
00739       }
00740 
00741       /* write header */
00742       fprintf (outFile,"BeginHeader\nconfiguration_id NA\ncoordframe_id NA\nencoding ASCII\nEndHeader\n");
00743       fprintf (outFile,"%d\n", SO->N_Node);
00744 
00745       j=0;
00746       for (i=0; i<SO->N_Node; ++i) {
00747          j=SO->NodeDim * i;
00748          fprintf (outFile, "%d %f %f %f\n", i, SO->NodeList[j], SO->NodeList[j+1], SO->NodeList[j+2]);
00749       }
00750 
00751       fclose (outFile);
00752    }
00753    
00754    if (strlen(Fname->name_topo)) {
00755       outFile = fopen(Fname->name_topo, "w");
00756       if (!outFile) {
00757          fprintf (SUMA_STDERR, "Error %s: Failed in opening %s for writing.\n",FuncName, Fname->name_topo);
00758          SUMA_RETURN (NOPE);
00759       }
00760 
00761       /* make sure you have the first neighbor list ! */
00762       if (!SO->FN) {
00763          fprintf (SUMA_STDERR, "%s: Must compute Node Neighborhood list.\n", FuncName);
00764          if (!SUMA_SurfaceMetrics(SO, "EdgeList", NULL)){
00765             fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_SurfaceMetrics.\n", FuncName);
00766             SUMA_RETURN (NOPE);
00767          }
00768          #if 0 /* better to use SUMA_SurfaceMetrics */
00769          if (!SO->EL) {
00770             fprintf (SUMA_STDERR, "%s: Computing Edge List...\n", FuncName);
00771             SO->EL = SUMA_Make_Edge_List (SO->FaceSetList, SO->N_FaceSet, SO->N_Node, SO->NodeList);
00772          }
00773          if (!SO->EL) {
00774             fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_Make_Edge_List.\n", FuncName);
00775             SUMA_RETURN (NOPE);
00776          }
00777          fprintf (SUMA_STDERR, "%s: Computing FirstNeighb list.\n", FuncName);
00778          SO->FN = SUMA_Build_FirstNeighb (SO->EL, SO->N_Node);
00779          if (!SO->FN) {
00780             fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_Build_FirstNeighb.\n", FuncName);
00781             SUMA_RETURN (NOPE);
00782          }
00783          #endif
00784 
00785       }
00786       /* write header */
00787       fprintf (outFile,"BeginHeader\ndate NA\nencoding ASCII\nperimeter_id NA\nEndHeader\n");
00788       fprintf (outFile,"%d\n", SO->N_Node);
00789            j = 0;
00790            while (j < SO->FN->N_Node)   {
00791          /* dunno what last 4 ints of upcoming line are */
00792                    fprintf (outFile,"%d %d 0 0 0 0\n", SO->FN->NodeId[j], SO->FN->N_Neighb[j]);
00793 
00794                    /* Now write the Neighbors info */
00795                    for (i=0; i < SO->FN->N_Neighb[j]; ++ i) {
00796                            fprintf (outFile,"%d %d\n", i, SO->FN->FirstNeighb[j][i]);
00797                    }
00798                    ++j;
00799            }
00800 
00801            fprintf (outFile,"%d\n", SO->N_FaceSet);
00802 
00803       j=0;
00804       for (i=0; i<SO->N_FaceSet; ++i) {
00805          j = SO->FaceSetDim * i;
00806          fprintf (outFile, "%d %d %d\n", SO->FaceSetList[j], SO->FaceSetList[j+1], SO->FaceSetList[j+2]);
00807       }
00808 
00809       fclose (outFile);
00810    }
00811    SUMA_RETURN (YUP);
00812 
00813 }
00814 
00815 /*!
00816 free data structure containing SureFit surface object
00817 */
00818 SUMA_Boolean SUMA_Free_SureFit (SUMA_SureFit_struct *SF)  
00819 {
00820         static char FuncName[]={"SUMA_Free_SureFit"};
00821         
00822         SUMA_ENTRY;
00823 
00824         if (SF->NodeList != NULL) SUMA_free(SF->NodeList);
00825         if (SF->NodeId != NULL) SUMA_free(SF->NodeId);
00826         if (SF->Specs_mat != NULL) SUMA_free2D ((char **)SF->Specs_mat, SF->N_Node_Specs);
00827         if (SF->FN.FirstNeighb != NULL) SUMA_free2D((char **)SF->FN.FirstNeighb, SF->FN.N_Node);
00828         if (SF->FN.N_Neighb != NULL) SUMA_free(SF->FN.N_Neighb);
00829         if (SF->FN.NodeId != NULL) SUMA_free(SF->FN.NodeId);
00830         if (SF->FaceSetList != NULL) SUMA_free(SF->FaceSetList);
00831         if (SF!= NULL) SUMA_free(SF);
00832         
00833         SUMA_RETURN (YUP);
00834 }
00835 
00836 /*!
00837 Read in some parameters from a .param file
00838 */
00839 SUMA_Boolean SUMA_Read_SureFit_Param (char *f_name, SUMA_SureFit_struct *SF)
00840 {
00841         static char FuncName[]={"SUMA_Read_SureFit_Param"};
00842         int ex, evl; 
00843    FILE *sf_file;
00844         SUMA_Boolean Done;
00845         char delimstr[] = {' ', '\0'}, stmp[100], s[1000], *st;
00846 
00847         SUMA_ENTRY;
00848 
00849         /* check for existence */
00850         if (!SUMA_filexists(f_name)) {
00851                 fprintf(SUMA_STDERR,"File %s does not exist or cannot be read.\n", f_name);
00852                 SUMA_RETURN (NOPE);
00853         }
00854 
00855         sprintf(SF->name_param, "%s", f_name);
00856 
00857         /* start reading */
00858         sf_file = fopen (f_name,"r");
00859         if (sf_file == NULL)
00860                 {
00861                         fprintf (SUMA_STDERR,"Error %s: Could not open input file ",FuncName);
00862                         SUMA_RETURN (NOPE);
00863                 }
00864 
00865         /* read until you reach something you like */
00866         ex = 1;
00867         Done = NOPE;                    
00868         sprintf(delimstr,"=");
00869         while (ex != EOF && !Done)
00870         {
00871                 ex = fscanf (sf_file,"%s",s);
00872                 
00873                 sprintf(stmp,"ACx_WholeVolume");
00874                 evl = SUMA_iswordin (s,stmp);
00875                 if (evl == 1) {
00876                         /* found ACx_WholeVolume */
00877                         /*fprintf(SUMA_STDOUT, "Found ACx_WholeVolume:");*/
00878                         /* go past the = sign and grab the value */
00879                         st = strtok(s, delimstr);
00880                         st = strtok(NULL, delimstr);
00881                         SF->AC_WholeVolume[0] = atof(st);
00882                         /*fprintf(SUMA_STDOUT, " %f\n", SF->AC_WholeVolume[0]);*/
00883                         continue;
00884                 }
00885                 sprintf(stmp,"ACy_WholeVolume");
00886                 evl = SUMA_iswordin (s,stmp);
00887                 if (evl == 1) {
00888                         /* found ACy_WholeVolume */
00889                         /*fprintf(SUMA_STDOUT, "Found ACy_WholeVolume:");*/
00890                         /* go past the = sign and grab the value */
00891                         st = strtok(s, delimstr);
00892                         st = strtok(NULL, delimstr);
00893                         SF->AC_WholeVolume[1] = atof(st);
00894                         /*fprintf(SUMA_STDOUT, " %f\n", SF->AC_WholeVolume[1]);*/
00895                         continue;
00896                 }
00897                 sprintf(stmp,"ACz_WholeVolume");
00898                 evl = SUMA_iswordin (s,stmp);
00899                 if (evl == 1) {
00900                         /* found ACz_WholeVolume */
00901                         /*fprintf(SUMA_STDOUT, "Found ACz_WholeVolume:");*/
00902                         /* go past the = sign and grab the value */
00903                         st = strtok(s, delimstr);
00904                         st = strtok(NULL, delimstr);
00905                         SF->AC_WholeVolume[2] = atof(st);
00906                         /*fprintf(SUMA_STDOUT, " %f\n", SF->AC_WholeVolume[2]);*/
00907                         continue;
00908                 }
00909                  
00910                 sprintf(stmp,"ACx");
00911                 evl = SUMA_iswordin (s,stmp);
00912                 if (evl == 1) {
00913                         /* found ACx */
00914                         /*fprintf(SUMA_STDOUT, "Found ACx:");*/
00915                         /* go past the = sign and grab the value */
00916                         st = strtok(s, delimstr);
00917                         st = strtok(NULL, delimstr);
00918                         SF->AC[0] = atof(st);
00919                         /*fprintf(SUMA_STDOUT, " %f\n", SF->AC[0]);*/
00920                         continue;
00921                 }
00922                 sprintf(stmp,"ACy");
00923                 evl = SUMA_iswordin (s,stmp);
00924                 if (evl == 1) {
00925                         /* found ACy */
00926                         /*fprintf(SUMA_STDOUT, "Found ACy:");*/
00927                         /* go past the = sign and grab the value */
00928                         st = strtok(s, delimstr);
00929                         st = strtok(NULL, delimstr);
00930                         SF->AC[1] = atof(st);
00931                         /*fprintf(SUMA_STDOUT, " %f\n", SF->AC[1]);*/
00932                         continue;
00933                 }
00934                 sprintf(stmp,"ACz");
00935                 evl = SUMA_iswordin (s,stmp);
00936                 if (evl == 1) {
00937                         /* found ACz */
00938                         /*fprintf(SUMA_STDOUT, "Found ACz:");*/
00939                         /* go past the = sign and grab the value */
00940                         st = strtok(s, delimstr);
00941                         st = strtok(NULL, delimstr);
00942                         SF->AC[2] = atof(st);
00943                         /*fprintf(SUMA_STDOUT, " %f\n", SF->AC[2]);*/
00944                         continue;
00945                 }
00946                 
00947         }
00948         
00949         fclose(sf_file);
00950         
00951         /* Sanity Checks */
00952         if (SF->AC[0] == 0.0 && SF->AC[1] == 0.0 && SF->AC[2] == 0.0) {
00953                 fprintf (SUMA_STDERR,"Error %s: All values for AC are 0.0. Check your params file.\n", FuncName);
00954                 SUMA_RETURN (NOPE);
00955         }
00956         
00957         if (SF->AC_WholeVolume[0] == 0.0 && SF->AC_WholeVolume[1] == 0.0 && SF->AC_WholeVolume[2] == 0.0) {
00958                 fprintf (SUMA_STDERR,"Error %s: All values for AC_WholeVolume are 0.0. Check your params file.\n", FuncName);
00959                 SUMA_RETURN (NOPE);
00960         }
00961         
00962         if (SF->AC[0] == SF->AC_WholeVolume[0] && SF->AC[1] == SF->AC_WholeVolume[1] && SF->AC[2] == SF->AC_WholeVolume[2])
00963         {
00964                 SUMA_SL_Warn("Idetincal values for AC and AC_WholeVolume.\nCheck your params file if not using Talairach-ed surfaces.\n");
00965       /* looks like that's OK for TLRC surfaces ...*/
00966       /*
00967       fprintf (SUMA_STDERR,"Error %s: Idetincal values for AC and AC_WholeVolume. Check your params file.\n", FuncName);
00968                 SUMA_RETURN (NOPE);
00969       */
00970         }
00971         if (SF->AC[0] < 0 || SF->AC[1] < 0 || SF->AC[2] < 0 || SF->AC_WholeVolume[0] < 0 || SF->AC_WholeVolume[1] < 0 || SF->AC_WholeVolume[2] < 0) 
00972         {
00973                 fprintf (SUMA_STDERR,"Error %s: Negative values in AC or AC_WholeVolume. Check you params file.\n", FuncName);
00974                 SUMA_RETURN (NOPE);
00975         }
00976         
00977         SUMA_RETURN (YUP);
00978 }
00979 #ifdef SUMA_SureFit_STAND_ALONE
00980 
00981 
00982 
00983 void usage_SUMA_SureFit_Main ()
00984    
00985   {/*Usage*/
00986           printf ("\nUsage:  SUMA_SureFit CoordRoot TopoRoot \n");
00987           printf ("\t ..... \n\n");
00988           printf ("\t To Compile:\ngcc -DSUMA_SureFit_STAND_ALONE -Wall -o $1 $1.c -I./ -I//usr/X11R6/include SUMA_lib.a\n");
00989           printf ("\t\t Ziad S. Saad SSCC/NIMH/NIH ziad@nih.gov \tFri Feb 8 16:29:06 EST 2002 \n");
00990           exit (0);
00991   }/*Usage*/
00992    
00993 int main (int argc,char *argv[])
00994 {/* Main */
00995    static char FuncName[]={"SUMA_SureFit_Main"}; 
00996    char SF_name[200];
00997         SUMA_SureFit_struct *SF;
00998         
00999         /* allocate space for CommonFields structure */
01000         SUMAg_CF = SUMA_Create_CommonFields ();
01001         if (SUMAg_CF == NULL) {
01002                 fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_Create_CommonFields\n", FuncName);
01003                 exit(1);
01004         }
01005         
01006         /* Allocate for SF */
01007         SF = (SUMA_SureFit_struct *) SUMA_malloc(sizeof(SUMA_SureFit_struct));  
01008         if (SF == NULL) {
01009                 fprintf(SUMA_STDERR,"Error %s: Failed to allocate for SF\n", FuncName);
01010                 exit(1);
01011         }
01012    
01013    if (argc < 3)
01014        {
01015           usage_SUMA_SureFit_Main ();
01016           exit (1);
01017        }
01018    
01019         sprintf(SF_name, "%s.coord", argv[1]);
01020         if (!SUMA_SureFit_Read_Coord (SF_name, SF)) {
01021                 fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_SureFit_Read_Coord.\n", FuncName);
01022                 exit(1);
01023         }
01024         
01025         sprintf(SF_name, "%s.topo", argv[2]);
01026         if (!SUMA_SureFit_Read_Topo (SF_name, SF)) {
01027                 fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_SureFit_Read_Topo.\n", FuncName);
01028                 exit(1);
01029         }
01030         
01031         SUMA_Show_SureFit (SF, NULL);
01032         fprintf(stdout, "freeing ..\n");
01033         if (!SUMA_Free_SureFit (SF)) {
01034                 fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_Free_SureFit.\n", FuncName);
01035                 exit(1);
01036         }
01037         
01038         if (!SUMA_Free_CommonFields(SUMAg_CF)) SUMA_error_message(FuncName,"SUMAg_CF Cleanup Failed!",1);
01039 
01040         SUMA_RETURN (0);
01041 }/* Main */
01042 #endif
01043 
01044 
01045 /*! Functions to read and manipulate FreeSurfer surfaces*/
01046 
01047 #define SUMA_FS_ANNOT_TAG_COLORTABLE   1
01048 #define SUMA_FS_STRLEN 50
01049 typedef struct {
01050    int r;
01051    int g;
01052    int b;
01053    int flag;
01054    char name[SUMA_FS_STRLEN];
01055 } SUMA_FS_COLORTABLE_ENTRY;
01056 
01057 typedef struct {
01058    char *fname;
01059    int nbins;
01060    SUMA_FS_COLORTABLE_ENTRY *bins;
01061 } SUMA_FS_COLORTABLE;
01062 
01063 SUMA_FS_COLORTABLE *SUMA_CreateFS_ColorTable(int nbins, int len)
01064 {
01065    static char FuncName[]={"SUMA_CreateFS_ColorTable"};
01066    SUMA_FS_COLORTABLE *ct = NULL;
01067    
01068    SUMA_ENTRY;
01069    
01070    ct = (SUMA_FS_COLORTABLE*) SUMA_malloc(sizeof(SUMA_FS_COLORTABLE));
01071    if (!ct) {
01072       SUMA_SL_Crit("Failed to allocate for ct");
01073       SUMA_RETURN(NULL);
01074    }
01075    ct->nbins = nbins;
01076    ct->bins = (SUMA_FS_COLORTABLE_ENTRY *) SUMA_malloc(nbins * 
01077                                           sizeof(SUMA_FS_COLORTABLE_ENTRY));
01078    
01079    ct->fname = (char *)SUMA_malloc((len + 1)*sizeof(char));
01080    if (!ct->bins || !ct->fname) {
01081       SUMA_SL_Crit("Failed to allocate for ct fields");
01082       if (ct->bins) SUMA_free(ct->bins);
01083       if (ct->fname) SUMA_free(ct->fname);
01084       SUMA_free(ct);
01085       SUMA_RETURN(NULL);
01086    }
01087    ct->fname[0] = '\0';
01088    SUMA_RETURN(ct);
01089 }
01090 
01091 SUMA_FS_COLORTABLE *SUMA_FreeFS_ColorTable (SUMA_FS_COLORTABLE *ct)
01092 {
01093    static char FuncName[]={"SUMA_FreeFS_ColorTable"};
01094    
01095    SUMA_ENTRY;
01096    
01097    if (!ct) SUMA_RETURN(NULL);
01098    
01099    if (ct->bins) SUMA_free(ct->bins);
01100    if (ct->fname) SUMA_free(ct->fname);
01101    
01102    SUMA_free(ct);
01103    
01104    SUMA_RETURN(NULL);
01105 }
01106 
01107 char *SUMA_FS_ColorTable_Info(SUMA_FS_COLORTABLE *ct)
01108 {
01109    static char FuncName[]={"SUMA_FS_ColorTable_Info"};
01110    char *s=NULL;
01111    int i;
01112    SUMA_STRING *SS = NULL;
01113 
01114    SUMA_ENTRY;
01115    
01116    SS = SUMA_StringAppend (NULL, NULL);
01117 
01118    if (!ct) SS = SUMA_StringAppend(SS,"NULL ct");
01119    else {
01120       if (ct->fname) SS = SUMA_StringAppend_va(SS, "fname: %s\nnbins: %d\n", ct->fname, ct->nbins);
01121       else SS = SUMA_StringAppend_va(SS, "fname: NULL\nnbins: %d\n", ct->nbins);
01122       if (!ct->bins) SS = SUMA_StringAppend_va(SS, "NULL bins\n");
01123       else {
01124          for (i=0; i<ct->nbins; ++i) {
01125             SS = SUMA_StringAppend_va(SS, "bin[%d]: %d %d %d %d : %s\n", 
01126                                        i, ct->bins[i].r, ct->bins[i].g, 
01127                                        ct->bins[i].b, ct->bins[i].flag,
01128                                        ct->bins[i].name);
01129          }
01130       }   
01131    }
01132    
01133    SS = SUMA_StringAppend(SS,NULL);
01134    s = SS->s; 
01135    SUMA_free(SS);
01136    
01137    SUMA_RETURN(s);
01138 
01139 }
01140 
01141 SUMA_Boolean SUMA_Show_FS_ColorTable(SUMA_FS_COLORTABLE *ct, FILE *fout)
01142 {
01143    static char FuncName[]={"SUMA_Show_FS_ColorTable"};
01144    char *s=NULL;
01145    
01146    SUMA_ENTRY;
01147    
01148    if (!fout) fout = stdout;
01149    
01150    s = SUMA_FS_ColorTable_Info(ct);
01151    if (s) {
01152       fprintf(fout, "%s\n", s);
01153       SUMA_free(s);
01154    } else {
01155       SUMA_SL_Err("Failed in SUMA_FS_ColorTable_Info");
01156       SUMA_RETURN(NOPE);
01157    }
01158    
01159    SUMA_RETURN(YUP);
01160 }
01161 
01162 /*!
01163    \brief
01164       function to read FS's annotation file 
01165       
01166    \param f_name (char *)
01167    \param ROIout (FILE *)
01168    \param cmapout (FILE *)
01169    
01170    - If a colormap is found, it should be added to SUMAg_CF->scm
01171    - Based on code provided by Bruce Fischl
01172 */
01173 SUMA_Boolean SUMA_readFSannot (char *f_name, char *f_ROI, char *f_cmap, char *f_col, int Showct)
01174 {
01175    static char FuncName[]={"SUMA_readFSannot"};
01176    int n_labels = -1, ex, ni, chnk, j, annot, r, g, b, imap;
01177    int tg, len, nbins, i;
01178    FILE *fl=NULL;
01179    FILE *fr=NULL;
01180    FILE *fc=NULL;
01181    FILE *fo=NULL; 
01182    SUMA_FS_COLORTABLE *ct=NULL;
01183    SUMA_FS_COLORTABLE_ENTRY *cte;
01184    SUMA_Boolean bs = NOPE;
01185    int *rv=NULL, *gv=NULL, *bv=NULL, *anv=NULL, *niv=NULL;
01186    SUMA_Boolean LocalHead = NOPE;
01187    
01188    SUMA_ENTRY;
01189    
01190    /* check for existence */
01191         if (!SUMA_filexists(f_name)) {
01192                 fprintf(SUMA_STDERR,"Error %s: File %s does not exist or cannot be read.\n", FuncName, f_name);
01193                 SUMA_RETURN (NOPE);
01194         }else if (LocalHead) {
01195                 fprintf(SUMA_STDERR,"%s: File %s exists and will be read.\n", FuncName, f_name);
01196         }
01197    if (f_ROI) { /* check for existence of ROI file */
01198       if (SUMA_filexists(f_ROI)) { 
01199          fprintf(SUMA_STDERR,"Error %s: File %s exists, will not overwrite.\n", FuncName, f_ROI);
01200               SUMA_RETURN (NOPE);
01201       }else {
01202          fr = fopen(f_ROI, "w");
01203          if (!fr) {
01204             SUMA_SL_Err("Failed to open file for writing.\n");
01205             SUMA_RETURN(NOPE);
01206          } 
01207       }
01208    }
01209    
01210    if (f_cmap) { /* check for existence of ROI file */
01211       if (SUMA_filexists(f_cmap)) { 
01212          fprintf(SUMA_STDERR,"Error %s: File %s exists, will not overwrite.\n", FuncName, f_cmap);
01213               SUMA_RETURN (NOPE);
01214       }else {
01215          fc = fopen(f_cmap, "w");
01216          if (!fc) {
01217             SUMA_SL_Err("Failed to open file for writing.\n");
01218             SUMA_RETURN(NOPE);
01219          }  
01220       }
01221    }
01222    
01223    if (f_col) { /* check for existence of ROI file */
01224       if (SUMA_filexists(f_col)) { 
01225          fprintf(SUMA_STDERR,"Error %s: File %s exists, will not overwrite.\n", FuncName, f_col);
01226               SUMA_RETURN (NOPE);
01227       }else {
01228          fo = fopen(f_col, "w");
01229          if (!fo) {
01230             SUMA_SL_Err("Failed to open file for writing.\n");
01231             SUMA_RETURN(NOPE);
01232          }  
01233       }
01234    }
01235    
01236    bs = NOPE;
01237    fl = fopen(f_name, "r");
01238    if (!fl) {
01239       SUMA_SL_Err("Failed to open file for reading.\n");
01240       SUMA_RETURN(NOPE);
01241    }
01242    chnk = sizeof(int);
01243    ex = fread (&n_labels, chnk, 1, fl);
01244    if (n_labels < 0 || n_labels > 500000) { /* looks like swapping is needed */
01245       if (LocalHead) {
01246          SUMA_SL_Warn("Byte swapping binary data.");
01247       }
01248       SUMA_swap_4( &n_labels ) ;
01249       bs = YUP;
01250    }
01251    
01252    
01253    niv = (int *) SUMA_malloc(sizeof(int)*n_labels);
01254    rv = (int *) SUMA_malloc(sizeof(int)*n_labels);
01255    gv = (int *) SUMA_malloc(sizeof(int)*n_labels);
01256    bv = (int *) SUMA_malloc(sizeof(int)*n_labels);
01257    anv = (int *) SUMA_malloc(sizeof(int)*n_labels);
01258    if (!rv || !gv || !bv || !anv || !niv) {
01259       SUMA_SL_Crit("Failed to allocate.");
01260       SUMA_RETURN(NOPE);
01261    }
01262 
01263    if (ex != EOF) {
01264       if (LocalHead) fprintf(SUMA_STDERR,"%s:\n Expecting to read %d labels\n", FuncName, n_labels);
01265    }   
01266    SUMA_LH("Reading annotations...");
01267    for (j=0; j<n_labels; ++j) {
01268       SUMA_READ_INT (&ni, bs, fl, ex);
01269       if (ni < 0 || ni >= n_labels) {
01270          fprintf(SUMA_STDERR,"Error %s:\n Read a node index of %d. Bad because  < 0 or > %d\n", FuncName, ni, n_labels);
01271          SUMA_RETURN(NOPE);
01272       }
01273       SUMA_READ_INT (&annot, bs, fl, ex);
01274       niv[j] = ni;
01275       anv[j] = annot;
01276       rv[j] = annot & 0x0000ff;
01277       gv[j] = (annot >> 8) & 0x0000ff;
01278       bv[j] = (annot >> 16) & 0x0000ff;
01279       if (LocalHead && ( j < 5 || j > n_labels - 5)) {
01280          fprintf (SUMA_STDERR, "annot[%d]: %d = %d %d %d\n", 
01281                                  ni, anv[j], rv[j], gv[j], bv[j]);
01282       }
01283    }
01284    
01285    SUMA_LH("Searching for colortables");
01286    while (!feof(fl)) {
01287       SUMA_READ_INT (&tg, bs, fl, ex);
01288       if (tg == SUMA_FS_ANNOT_TAG_COLORTABLE) {
01289          SUMA_LH("Found color table");
01290          SUMA_READ_INT (&nbins, bs, fl, ex);
01291          SUMA_READ_INT (&len, bs, fl, ex);
01292          ct = SUMA_CreateFS_ColorTable(nbins, len);
01293          fread(ct->fname, sizeof(char), len, fl) ;
01294          for (i = 0 ; i < nbins ; i++)
01295          {
01296                 cte = &ct->bins[i] ;
01297                 SUMA_READ_INT (&len, bs, fl, ex);
01298                 if (len < 0 || len > SUMA_FS_STRLEN ) {
01299                      SUMA_SL_Err("Too long a name");
01300                      SUMA_RETURN(NOPE);
01301                 }
01302                 fread(cte->name, sizeof(char), len, fl) ;
01303                 SUMA_READ_INT (&(cte->r), bs, fl, ex);
01304                 SUMA_READ_INT (&(cte->g), bs, fl, ex);
01305                 SUMA_READ_INT (&(cte->b), bs, fl, ex);
01306                 SUMA_READ_INT (&(cte->flag), bs, fl, ex);
01307          }
01308          
01309       }
01310    }             
01311    
01312    if (fc) { /* write the colormap to a file */
01313       fprintf(fc, "#name\n#bin  r  g  b  flag \n");
01314       for (i=0; i<ct->nbins; ++i) {
01315          fprintf(fc, "#%s\n", ct->bins[i].name);
01316          fprintf(fc, "%d   %f %f %f %d\n", 
01317                      i, (float)ct->bins[i].r/255.0, (float)ct->bins[i].g/255.0, 
01318                      (float)ct->bins[i].b/255.0, ct->bins[i].flag );
01319       }
01320    }
01321    
01322    if (fr) { /* write the annotation, ROI style  */
01323       if (ct) {
01324          fprintf(fr, "#NodeID  ROI(indexed into labels cmap)  r  g  b \n");
01325          for (i=0; i < n_labels; ++i) {
01326                j = 0;
01327                imap = -1;
01328                while (j < ct->nbins && imap < 0) {
01329                   if (  ct->bins[j].r == rv[i] &&
01330                         ct->bins[j].b == bv[i] &&
01331                         ct->bins[j].g == gv[i]  ) {
01332                      imap = j;
01333                   }
01334                   ++j;
01335                }
01336                if (imap < 0) {
01337                   static int iwarn;
01338                   if (!iwarn) {
01339                      SUMA_SL_Warn("Node Color (label) not found in cmap.\nMarking with annotation value.\nFurther occurences will not be reported.");
01340                      ++iwarn;
01341                   }
01342                   imap = anv[i];
01343                }
01344                fprintf(fr, "%d  %d  %f %f %f   \n",
01345                         niv[i], imap, (float)rv[i]/255.0, (float)gv[i]/255.0, (float)bv[i]/255.0);
01346          }
01347       } else { /* no color map */
01348          fprintf(fr, "#NodeID  Annotation\n");
01349          for (i=0; i < n_labels; ++i) {
01350             fprintf(fr, "%d  %d \n", niv[i], anv[i]);
01351          }
01352       }
01353    }
01354    
01355    if (fo) { /* write the annotation, ROI style  */
01356       if (ct) {
01357          fprintf(fo, "#NodeID  r  g  b \n");
01358          for (i=0; i < n_labels; ++i) {
01359                fprintf(fo, "%d  %f %f %f   \n",
01360                         niv[i], (float)rv[i]/255.0, (float)gv[i]/255.0, (float)bv[i]/255.0);
01361          }
01362       } else { /* no color map */
01363          fprintf(fo, "#NodeID  Annotation\n");
01364          for (i=0; i < n_labels; ++i) {
01365             fprintf(fo, "%d  %d \n", niv[i], anv[i]);
01366          }
01367       }
01368    }
01369    
01370    if (Showct) {
01371       if (ct) {
01372          SUMA_Show_FS_ColorTable(ct, NULL);
01373          ct = SUMA_FreeFS_ColorTable(ct);
01374       }else {
01375          fprintf(SUMA_STDOUT,"No color table found.\n");
01376       }
01377    }
01378    
01379    /* package the results for SUMA */
01380    /* 1- Transform ct to a SUMA_COLOR_MAP (do that BEFORE the free operation above) 
01381          The cname field in SUMA_COLOR_MAP was created for that purpose.
01382          First allocate for cmap then use SUMA_copy_string to fill it with 
01383          the names*/
01384    /* 2- Create a vector from the labels and create a data set from it */ 
01385    
01386    if (fl) fclose (fl); fl = NULL;
01387    if (fr) fclose (fr); fr = NULL;
01388    if (fc) fclose (fc); fc = NULL;
01389    if (fo) fclose (fo); fo = NULL;
01390    
01391    if (niv) SUMA_free(niv); niv = NULL;
01392    if (rv) SUMA_free(rv); rv = NULL;
01393    if (gv) SUMA_free(gv); gv = NULL;
01394    if (bv) SUMA_free(bv); bv = NULL;
01395    if (anv) SUMA_free(anv); anv = NULL;
01396    
01397    SUMA_RETURN(YUP);
01398 } 
01399 
01400 #ifdef SUMA_FSread_annot_STAND_ALONE
01401 
01402 void usage_SUMA_FSread_annot_Main ()
01403    
01404   {/*Usage*/
01405       static char FuncName[]={"usage_SUMA_FSread_annot_Main"};
01406       char * s = NULL;
01407           printf ("\n"
01408                   "Usage:  \n"
01409                   "  FSread_annot   <-input ANNOTFILE>  \n"
01410                   "                 [-col_1D annot.1D.col]  \n"
01411                   "                 [-roi_1D annot.1D.roi] \n"
01412                   "                 [-cmap_1D annot.1D.cmap]\n"
01413                   "                 [show_FScmap]\n"
01414                   "                 [-help]  \n"
01415                   "  Reads a FreeSurfer annotaion file and outputs\n"
01416                   "  an equivalent ROI file and/or a colormap file \n"
01417                   "  for use with SUMA.\n"
01418                   "\n"
01419                   "  Required options:\n"
01420                   "     -input ANNOTFILE: Binary formatted FreeSurfer\n"
01421                   "                       annotation file.\n"
01422                   "     AND one of the optional options.\n"
01423                   "  Optional options:\n"
01424                   "     -col_1D annot.1D.col: Write a 4-column 1D color file. \n"
01425                   "                           The first column is the node\n"
01426                   "                           index followed by r g b values.\n"
01427                   "                           This color file can be imported \n"
01428                   "                           using the 'c' option in SUMA.\n"
01429                   "                           If no colormap was found in the\n"
01430                   "                           ANNOTFILE then the file has 2 columns\n"
01431                   "                           with the second being the annotation\n"
01432                   "                           value.\n"
01433                   "     -roi_1D annot.1D.roi: Write a 5-column 1D roi file.\n"
01434                   "                           The first column is the node\n"
01435                   "                           index, followed by its index in the\n"
01436                   "                           colormap, followed by r g b values.\n"
01437                   "                           This roi file can be imported \n"
01438                   "                           using the 'Load' button in SUMA's\n"
01439                   "                           'Draw ROI' controller.\n"
01440                   "                           If no colormap was found in the\n"
01441                   "                           ANNOTFILE then the file has 2 columns\n"
01442                   "                           with the second being the annotation\n"
01443                   "                           value. \n"
01444                   "     -cmap_1D annot.1D.cmap: Write a 4-column 1D color map file.\n"
01445                   "                             The first column is the color index,\n"
01446                   "                             followed by r g b and flag values.\n"
01447                   "                             The name of each color is inserted\n"
01448                   "                             as a comment because 1D files do not\n"
01449                   "                             support text data.\n"
01450                   "     -show_FScmap: Show the info of the colormap in the ANNOT file.\n"
01451                   "\n"        
01452                   "\n");
01453        s = SUMA_New_Additions(0, 1); printf("%s\n", s);SUMA_free(s); s = NULL;
01454        printf("       Ziad S. Saad SSCC/NIMH/NIH ziad@nih.gov     \n");
01455        exit (0);
01456   }/*Usage*/
01457    
01458 int main (int argc,char *argv[])
01459 {/* Main */
01460    static char FuncName[]={"FSread_annot"};
01461    int kar, Showct;
01462    char *fname = NULL, *fcmap = NULL, *froi = NULL, *fcol = NULL;
01463    SUMA_Boolean SkipCoords = NOPE, brk;
01464    SUMA_Boolean LocalHead = NOPE;       
01465    
01466         /* allocate space for CommonFields structure */
01467         SUMAg_CF = SUMA_Create_CommonFields ();
01468         if (SUMAg_CF == NULL) {
01469                 fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_Create_CommonFields\n", FuncName);
01470                 exit(1);
01471         }
01472    
01473    /* parse command line */
01474    kar = 1;
01475    fname = NULL;
01476    froi = NULL;
01477    fcmap = NULL;
01478    fcol = NULL;
01479         brk = NOPE;
01480    Showct = 0;
01481         while (kar < argc) { /* loop accross command ine options */
01482                 /*fprintf(stdout, "%s verbose: Parsing command line...\n", FuncName);*/
01483                 if (strcmp(argv[kar], "-h") == 0 || strcmp(argv[kar], "-help") == 0) {
01484                          usage_SUMA_FSread_annot_Main();
01485           exit (0);
01486                 }
01487       
01488       if (!brk && (strcmp(argv[kar], "-show_FScmap") == 0)) {
01489          Showct = 1;
01490                         brk = YUP;
01491                 }
01492       
01493       if (!brk && (strcmp(argv[kar], "-input") == 0)) {
01494          kar ++;
01495                         if (kar >= argc)  {
01496                                 fprintf (SUMA_STDERR, "need argument after -input\n");
01497                                 exit (1);
01498                         }
01499          fname = argv[kar];
01500                         brk = YUP;
01501                 }
01502       
01503       if (!brk && (strcmp(argv[kar], "-roi_1D") == 0)) {
01504          kar ++;
01505                         if (kar >= argc)  {
01506                                 fprintf (SUMA_STDERR, "need argument after -ROI_1D\n");
01507                                 exit (1);
01508                         }
01509          froi = argv[kar];
01510                         brk = YUP;
01511                 }
01512       
01513       if (!brk && (strcmp(argv[kar], "-cmap_1D") == 0)) {
01514          kar ++;
01515                         if (kar >= argc)  {
01516                                 fprintf (SUMA_STDERR, "need argument after -cmap_1D\n");
01517                                 exit (1);
01518                         }
01519          fcmap = argv[kar];
01520                         brk = YUP;
01521                 }
01522       
01523       if (!brk && (strcmp(argv[kar], "-col_1D") == 0)) {
01524          kar ++;
01525                         if (kar >= argc)  {
01526                                 fprintf (SUMA_STDERR, "need argument after -col_1D\n");
01527                                 exit (1);
01528                         }
01529          fcol = argv[kar];
01530                         brk = YUP;
01531                 }
01532       
01533       if (!brk) {
01534                         fprintf (SUMA_STDERR,"Error %s:\nOption %s not understood. Try -help for usage\n", FuncName, argv[kar]);
01535                         exit (1);
01536                 } else {        
01537                         brk = NOPE;
01538                         kar ++;
01539                 }
01540    }
01541    
01542    if (!fcmap && !froi && !fcol && !Showct) {
01543       SUMA_SL_Err("Nothing to do.\nUse either -cmap_1D or \n -roi_1D or -col_1D or \n -show_FScmap options.");
01544       exit(1);
01545    }
01546    if (!fname) {
01547       SUMA_SL_Err("No input file specified.");
01548       exit(1);
01549    }
01550    
01551    SUMA_readFSannot (fname, froi, fcmap, fcol, Showct);
01552    
01553    exit(0);
01554 }
01555 #endif
01556 
01557 /*!
01558 
01559    \brief   v = SUMA_readFScurv (curvname, nrows, ncols, rowmajor, SkipCoords);
01560             Not terribly useful of a function because it is practically a .1D
01561             format!
01562    \param   curvname (char *) name of ascii curvature file
01563    \param   nrows (int *) will contain the number of elements in file
01564    \param   ncols (int *) will contain the number of columns in file.
01565                            This is 5 for curvature files if SkipCoords is not set
01566                            (node index, x, y, z, data)
01567                            2 if SkipCoords
01568                            (node index, data)
01569    \param   rowmajor (SUMA_Boolean) if (YUP) return results in row major order, else column major
01570    \param   SkipCoords (SUMA_Boolean) if (YUP) reads only node index and data value (1st and last column
01571                                        of curvature files (skips the intermediary coordinates)
01572    \return   v (float *) vector containing curvature file data
01573    
01574 */
01575 
01576 float * SUMA_readFScurv (char *f_name, int *nrows, int *ncols, SUMA_Boolean rowmajor, SUMA_Boolean SkipCoords)   
01577 {
01578    static char FuncName[]={"SUMA_readFScurv"};
01579    MRI_IMAGE *im = NULL;
01580    float *v = NULL, jnk, *far;
01581    int cnt, ex, id, i, ncol, nvec;
01582    char c, comment[SUMA_MAX_STRING_LENGTH];
01583    FILE *fs_file = NULL;
01584    SUMA_Boolean LocalHead = NOPE;
01585    
01586    SUMA_ENTRY;
01587    
01588    /* check for existence */
01589         if (!SUMA_filexists(f_name)) {
01590                 fprintf(SUMA_STDERR,"Error %s: File %s does not exist or cannot be read.\n", FuncName, f_name);
01591                 SUMA_RETURN (NULL);
01592         }else if (LocalHead) {
01593                 fprintf(SUMA_STDERR,"%s: File %s exists and will be read.\n", FuncName, f_name);
01594         }
01595    
01596    if (SkipCoords) *ncols = 2;
01597    else *ncols = 5; /* constant */      
01598 
01599    if (*ncols !=2 && *ncols != 5) {
01600       SUMA_SL_Crit("ncols must be either 2 or 5");
01601       SUMA_RETURN(NULL);
01602    }
01603 
01604 
01605    #if 0
01606       /* thought is had the number of nodes at the top ! */
01607       /* start reading */
01608            fs_file = fopen (f_name,"r");
01609            if (fs_file == NULL) {
01610          SUMA_SL_Err ("Could not open input file");
01611          SUMA_RETURN (v);
01612            }
01613 
01614            /* read first character and check if it is a comment */
01615            ex = fscanf (fs_file,"%c",&c);
01616            if (c == '#') {
01617                    if (LocalHead) fprintf (SUMA_STDOUT, "%s: Found comment\n", FuncName); 
01618 
01619          /*skip till next line */
01620                    cnt = 0;
01621                    while (ex != EOF && c != '\n') {
01622                            ex = fscanf (fs_file,"%c",&c);
01623                            if (cnt < SUMA_MAX_STRING_LENGTH-2) {
01624                                    sprintf(comment, "%s%c", comment, c);
01625                                    ++cnt;
01626                            } else {
01627                                    fprintf(SUMA_STDERR,"Error %s: Too long a comment in curvature file, increase SUMA_MAX_STRING_LENGTH\n", FuncName);
01628                                    SUMA_RETURN (NOPE);
01629                            }
01630                    }
01631            }
01632 
01633 
01634            /* read in the number of nodes */
01635            ex = fscanf(fs_file, "%d", nrows);
01636 
01637       if (*nrows <= 0) {
01638          SUMA_SL_Crit("Trouble parsing curvature file.\nNull or negative number of nodes\n");
01639          SUMA_RETURN(NULL);
01640       }
01641 
01642            if (LocalHead) fprintf (SUMA_STDOUT, "%s: Allocating for data (%dx%d) \n", FuncName, *nrows, *ncols);
01643 
01644       v = (float *) SUMA_calloc(*nrows * *ncols, sizeof(float));
01645       if (!v) {
01646          SUMA_SL_Crit("Failed to allocate for v");
01647          SUMA_RETURN(v);
01648       }
01649 
01650       if (LocalHead) fprintf (SUMA_STDOUT, "%s: Parsing file...\n", FuncName);
01651 
01652       if (rowmajor) {
01653          cnt = 0;
01654               if (*ncols == 5) {
01655             while (ex != EOF && cnt < *nrows) {
01656                          id = *ncols * cnt;
01657                          ex = fscanf(fs_file, "%f %f %f %f %f", &(v[id]), &(v[id+1]),&(v[id+2]), &(v[id+3]), &(v[id+4]) );
01658                          ++cnt;
01659                  }
01660          } else {
01661             while (ex != EOF && cnt < *nrows) {
01662                          id = *ncols * cnt;
01663                          ex = fscanf(fs_file, "%f %f %f %f %f", &(v[id]), &jnk, &jnk, &jnk, &(v[id+1]) );
01664                          ++cnt;
01665                  }
01666          } 
01667 
01668       } else {
01669          cnt = 0;
01670               if (*ncols == 5) {
01671             while (ex != EOF && cnt < *nrows) {
01672                          ex = fscanf(fs_file, "%f %f %f %f %f", &(v[cnt]), &(v[cnt+ *nrows]),&(v[cnt+ 2 * *nrows]), &(v[cnt+ 3 * *nrows]), &(v[cnt+ 4 * *nrows]));
01673                          ++cnt;
01674                  }
01675          } else if (*nrows == 2) {
01676             while (ex != EOF && cnt < *nrows) {
01677                          ex = fscanf(fs_file, "%f %f %f %f %f", &(v[cnt]), &jnk, &jnk, &jnk, &(v[cnt+ *nrows]));
01678                          ++cnt;
01679                  }
01680          } else {
01681 
01682          }
01683       }
01684 
01685       if (cnt != *nrows) {
01686                    fprintf(SUMA_STDERR,"Error %s: Expected %d rows, %d read.\n", FuncName, *nrows, cnt);
01687                    SUMA_free(v); v = NULL;
01688          SUMA_RETURN (NULL);
01689            }
01690    #else 
01691       /* now load the input data */
01692       SUMA_LH("Reading file...");
01693       im = mri_read_1D (f_name);
01694 
01695       if (!im) {
01696          SUMA_SL_Err("Failed to read 1D file");
01697          SUMA_RETURN(NULL);
01698       }
01699 
01700       far = MRI_FLOAT_PTR(im);
01701       nvec = im->nx;
01702       ncol = im->ny;
01703       /* data in column major order at this point */
01704 
01705       if (!nvec) {
01706          SUMA_SL_Err("Empty file");
01707          SUMA_RETURN(NULL);
01708       }
01709 
01710       if (ncol != 5) {
01711          SUMA_SL_Err("Must have 5 columns in data file.");
01712          mri_free(im); im = NULL;   /* done with that baby */
01713          SUMA_RETURN(NULL);
01714       }
01715       
01716       *nrows = nvec;
01717       
01718       if (LocalHead) fprintf (SUMA_STDOUT, "%s: Allocating for data (%dx%d) \n", FuncName, *nrows, *ncols);
01719 
01720       v = (float *) SUMA_calloc(*nrows * *ncols, sizeof(float));
01721       
01722       if (!v) {
01723          SUMA_SL_Crit("Failed to allocate for v");
01724          SUMA_RETURN(v);
01725       }
01726 
01727       if (LocalHead) fprintf (SUMA_STDOUT, "%s: Parsing file...\n", FuncName);
01728 
01729       if (rowmajor) {
01730               if (*ncols == 5) {
01731             SUMA_LH("RowMajor, All Coords");
01732             for (i=0; i< *nrows; ++i) {
01733                id = *ncols*i;
01734                v[id] = far[i];
01735                v[id+1] = far[i+*nrows];
01736                v[id+2] = far[i+2 * *nrows];
01737                v[id+3] = far[i+3 * *nrows];
01738                v[id+4] = far[i+4 * *nrows];
01739             }   
01740          } else {
01741             SUMA_LH("RowMajor, Skipping Coords");
01742             for (i=0; i< *nrows; ++i) {
01743                id = *ncols*i;
01744                v[id] = far[i];
01745                v[id+1] = far[i+4 * *nrows];
01746             }
01747          } 
01748       } else {
01749               if (*ncols == 5) {
01750             SUMA_LH("ColMajor, All Coords");
01751             for (i=0; i<*ncols * *nrows; ++i) v[i] = far[i];
01752          } else if (*ncols == 2) {
01753             SUMA_LH("ColMajor, Skipping Coords");
01754             for (i=0; i<*nrows; ++i) v[i] = far[i];
01755             for (i=*nrows; i< 2 * *nrows; ++i) v[i] = far[i+3 * *nrows];
01756          } 
01757       }
01758       mri_free(im); im = NULL; far = NULL;
01759    #endif
01760    SUMA_RETURN(v);
01761 }
01762 
01763 /* write a standalone version to convert to 1D format */
01764 #ifdef SUMA_FScurv_to_1D_STAND_ALONE
01765 
01766 void usage_SUMA_FScurv_to_1D_Main ()
01767    
01768   {/*Usage*/
01769       static char FuncName[]={"usage_FScurv_to_1D"};
01770       char * s = NULL;
01771           printf ("\n"
01772                   "Usage:  FScurv_to_1D [-skip_coords] [-output outfile] -input curv_name.asc  \n"
01773                   "   Reads in a FreeSurfer curvature file and writes it out in 1D format. \n"
01774                   "   But the format is 1D to begin with, so 'what is that program for?' you ask. \n"
01775                   "   Not much, I say. It is used to test a SUMA function and also allows you\n"
01776                   "   to select the node index and data values from the 5 columns of the curv files.\n"
01777                   "\n"
01778                   "   -input curv_name.asc: name of ASCII curvature file. To change a curvature file \n"
01779                   "                     to ASCII, use mris_convert -c curv_name surf curvfile.asc \n"
01780                   "                     surf is the surface over which the curvfile is defined, like\n"
01781                   "                     lh.inflated.\n"
01782                   "   -skip_coords: If specified, the node coordinates are not included in the output.\n"
01783                   "   -output outfile: If specified, the output goes to a file instead of stdout, \n"
01784                   "                    which is the screen\n"
01785                   "\n");
01786        s = SUMA_New_Additions(0, 1); printf("%s\n", s);SUMA_free(s); s = NULL;
01787        printf("       Ziad S. Saad SSCC/NIMH/NIH ziad@nih.gov     \n");
01788        exit (0);
01789   }/*Usage*/
01790    
01791 int main (int argc,char *argv[])
01792 {/* Main */
01793    static char FuncName[]={"FScurv_to_1D"};
01794    int i, j, id, nrows=0, ncols=0, kar;
01795    float *v = NULL;
01796    char *outname = NULL;
01797    char *fname = NULL;
01798    FILE *outfile=NULL;
01799    SUMA_Boolean SkipCoords = NOPE, brk, rowmajor;
01800    SUMA_Boolean LocalHead = NOPE;       
01801    
01802         /* allocate space for CommonFields structure */
01803         SUMAg_CF = SUMA_Create_CommonFields ();
01804         if (SUMAg_CF == NULL) {
01805                 fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_Create_CommonFields\n", FuncName);
01806                 exit(1);
01807         }
01808    
01809    /* parse command line */
01810    kar = 1;
01811    outname = NULL;
01812    fname = NULL;
01813    SkipCoords = NOPE;
01814    rowmajor = YUP;  /* just to test the function's execution */
01815         brk = NOPE;
01816         while (kar < argc) { /* loop accross command ine options */
01817                 /*fprintf(stdout, "%s verbose: Parsing command line...\n", FuncName);*/
01818                 if (strcmp(argv[kar], "-h") == 0 || strcmp(argv[kar], "-help") == 0) {
01819                          usage_SUMA_FScurv_to_1D_Main();
01820           exit (0);
01821                 }
01822       if (!brk && ( (strcmp(argv[kar], "-skip_coords") == 0) ) ) {
01823                         SkipCoords = YUP;
01824          brk = YUP;
01825                 }
01826       if (!brk && (strcmp(argv[kar], "-output") == 0)) {
01827          kar ++;
01828                         if (kar >= argc)  {
01829                                 fprintf (SUMA_STDERR, "need argument after -output\n");
01830                                 exit (1);
01831                         }
01832          outname = argv[kar];
01833                         brk = YUP;
01834                 }
01835       if (!brk && (strcmp(argv[kar], "-input") == 0)) {
01836          kar ++;
01837                         if (kar >= argc)  {
01838                                 fprintf (SUMA_STDERR, "need argument after -input\n");
01839                                 exit (1);
01840                         }
01841          fname = argv[kar];
01842                         brk = YUP;
01843                 }
01844       if (!brk) {
01845                         fprintf (SUMA_STDERR,"Error %s:\nOption %s not understood. Try -help for usage\n", FuncName, argv[kar]);
01846                         exit (1);
01847                 } else {        
01848                         brk = NOPE;
01849                         kar ++;
01850                 }
01851    }
01852    
01853    if (!fname) {
01854       SUMA_SL_Err("No input file specified.");
01855       exit(1);
01856    }
01857    /* work the output name */
01858    if (!outname) {
01859       outfile = SUMA_STDOUT;
01860    } else {
01861       outname = SUMA_Extension(outname, ".1D", NOPE); /* outname should be freed at the end */
01862       if (SUMA_filexists(outname)) {
01863          fprintf(SUMA_STDERR,"Error %s: Output file %s exists, will not overwrite.\n", FuncName, outname);
01864          exit(1);
01865       }
01866       outfile = fopen(outname, "w");
01867       if (!outfile) {
01868          SUMA_SL_Crit("Failed to open file for writing.\n"
01869                       "Check file permissions.");
01870          exit(1);
01871       }
01872    }
01873    
01874    /* do the deed */
01875    v = SUMA_readFScurv (fname, &nrows, &ncols, rowmajor, SkipCoords);   
01876    if (!v) {
01877       SUMA_SL_Err("Failed in SUMA_readFScurv");
01878       exit(1);
01879    }
01880    
01881    if (rowmajor) {
01882       for (i=0; i<nrows; ++i) {
01883          id = ncols * i;
01884          fprintf(outfile,"%d\t", (int) v[id]);
01885          for (j=1; j<ncols; ++j) fprintf(outfile,"%f\t", v[id+j]);
01886          fprintf(outfile,"\n");
01887       }
01888 
01889    } else {
01890       for (i=0; i<nrows; ++i) {
01891          fprintf(outfile,"%d\t", (int) v[i]);
01892          for (j=1; j<ncols; ++j) fprintf(outfile,"%f\t", v[i+j*nrows]);
01893          fprintf(outfile,"\n");
01894       }
01895    }
01896    
01897    if (outname) {
01898       fclose (outfile); outfile = NULL;
01899       SUMA_free(outname); outname = NULL;
01900    }
01901    SUMA_free(v); v = NULL;
01902    
01903    exit(0);
01904 }
01905 #endif
01906    
01907 /* just call engine with debug set                20 Oct 2003 [rickr] */
01908 SUMA_Boolean SUMA_FreeSurfer_Read (char * f_name, SUMA_FreeSurfer_struct *FS)
01909 {/* SUMA_FreeSurfer_Read */
01910    static char FuncName[]={"SUMA_FreeSurfer_Read"};
01911 
01912    SUMA_ENTRY;
01913 
01914    SUMA_RETURN(SUMA_FreeSurfer_Read_eng(f_name, FS, 1));
01915 }/* SUMA_FreeSurfer_Read */
01916 
01917    
01918 /* - changed function name to XXX_eng             20 Oct 2003 [rickr]
01919  * - added debug parameter
01920  * - print non-error info only if debug
01921 */
01922 /*!**  
01923 Usage : 
01924 Ret = SUMA_FreeSurfer_Read_eng (surfname, FreeSurfer, debug)
01925         
01926         For a full surface definition, it is assumed that the first line can be a comment.
01927         The second line contains the number of nodes followed by the number of FaceSets
01928         The NodeList follows with X Y Z 0
01929         The FaceSetList follows with i1 i2 i3 0
01930    
01931         
01932 Input paramters : 
01933 \param surfname (char *) name of surface (or patch) file output by:
01934         mris_convert <surface_name> <surface_name.asc>
01935    or if it is a patch by
01936         mris_convert -p <patch_name> <patch_name.asc>
01937        
01938 \param FreeSurfer (SUMA_FreeSurfer_struct *) pointer to the FreeSurfer structure
01939 
01940 \param debug (int) flag specifying whether to output non-error info
01941    
01942 Returns : 
01943 \return  (SUMA_Boolean) YUP/NOPE for success/failure
01944    
01945 Support : 
01946 \sa   LoadFreeSurf.m
01947 \sa   
01948    
01949 Side effects : 
01950    
01951    
01952    
01953 ***/
01954 SUMA_Boolean SUMA_FreeSurfer_Read_eng (char * f_name, SUMA_FreeSurfer_struct *FS, int debug)
01955 {/*SUMA_FreeSurfer_Read_eng*/
01956         static char FuncName[]={"SUMA_FreeSurfer_Read_eng"};
01957    char stmp[50]; 
01958    FILE *fs_file;
01959         int ex, cnt, jnki, amax[3], maxamax, maxamax2, id, ND, id2, NP, ip, *NodeId;
01960         float jnkf, *NodeList;
01961         char c;
01962         SUMA_Boolean LocalHead = NOPE;
01963            
01964         SUMA_ENTRY;
01965 
01966         /* check for existence */
01967         if (!SUMA_filexists(f_name)) {
01968                 fprintf(SUMA_STDERR,"Error %s: File %s does not exist or cannot be read.\n", FuncName, f_name);
01969                 SUMA_RETURN (NOPE);
01970         }else if ( debug > 1) {
01971                 fprintf(SUMA_STDERR,"%s: File %s exists and will be read.\n", FuncName, f_name);
01972         }
01973         
01974         
01975         /* start reading */
01976         fs_file = fopen (f_name,"r");
01977         if (fs_file == NULL)
01978                 {
01979                         SUMA_error_message (FuncName,"Could not open input file ",0);
01980                         SUMA_RETURN (NOPE);
01981                 }
01982 
01983         sprintf(FS->name, "%s", f_name);
01984         
01985         /* read first character and check if it is a comment */
01986         ex = fscanf (fs_file,"%c",&c);
01987         if (c == '#') {
01988                 if (LocalHead) fprintf (SUMA_STDOUT, "%s: Found comment\n", FuncName); 
01989                 
01990       /*skip till next line */
01991                 sprintf(FS->comment,"#"); 
01992                 cnt = 0;
01993                 while (ex != EOF && c != '\n') {
01994                         ex = fscanf (fs_file,"%c",&c);
01995                         if (cnt < SUMA_MAX_STRING_LENGTH-2) {
01996                                 sprintf(FS->comment, "%s%c", FS->comment, c);
01997                                 ++cnt;
01998                         } else {
01999                                 fprintf(SUMA_STDERR,"Error %s: Too long a comment in FS file, increase SUMA_FS_MAX_COMMENT_LENGTH\n", FuncName);
02000                                 SUMA_RETURN (NOPE);
02001                         }
02002                 }
02003         }
02004         
02005         /* find out if surface is patch */
02006         sprintf(stmp,"patch");
02007         if (SUMA_iswordin (FS->comment, stmp) == 1) {
02008                 FS->isPatch = YUP;
02009         }
02010         else {
02011                 FS->isPatch = NOPE;
02012         }
02013                 
02014         /* read in the number of nodes and the number of facesets */
02015         ex = fscanf(fs_file, "%d %d", &(FS->N_Node), &(FS->N_FaceSet));
02016         
02017    if (FS->N_Node <= 0 || FS->N_FaceSet <= 0) {
02018       SUMA_SL_Crit("Trouble parsing FreeSurfer file.\nNull or negative number of nodes &/| facesets.\n");
02019       SUMA_RETURN(NOPE);
02020    }
02021    
02022         if (LocalHead) fprintf (SUMA_STDOUT, "%s: Allocating for NodeList (%dx3) and FaceSetList(%dx3)\n", FuncName, FS->N_Node, FS->N_FaceSet);
02023    
02024    /* allocate space for NodeList and FaceSetList */
02025         FS->NodeList = (float *)SUMA_calloc(FS->N_Node * 3, sizeof(float));
02026         FS->FaceSetList = (int *)SUMA_calloc(FS->N_FaceSet * 3, sizeof(int));
02027         FS->NodeId = (int *)SUMA_calloc(FS->N_Node, sizeof(int));
02028         if (FS->NodeList == NULL || FS->FaceSetList == NULL || FS->NodeId == NULL) {
02029                 fprintf(SUMA_STDERR,"Error %s: Could not allocate for FS->NodeList &/| FS->FaceSetList &/| FS->NodeId\n", FuncName);
02030                 SUMA_RETURN (NOPE);
02031         } 
02032         if (FS->isPatch) {
02033                 FS->FaceSetIndexInParent = (int *)SUMA_calloc(FS->N_FaceSet, sizeof(int));
02034                 if (FS->FaceSetIndexInParent == NULL) {
02035                         fprintf(SUMA_STDERR,"Error %s: Could not allocate for FS->FaceSetIndexInParent\n", FuncName);
02036                         SUMA_RETURN (NOPE);
02037                 }
02038         } else {
02039                 FS->FaceSetIndexInParent = NULL;
02040         }
02041         
02042         if (!FS->isPatch) {
02043            if (LocalHead) fprintf (SUMA_STDOUT, "%s: Reading full surface...\n", FuncName);
02044                 /* read in the nodes */
02045                 cnt = 0;
02046                 while (ex != EOF && cnt < FS->N_Node) {
02047                         FS->NodeId[cnt] = cnt;
02048                         id = 3 * cnt;
02049                         ex = fscanf(fs_file, "%f %f %f %f", &(FS->NodeList[id]), &(FS->NodeList[id+1]),&(FS->NodeList[id+2]), &jnkf);
02050                         ++cnt;
02051                 }
02052                 if (cnt != FS->N_Node) {
02053                         fprintf(SUMA_STDERR,"Error %s: Expected %d nodes, %d read.\n", FuncName, FS->N_Node, cnt);
02054                         SUMA_RETURN (NOPE);
02055                 }
02056 
02057                 /* read in the facesets */
02058                 cnt = 0;
02059                 while (ex != EOF && cnt < FS->N_FaceSet) {
02060                         ip = 3 * cnt;
02061                         ex = fscanf(fs_file, "%d %d %d %d", &(FS->FaceSetList[ip]), &(FS->FaceSetList[ip+1]),&(FS->FaceSetList[ip+2]), &jnki);
02062                         ++cnt;
02063                 }
02064                 if (cnt != FS->N_FaceSet) {
02065                         fprintf(SUMA_STDERR,"Error %s: Expected %d FaceSets, %d read.\n", FuncName, FS->N_FaceSet, cnt);
02066                         SUMA_RETURN (NOPE);
02067                 }
02068         } /* read a full surface */
02069         else { /* that's a patch */
02070            #if 0 /* old way, simple parsing ... */
02071          if (LocalHead) fprintf (SUMA_STDOUT, "%s: Reading patch olde way...\n", FuncName);
02072                    /* Node IDs are a reference to those in the parent surface */
02073                    cnt = 0;
02074          while (ex != EOF && cnt < FS->N_Node) {
02075                            ex = fscanf(fs_file, "%d", &(FS->NodeId[cnt]));
02076                            id = 3 * cnt;
02077             /* 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); */ 
02078                            ex = fscanf(fs_file, "%f %f %f", &(FS->NodeList[id]),&(FS->NodeList[id+1]),&(FS->NodeList[id+2]));
02079                            ++cnt;
02080                    }
02081          if (cnt != FS->N_Node) {
02082                            fprintf(SUMA_STDERR,"Error %s: Expected %d nodes, %d read.\n", FuncName, FS->N_Node, cnt);
02083                            SUMA_RETURN (NOPE);
02084                    }
02085 
02086          if (LocalHead) fprintf (SUMA_STDOUT, "%s: Reading FaceSets...\n", FuncName);
02087                    /* read in the facesets */
02088                    cnt = 0;
02089                    while (ex != EOF && cnt < FS->N_FaceSet) {
02090                            ex = fscanf(fs_file, "%d", &(FS->FaceSetIndexInParent[cnt]));
02091                            ip = 3 * cnt;
02092                            ex = fscanf(fs_file, "%d %d %d",  &(FS->FaceSetList[ip]), &(FS->FaceSetList[ip+1]),&(FS->FaceSetList[ip+2]));
02093                            ++cnt;
02094                    }
02095                    if (cnt != FS->N_FaceSet) {
02096                            fprintf(SUMA_STDERR,"Error %s: Expected %d FaceSets, %d read.\n", FuncName, FS->N_FaceSet, cnt);
02097                            SUMA_RETURN (NOPE);
02098                    }
02099       #else 
02100       {
02101          char *fl=NULL, *eop=NULL, *florig=NULL;
02102          int ans, pnodes, ptri, Found, nchar;
02103          double dbuf;
02104          
02105          if (LocalHead) fprintf (SUMA_STDOUT, "%s: Reading patch new way...\n", FuncName);
02106          /* suck in the bastard, perhaps this should be done from the start, maybe in the future */  
02107          fl = florig = SUMA_file_suck(f_name, &nchar);
02108          if (!nchar || !fl) { 
02109             SUMA_SL_Err("Failed to read patch file.");
02110             SUMA_RETURN(NOPE);
02111          }
02112          /* skip comment, if any */
02113          SUMA_IS_COMMENT_LINE(fl, NULL, '#', ans);
02114          if (ans) {  
02115             SUMA_LH("Skipping comment..."); 
02116             SUMA_SKIP_LINE(fl, NULL);
02117          }else {
02118             SUMA_SL_Err("Expected comment line....");
02119          }
02120          /* read in first two nums */
02121          SUMA_ADVANCE_PAST_NUM(fl, dbuf, Found); pnodes = (int)dbuf;
02122          SUMA_ADVANCE_PAST_NUM(fl, dbuf, Found); ptri = (int)dbuf;
02123          
02124          /* Node IDs are a reference to those in the parent surface */
02125                    Found = 1;
02126          cnt = 0;
02127          while (Found && cnt < FS->N_Node) {
02128                            eop = fl+50; /* don't you dare use (fl+50) instead of eop below!, else you will serch till the end all the time!
02129                            Macro Danger! */
02130             SUMA_ADVANCE_PAST(fl, eop,"vno=",Found,0);  /* The new patch format ... */
02131             SUMA_ADVANCE_PAST_NUM(fl, dbuf, Found); FS->NodeId[cnt] = (int)dbuf;
02132                            id = 3 * cnt;
02133             /* 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); */ 
02134                            SUMA_ADVANCE_PAST_NUM(fl, dbuf, Found); FS->NodeList[id] = (float)dbuf;
02135             SUMA_ADVANCE_PAST_NUM(fl, dbuf, Found); FS->NodeList[id+1] = (float)dbuf;
02136             SUMA_ADVANCE_PAST_NUM(fl, dbuf, Found); FS->NodeList[id+2] = (float)dbuf;
02137                            ++cnt;
02138                    }
02139          if (cnt != FS->N_Node) {
02140                            fprintf(SUMA_STDERR,"Error %s: Expected %d nodes, %d read.\n", FuncName, FS->N_Node, cnt);
02141                            SUMA_RETURN (NOPE);
02142                    }
02143          if (LocalHead) fprintf (SUMA_STDOUT, "%s: Reading FaceSets...\n", FuncName);
02144                    /* read in the facesets */
02145                    Found = 1;
02146                    cnt = 0;
02147          while (Found && cnt < FS->N_FaceSet) {
02148                            SUMA_ADVANCE_PAST_NUM(fl, dbuf, Found); FS->FaceSetIndexInParent[cnt] = (int)dbuf;
02149                            ip = 3 * cnt;
02150                            SUMA_ADVANCE_PAST_NUM(fl, dbuf, Found); FS->FaceSetList[ip  ] = (int)dbuf;
02151                            SUMA_ADVANCE_PAST_NUM(fl, dbuf, Found); FS->FaceSetList[ip+1] = (int)dbuf;
02152                            SUMA_ADVANCE_PAST_NUM(fl, dbuf, Found); FS->FaceSetList[ip+2] = (int)dbuf;
02153                            ++cnt;
02154                    }
02155                    if (cnt != FS->N_FaceSet) {
02156                            fprintf(SUMA_STDERR,"Error %s: Expected %d FaceSets, %d read.\n", FuncName, FS->N_FaceSet, cnt);
02157                            SUMA_RETURN (NOPE);
02158                    }
02159          SUMA_free(florig); fl = florig = NULL; /*  */
02160       }   
02161       #endif   
02162       
02163                 /* The FaceSet List which will be read next, uses indices into the NodeList of the parent surface
02164                 This means that it expects a NodeList of the size of the NodeList in the parent surface. 
02165                 One could read the maximum number of nodes in the parent surface and create a NodeList of that size.
02166                 However, that would require keeping track of the link between the patch file and the parent file.
02167                 Instead, I will search through the FaceSetList for the highest index and allocate a new nodelist to match it*/
02168       
02169                 SUMA_MAX_VEC(FS->FaceSetList, FS->N_FaceSet * 3, maxamax); ++maxamax;
02170       /* make sure that the node list does not refer to nodes of an index higher than that in NodeId */
02171       SUMA_MAX_VEC(FS->NodeId, FS->N_Node, maxamax2); ++maxamax2;
02172       if (maxamax2 > maxamax) {
02173          fprintf(SUMA_STDERR,"Error %s: Found NodeId in the NodeList larger than Ids found in FaceSetList.\n", FuncName);
02174          SUMA_RETURN (NOPE);
02175       }
02176       if (LocalHead) fprintf (SUMA_STDOUT, "%s: Copying NodeList, allocating for new nodelist %dx3 elements...\n", \
02177          FuncName, maxamax);
02178          
02179                 NodeList = (float *)SUMA_calloc(maxamax * 3, sizeof(float));
02180                 NodeId = (int *)SUMA_calloc (maxamax, sizeof(int));
02181       
02182       if (NodeList == NULL || NodeId == NULL)
02183                 {
02184                         fprintf(SUMA_STDERR,"Error %s: Could not allocate for NodeList or NodeId\n", FuncName);
02185                         SUMA_RETURN (NOPE);
02186                 } 
02187                 /*Now copy pertinent nodes into NodeList */
02188                 
02189       for (cnt=0; cnt< FS->N_Node; ++cnt) {
02190                         id = 3*cnt; 
02191                         id2 = 3*FS->NodeId[cnt];
02192          /* fprintf (SUMA_STDERR, "%s: id = %d id2 = %d\n", FuncName, id, id2); */
02193                         NodeList[id2] = FS->NodeList[id];
02194                         NodeList[id2+1] = FS->NodeList[id+1];
02195                         NodeList[id2+2] = FS->NodeList[id+2];
02196                 }
02197                 
02198       /* this is redundant here, but should be done to match what comes out of a full surface */
02199       for (cnt=0; cnt< maxamax; ++cnt) {
02200          NodeId[cnt] = cnt;
02201       }
02202       
02203       /* Now free FS->NodeList & FS->NodeId */
02204                 SUMA_free(FS->NodeList);
02205                 SUMA_free(FS->NodeId);
02206       
02207                 /*make FS->NodeList be NodeList */
02208                 FS->NodeList = NodeList;
02209       FS->NodeId = NodeId;
02210                 FS->N_Node = maxamax;
02211         } /* read a patch */
02212         
02213         fclose (fs_file);
02214         SUMA_RETURN (YUP);
02215         
02216 }/* SUMA_FreeSurfer_Read_eng*/
02217 
02218 SUMA_Boolean SUMA_FreeSurfer_WritePatch (char *fileNm, SUMA_SurfaceObject *SO, char *firstLine, SUMA_SurfaceObject *SO_parent)
02219 {
02220    static char FuncName[]={"SUMA_FreeSurfer_WritePatch"};
02221    int cnt, i, iface;
02222    int *FaceSetIndexInParent=NULL;
02223    SUMA_Boolean *isInPatch=NULL;
02224    FILE *fout=NULL;
02225    
02226    SUMA_ENTRY;
02227    
02228    if (!fileNm || !SO || !SO_parent || !SO_parent->EL) {
02229       SUMA_SL_Err("NULL input params");
02230       SUMA_RETURN(NOPE);
02231    }
02232    
02233    if (SUMA_filexists(fileNm)) {
02234       SUMA_SL_Err("Output file exists, will not overwrite");
02235       SUMA_RETURN(NOPE);
02236    }
02237    
02238    fout = fopen(fileNm,"w");
02239    if (!fout) {
02240       SUMA_SL_Err("Failed to open file for writing.\nCheck permissions.");
02241       SUMA_RETURN(NOPE);
02242    }
02243    
02244    if (firstLine) {
02245       fprintf(fout, "%s\n", firstLine);
02246    } else {
02247       if (!SO->Label) SO->Label = SUMA_SurfaceFileName (SO, NOPE);
02248       fprintf(fout, "#!ascii version of patch %s\n", SO->Label);
02249    }
02250    
02251    /* which nodes are in this patch ? */
02252    isInPatch = SUMA_MaskOfNodesInPatch(SO, &cnt);
02253    if (!isInPatch) {
02254       SUMA_SL_Crit("Failed in SUMA_MaskOfNodesInPatch");
02255       SUMA_RETURN(NOPE);
02256    }
02257 
02258    /* number of nodes and number of triangles in mesh */
02259    fprintf(fout, "%d %d\n", cnt, SO->N_FaceSet);
02260    /* write the node coordinates */
02261    for (i=0; i < SO->N_Node; ++i) {
02262       if (isInPatch[i]) {
02263          fprintf(fout, "%d\n%f\t%f\t%f\n", i, SO->NodeList[3*i], SO->NodeList[3*i+1], SO->NodeList[3*i+2]);
02264       }
02265    }
02266    for (i=0; i < SO->N_FaceSet; ++i) {
02267       iface = SUMA_whichTri (SO_parent->EL, SO->FaceSetList[3*i], SO->FaceSetList[3*i+1], SO->FaceSetList[3*i+2], 0);
02268       if (iface < 0) {
02269          SUMA_SL_Warn("Parent surface does not contain triangle in patch!\nTriangle skipped.");
02270       } else {
02271          fprintf(fout, "%d\n%d\t%d\t%d\n", iface, SO->FaceSetList[3*i], SO->FaceSetList[3*i+1], SO->FaceSetList[3*i+2]);
02272       }
02273    }
02274    
02275    
02276    SUMA_free(FaceSetIndexInParent); FaceSetIndexInParent = NULL;
02277    SUMA_free(isInPatch); isInPatch = NULL;
02278 
02279    fclose(fout);
02280    SUMA_RETURN(YUP);
02281 }
02282 /*!
02283    
02284    Thanks for info from Graham Wideman, https://wideman-one.com/gw/brain/fs/surfacefileformats.htm
02285 */
02286 SUMA_Boolean SUMA_FreeSurfer_ReadBin_eng (char * f_name, SUMA_FreeSurfer_struct *FS, int debug)
02287 {/*SUMA_FreeSurfer_ReadBin_eng*/
02288         static char FuncName[]={"SUMA_FreeSurfer_ReadBin_eng"};
02289    char stmp[50]; 
02290    FILE *fs_file;
02291         int ex, End, rmax,  chnk, cnt, i, amax[3], maxamax, maxamax2, id, ND, id2, NP, ip, *NodeId, magic;
02292         float jnkf, *NodeList;
02293         char c;
02294    byte m1, m2, m3;
02295         SUMA_Boolean bs;
02296    SUMA_Boolean LocalHead = NOPE;
02297            
02298         SUMA_ENTRY;
02299    
02300    if (debug) LocalHead = YUP;
02301    
02302         /* check for existence */
02303         if (!SUMA_filexists(f_name)) {
02304                 fprintf(SUMA_STDERR,"Error %s: File %s does not exist or cannot be read.\n", FuncName, f_name);
02305                 SUMA_RETURN (NOPE);
02306         }else if ( debug > 1) {
02307                 fprintf(SUMA_STDERR,"%s: File %s exists and will be read.\n", FuncName, f_name);
02308         }
02309         
02310         /* start reading */
02311         fs_file = fopen (f_name,"r");
02312         if (fs_file == NULL)
02313                 {
02314                         SUMA_SL_Err ("Could not open input file ");
02315                         SUMA_RETURN (NOPE);
02316                 }
02317 
02318    SUMA_WHAT_ENDIAN(End);
02319    if (End == MSB_FIRST) {
02320       SUMA_LH("No swapping needed");
02321       bs = NOPE;
02322    } else {
02323       bs = YUP;
02324       SUMA_LH("Swapping needed");
02325    }
02326    
02327    ex = fread (&m1, 1, 1, fs_file);
02328    ex = fread (&m2, 1, 1, fs_file);
02329    ex = fread (&m3, 1, 1, fs_file);
02330    magic = (m1 << 16) + (m2 << 8) + m3 ;
02331    if (magic == (-2 & 0x00ffffff)) {
02332       SUMA_LH("OK tri");
02333    } else {
02334       SUMA_SL_Err("Failed to identify magic number for a triangulated surface.\n");
02335       SUMA_RETURN(NOPE);
02336    }
02337    chnk = sizeof(char);
02338    ex = fread (&c, chnk, 1, fs_file);
02339    rmax = 0;
02340    while (c != '\n' &&rmax < 5000) {
02341       if (LocalHead) fprintf(SUMA_STDERR,"%c",c);
02342       ex = fread (&c, chnk, 1, fs_file);
02343       ++rmax;
02344    }
02345    if (rmax >= 5000) {
02346       SUMA_SL_Err("Unexpected tres tres long comment.");
02347       SUMA_RETURN(NOPE);
02348    }
02349    SUMA_LH("End of comment");
02350    /* read one more to skip second \n */
02351    ex = fread (&c, chnk, 1, fs_file);
02352    if (c != '\n') {
02353       SUMA_SL_Err("Failed to find second newline.");
02354       SUMA_RETURN(NOPE);
02355    }else {
02356       SUMA_LH("Found end of comment");
02357    }
02358    
02359    /* read the number of nodes and the number of triangles */
02360    SUMA_READ_INT (&FS->N_Node, bs, fs_file, ex);
02361    if (FS->N_Node < 0 || FS->N_Node > 2000000) {
02362       SUMA_SL_Err("Failed to get number of nodes");
02363       SUMA_RETURN(NOPE);
02364    }else {
02365       if (LocalHead) fprintf(SUMA_STDERR,"%s: Expecting to read %d nodes.\n", FuncName, FS->N_Node);
02366    }
02367    
02368    SUMA_READ_INT (&FS->N_FaceSet, bs, fs_file, ex);
02369    if (FS->N_FaceSet < 0 || FS->N_FaceSet > 2000000) {
02370       SUMA_SL_Err("Failed to get number of triangles");
02371       SUMA_RETURN(NOPE);
02372    }else {
02373       if (LocalHead) fprintf(SUMA_STDERR,"%s: Expecting to read %d triangles.\n", FuncName, FS->N_FaceSet);
02374    }
02375    
02376    /* allocate */
02377         FS->NodeList = (float *)SUMA_calloc(FS->N_Node * 3, sizeof(float));
02378         FS->FaceSetList = (int *)SUMA_calloc(FS->N_FaceSet * 3, sizeof(int));
02379    if (!FS->NodeList || !FS->FaceSetList) {
02380       SUMA_SL_Err("Failed to allocate");
02381       SUMA_RETURN(NOPE);
02382    }
02383    
02384    /*read in the meat */
02385    for (i=0; i<FS->N_Node * 3; ++i) {
02386       SUMA_READ_FLOAT (&(FS->NodeList[i]), bs, fs_file, ex);
02387       if (ex == EOF) {
02388          SUMA_SL_Err("Premature end of file!");
02389          SUMA_free(FS->NodeList); SUMA_free(FS->FaceSetList);  FS->NodeList = NULL ; FS->FaceSetList = NULL;
02390          SUMA_RETURN(NOPE);
02391       }
02392    }
02393    for (i=0; i<FS->N_FaceSet * 3; ++i) {
02394       SUMA_READ_INT (&(FS->FaceSetList[i]), bs, fs_file, ex);
02395       if (ex == EOF) {
02396          SUMA_SL_Err("Premature end of file!");
02397          SUMA_free(FS->NodeList); SUMA_free(FS->FaceSetList);  FS->NodeList = NULL ; FS->FaceSetList = NULL;
02398          SUMA_RETURN(NOPE);
02399       }   
02400    }
02401    
02402    fclose(fs_file);
02403    SUMA_LH("Returning");
02404    SUMA_RETURN(YUP);
02405 }
02406 /*! 
02407         free memory allocated for FreeSurfer structure  
02408 */
02409 SUMA_Boolean SUMA_Free_FreeSurfer (SUMA_FreeSurfer_struct *FS)
02410 {
02411         static char FuncName[]={"SUMA_Free_FreeSurfer"};
02412    
02413    SUMA_ENTRY;
02414 
02415         if (FS->FaceSetList != NULL) SUMA_free(FS->FaceSetList);
02416         if (FS->NodeList != NULL) SUMA_free(FS->NodeList);
02417         if (FS->NodeId != NULL) SUMA_free(FS->NodeId);
02418         if (FS->FaceSetIndexInParent != NULL) SUMA_free(FS->FaceSetIndexInParent);
02419         if (FS != NULL) SUMA_free(FS);
02420         SUMA_RETURN (YUP);
02421 }
02422 
02423 /*! 
02424         Show elements of FreeSurfer structure 
02425 */
02426 void SUMA_Show_FreeSurfer (SUMA_FreeSurfer_struct *FS, FILE *Out)
02427 {       
02428         static char FuncName[]={"SUMA_Show_FreeSurfer"};
02429         int ND = 3, id, ip;
02430         
02431         SUMA_ENTRY;
02432 
02433         if (Out == NULL) Out = SUMA_STDOUT;
02434         if (FS->comment) fprintf (Out, "Comment: %s\n", FS->comment);
02435    else fprintf (Out, "Comment: NULL\n");
02436         fprintf (Out, "N_Node %d\n", FS->N_Node);
02437         if (FS->NodeId) {
02438       fprintf (Out, "First 2 points [id] X Y Z:\n\t[%d] %f %f %f\n\t[%d] %f %f %f\n", \
02439                    FS->NodeId[0], FS->NodeList[0], FS->NodeList[1], FS->NodeList[2],
02440                    FS->NodeId[1], FS->NodeList[3], FS->NodeList[4], FS->NodeList[5]);
02441            if (FS->N_Node > 2) {
02442          fprintf (Out, "Last 2 points [id] X Y Z:\n\t[%d] %f %f %f\n\t[%d] %f %f %f\n", \
02443                       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],
02444                       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]);
02445       }
02446    } else {
02447       fprintf (Out, "NULL NodeId\n");
02448       fprintf (Out, "First 2 points X Y Z:\n\t %f %f %f\n\t %f %f %f\n", \
02449                    FS->NodeList[0], FS->NodeList[1], FS->NodeList[2],
02450                    FS->NodeList[3], FS->NodeList[4], FS->NodeList[5]);
02451            if (FS->N_Node > 2) {
02452          fprintf (Out, "Last 2 points X Y Z:\n\t %f %f %f\n\t %f %f %f\n", \
02453                       FS->NodeList[3*(FS->N_Node-2)], FS->NodeList[3*(FS->N_Node-2)+1], FS->NodeList[3*(FS->N_Node-2)+2],
02454                       FS->NodeList[3*(FS->N_Node-1)], FS->NodeList[3*(FS->N_Node-1)+1], FS->NodeList[3*(FS->N_Node-1)+2]);
02455       }
02456    }
02457         fprintf (Out, "N_FaceSet %d\n", FS->N_FaceSet);
02458         if (!FS->isPatch) {
02459                 if (FS->N_FaceSet > 2) {
02460         fprintf (Out, "First 2 polygons:\n\t%d %d %d\n\t%d %d %d\n", \
02461                         FS->FaceSetList[0], FS->FaceSetList[1], FS->FaceSetList[2],
02462                         FS->FaceSetList[3], FS->FaceSetList[4], FS->FaceSetList[5]);
02463         fprintf (Out, "Last 2 polygons:\n%d %d %d\n%d %d %d\n", \
02464                         FS->FaceSetList[3 * (FS->N_FaceSet-2)], FS->FaceSetList[3 * (FS->N_FaceSet-2) + 1], FS->FaceSetList[3 * (FS->N_FaceSet-2) + 2],
02465                         FS->FaceSetList[3 * (FS->N_FaceSet-1)], FS->FaceSetList[3 * (FS->N_FaceSet-1) + 1], FS->FaceSetList[3 * (FS->N_FaceSet-1) + 2]);
02466       }else {
02467          fprintf (Out, "First polygon:\n\t%d %d %d\n", \
02468                         FS->FaceSetList[0], FS->FaceSetList[1], FS->FaceSetList[2]);
02469       }
02470         } else {
02471                 if (FS->N_FaceSet > 2) {
02472          fprintf (Out, "First 2 polygons:\n\t[parent ID:%d] %d %d %d\n\t[parent ID:%d] %d %d %d\n", \
02473                         FS->FaceSetIndexInParent[0], FS->FaceSetList[0], FS->FaceSetList[1], FS->FaceSetList[2],
02474                         FS->FaceSetIndexInParent[1], FS->FaceSetList[3], FS->FaceSetList[4], FS->FaceSetList[5]);
02475                    fprintf (Out, "Last 2 polygons:\n\t[parent ID:%d]%d %d %d\n\t[parent ID:%d]%d %d %d\n", \
02476                         FS->FaceSetIndexInParent[FS->N_FaceSet-2], FS->FaceSetList[3 * (FS->N_FaceSet-2)], \
02477                         FS->FaceSetList[3 * (FS->N_FaceSet-2) + 1], FS->FaceSetList[3 * (FS->N_FaceSet-2) + 2], \
02478                         FS->FaceSetIndexInParent[FS->N_FaceSet-1], FS->FaceSetList[3 * (FS->N_FaceSet-1)], \
02479                         FS->FaceSetList[3 * (FS->N_FaceSet-1) + 1], FS->FaceSetList[3 * (FS->N_FaceSet-1) + 2]);
02480       } else {
02481          fprintf (Out, "First polygon:\n\t[parent ID:%d] %d %d %d\n", \
02482                         FS->FaceSetIndexInParent[0], FS->FaceSetList[0], FS->FaceSetList[1], FS->FaceSetList[2]);
02483       }
02484         }
02485         SUMA_RETURNe;
02486 
02487 }
02488 
02489 /*!
02490    \brief Load a brain voyager surface model from a .srf file.
02491    
02492    Thanks to Nikolaus Kriegeskorte for code snippets and help.
02493    
02494    The following fields are set in SO:
02495    SO->NodeDim
02496    SO->FaceSetDim
02497    SO->NodeList
02498    SO->FaceSetList
02499    SO->N_Node;
02500    SO->N_FaceSet;
02501    SO->Name;
02502    SO->FileType;
02503    SO->FileFormat
02504 
02505 */
02506 SUMA_Boolean SUMA_BrainVoyager_Read(char *f_name, SUMA_SurfaceObject *SO, int debug) 
02507 {
02508    static char FuncName[]={"SUMA_BrainVoyager_Read"};
02509         float FileVersion, cx, cy, cz, *fbuf = NULL;
02510         int i, ii, chnk, ex, surf_type, n_neighbors, bs;
02511         char buffer[256];
02512    float fbuffer[256];
02513    FILE *fl=NULL;
02514    SUMA_Boolean LocalHead = NOPE;
02515    
02516    SUMA_ENTRY;
02517    
02518    /* check for existence */
02519         if (!SUMA_filexists(f_name)) {
02520                 fprintf(SUMA_STDERR,"Error %s: File %s does not exist or cannot be read.\n", FuncName, f_name);
02521                 SUMA_RETURN (NOPE);
02522         }else {
02523       if ( debug > 1) {
02524                    fprintf(SUMA_STDERR,"%s: File %s exists and will be read.\n", FuncName, f_name);
02525            }
02526    }
02527         
02528    fl = fopen(f_name, "r");
02529    if (!fl) {
02530       SUMA_SL_Err("Failed to open file for reading.\n");
02531       SUMA_RETURN(NOPE);
02532    }
02533    
02534    SO->N_Node=0;
02535         SO->N_FaceSet=0;
02536    
02537    /* read version, and number of nodes and facesets, assume no swapping for the moment */
02538    bs = 0;
02539    chnk = sizeof(float);
02540    ex = fread (&FileVersion, chnk, 1, fl);
02541    chnk = sizeof(int);
02542    ex = fread (&surf_type, chnk, 1, fl); /* must be 0, per website www.brainvoyager.com... */
02543    ex = fread (&(SO->N_Node), chnk, 1, fl);
02544    ex = fread (&(SO->N_FaceSet), chnk, 1, fl);
02545    if (FileVersion < 0 || FileVersion > 500000 || SO->N_Node < 0 || SO->N_FaceSet < 0) { /* trouble perhaps ? */
02546       SUMA_LH("Byte swapping needed...");
02547       bs = 1;
02548    }
02549    if (bs) {
02550       SUMA_SWAP_THIS(&FileVersion, sizeof(float));
02551       SUMA_SWAP_THIS(&surf_type, sizeof(int));
02552       SUMA_SWAP_THIS(&(SO->N_Node), sizeof(int));
02553       SUMA_SWAP_THIS(&(SO->N_FaceSet), sizeof(int));
02554    }
02555    
02556    if (LocalHead) {
02557       fprintf (SUMA_STDERR,"%s:\nSurfType is %d\nN_Node = %d, N_FaceSet = %d\n", 
02558                            FuncName, surf_type, SO->N_Node, SO->N_FaceSet);
02559    }
02560    
02561    if (FileVersion < 0 || FileVersion > 500000) { /* trouble perhaps ? */
02562       SUMA_SL_Err("Version number < 0 || > 500000 \nSeems like bad news to me, quitting...");
02563       fclose(fl);
02564       SUMA_RETURN(NOPE);
02565    }
02566    
02567    
02568    if (SO->N_Node < 0 || SO->N_FaceSet < 0) {
02569       SUMA_SL_Err("Negative values for N_Node and N_FaceSet.");
02570       fclose(fl);
02571       SUMA_RETURN(NOPE);
02572    } 
02573    
02574    SUMA_READ_FLOAT(&cx, bs, fl, ex);
02575    SUMA_READ_FLOAT(&cy, bs, fl, ex);
02576    SUMA_READ_FLOAT(&cz, bs, fl, ex);
02577    if (LocalHead) {
02578       fprintf (SUMA_STDERR,"%s:\ncenter = [%f, %f, %f]\n(Niko adds 30 to cy ...)\n", FuncName, cx, cy, cz);
02579    }
02580    SO->NodeDim = 3;
02581    SO->FaceSetDim = 3;
02582    fbuf = (float *)SUMA_malloc(SO->N_Node*sizeof(float));
02583    SO->NodeList = (float *)SUMA_malloc(SO->NodeDim*SO->N_Node*sizeof(float));
02584    SO->FaceSetList = (int *)SUMA_malloc(SO->FaceSetDim*SO->N_FaceSet*sizeof(int));
02585    if (!fbuf || !SO->NodeList || !SO->FaceSetList) {
02586       SUMA_SL_Crit("Failed to allocate.");
02587       SUMA_RETURN(NOPE);
02588    }
02589    
02590    /* read the coords */
02591    SUMA_LH("Reading coords...");
02592    ex = fread(fbuf, sizeof(float), SO->N_Node, fl);
02593    if (ex != SO->N_Node) { SUMA_SL_Warn("Failed to read all node X info"); }
02594    if (bs) SUMA_SWAP_VEC(fbuf,SO->N_Node,sizeof(float));
02595    for (i=0; i<SO->N_Node; ++i) SO->NodeList[3*i] = fbuf[i];
02596    ex = fread(fbuf, sizeof(float), SO->N_Node, fl);
02597    if (ex != SO->N_Node) { SUMA_SL_Warn("Failed to read all node Y info"); }
02598    if (bs) SUMA_SWAP_VEC(fbuf,SO->N_Node,sizeof(float));
02599    for (i=0; i<SO->N_Node; ++i) SO->NodeList[3*i+1] = fbuf[i];
02600    ex = fread(fbuf, sizeof(float), SO->N_Node, fl);
02601    if (ex != SO->N_Node) { SUMA_SL_Warn("Failed to read all node Z info"); }
02602    if (bs) SUMA_SWAP_VEC(fbuf,SO->N_Node,sizeof(float));
02603    for (i=0; i<SO->N_Node; ++i) SO->NodeList[3*i+2] = fbuf[i];
02604    SUMA_free(fbuf); fbuf = NULL;
02605    if (LocalHead) { 
02606       char *sdbg = SUMA_ShowMeSome((void *)SO->NodeList, SUMA_float, SUMA_MIN_PAIR(20, SO->N_Node), 20);
02607       fprintf(SUMA_STDERR,"%s NodeList:\n%s\n", FuncName, sdbg);
02608       SUMA_free(sdbg);sdbg = NULL;
02609    }
02610    /* skip the node normals, which would be read much like the x y z coords*/
02611    fseek(fl, SO->N_Node*3*sizeof(float), SEEK_CUR);
02612    
02613    /* skip the curvature color info */
02614    ex = fread(fbuffer, sizeof(float), 8, fl); /* colors of convex and concave stuff */
02615    if (bs) SUMA_SWAP_VEC(fbuffer,8, sizeof(float));
02616    if (LocalHead) { 
02617       char *sdbg = SUMA_ShowMeSome((void *)fbuffer, SUMA_float, 8,8);
02618       fprintf(SUMA_STDERR,"%s colorstuff:\n%s\n", FuncName, sdbg);
02619       SUMA_free(sdbg);sdbg = NULL;
02620    }
02621    fseek(fl, SO->N_Node*sizeof(float), SEEK_CUR); /* junp over mesh color */
02622    
02623    /* skip nearest neighbor info */
02624    for (i=0; i<SO->N_Node; ++i) {
02625       ex = fread(&n_neighbors, sizeof(int), 1, fl);
02626       if (bs) SUMA_SWAP_THIS(&n_neighbors, sizeof(int));
02627       fseek(fl, n_neighbors*sizeof(int), SEEK_CUR);
02628    }
02629    
02630    /* read dems triangles */
02631    SUMA_LH("Reading FaceSets...");
02632    ex = fread(SO->FaceSetList, sizeof(int), SO->N_FaceSet * SO->FaceSetDim , fl);
02633    if (ex != SO->N_FaceSet * SO->FaceSetDim) { 
02634       fprintf(SUMA_STDERR,"Error %s: Failed to read all faceset info.\nRead %d values, expected %d\n", FuncName, ex, SO->N_FaceSet * SO->FaceSetDim );
02635       SUMA_RETURN(NOPE);
02636    }
02637    
02638    if (bs) SUMA_SWAP_VEC(SO->FaceSetList,(SO->N_FaceSet * SO->FaceSetDim),sizeof(int));
02639    if (LocalHead) { 
02640       char *sdbg = SUMA_ShowMeSome((void *)SO->FaceSetList, SUMA_int, SUMA_MIN_PAIR(20, SO->N_FaceSet * SO->FaceSetDim), 20);
02641       fprintf(SUMA_STDERR,"%s FaceSetList:\n%s\n", FuncName, sdbg);
02642       SUMA_free(sdbg);sdbg = NULL;
02643    }
02644    fclose(fl); fl = NULL;
02645    
02646    SO->FileType = SUMA_BRAIN_VOYAGER;
02647    SO->Name = SUMA_StripPath(f_name);
02648    SO->FileFormat = SUMA_BINARY;    /* files are likely all BINARY_LE, must take care of that at some point*/
02649    
02650    SUMA_LH("Done.");
02651    
02652    SUMA_RETURN(YUP);
02653 }
02654 
02655 #ifdef SUMA_FreeSurfer_STAND_ALONE
02656 
02657 
02658 void usage_SUMA_FreeSurfer_Main ()
02659    
02660   {/*Usage*/
02661           printf ("\nUsage:  SUMA_FreeSurfer f_name \n");
02662           printf ("\t ..... \n\n");
02663           printf ("\t To Compile:\ngcc -DSUMA_FreeSurfer_STAND_ALONE -Wall -o $1 $1.c -I./ -I//usr/X11R6/include SUMA_lib.a\n");
02664           printf ("\t\t Ziad S. Saad SSCC/NIMH/NIH ziad@nih.gov \tFri Feb 8 16:29:06 EST 2002 \n");
02665           exit (0);
02666   }/*Usage*/
02667    
02668 int main (int argc,char *argv[])
02669 {/* Main */
02670    char FuncName[100]; 
02671    char FS_name[200];
02672         SUMA_FreeSurfer_struct *FS;
02673         
02674    /* initialize Main function name for verbose output */
02675    sprintf (FuncName,"SUMA_FreeSurfer-Main-");
02676    
02677         /* allocate space for CommonFields structure */
02678         SUMAg_CF = SUMA_Create_CommonFields ();
02679         if (SUMAg_CF == NULL) {
02680                 fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_Create_CommonFields\n", FuncName);
02681                 exit(1);
02682         }
02683         
02684         /* Allocate for FS */
02685         FS = (SUMA_FreeSurfer_struct *) SUMA_malloc(sizeof(SUMA_FreeSurfer_struct));    
02686         if (FS == NULL) {
02687                 fprintf(SUMA_STDERR,"Error %s: Failed to allocate for FS\n", FuncName);
02688                 exit(1);
02689         }
02690    
02691    if (argc < 2)
02692        {
02693           usage_SUMA_FreeSurfer_Main ();
02694           exit (1);
02695        }
02696    
02697         sprintf(FS_name, "%s", argv[1]);
02698    
02699    if (!SUMA_isExtension(FS_name, ".asc")) {
02700            if (!SUMA_FreeSurfer_ReadBin_eng (FS_name, FS, 0)) {
02701                    fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_FreeSurferBin_Read\n", FuncName);
02702                    exit(1);
02703            }
02704    }else {
02705       if (!SUMA_FreeSurfer_Read_eng (FS_name, FS, 0)) {
02706                    fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_FreeSurfer_Read\n", FuncName);
02707                    exit(1);
02708            }
02709    }
02710         
02711         
02712         SUMA_Show_FreeSurfer (FS, NULL);
02713         fprintf(stdout, "freeing ..\n");
02714         if (!SUMA_Free_FreeSurfer (FS)) {
02715                 fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_Free_FreeSurfer.\n", FuncName);
02716                 exit(1);
02717         }
02718         
02719         if (!SUMA_Free_CommonFields(SUMAg_CF)) SUMA_error_message(FuncName,"SUMAg_CF Cleanup Failed!",1);
02720 
02721         return (0);
02722 }/* Main */
02723 #endif
02724 
02725 /*** Code to read ply format data 
02726 Ply functions are based on code by Greg Turk. 
02727 ---------------------------------------------------------------
02728 
02729 Copyright (c) 1994 The Board of Trustees of The Leland Stanford
02730 Junior University.  All rights reserved.   
02731   
02732 Permission to use, copy, modify and distribute this software and its   
02733 documentation for any purpose is hereby granted without fee, provided   
02734 that the above copyright notice and this permission notice appear in   
02735 all copies of this software and that you do not sell the software.   
02736   
02737 THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,   
02738 EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY   
02739 WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.   
02740 
02741 
02742 */
02743 
02744 /* user's vertex and face definitions for a polygonal object */
02745 
02746 typedef struct Vertex {
02747   float x,y,z;             /* the usual 3-space position of a vertex */
02748 } Vertex;
02749 
02750 typedef struct Face {
02751   unsigned char intensity; /* this user attaches intensity to faces */
02752   unsigned char nverts;    /* number of vertex indices in list */
02753   int *verts;              /* vertex index list */
02754 } Face;
02755 
02756 /* information needed to describe the user's data to the PLY routines */
02757 
02758 PlyProperty vert_props[] = { /* list of property information for a vertex */
02759   {"x", PLY_FLOAT, PLY_FLOAT, offsetof(Vertex,x), 0, 0, 0, 0},
02760   {"y", PLY_FLOAT, PLY_FLOAT, offsetof(Vertex,y), 0, 0, 0, 0},
02761   {"z", PLY_FLOAT, PLY_FLOAT, offsetof(Vertex,z), 0, 0, 0, 0},
02762 };
02763 
02764 PlyProperty face_props[] = { /* list of property information for a vertex */
02765   {"intensity", PLY_UCHAR, PLY_UCHAR, offsetof(Face,intensity), 0, 0, 0, 0},
02766   {"vertex_indices", PLY_INT, PLY_INT, offsetof(Face,verts),
02767    1, PLY_UCHAR, PLY_UCHAR, offsetof(Face,nverts)},
02768 };
02769 
02770 
02771 /*!
02772    \brief Reads a Ply formatted file into a SUMA_SurfaceObject structure
02773    ans = SUMA_Ply_Read (f_name, SO);
02774    
02775    \param f_name (char *) name (and path) of .ply file to read. Extension .ply is optional
02776    \param SO (SUMA_SurfaceObject *) pointer to a structure to return surface in f_name in
02777    \return ans (SUMA_Boolean) YUP/NOPE
02778    
02779    The following fields are set in SO:
02780    SO->NodeDim
02781    SO->FaceSetDim
02782    SO->NodeList
02783    SO->FaceSetList
02784    SO->N_Node;
02785    SO->N_FaceSet;
02786    SO->Name;
02787    SO->FileType;
02788    SO->FileFormat
02789    
02790    \sa SUMA_Ply_Write()
02791    
02792    This function is a wrap around code by Greg Turk. 
02793    
02794 */
02795 SUMA_Boolean SUMA_Ply_Read (char * f_name, SUMA_SurfaceObject *SO) 
02796 {
02797    static char FuncName[]={"SUMA_Ply_Read"};
02798    int i,j,k, j3, ji;
02799    PlyFile *ply = NULL;
02800    int nelems;
02801    char **elist = NULL;
02802    int file_type;
02803    float version;
02804    int nprops;
02805    int num_elems;
02806    PlyProperty **plist = NULL;
02807    Vertex **vlist = NULL;
02808    Face **flist = NULL;
02809    char *elem_name;
02810    int num_comments;
02811    char **comments = NULL;
02812    int num_obj_info;
02813    char **obj_info = NULL;
02814    SUMA_Boolean LocalHead = NOPE;
02815    
02816    SUMA_ENTRY;
02817 
02818    /* open a PLY file for reading */
02819    ply = ply_open_for_reading(f_name, &nelems, &elist, &file_type, &version);
02820    if (!ply) {
02821       fprintf (SUMA_STDERR, "Error %s: Failed to find/read %s.\n", FuncName, f_name);
02822       SUMA_RETURN (NOPE);
02823    }
02824    
02825    /* print what we found out about the file */
02826    if (LocalHead) fprintf (SUMA_STDERR, "%s: version %f\n", FuncName, version);
02827    if (LocalHead) fprintf (SUMA_STDERR, "%s: type %d\n", FuncName, file_type);
02828 
02829    /* go through each kind of element that we learned is in the file */
02830    /* and read them */
02831 
02832    for (i = 0; i < nelems; i++) {
02833 
02834     /* get the description of the first element */
02835     elem_name = elist[i];
02836     plist = ply_get_element_description (ply, elem_name, &num_elems, &nprops);
02837 
02838     /* print the name of the element, for debugging */
02839     if (LocalHead) fprintf (SUMA_STDERR, "%s: element %s %d\n", FuncName, elem_name, num_elems);
02840 
02841     /* if we're on vertex elements, read them in */
02842     if (equal_strings ("vertex", elem_name)) {
02843 
02844       /* create a vertex list to hold all the vertices */
02845       #ifdef USE_PLY_VERTEX
02846       vlist = (Vertex **) SUMA_malloc (sizeof (Vertex *) * num_elems);
02847       #endif
02848       
02849       SO->NodeList = (float *) SUMA_calloc (3*num_elems, sizeof(float));
02850       if (!SO->NodeList) {
02851          fprintf (SUMA_STDERR, "Error %s: Failed to allocate for SO->NodeList.\n", FuncName);
02852          SUMA_RETURN(NOPE);
02853       }
02854       
02855       /* set up for getting vertex elements */
02856 
02857       ply_get_property (ply, elem_name, &vert_props[0]);
02858       ply_get_property (ply, elem_name, &vert_props[1]);
02859       ply_get_property (ply, elem_name, &vert_props[2]);
02860       
02861       SO->NodeDim = 3;
02862       SO->N_Node = num_elems;
02863       /* grab all the vertex elements */
02864       for (j = 0; j < num_elems; j++) {
02865 
02866         /* grab and element from the file */
02867         #ifdef USE_PLY_VERTEX
02868         //vlist[j] = (Vertex *) SUMA_malloc (sizeof (Vertex));
02869         //ply_get_element (ply, (void *) vlist[j]);
02870         /* print out vertex x,y,z for debugging */
02871         if (LocalHead) fprintf (SUMA_STDERR, "%s vertex: %g %g %g\n", FuncName, vlist[j]->x, vlist[j]->y, vlist[j]->z);
02872         /* copy to NodeList */
02873         j3 = SO->NodeDim*j;
02874         SO->NodeList[j3] = vlist[j]->x;
02875         SO->NodeList[j3+1] = vlist[j]->y;
02876         SO->NodeList[j3+2] = vlist[j]->z;
02877         
02878         #else
02879         j3 = SO->NodeDim*j;
02880         ply_get_element (ply, (void *) &(SO->NodeList[j3]));
02881         /* print out vertex x,y,z for debugging */
02882         if (LocalHead) fprintf (SUMA_STDERR, "%s vertex: %g %g %g\n", FuncName, 
02883          SO->NodeList[j3], SO->NodeList[j3+1], SO->NodeList[j3+2]);
02884         #endif
02885          
02886       }
02887     }
02888 
02889     /* if we're on face elements, read them in */
02890     if (equal_strings ("face", elem_name)) {
02891 
02892       /* create a list to hold all the face elements */
02893       flist = (Face **) SUMA_malloc (sizeof (Face *) * num_elems);
02894 
02895       /* set up for getting face elements */
02896 
02897       ply_get_property (ply, elem_name, &face_props[0]);
02898       ply_get_property (ply, elem_name, &face_props[1]);
02899 
02900       /* grab all the face elements */
02901       for (j = 0; j < num_elems; j++) {
02902 
02903         /* grab and element from the file */
02904         flist[j] = (Face *) SUMA_malloc (sizeof (Face));
02905         ply_get_element (ply, (void *) flist[j]);
02906 
02907         /* print out face info, for debugging */
02908         if (LocalHead) {
02909          fprintf (SUMA_STDERR,"%s face: %d, list = ", FuncName, flist[j]->intensity);
02910          for (k = 0; k < flist[j]->nverts; k++)
02911             fprintf (SUMA_STDERR,"%d ", flist[j]->verts[k]);
02912          fprintf (SUMA_STDERR,"\n");
02913         }
02914         
02915       }
02916       /* copy face elements to SO structure */
02917       SO->FaceSetDim = flist[0]->nverts;
02918       SO->N_FaceSet = num_elems;
02919       SO->FaceSetList = (int *) SUMA_calloc (SO->FaceSetDim * num_elems, sizeof(int));
02920       if (!SO->FaceSetList) {
02921          fprintf (SUMA_STDERR, "Error %s: Failed to allocate for SO->NodeList.\n", FuncName);
02922          if (SO->NodeList) SUMA_free(SO->NodeList); 
02923          SUMA_RETURN(NOPE);
02924       }
02925       
02926       for (j = 0; j < num_elems; j++) {
02927          if (flist[j]->nverts != SO->FaceSetDim) {
02928             fprintf (SUMA_STDERR, "Error %s: All FaceSets must have the same dimension for SUMA.\n", FuncName);
02929             if (SO->NodeList) SUMA_free(SO->NodeList); 
02930             if (SO->FaceSetList) SUMA_free(SO->FaceSetList);
02931             SO->NodeList = NULL;
02932             SO->FaceSetList = NULL;
02933             SUMA_RETURN(NOPE);
02934          }
02935          ji = SO->FaceSetDim * j;
02936          for (k = 0; k < flist[j]->nverts; k++)
02937             SO->FaceSetList[ji+k] = flist[j]->verts[k];
02938       }
02939     }
02940 
02941    /* fill up a few more fields */
02942    SO->FileType = SUMA_PLY;
02943    if (file_type == PLY_ASCII) SO->FileFormat = SUMA_ASCII;
02944       else if (file_type == PLY_BINARY_BE) SO->FileFormat = SUMA_BINARY_BE;
02945          else if (file_type == PLY_BINARY_LE) SO->FileFormat = SUMA_BINARY_LE;
02946             else {
02947                fprintf (SUMA_STDERR, "Error %s: PLY_TYPE %d not recognized.\n", FuncName, file_type);
02948             }
02949             
02950    SO->Name = SUMA_StripPath(f_name);
02951    
02952    /* print out the properties we got, for debugging */
02953       if (LocalHead) {
02954          for (j = 0; j < nprops; j++)
02955             fprintf (SUMA_STDERR, "%s property %s\n", FuncName, plist[j]->name);
02956       }
02957    }
02958 
02959    /* grab and print out the comments in the file */
02960    comments = ply_get_comments (ply, &num_comments);
02961    if (LocalHead) {   
02962       for (i = 0; i < num_comments; i++)
02963          fprintf (SUMA_STDERR, "%s comment = '%s'\n", FuncName, comments[i]);
02964    }
02965    
02966    /* grab and print out the object information */
02967    obj_info = ply_get_obj_info (ply, &num_obj_info);
02968    if (LocalHead) {   
02969       for (i = 0; i < num_obj_info; i++)
02970          fprintf (SUMA_STDERR, "%s obj_info = '%s'\n", FuncName, obj_info[i]);
02971    }
02972    
02973    /* free the allocations necessary for vertex and facesetlists */
02974    for (j = 0; j < SO->N_FaceSet; j++) {
02975       SUMA_free(flist[j]);
02976    }
02977    SUMA_free(flist); flist = NULL;
02978    
02979    #ifdef USE_PLY_VERTEX
02980    for (j = 0; j < SO->N_Node; j++) {
02981       SUMA_free(vlist[j]);
02982    }
02983    SUMA_free(vlist); vlist = NULL;
02984    #endif
02985    /* close the PLY file, ply structure is freed within*/
02986    ply_close (ply);
02987    
02988    /* free plist */
02989    for (j = 0; j < nprops; j++) if (plist[j]) SUMA_free (plist[j]);
02990    if (plist) SUMA_free(plist);
02991    
02992    /* free comments */
02993    for (i = 0; i < num_comments; i++) if (comments[i]) SUMA_free (comments[i]);
02994    if (comments) SUMA_free (comments);
02995    
02996    /* free elist */
02997    for (i = 0; i < nelems; i++) if (elist[i]) SUMA_free (elist[i]);
02998    if (elist) SUMA_free (elist);
02999    
03000    /* free obj_info */
03001    for (i = 0; i < num_obj_info; i++) if (obj_info[i]) SUMA_free (obj_info[i]);
03002    if (obj_info) SUMA_free (obj_info);
03003     
03004    SUMA_RETURN(YUP);
03005 }
03006 
03007 /*!
03008    \brief Writes an SO into a .ply file
03009    ans = SUMA_Ply_Write (f_name, SO);
03010    \param f_name (char *) name of .ply file. if .ply is not attached it will be added.
03011    \param SO (SUMA_SurfaceObject *) Surface object to write out. 
03012       if SO->FileFormat = SUMA_BINARY_BE or SUMA_BINARY_LE the surface is written in binary ply format.
03013       SUMA_BINARY is set to SUMA_BINARY_BE
03014    \return ans (SUMA_Boolean) success flag.
03015    
03016    In its current incarnation, the function does not overwrite a pre-existing file.
03017       
03018 */ 
03019 SUMA_Boolean SUMA_Ply_Write (char * f_name_in, SUMA_SurfaceObject *SO) 
03020 {
03021    static char FuncName[]={"SUMA_Ply_Write"};
03022    int i,j;
03023    PlyFile *ply = NULL;
03024    int nelems;
03025    int file_type;
03026    float version;
03027    int nverts ;
03028    int nfaces ;
03029    char *f_name, *f_name2, *elem_names[] = { "vertex", "face" };/* list of the kinds of elements in the user's object */
03030    int n_elem_names = 2;
03031    Vertex **verts = NULL;
03032    Face *faces = NULL;
03033    SUMA_Boolean LocalHead = NOPE;
03034    
03035    SUMA_ENTRY;
03036    
03037    if (!f_name_in) {
03038       fprintf (SUMA_STDERR, "Error %s: NULL filename\n", FuncName);
03039       SUMA_RETURN (NOPE);
03040    }
03041    
03042    f_name = SUMA_Extension(f_name_in,".ply" , YUP); 
03043    f_name2  = SUMA_append_string(f_name,".ply");
03044    if (SUMA_filexists (f_name2)) {
03045       fprintf (SUMA_STDERR, "Error %s: file %s exists, will not overwrite.\n", FuncName, f_name2);
03046       SUMA_free(f_name2);f_name2 = NULL;
03047       SUMA_free(f_name);f_name = NULL;
03048       SUMA_RETURN (NOPE);
03049    }
03050    SUMA_free(f_name2); f_name2 = NULL;
03051       
03052    nverts = SO->N_Node;
03053    nfaces = SO->N_FaceSet;
03054    
03055    /* must have XYZ */
03056    if (SO->NodeDim != 3) {
03057       fprintf (SUMA_STDERR, "Error %s: SO->NodeDim != 3.\n", FuncName);
03058       SUMA_RETURN (NOPE);
03059    }
03060 
03061    /* create the object in ply format */
03062    verts = (Vertex **) SUMA_malloc (nverts*sizeof(Vertex *));
03063    faces = (Face *) SUMA_malloc (nfaces*sizeof(Face));
03064    if (!verts || !faces) {
03065       fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
03066       if (verts) SUMA_free(verts);
03067       if (faces) SUMA_free(faces);
03068       SUMA_RETURN (NOPE);
03069    }
03070 
03071    for (i = 0; i < nfaces; i++) {
03072       faces[i].intensity = '\001';
03073       faces[i].nverts = SO->FaceSetDim;
03074       faces[i].verts = &(SO->FaceSetList[SO->FaceSetDim*i]);
03075    }
03076    
03077    /* open either a binary or ascii PLY file for writing */
03078    /* (the file will be called "test.ply" because the routines */
03079    /*  enforce the .ply filename extension) */
03080 
03081    switch (SO->FileFormat) {
03082       case SUMA_BINARY_BE:
03083          ply = ply_open_for_writing(f_name, n_elem_names, elem_names, PLY_BINARY_BE, &version);
03084          break;
03085       
03086       case SUMA_BINARY_LE:
03087          ply = ply_open_for_writing(f_name, n_elem_names, elem_names, PLY_BINARY_LE, &version);
03088          break;
03089       
03090       case SUMA_ASCII:
03091          ply = ply_open_for_writing(f_name, n_elem_names, elem_names, PLY_ASCII, &version);
03092          break;
03093       
03094       case SUMA_BINARY:
03095          ply = ply_open_for_writing(f_name, n_elem_names, elem_names, PLY_BINARY_BE, &version);
03096          break;
03097       
03098       case SUMA_FF_NOT_SPECIFIED:
03099          ply = ply_open_for_writing(f_name, n_elem_names, elem_names, PLY_ASCII, &version);
03100          break;      
03101       
03102       default:
03103          fprintf (SUMA_STDERR, "Error %s: %d Unrecognized file format.\n", FuncName, SO->FileFormat);
03104          SUMA_RETURN (NOPE);
03105          break;  
03106    }
03107 
03108    if (!ply) {
03109       fprintf (SUMA_STDERR,"Error %s: Failed to create %s.ply\n", FuncName, f_name);
03110       if (verts) SUMA_free(verts);
03111       if (faces) SUMA_free(faces);
03112       SUMA_RETURN (NOPE);
03113    }
03114    /* describe what properties go into the vertex and face elements */
03115 
03116    ply_element_count (ply, "vertex", nverts);
03117    ply_describe_property (ply, "vertex", &vert_props[0]);
03118    ply_describe_property (ply, "vertex", &vert_props[1]);
03119    ply_describe_property (ply, "vertex", &vert_props[2]);
03120 
03121    ply_element_count (ply, "face", nfaces);
03122    ply_describe_property (ply, "face", &face_props[0]);
03123    ply_describe_property (ply, "face", &face_props[1]);
03124 
03125    /* write a comment and an object information field */
03126    ply_put_comment (ply, "author: Greg Turk");
03127    ply_put_obj_info (ply, "random information");
03128 
03129    /* we have described exactly what we will put in the file, so */
03130    /* we are now done with the header info */
03131    ply_header_complete (ply);
03132 
03133    /* set up and write the vertex elements */
03134    ply_put_element_setup (ply, "vertex");
03135    for (i = 0; i < nverts; i++)
03136     ply_put_element (ply, (void *) &(SO->NodeList[SO->NodeDim*i]));
03137 
03138    /* set up and write the face elements */
03139    ply_put_element_setup (ply, "face");
03140    for (i = 0; i < nfaces; i++)
03141     ply_put_element (ply, (void *) &faces[i]);
03142 
03143    /* close the PLY file */
03144    ply_close (ply);
03145 
03146    /* free */
03147    if (verts) SUMA_free(verts);
03148    if (faces) SUMA_free(faces);
03149    if (f_name) SUMA_free(f_name);
03150    SUMA_RETURN (YUP);
03151 }
03152 
03153 
03154 /*! 
03155    \brief Function to write a surface object to a FreeSurfer .asc file format
03156    ans = SUMA_Boolean SUMA_FS_Write (fileNm, SO, firstLine);
03157    \param  fileNm (char *) name (and path) of file.
03158    \param  SO (SUMA_SurfaceObject *) Surface Object
03159    \param firstLine (char *) string to place as comment (begins with #) in fileNm
03160    \return YUP/NOPE
03161    
03162    
03163    The function will not overwrite pre-existing.
03164    Written by Brenna Bargall
03165 */
03166 SUMA_Boolean SUMA_FS_Write (char *fileNm, SUMA_SurfaceObject *SO, char *firstLine) 
03167 {
03168    static char FuncName[]={"SUMA_FS_Write"};
03169    int i, j;
03170    FILE *outFile = NULL;
03171    
03172    SUMA_ENTRY;
03173    
03174    if (SUMA_filexists(fileNm)) {
03175       fprintf (SUMA_STDERR, "Error %s: file %s exists, will not overwrite.\n",FuncName, fileNm);
03176       SUMA_RETURN (NOPE);
03177    }
03178    
03179    if (SO->NodeDim != 3 || SO->FaceSetDim != 3) {
03180       fprintf (SUMA_STDERR, "Error %s: Must have NodeDim and FaceSetDim = 3.\n",FuncName);
03181       SUMA_RETURN (NOPE);
03182    }
03183 
03184    outFile = fopen(fileNm, "w");
03185    if (!outFile) {
03186       fprintf (SUMA_STDERR, "Error %s: Failed in opening %s for writing.\n",FuncName, fileNm);
03187       SUMA_RETURN (NOPE);
03188    } 
03189    
03190    fprintf (outFile,"#%s\n", firstLine);
03191    fprintf (outFile, "%d %d\n", SO->N_Node, SO->N_FaceSet);
03192 
03193    j=0;
03194    for (i=0; i<SO->N_Node; ++i) {
03195       j=SO->NodeDim * i;
03196       fprintf (outFile, "%f  %f  %f  0\n", SO->NodeList[j], SO->NodeList[j+1], SO->NodeList[j+2]);
03197    }
03198 
03199    j=0;
03200    for (i=0; i<SO->N_FaceSet; ++i) {
03201       j = SO->FaceSetDim * i;
03202       fprintf (outFile, "%d %d %d 0\n", SO->FaceSetList[j], SO->FaceSetList[j+1], SO->FaceSetList[j+2]);
03203    }
03204     
03205    
03206    fclose(outFile);
03207 
03208    SUMA_RETURN (YUP);
03209    
03210 }
03211 
03212 /*!
03213    \brief writes the NodeList and FaceSetList of SO to 2 ascii files
03214    ans = SUMA_Boolean SUMA_VEC_Write (SUMA_SFname *Fname, SUMA_SurfaceObject *SO);
03215    \param  Fname (SUMA_SFname *) uses the SureFit filename structure to store
03216                                  the names (and paths) of the NodeList (name_coord)
03217                                  and the FaceSetList (name_topo) files.
03218                                  if (strlen(name_coord) == 0) no coord is written
03219                                  if (strlen(name_topo) == 0) no topo is written
03220    \param SO (SUMA_SurfaceObject *) pointer to SO structure.
03221    \return YUP/NOPE
03222    
03223    \sa SUMA_VEC_Read
03224    The function will not overwrite pre-existing files.
03225    
03226 */
03227 SUMA_Boolean SUMA_VEC_Write (SUMA_SFname *Fname, SUMA_SurfaceObject *SO)
03228 {
03229    
03230    static char FuncName[]={"SUMA_VEC_Write"};
03231    int i, j;
03232    FILE *outFile = NULL;
03233    
03234    SUMA_ENTRY;
03235 
03236    if (strlen(Fname->name_coord)) {
03237       if (SUMA_filexists(Fname->name_coord)) {
03238          fprintf (SUMA_STDERR, "Error %s: file %s exists, will not overwrite.\n",FuncName, Fname->name_coord);
03239          SUMA_RETURN (NOPE);
03240       }
03241    }
03242    if (strlen(Fname->name_topo)) {
03243       if (SUMA_filexists(Fname->name_topo)) {
03244          fprintf (SUMA_STDERR, "Error %s: file %s exists, will not overwrite.\n",FuncName, Fname->name_topo);
03245          SUMA_RETURN (NOPE);
03246       }
03247    }
03248    if (SO->NodeDim != 3 || SO->FaceSetDim != 3) {
03249       fprintf (SUMA_STDERR, "Error %s: Must have NodeDim and FaceSetDim = 3.\n",FuncName);
03250       SUMA_RETURN (NOPE);
03251    }
03252    
03253    if (strlen(Fname->name_coord)) {
03254       outFile = fopen(Fname->name_coord, "w");
03255       if (!outFile) {
03256          fprintf (SUMA_STDERR, "Error %s: Failed in opening %s for writing.\n",FuncName, Fname->name_coord);
03257          SUMA_RETURN (NOPE);
03258       }
03259 
03260       j=0;
03261       for (i=0; i<SO->N_Node; ++i) {
03262          j=SO->NodeDim * i;
03263          fprintf (outFile, "%f  %f  %f \n", SO->NodeList[j], SO->NodeList[j+1], SO->NodeList[j+2]);
03264       }
03265 
03266       fclose (outFile);
03267    }
03268    
03269    if (strlen(Fname->name_topo)) {   
03270       outFile = fopen(Fname->name_topo, "w");
03271       if (!outFile) {
03272          fprintf (SUMA_STDERR, "Error %s: Failed in opening %s for writing.\n",FuncName, Fname->name_topo);
03273          SUMA_RETURN (NOPE);
03274       }
03275       j=0;
03276       for (i=0; i<SO->N_FaceSet; ++i) {
03277          j = SO->FaceSetDim * i;
03278          fprintf (outFile, "%d %d %d\n", SO->FaceSetList[j], SO->FaceSetList[j+1], SO->FaceSetList[j+2]);
03279       }
03280 
03281       fclose (outFile);
03282    }
03283    
03284    SUMA_RETURN (YUP);
03285 
03286 }
03287 
03288 /*!
03289    \brief function to read 1D (vec) format surfaces
03290    \sa SUMA_VEC_Write
03291 */
03292 SUMA_Boolean SUMA_VEC_Read(SUMA_SFname *Fname, SUMA_SurfaceObject *SO)
03293 {
03294    static char FuncName[]={"SUMA_VEC_Read"};
03295    MRI_IMAGE *im = NULL;
03296    float *far=NULL;
03297    int icnt;
03298    SUMA_Boolean LocalHead = NOPE;
03299    
03300    SUMA_ENTRY;
03301 
03302    if (!SO || !Fname) {
03303       SUMA_SL_Err("NULL input");
03304       SUMA_RETURN(NOPE);
03305    }
03306    if (SO->NodeList || SO->FaceSetList) {
03307       SUMA_SL_Err("Non NULL SO->NodeList || SO->FaceSetList");
03308       SUMA_RETURN(NOPE);   
03309    }
03310 
03311    im = mri_read_1D (Fname->name_coord);
03312    if (!im) {
03313       SUMA_SLP_Err("Failed to read 1D file");
03314       SUMA_RETURN(NOPE);
03315    }
03316    far = MRI_FLOAT_PTR(im);
03317    SO->N_Node = im->nx;
03318    SO->NodeDim = im->ny;
03319    if (!SO->N_Node) {
03320       SUMA_SL_Err("Empty file");
03321       SUMA_RETURN(NOPE);
03322    }
03323    if (SO->NodeDim !=  3 ) {
03324       SUMA_SL_Err("File must have\n"
03325                   "3 columns.");
03326       mri_free(im); im = NULL;   /* done with that baby */
03327       SUMA_RETURN(NOPE);
03328    }
03329 
03330    SO->NodeList = (float *)SUMA_calloc (SO->N_Node*SO->NodeDim, sizeof(float));
03331    if (!SO->NodeList) {
03332       fprintf(SUMA_STDERR,"Error %s: Failed to allocate for NodeList.\n", FuncName);
03333       if (SO->NodeList) SUMA_free(SO->NodeList);
03334       if (SO->FaceSetList) SUMA_free(SO->FaceSetList);
03335       SUMA_RETURN (NOPE);
03336    }
03337 
03338    for (icnt=0; icnt < SO->N_Node; ++icnt) {
03339       SO->NodeList[3*icnt] = far[icnt];
03340       SO->NodeList[3*icnt+1] = far[icnt+SO->N_Node];
03341       SO->NodeList[3*icnt+2] = far[icnt+2*SO->N_Node];
03342    }   
03343    if (LocalHead) {
03344       fprintf (SUMA_STDERR,"%s: SO->NodeList\n Node 0: %f, %f, %f \n Node %d: %f, %f, %f \n",
03345          FuncName,
03346          SO->NodeList[0], SO->NodeList[1], SO->NodeList[2], SO->N_Node -1, 
03347          SO->NodeList[3*(SO->N_Node-1)], SO->NodeList[3*(SO->N_Node-1)+1], SO->NodeList[3*(SO->N_Node-1)+2]);
03348    }
03349    mri_free(im); im = NULL;
03350 
03351    im = mri_read_1D (Fname->name_topo);
03352    if (!im) {
03353       SUMA_SL_Err("Failed to read 1D file");
03354       SUMA_RETURN(NOPE);
03355    }
03356    far = MRI_FLOAT_PTR(im);
03357    SO->N_FaceSet = im->nx;
03358    SO->FaceSetDim = im->ny;
03359    if (!SO->N_FaceSet) {
03360       SUMA_SL_Err("Empty file");
03361       SUMA_RETURN(NOPE);
03362    }
03363    if (SO->FaceSetDim !=  3 ) {
03364       SUMA_SL_Err("File must have\n"
03365                   "3 columns.");
03366       mri_free(im); im = NULL;   /* done with that baby */
03367       SUMA_RETURN(NOPE);
03368    }
03369 
03370    SO->FaceSetList = (int *)SUMA_calloc (SO->N_FaceSet*SO->FaceSetDim, sizeof(int));
03371    if (!SO->FaceSetList) {
03372       fprintf(SUMA_STDERR,"Error %s: Failed to allocate for FaceSetList.\n", FuncName);
03373       if (SO->NodeList) SUMA_free(SO->NodeList);
03374       if (SO->FaceSetList) SUMA_free(SO->FaceSetList);
03375       SUMA_RETURN (NOPE);
03376    }
03377 
03378    for (icnt=0; icnt < SO->N_FaceSet; ++icnt) {
03379       SO->FaceSetList[3*icnt] = (int)far[icnt];
03380       SO->FaceSetList[3*icnt+1] = (int)far[icnt+SO->N_FaceSet];
03381       SO->FaceSetList[3*icnt+2] = (int)far[icnt+2*SO->N_FaceSet];
03382    }   
03383 
03384    if (LocalHead) {
03385       fprintf (SUMA_STDERR,"%s: SO->FaceSetList\n Node 0: %d, %d, %d \n Node %d: %d, %d, %d \n",
03386          FuncName,
03387          SO->FaceSetList[0], SO->FaceSetList[1], SO->FaceSetList[2], SO->N_FaceSet -1, 
03388          SO->FaceSetList[3*(SO->N_FaceSet-1)], SO->FaceSetList[3*(SO->N_FaceSet-1)+1], SO->FaceSetList[3*(SO->N_FaceSet-1)+2]);
03389    } 
03390    mri_free(im); im = NULL;
03391 
03392    SUMA_RETURN(YUP);
03393 }
03394 
03395 /*!
03396    \brief A function to write a Surface Object into a Surefit ascii format 
03397    \param F_prefix (char *) Prefix of surace filenames. Output will be of the form:
03398          Prefix.N_NODE.topo
03399          Prefix.N_NODE.coord where N_Node is the number of nodes making up the surface.
03400    \param SO (SUMA_SurfaceObject *) surface object
03401    \return YUP/NOPE
03402    
03403 */
03404 
03405 
03406 #ifdef SUMA_Ply_Read_STAND_ALONE
03407 void usage_SUMA_Ply_Read_Main ()
03408    
03409   {/*Usage*/
03410           printf ("\nUsage:  SUMA_Ply_Read -s f_name \n");
03411           printf ("\t reads in a .ply file and writes it out to copy_f_name.ply\n");
03412           printf ("\t\t Ziad S. Saad SSCC/NIMH/NIH ziad@nih.gov \t Wed Jan  8 13:44:29 EST 2003 \n");
03413           exit (0);
03414   }/*Usage*/
03415    
03416 int main (int argc,char *argv[])
03417 {/* Main */
03418    static char FuncName[]={"SUMA_Ply_Read_Main"}; 
03419         int kar;
03420    char *f_name=NULL, out_f_name[200];
03421    SUMA_SurfaceObject *SO = NULL;
03422    SUMA_Boolean brk;
03423    
03424         /* allocate space for CommonFields structure */
03425         SUMAg_CF = SUMA_Create_CommonFields ();
03426         if (SUMAg_CF == NULL) {
03427                 fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_Create_CommonFields\n", FuncName);
03428                 exit(1);
03429         }
03430    
03431    if (argc < 3)
03432        {
03433           usage_SUMA_Ply_Read_Main ();
03434           exit (1);
03435        }
03436    
03437    kar = 1;
03438         brk = NOPE;
03439         while (kar < argc) { /* loop accross command ine options */
03440                 /*fprintf(stdout, "%s verbose: Parsing command line...\n", FuncName);*/
03441                 if (strcmp(argv[kar], "-h") == 0 || strcmp(argv[kar], "-help") == 0) {
03442                          usage_SUMA_Ply_Read_Main();
03443           exit (1);
03444                 }
03445                 
03446                 if (!brk && (strcmp(argv[kar], "-s") == 0)) {
03447                         kar ++;
03448                         if (kar >= argc)  {
03449                                 fprintf (SUMA_STDERR, "need argument after -s ");
03450                                 exit (1);
03451                         }
03452                         f_name = argv[kar];
03453                         /*fprintf(SUMA_STDOUT, "Found: %s\n", f_name);*/
03454 
03455                         brk = YUP;
03456                 }
03457       
03458       if (!brk) {
03459                         fprintf (SUMA_STDERR,"Error %s: Option %s not understood. Try -help for usage\n", FuncName, argv[kar]);
03460                         exit (1);
03461                 } else {        
03462                         brk = NOPE;
03463                         kar ++;
03464                 }
03465    }
03466    
03467    if (!f_name) {
03468       fprintf (SUMA_STDERR,"Error %s: Missing filename.\n", FuncName);
03469       exit(1);
03470    }
03471    
03472    SO = SUMA_Alloc_SurfObject_Struct(1);   
03473    if (!SUMA_Ply_Read (f_name, SO)) {
03474       fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_Ply_Read.\n", FuncName);
03475       exit (1);
03476    } 
03477    
03478    SO->Label = SUMA_SurfaceFileName (SO, NOPE);
03479    sprintf (out_f_name , "copy_%s", SO->Label);   
03480    fprintf (SUMA_STDERR,"%s: Success apparent. Now writing SO to %s\n", FuncName, out_f_name);
03481    if (!SUMA_Ply_Write (out_f_name, SO)) {
03482       fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_Ply_Write.\n", FuncName);
03483       exit (1);
03484    } 
03485       
03486    SUMA_Free_Surface_Object (SO);
03487    
03488    return (0);
03489  } /* Main */  
03490 #endif
03491 
03492 #ifdef SUMA_ConvertSurface_STAND_ALONE
03493 void usage_SUMA_ConvertSurface (SUMA_GENERIC_ARGV_PARSE *ps)
03494    
03495   {/*Usage*/
03496           static char FuncName[]={"usage_SUMA_ConvertSurface"};
03497           char * s = NULL, *sio=NULL;
03498           
03499           s = SUMA_help_basics();
03500           sio  = SUMA_help_IO_Args(ps);
03501          
03502           printf ("\nUsage:  ConvertSurface <-i_TYPE inSurf> <-o_TYPE outSurf> \n"
03503                   "    [<-sv SurfaceVolume [VolParam for sf surfaces]>] [-tlrc] [-MNI_rai/-MNI_lpi]\n"
03504                   "    reads in a surface and writes it out in another format.\n"
03505                   "    Note: This is a not a general utility conversion program. \n"
03506                   "    Only fields pertinent to SUMA are preserved.\n"
03507                   "%s"
03508 /*                  "    -i_TYPE inSurf specifies the input surface, TYPE is one of the following:\n"
03509                   "       fs: FreeSurfer surface. \n"
03510                   "           If surface name has .asc it is assumed to be\n"
03511                   "           in ASCII format. Otherwise it is assumed to be\n"
03512                   "           in BINARY_BE (Big Endian) format.\n"
03513                   "           Patches in Binary format cannot be read at the moment.\n"
03514                   "       sf: SureFit surface. \n"
03515                   "           You must specify the .coord followed by the .topo file.\n"
03516                   "       vec (or 1d): Simple ascii matrix format. \n"
03517                   "            You must specify the NodeList file followed by the FaceSetList file.\n"
03518                   "            NodeList contains 3 floats per line, representing X Y Z vertex coordinates.\n"
03519                   "            FaceSetList contains 3 ints per line, representing v1 v2 v3 triangle vertices.\n"
03520                   "       ply: PLY format, ascii or binary.\n"
03521                   "            Only vertex and triangulation info is preserved.\n"
03522                   "       bv: BrainVoyager format. \n"
03523                   "           Only vertex and triangulation info is preserved.\n"
03524                   "    -ipar_TYPE ParentSurf specifies the parent surface. Only used\n"
03525                   "            when -o_fsp is used, see below.\n"
03526                   "    -o_TYPE outSurf specifies the output surface, TYPE is one of the following:\n"
03527                   "       fs: FreeSurfer ascii surface. \n"
03528                   "       fsp: FeeSurfer ascii patch surface. \n" 
03529                   "            In addition to outSurf, you need to specify\n"
03530                   "            the name of the parent surface for the patch.\n"
03531                   "            using the -ipar_TYPE option\n"
03532                   "       sf: SureFit surface. \n"
03533                   "           You must specify the .coord followed by the .topo file.\n"
03534                   "       vec (or 1D): Simple ascii matrix format. \n"
03535                   "            see help for vec under -i_TYPE options for format specifications.\n"
03536                   "       ply: PLY format, ascii or binary.\n"
03537                   "    -sv SurfaceVolume [VolParam for sf surfaces]\n"
03538                   "       This option must not come before the -i_TYPE option.\n"
03539                   "       If you supply a surface volume, the coordinates of the input surface.\n"
03540                   "        are modified to SUMA's convention and aligned with SurfaceVolume.\n"
03541                   "        You must also specify a VolParam file for SureFit surfaces.\n" */
03542                   "    -orient_out STR: Output coordinates in STR coordinate system. \n"
03543                   "                      STR is a three character string following AFNI's \n"
03544                   "                      naming convention. The program assumes that the native  \n"
03545                   "                      orientation of the surface is RAI, unless you use the \n"
03546                   "                      -MNI_lpi option. The coordinate transformation is carried \n"
03547                   "                      out last, just before writing the surface to disk.\n"
03548                   "    -make_consistent: Check the consistency of the surface's mesh (triangle\n"
03549                   "                      winding). This option will write out a new surface even \n"
03550                   "                      if the mesh was consistent.\n"
03551                   "                      See SurfQual -help for mesh checks.\n"
03552                   "    -acpc: Apply acpc transform (which must be in acpc version of \n"
03553                   "        SurfaceVolume) to the surface vertex coordinates. \n"
03554                   "        This option must be used with the -sv option.\n"
03555                   "    -tlrc: Apply Talairach transform (which must be a talairach version of \n"
03556                   "        SurfaceVolume) to the surface vertex coordinates. \n"
03557                   "        This option must be used with the -sv option.\n"
03558                   "    -MNI_rai/-MNI_lpi: Apply Andreas Meyer Lindenberg's transform to turn \n"
03559                   "        AFNI tlrc coordinates (RAI) into MNI coord space \n"
03560                   "        in RAI (with -MNI_rai) or LPI (with -MNI_lpi)).\n"
03561                   "        NOTE: -MNI_lpi option has not been tested yet (I have no data\n"
03562                   "        to test it on. Verify alignment with AFNI and please report\n"
03563                   "        any bugs.\n" 
03564                   "        This option can be used without the -tlrc option.\n"
03565                   "        But that assumes that surface nodes are already in\n"
03566                   "        AFNI RAI tlrc coordinates .\n"    
03567                   "   NOTE: The vertex coordinates coordinates of the input surfaces are only\n"
03568                   "         transformed if -sv option is used. If you do transform surfaces, \n"
03569                   "         take care not to load them into SUMA with another -sv option.\n"
03570                   "\n"
03571                   "    Options for applying arbitrary affine transform:\n"
03572                   "    [xyz_new] = [Mr] * [xyz_old - cen] + D + cen\n"
03573                   "    -xmat_1D mat: Apply transformation specified in 1D file mat.1D.\n"
03574                   "                  to the surface's coordinates.\n"
03575                   "                  [mat] = [Mr][D] is of the form:\n"
03576                   "                  r11 r12 r13 D1\n"
03577                   "                  r21 r22 r23 D2\n"
03578                   "                  r31 r32 r33 D3\n"
03579                   "    -xcenter x y z: Use vector cen = [x y z]' for rotation center.\n"
03580                   "                    Default is cen = [0 0 0]'\n"
03581                   "%s\n"
03582                   , sio, s); SUMA_free(sio); sio = NULL; SUMA_free(s); s = NULL; 
03583           s = SUMA_New_Additions(0, 1); printf("%s\n", s);SUMA_free(s); s = NULL; 
03584           printf ("\t\t Ziad S. Saad SSCC/NIMH/NIH ziad@nih.gov \t Wed Jan  8 13:44:29 EST 2003 \n");
03585           exit (0);
03586   }/*Usage*/
03587    
03588 int main (int argc,char *argv[])
03589 {/* Main */
03590    static char FuncName[]={"ConvertSurface"}; 
03591         int kar, volexists, i;
03592    float xcen[3], M[3][4];
03593    char  *if_name = NULL, *of_name = NULL, *if_name2 = NULL, 
03594          *of_name2 = NULL, *sv_name = NULL, *vp_name = NULL,
03595          *OF_name = NULL, *OF_name2 = NULL, *tlrc_name = NULL,
03596          *acpc_name=NULL, *xmat_name = NULL, *ifpar_name = NULL, *ifpar_name2 = NULL;
03597    SUMA_SO_File_Type iType = SUMA_FT_NOT_SPECIFIED, iparType = SUMA_FT_NOT_SPECIFIED,
03598                      oType = SUMA_FT_NOT_SPECIFIED;
03599    SUMA_SO_File_Format iForm = SUMA_FF_NOT_SPECIFIED, iparForm = SUMA_FF_NOT_SPECIFIED;
03600    SUMA_SurfaceObject *SO = NULL, *SOpar = NULL, *SOsurf = NULL;
03601    SUMA_PARSED_NAME *of_name_strip = NULL, *of_name2_strip = NULL;
03602    SUMA_SFname *SF_name = NULL;
03603    void *SO_name = NULL;
03604    char orsurf[3], orcode[3];
03605    THD_warp *warp=NULL ;
03606    THD_3dim_dataset *aset=NULL;
03607    SUMA_Boolean brk, Do_tlrc, Do_mni_RAI, Do_mni_LPI, Do_acpc, Docen, Doxmat, Do_wind, onemore;
03608    SUMA_GENERIC_ARGV_PARSE *ps=NULL;
03609    SUMA_Boolean exists;
03610    SUMA_Boolean LocalHead = NOPE;
03611    
03612         SUMA_mainENTRY;
03613    SUMA_STANDALONE_INIT;
03614         
03615    /* Allocate space for DO structure */
03616         SUMAg_DOv = SUMA_Alloc_DisplayObject_Struct (SUMA_MAX_DISPLAYABLE_OBJECTS);
03617    ps = SUMA_Parse_IO_Args(argc, argv, "-o;-i;-sv;-ipar;");
03618    
03619    if (argc < 4)
03620        {
03621           usage_SUMA_ConvertSurface (ps);
03622           exit (1);
03623        }
03624    
03625    
03626    kar = 1;
03627    xmat_name = NULL;
03628    xcen[0] = 0.0; xcen[1] = 0.0; xcen[2] = 0.0;
03629         brk = NOPE;
03630    orcode[0] = '\0'; 
03631    sprintf(orsurf,"RAI");
03632    Docen = NOPE;
03633    Doxmat = NOPE;
03634    Do_tlrc = NOPE;
03635    Do_mni_RAI = NOPE;
03636    Do_mni_LPI = NOPE;
03637    Do_acpc = NOPE;
03638    Do_wind = NOPE;
03639    onemore = NOPE;
03640         while (kar < argc) { /* loop accross command ine options */
03641                 /*fprintf(stdout, "%s verbose: Parsing command line...\n", FuncName);*/
03642                 if (strcmp(argv[kar], "-h") == 0 || strcmp(argv[kar], "-help") == 0) {
03643                          usage_SUMA_ConvertSurface(ps);
03644           exit (0);
03645                 }
03646                 
03647       SUMA_SKIP_COMMON_OPTIONS(brk, kar);
03648       
03649       SUMA_TO_LOWER(argv[kar]);
03650                 
03651       #if 0
03652       if (!brk && (strcmp(argv[kar], "-i_bv") == 0)) {
03653          kar ++;
03654                         if (kar >= argc)  {
03655                                 fprintf (SUMA_STDERR, "need argument after -i_bv\n ");
03656                                 exit (1);
03657                         }
03658                         if_name = argv[kar];
03659          iType = SUMA_BRAIN_VOYAGER;
03660          iForm = SUMA_BINARY;
03661                         brk = YUP;
03662                 }
03663       
03664       if (!brk && (strcmp(argv[kar], "-i_fs") == 0)) {
03665          kar ++;
03666                         if (kar >= argc)  {
03667                                 fprintf (SUMA_STDERR, "need argument after -i_fs\n ");
03668                                 exit (1);
03669                         }
03670                         if_name = argv[kar];
03671          iType = SUMA_FREE_SURFER;
03672          if (SUMA_isExtension(if_name, ".asc")) 
03673             iparForm = SUMA_ASCII;
03674          else
03675             iparForm = SUMA_BINARY_BE;
03676                         brk = YUP;
03677                 }
03678       
03679       if (!brk && (strcmp(argv[kar], "-i_sf") == 0)) {
03680          kar ++;
03681                         if (kar+1 >= argc)  {
03682                                 fprintf (SUMA_STDERR, "need 2 arguments after -i_sf\n");
03683                                 exit (1);
03684                         }
03685                         if_name = argv[kar]; kar ++;
03686          if_name2 = argv[kar];
03687          iType = SUMA_SUREFIT;
03688          iForm = SUMA_ASCII;
03689                         brk = YUP;
03690                 }
03691       
03692       if (!brk && ( (strcmp(argv[kar], "-i_vec") == 0) || (strcmp(argv[kar], "-i_1d") == 0) ) ) {
03693          kar ++;
03694                         if (kar+1 >= argc)  {
03695                                 fprintf (SUMA_STDERR, "need 2 argument after -i_vec (or -i_1D)\n");
03696                                 exit (1);
03697                         }
03698                         if_name = argv[kar]; kar ++;
03699          if_name2 = argv[kar];
03700          iType = SUMA_VEC;
03701          iForm = SUMA_ASCII;
03702                         brk = YUP;
03703                 }
03704       
03705       if (!brk && (strcmp(argv[kar], "-i_ply") == 0)) {
03706          kar ++;
03707                         if (kar >= argc)  {
03708                                 fprintf (SUMA_STDERR, "need argument after -i_ply \n");
03709                                 exit (1);
03710                         }
03711                         if_name = argv[kar];
03712          iType = SUMA_PLY;
03713          iForm = SUMA_FF_NOT_SPECIFIED;
03714                         brk = YUP;
03715                 }
03716       
03717       if (!brk && (strcmp(argv[kar], "-ipar_bv") == 0)) {
03718          kar ++;
03719                         if (kar >= argc)  {
03720                                 fprintf (SUMA_STDERR, "need argument after -ipar_bv \n");
03721                                 exit (1);
03722                         }
03723                         ifpar_name = argv[kar];
03724          iparType = SUMA_BRAIN_VOYAGER;
03725          iparForm = SUMA_BINARY;
03726                         brk = YUP;
03727                 }
03728       
03729       if (!brk && (strcmp(argv[kar], "-ipar_fs") == 0)) {
03730          kar ++;
03731                         if (kar >= argc)  {
03732                                 fprintf (SUMA_STDERR, "need argument after -ipar_fs \n");
03733                                 exit (1);
03734                         }
03735                         ifpar_name = argv[kar];
03736          iparType = SUMA_FREE_SURFER;
03737          if (SUMA_isExtension(ifpar_name, ".asc")) 
03738             iparForm = SUMA_ASCII;
03739          else
03740             iparForm = SUMA_BINARY_BE;
03741                         brk = YUP;
03742                 }
03743       
03744       if (!brk && (strcmp(argv[kar], "-ipar_sf") == 0)) {
03745          kar ++;
03746                         if (kar+1 >= argc)  {
03747                                 fprintf (SUMA_STDERR, "need 2 arguments after -ipar_sf\n");
03748                                 exit (1);
03749                         }
03750                         ifpar_name = argv[kar]; kar ++;
03751          ifpar_name2 = argv[kar];
03752          iparType = SUMA_SUREFIT;
03753          iparForm = SUMA_ASCII;
03754                         brk = YUP;
03755                 }
03756       
03757       if (!brk && ( (strcmp(argv[kar], "-ipar_vec") == 0) || (strcmp(argv[kar], "-ipar_1d") == 0) ) ) {
03758          kar ++;
03759                         if (kar+1 >= argc)  {
03760                                 fprintf (SUMA_STDERR, "need 2 argument after -ipar_vec (or -ipar_1D)\n");
03761                                 exit (1);
03762                         }
03763                         ifpar_name = argv[kar]; kar ++;
03764          ifpar_name2 = argv[kar];
03765          iparType = SUMA_VEC;
03766          iparForm = SUMA_ASCII;
03767                         brk = YUP;
03768                 }
03769       
03770       if (!brk && (strcmp(argv[kar], "-ipar_ply") == 0)) {
03771          kar ++;
03772                         if (kar >= argc)  {
03773                                 fprintf (SUMA_STDERR, "need argument after -ipar_ply \n");
03774                                 exit (1);
03775                         }
03776                         ifpar_name = argv[kar];
03777          iparType = SUMA_PLY;
03778          iparForm = SUMA_FF_NOT_SPECIFIED;
03779                         brk = YUP;
03780                 }
03781 
03782       if (!brk && (strcmp(argv[kar], "-sv") == 0)) {
03783          if (iType == SUMA_FT_NOT_SPECIFIED) {
03784             fprintf (SUMA_STDERR, " -sv option must be preceeded by -i_TYPE option.\n");
03785             exit(1);
03786          }
03787          kar ++;
03788                         if (iType == SUMA_SUREFIT) {
03789             if (kar+1 >= argc)  {
03790                                    fprintf (SUMA_STDERR, "need 2 argument after -sv (SurfaceVolume and VolumeParent)\n");
03791                                    exit (1);
03792                            }
03793             sv_name = argv[kar]; kar ++;
03794             vp_name = argv[kar];
03795          } else {
03796             if (kar >= argc)  {
03797                                    fprintf (SUMA_STDERR, "need argument after -sv \n");
03798                                    exit (1);
03799                            }
03800                            sv_name = argv[kar];
03801          }
03802                         brk = YUP;
03803                 }
03804       
03805       if (!brk && (strcmp(argv[kar], "-o_fs") == 0)) {
03806          kar ++;
03807                         if (kar >= argc)  {
03808                                 fprintf (SUMA_STDERR, "need argument after -o_fs \n");
03809                                 exit (1);
03810                         }
03811                         of_name = argv[kar];
03812          oType = SUMA_FREE_SURFER;
03813                         brk = YUP;
03814                 }
03815       
03816       if (!brk && (strcmp(argv[kar], "-o_sf") == 0)) {
03817          kar ++;
03818                         if (kar+1 >= argc)  {
03819                                 fprintf (SUMA_STDERR, "need 2 arguments after -o_sf\n");
03820                                 exit (1);
03821                         }
03822                         of_name = argv[kar]; kar ++;
03823          of_name2 = argv[kar];
03824          oType = SUMA_SUREFIT;
03825                         brk = YUP;
03826                 }
03827       
03828       if (!brk && (strcmp(argv[kar], "-o_fsp") == 0)) {
03829          kar ++;
03830                         if (kar >= argc)  {
03831                                 fprintf (SUMA_STDERR, "need 1 argument after -o_fsp\n");
03832                                 exit (1);
03833                         }
03834                         of_name = argv[kar]; 
03835          oType = SUMA_FREE_SURFER_PATCH;
03836                         brk = YUP;
03837                 }
03838       
03839       if (!brk && ( (strcmp(argv[kar], "-o_vec") == 0) || (strcmp(argv[kar], "-o_1d") == 0) ) ) {
03840          kar ++;
03841                         if (kar+1 >= argc)  {
03842                                 fprintf (SUMA_STDERR, "need 2 argument after -o_vec\n");
03843                                 exit (1);
03844                         }
03845                         of_name = argv[kar]; kar ++;
03846          of_name2 = argv[kar];
03847          oType = SUMA_VEC;
03848                         brk = YUP;
03849                 }
03850       
03851       if (!brk && (strcmp(argv[kar], "-o_ply") == 0)) {
03852          kar ++;
03853                         if (kar >= argc)  {
03854                                 fprintf (SUMA_STDERR, "need argument after -o_ply\n");
03855                                 exit (1);
03856                         }
03857                         of_name = argv[kar];
03858          oType = SUMA_PLY;
03859                         brk = YUP;
03860                 }
03861       #endif
03862       
03863       if (!brk && (strcmp(argv[kar], "-xmat_1d") == 0)) {
03864          kar ++;
03865                         if (kar >= argc)  {
03866                                 fprintf (SUMA_STDERR, "need 1 argument after -xmat_1D\n");
03867                                 exit (1);
03868                         }
03869                         xmat_name = argv[kar]; 
03870          Doxmat = YUP;
03871                         brk = YUP;
03872                 }
03873       
03874       if (!brk && (strcmp(argv[kar], "-make_consistent") == 0)) {
03875          Do_wind = YUP;
03876                         brk = YUP;
03877                 }
03878       
03879       if (!brk && (strcmp(argv[kar], "-xcenter") == 0)) {
03880          kar ++;
03881                         if (kar+2>= argc)  {
03882                                 fprintf (SUMA_STDERR, "need 3 arguments after -xcenter\n");
03883                                 exit (1);
03884                         }
03885                         xcen[0] = atof(argv[kar]); ++kar;
03886                         xcen[1] = atof(argv[kar]); ++kar;
03887                         xcen[2] = atof(argv[kar]); 
03888          Docen = YUP;
03889                         brk = YUP;
03890                 }
03891       
03892       if (!brk && (strcmp(argv[kar], "-orient_out") == 0)) {
03893          kar ++;
03894                         if (kar>= argc)  {
03895                                 fprintf (SUMA_STDERR, "need 1 argument after -orient_out\n");
03896                                 exit (1);
03897                         }
03898                         snprintf(orcode, 4*sizeof(char), "%s", argv[kar]);
03899          if (!SUMA_ok_orstring(orcode)) {
03900             fprintf (SUMA_STDERR, "%s is a bad orientation string\n", orcode);
03901                                 exit (1);
03902          } 
03903                         brk = YUP;
03904                 }
03905       
03906       if (!brk && (strcmp(argv[kar], "-tlrc") == 0)) {
03907          Do_tlrc = YUP;
03908          brk = YUP;
03909       }
03910       
03911       if (!brk && (strcmp(argv[kar], "-acpc") == 0)) {
03912          Do_acpc = YUP;
03913          brk = YUP;
03914       }
03915       
03916       if (!brk && (strcmp(argv[kar], "-mni_rai") == 0)) {
03917          Do_mni_RAI = YUP;
03918          brk = YUP;
03919       }
03920       
03921       if (!brk && (strcmp(argv[kar], "-mni_lpi") == 0)) {
03922          Do_mni_LPI = YUP;
03923          brk = YUP;
03924       }
03925       
03926       if (!brk && !ps->arg_checked[kar]) {
03927                         fprintf (SUMA_STDERR,"Error %s: Option %s not understood. Try -help for usage\n", FuncName, argv[kar]);
03928                         exit (1);
03929                 } else {        
03930                         brk = NOPE;
03931                         kar ++;
03932                 }
03933    }
03934    /* transfer info from ps structure (backward compat) */
03935 
03936    if (ps->o_N_surfnames) {
03937       of_name = ps->o_surfnames[0];
03938       of_name2 = ps->o_surftopo[0];
03939       oType = ps->o_FT[0];
03940    }
03941    if (ps->i_N_surfnames) {
03942       if_name = ps->i_surfnames[0];
03943       if_name2 = ps->i_surftopo[0];
03944       iType = ps->i_FT[0];
03945       iForm = ps->i_FF[0];
03946    }
03947    if (ps->ipar_N_surfnames) {
03948       ifpar_name = ps->ipar_surfnames[0];
03949       ifpar_name2 = ps->ipar_surftopo[0];
03950       iparType = ps->ipar_FT[0];
03951       iparForm = ps->ipar_FF[0];
03952    }
03953    
03954    if (ps->N_sv) sv_name = ps->sv[0];
03955    if (ps->N_vp) vp_name = ps->vp[0];
03956          
03957    /* sanity checks */
03958    if (Do_mni_LPI && Do_mni_RAI) {
03959       fprintf (SUMA_STDERR,"Error %s:\nCombining -MNI_lpi and -MNI_rai options.\nNot good.", FuncName);
03960       exit(1);
03961    }
03962    
03963    if (!if_name) {
03964       fprintf (SUMA_STDERR,"Error %s: input surface not specified.\n", FuncName);
03965       exit(1);
03966    }
03967    if (!of_name) {
03968       fprintf (SUMA_STDERR,"Error %s: output surface not specified.\n", FuncName);
03969       exit(1);
03970    }
03971    if (iType == SUMA_FT_NOT_SPECIFIED) {
03972       fprintf (SUMA_STDERR,"Error %s: input type not recognized.\n", FuncName);
03973       exit(1);
03974    }
03975    if (oType == SUMA_FT_NOT_SPECIFIED) {
03976       fprintf (SUMA_STDERR,"Error %s: output type not recognized.\n", FuncName);
03977       exit(1);
03978    }
03979    if (iType == SUMA_SUREFIT) {
03980       if (!if_name2) {
03981          fprintf (SUMA_STDERR,"Error %s: input SureFit surface incorrectly specified.\n", FuncName);
03982          exit(1);
03983       }
03984       if (sv_name && !vp_name) {
03985          fprintf (SUMA_STDERR,"Error %s: VolParent must specified with -sv potion for SureFit surfaces. \n", FuncName);
03986          exit(1);
03987       }
03988    }
03989    if (iType == SUMA_VEC) {
03990       if (!if_name2) {
03991          fprintf (SUMA_STDERR,"Error %s: input vec surface incorrectly specified.\n", FuncName);
03992          exit(1);
03993       }
03994    }
03995 
03996    if (( Do_mni_RAI || Do_mni_LPI) && !Do_tlrc) {
03997       SUMA_SL_Warn ("I hope you know what you're doing.\nThe MNI transform should only be applied to a\nSurface in the AFNI tlrc coordinate space.\n");
03998    }
03999    
04000    if (Do_acpc && Do_tlrc) {
04001       fprintf (SUMA_STDERR,"Error %s: You can't do -tlrc and -acpc simultaneously.\n", FuncName);
04002       exit(1);
04003    }
04004    
04005    if ((Doxmat || Docen) && (Do_acpc || Do_tlrc)) {
04006       fprintf (SUMA_STDERR,"Error %s: You can't do -tlrc or -acpc with -xmat_1D and -xcenter.\n", FuncName);
04007       exit(1);
04008    }
04009    
04010    if ((!Doxmat && Docen)) {
04011       fprintf (SUMA_STDERR,"Error %s: You can't use -xcenter without -xmat_1D.\n", FuncName);
04012       exit(1);
04013    }
04014    if (oType == SUMA_SUREFIT) {
04015       if (!of_name2) {
04016        fprintf (SUMA_STDERR,"Error %s: output SureFit surface incorrectly specified. \n", FuncName);
04017        exit(1);
04018       }
04019    }
04020    
04021    if (oType == SUMA_VEC) {
04022       if (!of_name2) {
04023        fprintf (SUMA_STDERR,"Error %s: output vec surface incorrectly specified. \n", FuncName);
04024        exit(1);
04025       }
04026    }
04027    
04028    
04029    /* test for existence of input files */
04030    if (!SUMA_filexists(if_name)) {
04031       fprintf (SUMA_STDERR,"Error %s: %s not found.\n", FuncName, if_name);
04032       exit(1);
04033    }
04034    
04035    if (if_name2) {
04036       if (!SUMA_filexists(if_name2)) {
04037          fprintf (SUMA_STDERR,"Error %s: %s not found.\n", FuncName, if_name2);
04038          exit(1);
04039       }
04040    }
04041 
04042    if (ifpar_name2) {
04043       if (!SUMA_filexists(ifpar_name2)) {
04044          fprintf (SUMA_STDERR,"Error %s: %s not found.\n", FuncName, ifpar_name2);
04045          exit(1);
04046       }
04047    }
04048    
04049    if (ifpar_name) {
04050       if (!SUMA_filexists(ifpar_name)) {
04051          fprintf (SUMA_STDERR,"Error %s: %s not found.\n", FuncName, ifpar_name);
04052          exit(1);
04053       }
04054    }
04055    
04056    if (xmat_name) {
04057       if (!SUMA_filexists(xmat_name)) {
04058          fprintf (SUMA_STDERR,"Error %s: %s not found.\n", FuncName, xmat_name);
04059          exit(1);
04060       }
04061    }
04062 
04063    if (sv_name) {
04064       char *head = NULL, view[10];
04065       head = SUMA_AfniPrefix(sv_name, view, NULL, &volexists);
04066       if (!SUMA_AfniExistsView(volexists, view)) {
04067          fprintf (SUMA_STDERR,"Error %s: volume %s not found.\n", FuncName, head);
04068          exit(1);
04069       }
04070       if (head) SUMA_free(head); head = NULL;
04071    }
04072    
04073   
04074    if ((Do_tlrc || Do_acpc) && (!sv_name)) {
04075       fprintf (SUMA_STDERR,"Error %s: -tlrc must be used with -sv option.\n", FuncName);
04076       exit(1);
04077    }
04078    
04079    if (vp_name) {
04080       if (!SUMA_filexists(vp_name)) {
04081          fprintf (SUMA_STDERR,"Error %s: %s not found.\n", FuncName, vp_name);
04082          exit(1);
04083       }
04084    }
04085 
04086    /* check for existence of output files */
04087    if (of_name2) {
04088       SUMA_SFname *SFname;
04089 
04090       SO_name = SUMA_2Prefix2SurfaceName (of_name, of_name2, NULL, vp_name, oType, &exists);
04091       SFname = (SUMA_SFname *)SO_name;
04092       OF_name2 = SUMA_copy_string(SFname->name_topo);
04093       OF_name = SUMA_copy_string(SFname->name_coord);
04094    } else {
04095       SO_name = SUMA_Prefix2SurfaceName (of_name, vp_name, NULL, oType, &exists);
04096       OF_name = SUMA_copy_string((char *) SO_name);
04097    }
04098    
04099    if (exists) {
04100       if (OF_name2) fprintf (SUMA_STDERR,"Error %s: output file(s) %s and/or %s exist already.\n", FuncName, OF_name, OF_name2);
04101       else fprintf (SUMA_STDERR,"Error %s: output file %s exists already.\n", FuncName, OF_name);
04102       exit(1);
04103    }
04104       
04105    /* now for the real work */
04106    if (Doxmat) {
04107       MRI_IMAGE *im = NULL;
04108       float *far=NULL;
04109       int ncol, nrow;
04110       
04111       im = mri_read_1D (xmat_name);
04112    
04113       if (!im) {
04114          SUMA_SLP_Err("Failed to read 1D file");
04115          exit(1);
04116       }
04117       far = MRI_FLOAT_PTR(im);
04118       ncol = im->nx;
04119       nrow = im->ny;
04120       if (nrow < 4 ) {
04121          SUMA_SL_Err("Mat file must have\n"
04122                      "at least 4 columns.");
04123          mri_free(im); im = NULL;   /* done with that baby */
04124          exit(1);
04125       }
04126       if (ncol < 3 ) {
04127          SUMA_SL_Err("Mat file must have\n"
04128                      "at least 3 rows.");
04129          mri_free(im); im = NULL;   /* done with that baby */
04130          exit(1);
04131       }
04132       if (nrow > 4) {
04133          SUMA_SL_Warn(  "Ignoring entries beyond 4th \n"
04134                         "column in transform file.");
04135       }
04136       if (ncol > 3) {
04137          SUMA_SL_Warn(  "Ignoring entries beyond 3rd\n"
04138                         "row in transform file.\n");
04139       }
04140       for (i=0; i < 3; ++i) {
04141          M[i][0] = far[i];
04142          M[i][1] = far[i+ncol];
04143          M[i][2] = far[i+2*ncol];
04144          M[i][3] = far[i+3*ncol];
04145       } 
04146       mri_free(im); im = NULL;
04147    }
04148    /* prepare the name of the surface object to read*/
04149    SO = SUMA_Load_Surface_Object_Wrapper ( if_name, if_name2, vp_name, iType, iForm, sv_name, 1);
04150    if (!SO) {
04151       fprintf (SUMA_STDERR,"Error %s: Failed to read input surface.\n", FuncName);
04152       exit (1);
04153    }
04154 
04155    if (ifpar_name) {
04156       SOpar = SUMA_Load_Surface_Object_Wrapper ( ifpar_name, ifpar_name2, vp_name, iparType, iparForm, sv_name, 1);
04157       if (!SOpar) {
04158          fprintf (SUMA_STDERR,"Error %s: Failed to read input parent surface.\n", FuncName);
04159          exit (1);
04160       }
04161       /* need edge list */
04162       if (!SUMA_SurfaceMetrics_eng (SOpar,"EdgeList", NULL, 0, SUMAg_CF->DsetList)) {
04163          SUMA_SL_Err("Failed to create edgelist for parent");
04164          exit(1);
04165       }
04166    }
04167    
04168    
04169    /* if Do_wind */
04170    if (Do_wind) {
04171       fprintf (SUMA_STDOUT,"Checking and repairing mesh's winding consistency...\n");
04172       /* check the winding, but that won't fix the normals, 
04173       you'll have to recalculate those things, if need be ... */
04174       if (!SUMA_SurfaceMetrics_eng (SO, "CheckWind", NULL, 0, SUMAg_CF->DsetList)) {
04175          fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_SurfaceMetrics.\n", FuncName);
04176          exit(1);
04177       }   
04178    }
04179    
04180    if (Do_tlrc) {
04181       fprintf (SUMA_STDOUT,"Performing talairach transform...\n");
04182 
04183       /* form the tlrc version of the surface volume */
04184       tlrc_name = (char *) SUMA_calloc (strlen(SO->VolPar->dirname)+strlen(SO->VolPar->prefix)+60, sizeof(char));
04185       sprintf (tlrc_name, "%s%s+tlrc.HEAD", SO->VolPar->dirname, SO->VolPar->prefix);
04186       if (!SUMA_filexists(tlrc_name)) {
04187          fprintf (SUMA_STDERR,"Error %s: %s not found.\n", FuncName, tlrc_name);
04188          exit(1);
04189       }
04190       
04191       /* read the tlrc header */
04192       aset = THD_open_dataset(tlrc_name) ;
04193       if( !ISVALID_DSET(aset) ){
04194          fprintf (SUMA_STDERR,"Error %s: %s is not a valid data set.\n", FuncName, tlrc_name) ;
04195          exit(1);
04196       }
04197       if( aset->warp == NULL ){
04198          fprintf (SUMA_STDERR,"Error %s: tlrc_name does not contain a talairach transform.\n", FuncName);
04199          exit(1);
04200       }
04201       
04202       warp = aset->warp ;
04203       
04204       /* now warp the coordinates, one node at a time */
04205       if (!SUMA_AFNI_forward_warp_xyz(warp, SO->NodeList, SO->N_Node)) {
04206          fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_AFNI_forward_warp_xyz.\n", FuncName);
04207          exit(1);
04208       }
04209 
04210       
04211    }
04212    
04213    if (Do_acpc) {
04214       fprintf (SUMA_STDOUT,"Performing acpc transform...\n");
04215 
04216       /* form the acpc version of the surface volume */
04217       acpc_name = (char *) SUMA_calloc (strlen(SO->VolPar->dirname)+strlen(SO->VolPar->prefix)+60, sizeof(char));
04218       sprintf (acpc_name, "%s%s+acpc.HEAD", SO->VolPar->dirname, SO->VolPar->prefix);
04219       if (!SUMA_filexists(acpc_name)) {
04220          fprintf (SUMA_STDERR,"Error %s: %s not found.\n", FuncName, acpc_name);
04221          exit(1);
04222       }
04223       
04224       /* read the acpc header */
04225       aset = THD_open_dataset(acpc_name) ;
04226       if( !ISVALID_DSET(aset) ){
04227          fprintf (SUMA_STDERR,"Error %s: %s is not a valid data set.\n", FuncName, acpc_name) ;
04228          exit(1);
04229       }
04230       if( aset->warp == NULL ){
04231          fprintf (SUMA_STDERR,"Error %s: acpc_name does not contain an acpc transform.\n", FuncName);
04232          exit(1);
04233       }
04234       
04235       warp = aset->warp ;
04236       
04237       /* now warp the coordinates, one node at a time */
04238       if (!SUMA_AFNI_forward_warp_xyz(warp, SO->NodeList, SO->N_Node)) {
04239          fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_AFNI_forward_warp_xyz.\n", FuncName);
04240          exit(1);
04241       }
04242 
04243       
04244    }
04245    
04246    if (Do_mni_RAI) {
04247       fprintf (SUMA_STDOUT,"Performing MNI_RAI transform...\n");
04248       /* apply the mni warp */
04249       if (!SUMA_AFNItlrc_toMNI(SO->NodeList, SO->N_Node, "RAI")) {
04250          fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_AFNItlrc_toMNI.\n", FuncName);
04251          exit(1);
04252       }
04253       sprintf(orsurf,"RAI");
04254    }
04255    
04256    if (Do_mni_LPI) {
04257       fprintf (SUMA_STDOUT,"Performing MNI_LPI transform...\n");
04258       /* apply the mni warp */
04259       if (!SUMA_AFNItlrc_toMNI(SO->NodeList, SO->N_Node, "LPI")) {
04260          fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_AFNItlrc_toMNI.\n", FuncName);
04261          exit(1);
04262       }
04263       sprintf(orsurf,"LPI");
04264    }
04265    
04266    if (Doxmat) {
04267       fprintf (SUMA_STDOUT,"Performing affine transform...\n");
04268       if (LocalHead) {
04269          for (i=0; i<3 ; ++i) {
04270             fprintf (SUMA_STDERR,"M[%d][:] = %f %f %f %f\n", i, M[i][0], M[i][1], M[i][2], M[i][3]);
04271          }
04272          fprintf (SUMA_STDERR,"Cen[:] %f %f %f\n", xcen[0], xcen[1], xcen[2]);
04273       }
04274       if (Docen) {
04275          if (!SUMA_ApplyAffine (SO->NodeList, SO->N_Node, M, xcen)) { SUMA_SL_Err("Failed to xform coordinates"); exit(1); }
04276       } else {
04277          if (!SUMA_ApplyAffine (SO->NodeList, SO->N_Node, M, NULL)) { SUMA_SL_Err("Failed to xform coordinates"); exit(1); }
04278       }
04279    }
04280    
04281    if (orcode[0] != '\0') {
04282       if (LocalHead) fprintf (SUMA_STDERR,"%s: Changing coordinates from %s to %s\n", FuncName, orsurf, orcode);
04283       if (!SUMA_CoordChange(orsurf, orcode, SO->NodeList, SO->N_Node)) {
04284          SUMA_S_Err("Failed to change coords.");
04285          exit(1);
04286       }
04287    }
04288    
04289    if (LocalHead) SUMA_Print_Surface_Object (SO, stderr);
04290    
04291    fprintf (SUMA_STDOUT,"Writing surface...\n");
04292    
04293    
04294    /* write the surface object */
04295    switch (oType) {
04296       case SUMA_SUREFIT:
04297          if (!SUMA_Save_Surface_Object (SO_name, SO,  SUMA_SUREFIT, SUMA_ASCII, NULL)) {
04298             fprintf (SUMA_STDERR,"Error %s: Failed to write surface object.\n", FuncName);
04299             exit (1);
04300          }
04301          break;
04302       case SUMA_VEC:
04303          if (!SUMA_Save_Surface_Object (SO_name, SO, SUMA_VEC, SUMA_ASCII, NULL)) {
04304             fprintf (SUMA_STDERR,"Error %s: Failed to write surface object.\n", FuncName);
04305             exit (1);
04306          }
04307          break;
04308       case SUMA_FREE_SURFER:
04309          if (!SUMA_Save_Surface_Object (SO_name, SO, SUMA_FREE_SURFER, SUMA_ASCII, NULL)) {
04310             fprintf (SUMA_STDERR,"Error %s: Failed to write surface object.\n", FuncName);
04311             exit (1);
04312          }
04313          break;
04314       case SUMA_FREE_SURFER_PATCH:
04315          if (!SUMA_Save_Surface_Object (SO_name, SO, SUMA_FREE_SURFER_PATCH, SUMA_ASCII, SOpar)) {
04316             fprintf (SUMA_STDERR,"Error %s: Failed to write surface object.\n", FuncName);
04317             exit (1);
04318          }
04319          break;  
04320       case SUMA_OPENDX_MESH:
04321          if (!SUMA_Save_Surface_Object (SO_name, SO, SUMA_OPENDX_MESH, SUMA_ASCII, NULL)) {
04322             fprintf (SUMA_STDERR,"Error %s: Failed to write surface object.\n", FuncName);
04323             exit (1);
04324          }
04325          break;  
04326       case SUMA_PLY:
04327          if (!SUMA_Save_Surface_Object (SO_name, SO, SUMA_PLY, SUMA_FF_NOT_SPECIFIED, NULL)) {
04328             fprintf (SUMA_STDERR,"Error %s: Failed to write surface object.\n", FuncName);
04329             exit (1);
04330          }
04331          break;  
04332       default:
04333          fprintf (SUMA_STDERR,"Error %s: Bad format.\n", FuncName);
04334          exit(1);
04335    }
04336    
04337    
04338    
04339    if (of_name_strip) of_name_strip = SUMA_Free_Parsed_Name (of_name_strip);
04340    if (of_name2_strip) of_name2_strip = SUMA_Free_Parsed_Name (of_name2_strip);
04341    if (OF_name) SUMA_free(OF_name);
04342    if (OF_name2) SUMA_free(OF_name2);
04343    if (SF_name) SUMA_free(SF_name);
04344    if (SO_name) SUMA_free(SO_name);
04345    if (SO) SUMA_Free_Surface_Object(SO);
04346    if (SOpar) SUMA_Free_Surface_Object(SOpar);
04347    if (ps) SUMA_FreeGenericArgParse(ps); ps = NULL;
04348    return (0);
04349 }
04350 #endif
04351 
04352 /*!
04353    \brief Handles opening an ROI file
04354    \param filename (char *)
04355    \param data(void *) 
04356    
04357    - results are placed in SUMAg_DOv
04358    
04359 */
04360 void SUMA_OpenDrawnROI (char *filename, void *data)
04361 {
04362    static char FuncName[]={"SUMA_OpenDrawnROI"};
04363    DList *list=NULL;
04364    SUMA_DRAWN_ROI **ROIv=NULL;
04365    int i, N_ROI;
04366    SUMA_SurfaceObject *SO=NULL;
04367    
04368    SUMA_Boolean LocalHead = NOPE;
04369    
04370    SUMA_ENTRY;
04371 
04372    SUMA_LH("Called");   
04373 
04374    /* check for type ... */
04375    
04376    if (SUMA_isExtension(filename, ".niml.roi")) {
04377       /* load niml ROI */
04378       if (!( ROIv = SUMA_OpenDrawnROI_NIML (filename, &N_ROI, YUP))) {
04379          SUMA_SLP_Err("Failed to read NIML ROI.");
04380          SUMA_RETURNe;
04381       }
04382    }else if (SUMA_isExtension(filename, ".1D.roi")) {
04383       /* load 1D ROI */
04384       /* You need to select a parent surface */
04385       SUMA_SLP_Warn("Assuming parent surface.");
04386       SO = (SUMA_SurfaceObject *)(SUMAg_DOv[SUMAg_SVv[0].Focus_SO_ID].OP);
04387       if (!( ROIv = SUMA_OpenDrawnROI_1D (filename, SO->idcode_str, &N_ROI, YUP))) {
04388          SUMA_SLP_Err("Failed to read NIML ROI.");
04389          SUMA_RETURNe;
04390       }
04391    }else {
04392       SUMA_SLP_Err(  "Failed to recognize\n"
04393                      "ROI type from filename.");
04394       SUMA_RETURNe;
04395    } 
04396    
04397    /* put those ROIs in SUMAg_DOv */
04398    for (i=0; i < N_ROI; ++i) {
04399       /* add ROI to DO list */
04400       if (!SUMA_AddDO (SUMAg_DOv, &SUMAg_N_DOv, (void *)ROIv[i], ROIdO_type, SUMA_LOCAL)) {
04401          fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AddDO.\n", FuncName);
04402       }
04403    }
04404    /* free ROIv */
04405    if (ROIv) SUMA_free(ROIv); ROIv = NULL;
04406 
04407    /* if there are no currentROIs selected, set currentROI to the
04408       first in the list */
04409    if (!SUMAg_CF->X->DrawROI->curDrawnROI) {
04410       i = 0;
04411       do {
04412          if (SUMAg_DOv[i].ObjectType == ROIdO_type) SUMAg_CF->X->DrawROI->curDrawnROI =
04413                                              (SUMA_DRAWN_ROI *)SUMAg_DOv[i].OP;
04414          ++i;
04415       } while (i < SUMAg_N_DOv && !SUMAg_CF->X->DrawROI->curDrawnROI);
04416    }
04417    
04418    if (SUMAg_CF->X->DrawROI->curDrawnROI) {
04419       SUMA_InitializeDrawROIWindow(SUMAg_CF->X->DrawROI->curDrawnROI);   
04420    }
04421    
04422    /* Now update the Paint job on the ROI plane */
04423    if (!SUMA_Paint_SO_ROIplanes_w (
04424             SUMA_findSOp_inDOv(SUMAg_CF->X->DrawROI->curDrawnROI->Parent_idcode_str, 
04425             SUMAg_DOv, SUMAg_N_DOv), SUMAg_DOv, SUMAg_N_DOv)) {
04426       SUMA_SLP_Err("Failed in SUMA_Paint_SO_ROIplanes_w.");
04427       SUMA_RETURNe;
04428    }
04429    
04430    /* put a nice redisplay here */
04431    if (!list) list = SUMA_CreateList ();
04432    SUMA_REGISTER_TAIL_COMMAND_NO_DATA(list, SE_Redisplay_AllVisible, SES_Suma, NULL); 
04433    if (!SUMA_Engine(&list)) {
04434       SUMA_SLP_Err("Failed to redisplay.");
04435       SUMA_RETURNe;
04436    }
04437    
04438    SUMA_RETURNe; 
04439 }
04440 
04441 /*!
04442    Since parent information does not exist in ROI 1D files, 
04443    you need to specify the parent surface.
04444    
04445    ans = SUMA_OpenDrawnROI_1D (filename, Parent_idcode_str);
04446    
04447    \param filename (char *) name of 1D file (see below for formats)
04448    \param Parent_idcode_str (char *) idcode of parent surface
04449    \param N_ROI (int *) will contain the number of ROIs read in
04450    \param ForDisplay (SUMA_Boolean) YUP: prepares ROI for display
04451    \return ans (SUMA_Boolean) YUP for good NOPE for not good.
04452    
04453    - The ROI is added to SUMAg_DOv
04454    
04455    - The 1D file can have multiple formats. Some are particularly
04456    inefficient and should not be used. But we aim to please so 
04457    anything goes. You can have a varying number of columns which 
04458    are i, l, r, g, b. These columns stand for index, label, red,
04459    green and blue, respectively.
04460       * format 1: i 
04461       Only a bunch of node (int) indices are supplied. Label of all nodes
04462       defaults to 0 and a default color is given
04463       * format 2: i l
04464       Each node carries a label (int) with it. This way you can
04465       have multiple ROIs specified in one 1D file. The same
04466       color is assigned to each of the ROIs. 
04467       * format 3: i r g b
04468       A bunch of nodes with r g b (float) triplet specifying the nodes'
04469       colors. Obviously, since all nodes belong to the same ROI, 
04470       the specification of an r g b for each node is redundant since
04471       all nodes in the same ROI have the same color. Use the 
04472       niml format if that sounds crazy to you. If you want a different
04473       color for each node then you should not load the data as an ROI
04474       but as a node color file. 
04475       * format 4: i l r g b
04476       A bunch of nodes with labels and r g b .
04477       Like format 2 but with the possibility of specifying the colors of
04478       each ROI. 
04479        
04480 */ 
04481 SUMA_DRAWN_ROI ** SUMA_OpenDrawnROI_1D (char *filename, char *Parent_idcode_str,
04482                                         int *N_ROI, SUMA_Boolean ForDisplay)
04483 {
04484    static char FuncName[]={"SUMA_OpenDrawnROI_1D"};
04485    MRI_IMAGE *im = NULL;
04486    int ncol, nrow, *iLabel=NULL, *iNode = NULL, *isort=NULL,
04487       i, N_Labels = 0, *iStart=NULL, *iStop=NULL, cnt = 0;
04488    float *far=NULL, *r=NULL, *g=NULL, *b=NULL, *RGB=NULL;
04489    SUMA_DRAWN_ROI **ROIv=NULL;
04490    SUMA_Boolean LocalHead = NOPE;
04491    
04492    SUMA_ENTRY;
04493 
04494    SUMA_LH("Called");
04495    
04496    *N_ROI = 0;
04497    
04498    im = mri_read_1D (filename);
04499    
04500    if (!im) {
04501       SUMA_SLP_Err("Failed to read 1D file");
04502       SUMA_RETURN(NULL);
04503    }
04504    
04505    far = MRI_FLOAT_PTR(im);
04506    ncol = im->nx;
04507    nrow = im->ny;
04508    
04509    if (!ncol) {
04510       SUMA_SL_Err("Empty file");
04511       SUMA_RETURN(NULL);
04512    }
04513    if (nrow != 1 && nrow != 2 && nrow != 4 && nrow != 5) {
04514       SUMA_SL_Err("File must have\n"
04515                   " 1,2,4 or 5 columns.");
04516       mri_free(im); im = NULL;   /* done with that baby */
04517       SUMA_RETURN(NULL);
04518    }
04519    
04520    if (0 && LocalHead) {
04521       SUMA_disp_vect(far, ncol*nrow);
04522    }
04523       
04524    switch (nrow) {
04525       case 1:
04526          /* Node index only*/
04527          SUMA_LH ("1D format: i");
04528          iNode = (int *)SUMA_malloc(ncol*sizeof(int));
04529          iLabel = (int *)SUMA_malloc(1*sizeof(int));
04530          if (!iNode ||!iLabel) {
04531             SUMA_SL_Err("Failed to allocate");
04532             SUMA_RETURN(NULL);
04533          }
04534          for (i=0; i < ncol; ++i) iNode[i] = (int)far[i];
04535          mri_free(im); im = NULL;   /* done with that baby */
04536          
04537          iLabel[0] = 0;
04538          N_Labels = 1;
04539          iStart = (int *)SUMA_malloc(1*sizeof(int));
04540          iStop = (int *)SUMA_malloc(1*sizeof(int));
04541          RGB = (float *)SUMA_malloc(3*1*sizeof(float));
04542          iStart[0] = 0;
04543          iStop[0] = ncol-1;
04544          RGB[0] = 1.0; RGB[1] = 1.0; RGB[2] = 0;
04545          break;
04546       case 2:
04547          /* Node index & Node Label */
04548          SUMA_LH("1D format: i l");
04549          /* copy the node indices and labels for cleanliness */
04550          iLabel = (int *)SUMA_malloc(ncol*sizeof(int));
04551          iNode = (int *)SUMA_malloc(ncol*sizeof(int));
04552          if (!iNode || !iLabel) {
04553             SUMA_SL_Err("Failed to allocate");
04554             SUMA_RETURN(NULL);
04555          }
04556          for (i=0; i < ncol; ++i) iLabel[i] = (int)far[i+ncol];
04557          /* sort the Labels and the iNode accordingly */
04558          isort = SUMA_z_dqsort( iLabel, ncol);
04559          for (i=0; i < ncol; ++i) iNode[i] = (int)far[isort[i]];
04560 
04561          mri_free(im); im = NULL;   /* done with that baby */
04562 
04563          /* Count the number of distinct labels */
04564          N_Labels = 1;
04565          for (i=1; i < ncol; ++i) if (iLabel[i] != iLabel[i-1]) ++N_Labels;
04566          /* store where each label begins and ends */
04567          iStart = (int *)SUMA_malloc(N_Labels*sizeof(int));
04568          iStop = (int *)SUMA_malloc(N_Labels*sizeof(int));
04569          RGB = (float *)SUMA_malloc(3*N_Labels*sizeof(float));
04570          if (!iStart || !iStop) {
04571             SUMA_SL_Err("Failed to allocate");
04572             SUMA_RETURN(NULL);
04573          }
04574          cnt = 0;
04575          iStart[cnt] = 0;
04576          iStop[cnt] = ncol -1;
04577          RGB[3*cnt] = 1.0; RGB[3*cnt+1] = 1.0; RGB[3*cnt+2] = 0;
04578          for (i=1; i < ncol; ++i) {
04579             if (iLabel[i] != iLabel[i-1]) {
04580                iStop[cnt] = i-1;
04581                ++cnt; 
04582                iStart[cnt] = i;
04583                iStop[cnt] = ncol -1;
04584                RGB[3*cnt] = 1.0; RGB[3*cnt+1] = 1.0; RGB[3*cnt+2] = 0;
04585             }
04586          }
04587          break;
04588       case 4:
04589          /* Node index, R G B */
04590          SUMA_LH("1D format: i R G B");
04591          iNode = (int *)SUMA_malloc(ncol*sizeof(int));
04592          iLabel = (int *)SUMA_malloc(1*sizeof(int));
04593          r = (float *)SUMA_malloc(ncol*sizeof(float));
04594          g = (float *)SUMA_malloc(ncol*sizeof(float));
04595          b = (float *)SUMA_malloc(ncol*sizeof(float));
04596          if (!iNode || !iLabel || !r || !g || !b) {
04597             SUMA_SL_Err("Failed to allocate");
04598             SUMA_RETURN(NULL);
04599          }
04600          
04601          for (i=0; i < ncol; ++i) {
04602             iNode[i] = (int)far[i];
04603             r[i] = (float)far[i+ncol];
04604             g[i] = (float)far[i+2*ncol];
04605             b[i] = (float)far[i+3*ncol];
04606          }
04607          
04608          iLabel[0] = 0;
04609          N_Labels = 1;
04610          iStart = (int *)SUMA_malloc(1*sizeof(int));
04611          iStop = (int *)SUMA_malloc(1*sizeof(int));
04612          RGB = (float *)SUMA_malloc(3*1*sizeof(float));
04613          mri_free(im); im = NULL;   /* done with that baby */
04614         
04615          iStart[0] = 0;
04616          iStop[0] = ncol-1;
04617          RGB[0] = r[0]; RGB[1] = g[0]; RGB[2] = b[0];
04618          break;
04619       case 5:
04620          /* Node index, Node Label, R G B */
04621          SUMA_LH("1D format: i l R G B");
04622          /* copy the node indices and labels for cleanliness */
04623          iLabel = (int *)SUMA_malloc(ncol*sizeof(int));
04624          iNode = (int *)SUMA_malloc(ncol*sizeof(int));
04625          r = (float *)SUMA_malloc(ncol*sizeof(float));
04626          g = (float *)SUMA_malloc(ncol*sizeof(float));
04627          b = (float *)SUMA_malloc(ncol*sizeof(float));
04628          if (!iNode || !iLabel || !r || !g || !b) {
04629             SUMA_SL_Err("Failed to allocate");
04630             SUMA_RETURN(NULL);
04631          }
04632          for (i=0; i < ncol; ++i) iLabel[i] = (int)far[i+ncol];
04633          /* sort the Labels and the iNode accordingly */
04634          isort = SUMA_z_dqsort( iLabel, ncol);
04635          for (i=0; i < ncol; ++i) {
04636             iNode[i] = (int)far[isort[i]];
04637             r[i] = (float)far[isort[i]+2*ncol];
04638             g[i] = (float)far[isort[i]+3*ncol];
04639             b[i] = (float)far[isort[i]+4*ncol];
04640          }     
04641          mri_free(im); im = NULL;   /* done with that baby */
04642 
04643          /* Count the number of distinct labels */
04644          N_Labels = 1;
04645          for (i=1; i < ncol; ++i) if (iLabel[i] != iLabel[i-1]) ++N_Labels;
04646          /* store where each label begins and ends */
04647          iStart = (int *)SUMA_malloc(N_Labels*sizeof(int));
04648          iStop = (int *)SUMA_malloc(N_Labels*sizeof(int));
04649          RGB = (float *)SUMA_malloc(3*N_Labels*sizeof(float));
04650          if (!iStart || !iStop || !RGB) {
04651             SUMA_SL_Err("Failed to allocate");
04652             SUMA_RETURN(NULL);
04653          }
04654          cnt = 0;
04655          iStart[cnt] = 0;
04656          iStop[cnt] = ncol -1;
04657          RGB[3*cnt] = r[0]; RGB[3*cnt+1] = g[0]; RGB[3*cnt+2] = b[0];
04658          for (i=1; i < ncol; ++i) {
04659             if (iLabel[i] != iLabel[i-1]) {
04660                iStop[cnt] = i-1;
04661                ++cnt; 
04662                iStart[cnt] = i;
04663                iStop[cnt] = ncol -1;
04664                RGB[3*cnt] = r[i]; RGB[3*cnt+1] = g[i]; RGB[3*cnt+2] = b[i];
04665             }
04666          }
04667          break;
04668       default:
04669          SUMA_SLP_Err("Unrecognized 1D format");
04670          mri_free(im); im = NULL;   /* done with that baby */
04671          break;
04672    }
04673    
04674    
04675    ROIv = (SUMA_DRAWN_ROI **)SUMA_malloc(N_Labels*sizeof(SUMA_DRAWN_ROI*));
04676    
04677    for (i=0; i < N_Labels; ++i) {
04678       int Value, N_Node, *Node=NULL;
04679       float fillcolor[3], edgecolor[3];
04680       int edgethickness;
04681       char stmp[20], *Label=NULL;
04682       SUMA_PARSED_NAME *NewName=NULL; 
04683       
04684       edgethickness = 3;
04685       fillcolor[0] = RGB[3*i]; fillcolor[1] = RGB[3*i+1]; fillcolor[2] = RGB[3*i+2]; 
04686       edgecolor[0] = 0; edgecolor[1] = 0; edgecolor[2] = 1; 
04687       Value = iLabel[iStart[i]]; /* the index label of this ROI */
04688       N_Node = iStop[i] - iStart[i] + 1; /* Number of Nodes in this ROI */
04689       Node = &(iNode[iStart[i]]); /* pointer to location of first index in this ROI */
04690       /* prepare a label for these ROIs */
04691       NewName = SUMA_ParseFname (filename);
04692       if (!NewName) {
04693          Label = SUMA_copy_string("BadLabel");
04694       }else {
04695          sprintf(stmp,"(%d)", Value);
04696          Label = SUMA_append_string(stmp,NewName->FileName_NoExt);
04697       }
04698       SUMA_LH("Transforming to Drawn ROIs...");
04699       ROIv[i] = SUMA_1DROI_to_DrawnROI( Node, N_Node , 
04700                                     Value, Parent_idcode_str,
04701                                     Label, NULL,
04702                                     fillcolor, edgecolor, edgethickness, 
04703                                     SUMAg_DOv, SUMAg_N_DOv,
04704                                     ForDisplay);
04705       if (nrow == 5 || nrow == 4) {
04706          SUMA_LH("Marking as color by fillcolor");
04707          ROIv[i]->ColorByLabel = NOPE;
04708       }
04709       if (Label) SUMA_free(Label); Label = NULL;
04710       if (NewName) SUMA_Free_Parsed_Name(NewName); NewName = NULL;
04711       if (LocalHead) fprintf (SUMA_STDERR, "%s: ROI->Parent_idcode_str %s\n", FuncName, ROIv[i]->Parent_idcode_str);
04712 
04713    }
04714  
04715    SUMA_LH("Freeing...");
04716    
04717    if (iLabel) SUMA_free(iLabel); iLabel = NULL;
04718    if (isort) SUMA_free(isort); isort = NULL;
04719    if (iNode) SUMA_free(iNode); iNode = NULL;
04720    if (iStart) SUMA_free(iStart); iStart = NULL;
04721    if (iStop) SUMA_free(iStop); iStop = NULL;
04722    if (r) SUMA_free(r); r = NULL;
04723    if (g) SUMA_free(g); g = NULL;
04724    if (b) SUMA_free(b); b = NULL;
04725    if (RGB) SUMA_free(RGB); RGB = NULL;
04726    
04727    *N_ROI = N_Labels;
04728    SUMA_RETURN(ROIv);
04729      
04730 }
04731 
04732 /*!
04733    \brief Loads a niml ROI 
04734    
04735    \param ForDisplay (SUMA_Boolean) YUP: Performs checks to see if ROI with similar idcode already
04736                                           exists and if parent surface is loaded.
04737                                     NOPE: Does not check for above conditions.
04738 */
04739 SUMA_DRAWN_ROI ** SUMA_OpenDrawnROI_NIML (char *filename, int *N_ROI, SUMA_Boolean ForDisplay)
04740 { /* begin embedded function */
04741    static char FuncName[]={"SUMA_OpenDrawnROI_NIML"};
04742    char stmp[SUMA_MAX_NAME_LENGTH+100], *nel_idcode;
04743    NI_element *nel = NULL;
04744    NI_element **nelv=NULL;
04745    NI_stream ns ;
04746    int n_read=0, idat, answer, inel, iDO, N_nel;
04747    SUMA_NIML_ROI_DATUM *niml_ROI_datum_buff=NULL;
04748    SUMA_NIML_DRAWN_ROI * nimlROI=NULL;
04749    SUMA_DRAWN_ROI **ROIv=NULL;
04750    SUMA_Boolean found = YUP, AddNel = YUP, AlwaysReplace = NOPE, NeverReplace = NOPE;
04751    SUMA_Boolean LocalHead = NOPE;
04752    
04753    SUMA_ENTRY;
04754 
04755    *N_ROI = 0;
04756    
04757    if (SUMAg_CF->nimlROI_Datum_type < 0) {
04758       SUMA_SL_Err("Bad niml type code");
04759       SUMA_RETURN(NULL);
04760    }
04761    if (LocalHead) fprintf(SUMA_STDERR, "%s: roi_type code = %d\n", FuncName, SUMAg_CF->nimlROI_Datum_type) ;
04762 
04763    sprintf(stmp,"file:%s", filename);
04764    ns = NI_stream_open( stmp , "r" ) ;
04765    if( ns == NULL ){
04766       SUMA_SL_Err("Can't open ROI file"); 
04767       SUMA_RETURN(NULL);
04768    }
04769    
04770    nelv = (NI_element **) SUMA_calloc(SUMA_MAX_DISPLAYABLE_OBJECTS, sizeof(NI_element *));
04771    if (!nelv) {
04772       SUMA_SLP_Crit("Failed to allocate");
04773       SUMA_RETURN(NULL);
04774    }
04775    
04776    NeverReplace = NOPE;
04777    AlwaysReplace = NOPE;
04778    inel = 0;
04779    do {
04780       nel = NI_read_element(ns,1) ;
04781       
04782       if (nel) {
04783          found = YUP;
04784          
04785          if (LocalHead && 0) SUMA_nel_stdout (nel);
04786          
04787          if (strcmp(nel->name,SUMA_Dset_Type_Name(SUMA_NODE_ROI))) {
04788             SUMA_SLP_Err ("ni element not of the \n Node ROI variety.\nElement discarded.");
04789             NI_free_element(nel) ; nel = NULL;
04790             SUMA_RETURN(NULL);
04791          }
04792          /* somewhat redundant test */
04793          if (nel->vec_typ[0] != SUMAg_CF->nimlROI_Datum_type) {
04794             SUMA_SLP_Err ("Datum type mismatch.");
04795             NI_free_element(nel) ; nel = NULL;
04796             SUMA_RETURN(NULL);
04797          }
04798 
04799          if (ForDisplay) {
04800             /* find out if a displayable object exists with the same idcode_str */
04801             nel_idcode = NI_get_attribute( nel , "idcode_str"); /* obsolete*/
04802             if (!nel_idcode) nel_idcode = NI_get_attribute( nel , "Object_ID"); 
04803             if (SUMA_existDO(nel_idcode, SUMAg_DOv, SUMAg_N_DOv)) {
04804                if (AlwaysReplace) {
04805                   AddNel = YUP; 
04806                }
04807                if (NeverReplace) {
04808                   AddNel = NOPE;
04809                }
04810                if (!AlwaysReplace && !NeverReplace) {   /* ASk */
04811                   sprintf(stmp, "Found duplicate ROIs.\n"\
04812                                              "Replace ROI %s (%s) by\n" \
04813                                              "version in file ?", 
04814                   NI_get_attribute( nel , "Label"), nel_idcode); 
04815 
04816                   answer = SUMA_ForceUser_YesNo (SUMAg_SVv[0].X->TOPLEVEL, 
04817                                     stmp, 
04818                                     0, SWP_DONT_CARE);
04819                   if (LocalHead) fprintf (SUMA_STDERR,"%s: Got %d, You ?\n", FuncName, answer);
04820                   switch (answer) {
04821                      case SUMA_YES:
04822                         SUMA_LH("YES");
04823                         AddNel = YUP;
04824                         break;
04825 
04826                      case SUMA_NO:
04827                         SUMA_LH("NO");
04828                         /* don't add this one */
04829                         AddNel = NOPE;
04830                         break;
04831 
04832                      case SUMA_YES_ALL:
04833                         SUMA_LH("YES ALL");
04834                         /* cancel Check_Prior */
04835                         AddNel = YUP;
04836                         AlwaysReplace = YUP;
04837                         break;
04838 
04839                      case SUMA_NO_ALL:
04840                         SUMA_LH("NO ALL");
04841                         /* don't add this one and set flag to ignore the doubles */
04842                         AddNel = NOPE;
04843                         NeverReplace = YUP;
04844                         break;
04845 
04846                      default:
04847                         SUMA_SLP_Crit("Don't know what to do with this button.");
04848                         SUMA_RETURN(NULL);
04849                         break;
04850                   }
04851                } 
04852             } else {
04853                AddNel = YUP;
04854             } 
04855          
04856             /* make sure element's parent exists */
04857             if (AddNel) {
04858                SUMA_LH("Checking for Parent surface...");
04859                iDO = SUMA_whichDO(NI_get_attribute( nel , "Parent_idcode_str"), SUMAg_DOv, SUMAg_N_DOv); /* obsolete */
04860                if (iDO < 0) iDO = SUMA_whichDO(NI_get_attribute( nel , "Parent_ID"), SUMAg_DOv, SUMAg_N_DOv);
04861               
04862                if (iDO < 0) {
04863                   SUMA_SLP_Err(  "ROI's parent surface\n"
04864                                  "is not loaded. ROI is\n"
04865                                  "discarded." );
04866                   AddNel = NOPE;
04867                }
04868             }
04869          } else {
04870             AddNel = YUP; /* ignore checks */
04871          }         
04872          
04873          if (AddNel) {
04874             SUMA_LH("Adding Nel");
04875             nelv[inel] = nel;
04876             ++inel; 
04877          }else {
04878             SUMA_LH("Skipping Nel");
04879          }
04880          
04881          ++n_read;
04882       }else {
04883          found = NOPE;
04884       } 
04885       
04886    } while (found);
04887    
04888    NI_stream_close(ns) ;
04889    N_nel = inel;
04890    
04891    if( !n_read){
04892       SUMA_SL_Err("Found no elements in file!"); 
04893       SUMA_free(nelv);
04894       SUMA_RETURN(NULL);
04895    }
04896    
04897    /* Now turn those nel into ROIS */
04898    ROIv = (SUMA_DRAWN_ROI **) SUMA_malloc(N_nel*sizeof(SUMA_DRAWN_ROI*));
04899    for (inel=0; inel < N_nel; ++inel) {
04900       if (LocalHead) fprintf (SUMA_STDERR,"%s: Processing nel %d/%d...\n", FuncName, inel, N_nel);
04901       nel = nelv[inel];
04902       nel_idcode = NI_get_attribute( nel , "idcode_str"); /* obsolete */
04903       if (!nel_idcode) nel_idcode = NI_get_attribute( nel , "Object_ID"); 
04904 
04905       /* store nel in nimlROI struct */
04906 
04907       /* allocate for nimlROI */
04908       nimlROI = (SUMA_NIML_DRAWN_ROI *)SUMA_malloc(sizeof(SUMA_NIML_DRAWN_ROI));
04909       nimlROI->Type = (int)strtod(NI_get_attribute( nel , "Type"), NULL);
04910       nimlROI->idcode_str = SUMA_copy_string(NI_get_attribute( nel , "idcode_str")); /* obsolete */
04911       if (SUMA_IS_EMPTY_STR_ATTR(nimlROI->idcode_str)) nimlROI->idcode_str = SUMA_copy_string(NI_get_attribute( nel , "Object_ID"));
04912       nimlROI->Parent_idcode_str = SUMA_copy_string(NI_get_attribute( nel , "Parent_idcode_str")); /* obsolete */
04913       if (SUMA_IS_EMPTY_STR_ATTR(nimlROI->Parent_idcode_str)) nimlROI->Parent_idcode_str = SUMA_copy_string(NI_get_attribute( nel , "Parent_ID"));
04914       nimlROI->Label = SUMA_copy_string(NI_get_attribute( nel , "Label"));
04915       nimlROI->iLabel = (int)strtod(NI_get_attribute( nel , "iLabel"), NULL);
04916       nimlROI->N_ROI_datum = nel->vec_len;
04917       nimlROI->ColPlaneName = SUMA_copy_string(NI_get_attribute( nel , "ColPlaneName"));
04918       if (SUMA_StringToNum (NI_get_attribute( nel , "FillColor"), 
04919                            nimlROI->FillColor, 3) < 0) {
04920          SUMA_SLP_Err("Failed in reading FillColor.");
04921          SUMA_free(nelv);
04922          SUMA_RETURN(NULL);
04923       }
04924       if (SUMA_StringToNum (NI_get_attribute( nel , "EdgeColor"), 
04925                            nimlROI->EdgeColor, 3) < 0) {
04926          SUMA_SLP_Err("Failed in reading EdgeColor.");
04927          SUMA_free(nelv);
04928          SUMA_RETURN(NULL);
04929       }
04930       nimlROI->EdgeThickness = (int)strtod(NI_get_attribute( nel , "EdgeThickness"), NULL);              
04931       
04932       if (LocalHead) {
04933          fprintf (SUMA_STDERR,"%s: vec_type[0] = %d (%d)\n", 
04934             FuncName, nel->vec_typ[0], SUMAg_CF->nimlROI_Datum_type) ;
04935          fprintf (SUMA_STDERR,"%s: vec_len =%d\tvec_num = %d\nidcode_str %s, Parent_idcode_str %s\n",
04936             FuncName, nel->vec_len, nel->vec_num,
04937             nimlROI->idcode_str, nimlROI->Parent_idcode_str);
04938       }
04939 
04940       nimlROI->ROI_datum = (SUMA_NIML_ROI_DATUM *)SUMA_malloc(nimlROI->N_ROI_datum*sizeof(SUMA_NIML_ROI_DATUM));
04941 
04942       /* DO NOT use niml_ROI_datum_buff = (SUMA_NIML_ROI_DATUM *)nel->vec[idat];
04943       inside the loop.
04944       For the SUMA_NIML_DRAWN_ROI you have one column of (SUMA_NIML_ROI_DATUM *)
04945       ni_type = "SUMA_NIML_ROI_DATUM". If you had for type:
04946       "SUMA_NIML_ROI_DATUM, int" then you'd have two columns with the second
04947       column being a vector of ints. The only caveat is that the second column
04948       must be of equal length to the first. */
04949       niml_ROI_datum_buff = (SUMA_NIML_ROI_DATUM *)nel->vec[0]; 
04950       /* now fill the ROI_datum structures */
04951       SUMA_LH("Filling ROI datum structures...");
04952       for (idat=0; idat< nimlROI->N_ROI_datum ; ++idat) {
04953          if (LocalHead) fprintf (SUMA_STDERR,"%s: i=%d\n", FuncName, idat);
04954          nimlROI->ROI_datum[idat].action = niml_ROI_datum_buff[idat].action;
04955          nimlROI->ROI_datum[idat].Type = niml_ROI_datum_buff[idat].Type;
04956          nimlROI->ROI_datum[idat].N_n = niml_ROI_datum_buff[idat].N_n;
04957          if (nimlROI->ROI_datum[idat].N_n > 0) {
04958             if (LocalHead) fprintf (SUMA_STDERR,"%s: Copying nPath, %d values\n", FuncName, nimlROI->ROI_datum[idat].N_n);
04959             nimlROI->ROI_datum[idat].nPath = (int *)SUMA_malloc(sizeof(int)*nimlROI->ROI_datum[idat].N_n);
04960             memcpy(nimlROI->ROI_datum[idat].nPath, niml_ROI_datum_buff[idat].nPath, sizeof(int)*nimlROI->ROI_datum[idat].N_n);
04961          } else {
04962             SUMA_LH("Null nPath");
04963             nimlROI->ROI_datum[idat].nPath = NULL;
04964          } 
04965          if (LocalHead) { 
04966             fprintf (SUMA_STDERR,"%s: Segment %d\tType %d\tN_n %d\taction %d\n", 
04967                FuncName, idat, nimlROI->ROI_datum[idat].Type,  
04968                nimlROI->ROI_datum[idat].N_n,nimlROI->ROI_datum[idat].action);
04969          }
04970       }
04971 
04972       /* Does ROI already exist with the same idcode_str ?*/
04973       
04974       SUMA_LH("Checking for duplicates...");
04975       if ((iDO = SUMA_whichDO(nel_idcode, SUMAg_DOv, SUMAg_N_DOv)) >= 0) {
04976          SUMA_LH("Duplicate found ... Deleteing old one...");
04977          /* ROI already exists delete it */
04978          if (!SUMA_DeleteROI ((SUMA_DRAWN_ROI *)SUMAg_DOv[iDO].OP)) {
04979             SUMA_SLP_Err("Failed to delete ROI");
04980             SUMA_RETURN(NULL); 
04981          }
04982       }
04983       
04984       /* transfom nimlROI to a series of drawing actions */
04985       SUMA_LH("Transforming ROI to a series of actions...");
04986       ROIv[inel] = SUMA_NIMLDrawnROI_to_DrawnROI (nimlROI, ForDisplay);
04987       if (LocalHead) fprintf (SUMA_STDERR, "%s: ROI->Parent_idcode_str %s\n", FuncName, ROIv[inel]->Parent_idcode_str);
04988 
04989       /* manually free nimlROI fields that received copies of allocated space as opposed to pointer copies */
04990       if (nimlROI->idcode_str) SUMA_free(nimlROI->idcode_str);
04991       if (nimlROI->Parent_idcode_str) SUMA_free(nimlROI->Parent_idcode_str); 
04992       if (nimlROI->Label) SUMA_free(nimlROI->Label);
04993       if (nimlROI->ColPlaneName) SUMA_free(nimlROI->ColPlaneName);
04994 
04995 
04996       /* free nimlROI */
04997       nimlROI = SUMA_Free_NIMLDrawROI(nimlROI);
04998 
04999       /* free nel and get it ready for the next load */
05000       NI_free_element(nel) ; nel = NULL; 
05001             
05002    }
05003    
05004    /* free nelv */
05005    SUMA_free(nelv);
05006    
05007    *N_ROI = N_nel;
05008    SUMA_RETURN(ROIv);
05009 } 
05010 
05011 /*!
05012    \brief turns a bunch of ROIs into a NI dataset
05013             A new version of SUMA_ROIv2dataset that allows 
05014             the use of dsets as groups
05015    \param ROIv (SUMA_DRAWN_ROI**) vector of ROI structures
05016    \param N_ROIv (int) number of ROI structures
05017    \param Parent_idcode_str (char *) idcode of parent surface
05018    \param Pad_to (int)  create Dset that has a full node listing 
05019                         from node 0 to node Pad_to (a total of Pad_to + 1 nodes)
05020                         Use -1 to turn off padding.
05021    \param Pad_val (int) use this value (usually 0) to label a node being padded
05022                         as oppsed to a node being a part of an ROI. This option
05023                         is only useful with Pad_to
05024    \return nel (NI_element *) structure to data set
05025                               NULL if failed
05026 */
05027 SUMA_DSET *SUMA_ROIv2Grpdataset (SUMA_DRAWN_ROI** ROIv, int N_ROIv, char *Parent_idcode_str, int Pad_to, int Pad_val) 
05028 {
05029    static char FuncName[]={"SUMA_ROIv2Grpdataset"};
05030    int ii, i, nn, cnt, N_NodesTotal = 0, MaxIndex = 0,
05031       *ip=NULL, *NodesTotal=NULL, *LabelsTotal=NULL,
05032       *NodesTotal_p=NULL, *LabelsTotal_p=NULL;
05033    SUMA_DSET *dset =NULL;
05034    SUMA_Boolean LocalHead = NOPE;
05035    
05036    SUMA_ENTRY;
05037    
05038    /* Now you have the ROIs, concatenate all NodesInROI vectors into 1*/
05039    /* count the total number of nodes */
05040    N_NodesTotal = 0;
05041    for (ii=0; ii < N_ROIv; ++ii) {
05042       SUMA_ROI_CRUDE_COUNT_NODES(ROIv[ii], cnt);
05043       if (LocalHead) {
05044          fprintf (SUMA_STDERR,"%s: ROI #%d: %d nodes\n", FuncName, ii, cnt);
05045       }
05046       N_NodesTotal += cnt;
05047    }
05048    if (LocalHead) fprintf (SUMA_STDERR,"%s: %d nodes total.\n", FuncName, N_NodesTotal);
05049 
05050    NodesTotal = (int *)SUMA_calloc(N_NodesTotal, sizeof(int));
05051    LabelsTotal = (int *)SUMA_calloc(N_NodesTotal, sizeof(int));
05052 
05053    if (!NodesTotal || !LabelsTotal) {
05054       SUMA_S_Err("Failed to allocate.");
05055       SUMA_RETURN(dset);
05056    }
05057 
05058    cnt = 0;
05059    N_NodesTotal = 0;
05060    MaxIndex = -1;
05061    for (ii=0; ii <  N_ROIv; ++ii) {
05062       SUMA_LH("Appending ROI");
05063       /* You do not need the Unique operation in SUMA_NodesInROI,
05064       but it is nice to have so that you can report the nodes that 
05065       were part of more than one ROI. If you do not Set the Unique 
05066       flag in SUMA_NodesInROI you will likely get node duplication
05067       but these nodes are in the same ROI and therefore are not
05068       duplicates to be removed....*/
05069       ip = SUMA_NodesInROI (ROIv[ii], &nn, YUP);
05070       if (LocalHead) {
05071          fprintf (SUMA_STDERR,"%s: Nodes in ROI #%d\n", FuncName, ii);
05072          SUMA_disp_dvect (ip, nn);
05073       }
05074       for (i=0; i < nn; ++i) {
05075          NodesTotal[cnt] = ip[i];
05076          LabelsTotal[cnt] = ROIv[ii]->iLabel;
05077          if (ip[i] > MaxIndex) MaxIndex = ip[i];
05078          ++cnt;
05079       }
05080       N_NodesTotal += nn;
05081       SUMA_freeDrawnROI (ROIv[ii]); ROIv[ii] = NULL; /* free the Drawn ROI */
05082       SUMA_free(ip);ip=NULL;
05083    }
05084 
05085    if (LocalHead) {
05086       SUMA_disp_dvect (NodesTotal, N_NodesTotal);
05087    }
05088 
05089    /* Now you want to make sure that no two nodes are listed twice */
05090    /* sort NodesTotal and rearrange LabelsTotal accordingly */
05091    {  int *isort = NULL, *LabelsTotal_r = NULL,
05092          *NodesTotal_u = NULL, N_NodesTotal_u, *iu = NULL;
05093       char report[100];
05094 
05095       isort = SUMA_z_dqsort(NodesTotal, N_NodesTotal);
05096       LabelsTotal_r = SUMA_reorder (LabelsTotal, isort, N_NodesTotal);
05097       SUMA_free(LabelsTotal);
05098       LabelsTotal = LabelsTotal_r; LabelsTotal_r = NULL;
05099       SUMA_free(isort); isort = NULL;
05100 
05101       /* now get the unique set of nodes */
05102       NodesTotal_u = SUMA_UniqueInt_ind (NodesTotal, N_NodesTotal, &N_NodesTotal_u, &iu);
05103       /* reorder LabelsTotal to contain data from the nodes left in NodesTotal_u */
05104       LabelsTotal_r = SUMA_reorder (LabelsTotal, iu, N_NodesTotal_u);
05105       SUMA_free(NodesTotal); NodesTotal = NULL;
05106       SUMA_free(LabelsTotal); LabelsTotal = NULL;
05107       SUMA_free(iu); iu = NULL;
05108       NodesTotal = NodesTotal_u; NodesTotal_u = NULL;
05109       LabelsTotal = LabelsTotal_r; LabelsTotal_r = NULL;
05110 
05111       if (N_NodesTotal - N_NodesTotal_u) {
05112          sprintf(report, "%d/%d nodes had duplicate entries.\n"
05113                          "(ie same node part of more than 1 ROI)\n"
05114                          "Duplicate entries were eliminated.", 
05115                          N_NodesTotal - N_NodesTotal_u , N_NodesTotal);
05116 
05117          N_NodesTotal = N_NodesTotal_u; N_NodesTotal_u = 0;
05118          SUMA_SLP_Warn(report);
05119       }
05120    }
05121 
05122    if (Pad_to > 0) {
05123       SUMA_LH("Padding to desired length");
05124       if (Pad_to < MaxIndex) {
05125          SUMA_SL_Err("ROI contains node index > padding limit\nNo padding done.");
05126          if (NodesTotal) SUMA_free(NodesTotal); NodesTotal = NULL;
05127          if (LabelsTotal) SUMA_free(LabelsTotal); LabelsTotal = NULL;
05128          SUMA_RETURN(NULL);
05129       }else {
05130          NodesTotal_p =  (int *)SUMA_calloc(Pad_to+1, sizeof(int));
05131          LabelsTotal_p = (int *)SUMA_calloc(Pad_to+1, sizeof(int));
05132          if (!NodesTotal_p || !LabelsTotal_p) {
05133             SUMA_SL_Crit("Failed to allocate for NodesTotal_p || LabelsTotal_p");
05134             if (NodesTotal) SUMA_free(NodesTotal); NodesTotal = NULL;
05135             if (LabelsTotal) SUMA_free(LabelsTotal); LabelsTotal = NULL;
05136             SUMA_RETURN(NULL);
05137          }
05138          if (Pad_val)  for(i=0; i<=Pad_to; ++i) LabelsTotal_p[i] = Pad_val;
05139          for(i=0; i<=Pad_to; ++i) NodesTotal_p[i] = i;
05140          for(i=0; i<N_NodesTotal; ++i) {
05141             LabelsTotal_p[NodesTotal[i]] = LabelsTotal[i];
05142          }
05143          SUMA_free(NodesTotal); NodesTotal = NodesTotal_p; NodesTotal_p = NULL;
05144          SUMA_free(LabelsTotal);  LabelsTotal = LabelsTotal_p; LabelsTotal_p = NULL;
05145          N_NodesTotal = Pad_to + 1;
05146       }
05147    }
05148    
05149    /* construct a NIML data set for the output */
05150    SUMA_LH("Creating dset ");
05151    dset = SUMA_CreateDsetPointer(
05152                                  NULL,         /* usually the filename */
05153                                  SUMA_NODE_ROI,                /* mix and match */
05154                                  NULL,    /* no idcode, let the function create one from the filename*/
05155                                  Parent_idcode_str,       /* no domain str specified */
05156                                  N_NodesTotal    /* Number of nodes allocated for */
05157                                  ); /* DO NOT free dset, it is store in DsetList */
05158 
05159    
05160    
05161    if (!dset) {
05162       SUMA_SL_Err("Failed in SUMA_CreateDsetPointer");
05163       SUMA_RETURN(NULL);
05164    }
05165 
05166    /* Add the index column */
05167    SUMA_LH("Adding index column...");
05168    if (!SUMA_AddDsetNelCol (dset, "node index", SUMA_NODE_INDEX, (void *)NodesTotal, NULL, 1)) {
05169       SUMA_SL_Err("Failed in SUMA_AddNelCol");
05170       SUMA_RETURN(dset);
05171    }
05172 
05173    /* Add the label column */
05174    SUMA_LH("Adding label column...");
05175    if (!SUMA_AddDsetNelCol (dset, "integer label", SUMA_NODE_ILABEL, (void *)LabelsTotal, NULL, 1)) {
05176       SUMA_SL_Err("Failed in SUMA_AddNelCol");
05177       SUMA_RETURN(dset);
05178    }
05179    
05180    /* make it easy */
05181    dset->dnel = SUMA_FindDsetDataAttributeElement(dset);
05182 
05183    SUMA_LH("cleanup ...");
05184    if (NodesTotal) SUMA_free(NodesTotal); NodesTotal = NULL;
05185    if (LabelsTotal) SUMA_free(LabelsTotal); LabelsTotal = NULL;
05186    
05187    SUMA_RETURN(dset);
05188 }
05189    
05190 /*!
05191    \brief turns a bunch of ROIs into a NI dataset
05192    
05193    \param ROIv (SUMA_DRAWN_ROI**) vector of ROI structures
05194    \param N_ROIv (int) number of ROI structures
05195    \param Parent_idcode_str (char *) idcode of parent surface
05196    \param Pad_to (int)  create Dset that has a full node listing 
05197                         from node 0 to node Pad_to (a total of Pad_to + 1 nodes)
05198                         Use -1 to turn off padding.
05199    \param Pad_val (int) use this value (usually 0) to label a node being padded
05200                         as oppsed to a node being a part of an ROI. This option
05201                         is only useful with Pad_to
05202    \return nel (NI_element *) structure to data set
05203                               NULL if failed
05204 */
05205 NI_element *SUMA_ROIv2dataset (SUMA_DRAWN_ROI** ROIv, int N_ROIv, char *Parent_idcode_str, int Pad_to, int Pad_val) 
05206 {
05207    static char FuncName[]={"SUMA_ROIv2dataset"};
05208    int ii, i, nn, cnt, N_NodesTotal = 0, MaxIndex = 0,
05209       *ip=NULL, *NodesTotal=NULL, *LabelsTotal=NULL,
05210       *NodesTotal_p=NULL, *LabelsTotal_p=NULL;
05211    NI_element *nel=NULL;
05212    SUMA_Boolean LocalHead = NOPE;
05213    
05214    SUMA_ENTRY;
05215    
05216    SUMA_SL_Err("Obsolete, use SUMA_ROIv2Grpdataset");
05217    SUMA_RETURN(NULL);
05218    
05219    /* Now you have the ROIs, concatenate all NodesInROI vectors into 1*/
05220    /* count the total number of nodes */
05221    N_NodesTotal = 0;
05222    for (ii=0; ii < N_ROIv; ++ii) {
05223       SUMA_ROI_CRUDE_COUNT_NODES(ROIv[ii], cnt);
05224       if (LocalHead) {
05225          fprintf (SUMA_STDERR,"%s: ROI #%d: %d nodes\n", FuncName, ii, cnt);
05226       }
05227       N_NodesTotal += cnt;
05228    }
05229    if (LocalHead) fprintf (SUMA_STDERR,"%s: %d nodes total.\n", FuncName, N_NodesTotal);
05230 
05231    NodesTotal = (int *)SUMA_calloc(N_NodesTotal, sizeof(int));
05232    LabelsTotal = (int *)SUMA_calloc(N_NodesTotal, sizeof(int));
05233 
05234    if (!NodesTotal || !LabelsTotal) {
05235       SUMA_S_Err("Failed to allocate.");
05236       SUMA_RETURN(nel);
05237    }
05238 
05239    cnt = 0;
05240    N_NodesTotal = 0;
05241    MaxIndex = -1;
05242    for (ii=0; ii <  N_ROIv; ++ii) {
05243       SUMA_LH("Appending ROI");
05244       /* You do not need the Unique operation in SUMA_NodesInROI,
05245       but it is nice to have so that you can report the nodes that 
05246       were part of more than one ROI. If you do not Set the Unique 
05247       flag in SUMA_NodesInROI you will likely get node duplication
05248       but these nodes are in the same ROI and therefore are not
05249       duplicates to be removed....*/
05250       ip = SUMA_NodesInROI (ROIv[ii], &nn, YUP);
05251       if (LocalHead) {
05252          fprintf (SUMA_STDERR,"%s: Nodes in ROI #%d\n", FuncName, ii);
05253          SUMA_disp_dvect (ip, nn);
05254       }
05255       for (i=0; i < nn; ++i) {
05256          NodesTotal[cnt] = ip[i];
05257          LabelsTotal[cnt] = ROIv[ii]->iLabel;
05258          if (ip[i] > MaxIndex) MaxIndex = ip[i];
05259          ++cnt;
05260       }
05261       N_NodesTotal += nn;
05262       SUMA_freeDrawnROI (ROIv[ii]); ROIv[ii] = NULL; /* free the Drawn ROI */
05263       SUMA_free(ip);ip=NULL;
05264    }
05265 
05266    if (LocalHead) {
05267       SUMA_disp_dvect (NodesTotal, N_NodesTotal);
05268    }
05269 
05270    /* Now you want to make sure that no two nodes are listed twice */
05271    /* sort NodesTotal and rearrange LabelsTotal accordingly */
05272    {  int *isort = NULL, *LabelsTotal_r = NULL,
05273          *NodesTotal_u = NULL, N_NodesTotal_u, *iu = NULL;
05274       char report[100];
05275 
05276       isort = SUMA_z_dqsort(NodesTotal, N_NodesTotal);
05277       LabelsTotal_r = SUMA_reorder (LabelsTotal, isort, N_NodesTotal);
05278       SUMA_free(LabelsTotal);
05279       LabelsTotal = LabelsTotal_r; LabelsTotal_r = NULL;
05280       SUMA_free(isort); isort = NULL;
05281 
05282       /* now get the unique set of nodes */
05283       NodesTotal_u = SUMA_UniqueInt_ind (NodesTotal, N_NodesTotal, &N_NodesTotal_u, &iu);
05284       /* reorder LabelsTotal to contain data from the nodes left in NodesTotal_u */
05285       LabelsTotal_r = SUMA_reorder (LabelsTotal, iu, N_NodesTotal_u);
05286       SUMA_free(NodesTotal); NodesTotal = NULL;
05287       SUMA_free(LabelsTotal); LabelsTotal = NULL;
05288       SUMA_free(iu); iu = NULL;
05289       NodesTotal = NodesTotal_u; NodesTotal_u = NULL;
05290       LabelsTotal = LabelsTotal_r; LabelsTotal_r = NULL;
05291 
05292       if (N_NodesTotal - N_NodesTotal_u) {
05293          sprintf(report, "%d/%d nodes had duplicate entries.\n"
05294                          "(ie same node part of more than 1 ROI)\n"
05295                          "Duplicate entries were eliminated.", 
05296                          N_NodesTotal - N_NodesTotal_u , N_NodesTotal);
05297 
05298          N_NodesTotal = N_NodesTotal_u; N_NodesTotal_u = 0;
05299          SUMA_SLP_Warn(report);
05300       }
05301    }
05302 
05303    if (Pad_to > 0) {
05304       SUMA_LH("Padding to desired length");
05305       if (Pad_to < MaxIndex) {
05306          SUMA_SL_Err("ROI contains node index > padding limit\nNo padding done.");
05307          if (NodesTotal) SUMA_free(NodesTotal); NodesTotal = NULL;
05308          if (LabelsTotal) SUMA_free(LabelsTotal); LabelsTotal = NULL;
05309          SUMA_RETURN(NULL);
05310       }else {
05311          NodesTotal_p =  (int *)SUMA_calloc(Pad_to+1, sizeof(int));
05312          LabelsTotal_p = (int *)SUMA_calloc(Pad_to+1, sizeof(int));
05313          if (!NodesTotal_p || !LabelsTotal_p) {
05314             SUMA_SL_Crit("Failed to allocate for NodesTotal_p || LabelsTotal_p");
05315             if (NodesTotal) SUMA_free(NodesTotal); NodesTotal = NULL;
05316             if (LabelsTotal) SUMA_free(LabelsTotal); LabelsTotal = NULL;
05317             SUMA_RETURN(NULL);
05318          }
05319          if (Pad_val)  for(i=0; i<=Pad_to; ++i) LabelsTotal_p[i] = Pad_val;
05320          for(i=0; i<=Pad_to; ++i) NodesTotal_p[i] = i;
05321          for(i=0; i<N_NodesTotal; ++i) {
05322             LabelsTotal_p[NodesTotal[i]] = LabelsTotal[i];
05323          }
05324          SUMA_free(NodesTotal); NodesTotal = NodesTotal_p; NodesTotal_p = NULL;
05325          SUMA_free(LabelsTotal);  LabelsTotal = LabelsTotal_p; LabelsTotal_p = NULL;
05326          N_NodesTotal = Pad_to + 1;
05327       }
05328    }
05329    
05330    /* construct a NIML data set for the output */
05331    SUMA_LH("Creating nel ");
05332    nel = SUMA_NewNel ( SUMA_NODE_ROI, /* one of SUMA_DSET_TYPE */
05333                        Parent_idcode_str, /* idcode of Domain Parent */
05334                        NULL, /* idcode of geometry parent, not useful here*/
05335                        N_NodesTotal,/* Number of elements */
05336                        NULL,
05337                        NULL); 
05338 
05339    if (!nel) {
05340       SUMA_SL_Err("Failed in SUMA_NewNel");
05341       SUMA_RETURN(nel);
05342    }
05343 
05344    /* Add the index column */
05345    SUMA_LH("Adding index column...");
05346    if (!SUMA_AddNelCol (nel, "node index", SUMA_NODE_INDEX, (void *)NodesTotal, NULL, 1)) {
05347       SUMA_SL_Err("Failed in SUMA_AddNelCol");
05348       SUMA_RETURN(nel);
05349    }
05350 
05351    /* Add the label column */
05352    SUMA_LH("Adding label column...");
05353    if (!SUMA_AddNelCol (nel, "integer label", SUMA_NODE_ILABEL, (void *)LabelsTotal, NULL, 1)) {
05354       SUMA_SL_Err("Failed in SUMA_AddNelCol");
05355       SUMA_RETURN(nel);
05356    }
05357    
05358    SUMA_LH("cleanup ...");
05359    if (NodesTotal) SUMA_free(NodesTotal); NodesTotal = NULL;
05360    if (LabelsTotal) SUMA_free(LabelsTotal); LabelsTotal = NULL;
05361    
05362    SUMA_RETURN(nel);
05363 }
05364    
05365 #ifdef SUMA_ROI2dataset_STAND_ALONE
05366 void usage_ROI2dataset_Main ()
05367    
05368   {/*Usage*/
05369       static char FuncName[]={"usage_ROI2dataset_Main"};
05370       char * s = NULL;
05371       fprintf(SUMA_STDOUT, 
05372             "\n"
05373             "Usage: \n"
05374             "   ROI2dataset <-prefix dsetname> [...] <-input ROI1 ROI2 ...>\n"
05375             "               [<-of ni_bi|ni_as|1D>] \n"
05376             "               [<-dom_par_id idcode>] \n"
05377           /* "   [<-dom_par domain> NOT IMPLEMENTED YET] \n" */
05378             "    This program transforms a series of ROI files\n"
05379             "    to a node dataset. This data set will contain\n"
05380             "    the node indices in the first column and their\n"
05381             "    ROI values in the second column.\n"
05382             "    Duplicate node entries (nodes that are part of\n"
05383             "    multiple ROIs) will get ignored. You will be\n"
05384             "    notified when this occurs. \n"
05385             "\n"
05386             "Mandatory parameters:\n"
05387             "    -prefix dsetname: Prefix of output dataset.\n"
05388             "                      Program will not overwrite existing\n"
05389             "                      datasets.\n"
05390             "    -input ROI1 ROI2....: ROI files to turn into a \n"
05391             "                          data set. This parameter MUST\n"
05392             "                          be the last one on command line.\n"
05393             "\n"
05394             "Optional parameters:\n"
05395             "(all optional parameters must be specified before the\n"
05396             " -input parameters.)\n"
05397             "    -h | -help: This help message\n"
05398             "    -of FORMAT: Output format of dataset. FORMAT is one of:\n"
05399             "                ni_bi: NIML binary\n"
05400             "                ni_as: NIML ascii (default)\n"
05401             "                1D   : 1D AFNI format.\n"
05402             "    -dom_par_id id: Idcode of domain parent.\n"
05403             "                    When specified, only ROIs have the same\n"
05404             "                    domain parent are included in the output.\n"
05405             "                    If id is not specified then the first\n"
05406             "                    domain parent encountered in the ROI list\n"
05407             "                    is adopted as dom_par_id.\n"
05408             "                    1D roi files do not have domain parent \n"
05409             "                    information. They will be added to the \n"
05410             "                    output data under the chosen dom_par_id.\n"
05411             "    -pad_to_node max_index: Output a full dset from node 0 \n"
05412             "                            to node max_index (a total of \n"
05413             "                            max_index + 1 nodes). Nodes that\n"
05414             "                            are not part of any ROI will get\n"
05415             "                            a default label of 0 unless you\n"
05416             "                            specify your own padding label.\n"
05417             "    -pad_val padding_label: Use padding_label (an integer) to\n"
05418             "                            label nodes that do not belong\n"
05419             "                            to any ROI. Default is 0.\n" 
05420             "\n");
05421          s = SUMA_New_Additions(0, 1); printf("%s\n", s);SUMA_free(s); s = NULL;
05422          fprintf(SUMA_STDOUT, 
05423             "       Ziad S. Saad SSCC/NIMH/NIH ziad@nih.gov \n");
05424      exit (0);
05425   }/*Usage*/
05426    
05427 int main (int argc,char *argv[])
05428 {/* Main */
05429    static char FuncName[]={"ROI2dataset"}; 
05430    char  *prefix_name, **input_name_v=NULL, *out_name=NULL, 
05431          *Parent_idcode_str = NULL, *dummy_idcode_str = NULL, *stmp=NULL;
05432    int kar, brk, N_input_name, cnt = 0, N_ROIv, N_tROI, ii, i, nn, pad_to, pad_val;
05433    SUMA_DSET *dset=NULL;
05434    NI_stream ns;
05435    SUMA_DSET_FORMAT Out_Format = SUMA_ASCII_NIML;
05436    SUMA_DRAWN_ROI ** ROIv = NULL, **tROIv = NULL;
05437         SUMA_Boolean AddThis = NOPE;
05438    SUMA_Boolean LocalHead = NOPE;
05439         
05440    SUMA_mainENTRY;
05441    SUMA_STANDALONE_INIT;
05442         
05443    if (argc < 4) {
05444       usage_ROI2dataset_Main ();
05445    }
05446    
05447    /* parse the command line */
05448    kar = 1;
05449         brk = NOPE;
05450    prefix_name = NULL;
05451    input_name_v = NULL;
05452    N_input_name = 0;
05453    Out_Format = SUMA_ASCII_NIML;
05454    Parent_idcode_str = NULL;
05455    pad_to = -1;
05456    pad_val = 0;
05457    while (kar < argc) { /* loop accross command ine options */
05458                 /* SUMA_LH("Parsing command line..."); */
05459       
05460                 if (strcmp(argv[kar], "-h") == 0 || strcmp(argv[kar], "-help") == 0) {
05461                          usage_ROI2dataset_Main();
05462           exit (1);
05463                 }
05464       
05465       SUMA_SKIP_COMMON_OPTIONS(brk, kar);
05466       
05467       if (!brk && (strcmp(argv[kar], "-prefix") == 0)) {
05468          kar ++;
05469                         if (kar >= argc)  {
05470                                 fprintf (SUMA_STDERR, "need argument after -prefix ");
05471                                 exit (1);
05472                         }
05473                         prefix_name = argv[kar];
05474          brk = YUP;
05475                 }
05476       
05477       if (!brk && (strcmp(argv[kar], "-of") == 0)) {
05478          kar ++;
05479                         if (kar >= argc)  {
05480                                 fprintf (SUMA_STDERR, "need argument after -of ");
05481                                 exit (1);
05482                         }
05483                         if (!strcmp(argv[kar], "ni_as")) Out_Format = SUMA_ASCII_NIML;
05484          else if (!strcmp(argv[kar], "ni_bi")) Out_Format = SUMA_BINARY_NIML;
05485          else if (!strcmp(argv[kar], "1D")) Out_Format = SUMA_1D;
05486          else {
05487             fprintf (SUMA_STDERR, "%s not a valid option with -of.\n", argv[kar]);
05488                                 exit (1);
05489          }   
05490          brk = YUP;
05491                 }
05492       
05493       if (!brk && (strcmp(argv[kar], "-dom_par_id") == 0)) {
05494          kar ++;
05495                         if (kar >= argc)  {
05496                                 fprintf (SUMA_STDERR, "need argument after -dom_par_id");
05497                                 exit (1);
05498                         }
05499                         Parent_idcode_str = SUMA_copy_string(argv[kar]);
05500          brk = YUP;
05501       }
05502       
05503       if (!brk && (strcmp(argv[kar], "-input") == 0)) {
05504          kar ++;
05505                         if (kar >= argc)  {
05506                                 fprintf (SUMA_STDERR, "need at least one argument after -input ");
05507                                 exit (1);
05508                         }
05509          input_name_v = (char **)SUMA_malloc((argc-kar+1)*sizeof(char *));
05510          
05511          cnt = 0;
05512          while (kar < argc) {
05513             input_name_v[cnt] = argv[kar];
05514             ++cnt; ++kar;
05515          }
05516          N_input_name = cnt;
05517          brk = YUP;
05518       }
05519       
05520       if (!brk && (strcmp(argv[kar], "-pad_to_node") == 0)) {
05521          kar ++;
05522                         if (kar >= argc)  {
05523                                 fprintf (SUMA_STDERR, "need argument after -pad_to_node");
05524                                 exit (1);
05525                         }
05526                         pad_to = atoi(argv[kar]);
05527          brk = YUP;
05528       }
05529       
05530       if (!brk && (strcmp(argv[kar], "-pad_label") == 0)) {
05531          kar ++;
05532                         if (kar >= argc)  {
05533                                 fprintf (SUMA_STDERR, "need argument after -pad_label");
05534                                 exit (1);
05535                         }
05536                         pad_val = atoi(argv[kar]);
05537          brk = YUP;
05538       }
05539       
05540       if (!brk) {
05541                         fprintf (SUMA_STDERR,"Error %s: Option %s not understood. Try -help for usage\n", FuncName, argv[kar]);
05542                         exit (1);
05543                 } else {        
05544                         brk = NOPE;
05545                         kar ++;
05546                 }   
05547    }   
05548    
05549    if (!prefix_name) {
05550       fprintf (SUMA_STDERR,"Error %s: No output prefix was specified.\n", FuncName);
05551       exit(1);
05552    }
05553    
05554    /* form the output name and check for existence */
05555    switch (Out_Format) {
05556       case SUMA_ASCII_NIML:
05557       case SUMA_BINARY_NIML:
05558          out_name = SUMA_Extension(prefix_name, ".niml.dset", NOPE); 
05559          break;
05560       case SUMA_1D:
05561          out_name = SUMA_Extension(prefix_name, ".1D.dset", NOPE); 
05562          break;
05563       default:
05564          SUMA_S_Err("Output format not supported");
05565          exit(1);
05566          break;
05567    }
05568    
05569    SUMA_LH (out_name);
05570     
05571    /* check for existence of out_name */
05572    if (SUMA_filexists(out_name)) {
05573       fprintf(SUMA_STDERR,"Error %s:\n Output file %s exists.\n", 
05574                            FuncName, out_name);
05575       exit(1); 
05576    }
05577    
05578    /* check for input files */
05579    if (N_input_name <= 0) {
05580       fprintf(SUMA_STDERR,"Error %s:\n No ROI files specified.\n",
05581                            FuncName);
05582       exit(1); 
05583    }
05584     
05585    /* read in the data sets */
05586    /* create a dummy idcode_str for potential 1D data sets */
05587    N_ROIv = 0;
05588    Parent_idcode_str = NULL;
05589    dummy_idcode_str = UNIQ_hashcode("DummyNameNothingLikeIt");
05590    for (i=0; i < N_input_name; ++i) {
05591       if (SUMA_isExtension(input_name_v[i], ".niml.roi")) {
05592          /* load niml ROI */
05593          if (!( tROIv = SUMA_OpenDrawnROI_NIML (input_name_v[i], &N_tROI, NOPE))) {
05594             SUMA_S_Err("Failed to read NIML ROI.");
05595             exit(1);
05596          }
05597       }else if (SUMA_isExtension(input_name_v[i], ".1D.roi")) {
05598          /* load 1D ROI */
05599          if (!( tROIv = SUMA_OpenDrawnROI_1D (input_name_v[i], dummy_idcode_str, &N_tROI, NOPE))) {
05600             SUMA_S_Err("Failed to read NIML ROI.");
05601             exit(1);
05602          }
05603       }else {
05604          SUMA_S_Err(  "Failed to recognize\n"
05605                       "ROI type from filename.");
05606          exit(1);
05607       } 
05608       
05609       /* copy temporary ROIv into the main ROIv */
05610       ROIv = (SUMA_DRAWN_ROI **)SUMA_realloc(ROIv, (N_ROIv + N_tROI) * sizeof(SUMA_DRAWN_ROI*));
05611       if (!ROIv) {
05612          SUMA_S_Err("Failed to allocate.");
05613          exit(1);
05614       }
05615 
05616       /* Now go throught the ROIs and load them if possible into ROIv */
05617       for (ii=0; ii < N_tROI; ++ii) {
05618          if (!Parent_idcode_str) {
05619             /* try to find out what the Parent_idcode_str is */
05620             if (strcmp(tROIv[ii]->Parent_idcode_str, dummy_idcode_str)) {
05621                fprintf (SUMA_STDERR,"%s: Adopting Parent_idcode_str (%s) in ROI %s\n",
05622                                   FuncName, tROIv[ii]->Parent_idcode_str, tROIv[ii]->Label);
05623                /* good, use it as the Parent_idcode_str for all upcoming ROIs */
05624                Parent_idcode_str = SUMA_copy_string(tROIv[ii]->Parent_idcode_str);
05625             }
05626          } 
05627          
05628          AddThis = NOPE;
05629          if (!strcmp(tROIv[ii]->Parent_idcode_str, dummy_idcode_str)) {
05630             AddThis = YUP;
05631          } else {
05632             if (strcmp(tROIv[ii]->Parent_idcode_str, Parent_idcode_str)) {
05633                fprintf (SUMA_STDERR,"Warning %s:\n Ignoring ROI labeled %s\n"
05634                                     "because of Parent_idcode_str mismatch.\n", 
05635                                     FuncName, tROIv[ii]->Label); 
05636                AddThis = NOPE;
05637                /* free structure of tROIv[ii] */
05638                SUMA_freeDrawnROI (tROIv[ii]); tROIv[ii] = NULL;
05639             }
05640             else AddThis = YUP;
05641             
05642          }
05643          if (AddThis) {
05644             if (LocalHead) fprintf (SUMA_STDERR,"%s: Adding %dth ROI to ROIv...\n",
05645                             FuncName, N_ROIv);
05646             ROIv[N_ROIv] = tROIv[ii];
05647             
05648             ++N_ROIv;
05649          }
05650           
05651       }
05652       /* now free tROIv vector */
05653       if (tROIv) SUMA_free(tROIv); tROIv = NULL;  
05654    }
05655    
05656    if (LocalHead) {
05657       fprintf (SUMA_STDERR,"%s: Kept a total of %d ROIs with parent %s\n",
05658                         FuncName, N_ROIv, Parent_idcode_str);
05659         
05660    }
05661    
05662    if (!(dset = SUMA_ROIv2Grpdataset (ROIv, N_ROIv, Parent_idcode_str, pad_to, pad_val))) {
05663       SUMA_SL_Err("Failed in SUMA_ROIv2Grpdataset");
05664       exit(1);
05665    }
05666    
05667    if (LocalHead) {
05668       fprintf (SUMA_STDERR,"%s: Adding history\n",
05669                         FuncName);
05670         
05671    }
05672    
05673    /* Add the history line */
05674    if (!SUMA_AddNgrHist (dset->ngr, FuncName, argc, argv)) {
05675       SUMA_SL_Err("Failed in SUMA_AddNgrHist");
05676       exit(1);
05677    }
05678 
05679 
05680    if (LocalHead) {
05681       fprintf (SUMA_STDERR,"%s: preparing to write results\n",
05682                         FuncName);
05683         
05684    }
05685    
05686    /* open stream */
05687    stmp = SUMA_append_string ("file:", out_name);
05688    ns = NI_stream_open( stmp , "w" ) ;
05689    if( ns == NULL ){
05690       fprintf (stderr,"Error  %s:\nCan't open %s!"
05691                   , FuncName, stmp); 
05692       exit(1);
05693    }
05694    
05695    /* write nel */
05696    switch (Out_Format) {
05697       case SUMA_ASCII_NIML:
05698          nn = NI_write_element(  ns , dset->ngr , NI_TEXT_MODE ); 
05699          break;
05700       case SUMA_BINARY_NIML:
05701          nn = NI_write_element(  ns , dset->ngr , NI_BINARY_MODE ); 
05702          break;
05703       case SUMA_1D:
05704          nn = NI_write_element(  ns , dset->dnel , NI_TEXT_MODE | NI_HEADERSHARP_FLAG);  
05705          break;
05706       default:
05707          SUMA_S_Err("Output format not supported");
05708          exit(1);
05709          break;
05710    }
05711  
05712    if (nn < 0) {
05713       SUMA_S_Err ("Failed in NI_write_element");
05714       exit(1);
05715    }
05716    
05717    /* close the stream */
05718    NI_stream_close( ns ) ; 
05719    
05720    /* free nel */
05721    SUMA_FreeDset(dset); dset = NULL;
05722    
05723    /* free others */
05724    if (stmp) SUMA_free(stmp);
05725    if (ROIv) SUMA_free (ROIv);
05726    if (out_name) SUMA_free(out_name);
05727    if (Parent_idcode_str) SUMA_free(Parent_idcode_str);
05728    if (dummy_idcode_str) free(dummy_idcode_str); /* this one's allocated 
05729                                                    by Bob's functions */
05730    return(0);
05731 }/* Main */
05732 #endif   
05733 
05734 /*!
05735    \brief handles savinf SO to ascii filename
05736    
05737    \param filename (char *)
05738    \param data(void *) pointer to SUMA_SAVESO_STRUCT containing sv and SO be saved
05739    
05740    - This function frees the SUMA_SAVESO_STRUCT before returning
05741 */
05742 void SUMA_SaveSOascii (char *filename, void *data)
05743 {
05744    static char FuncName[]={"SUMA_SaveSOascii"};
05745    char *newname = NULL, *newprefix = NULL, *tmp1= NULL, *tmp2= NULL;
05746    FILE *Fout = NULL;
05747    static int answer;
05748    int ND=-1, NP=-1, ii=-1, id=-1,ip=-1; 
05749    GLfloat *glar_ColorList = NULL;
05750    SUMA_SAVESO_STRUCT *SaveSO_data = NULL;
05751    SUMA_Boolean LocalHead = NOPE;
05752    
05753    SUMA_ENTRY;
05754 
05755    SUMA_LH("Called");   
05756       
05757    if (!data) {
05758       SUMA_SLP_Err("NULL data");
05759       SUMA_RETURNe;
05760    }
05761    
05762    SaveSO_data = (SUMA_SAVESO_STRUCT *)data;
05763    if (!SaveSO_data->SO || !SaveSO_data->sv) {
05764       SUMA_SLP_Err("Null SO or Null sv");
05765       if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
05766       SUMA_RETURNe;
05767    }
05768    
05769    /* remove any of the extensions to be used */
05770    tmp1 = SUMA_Extension(filename, ".1D.xyz", YUP);
05771    tmp2 = SUMA_Extension(tmp1, ".1D.tri", YUP);
05772    newprefix = SUMA_Extension(tmp2, ".1D.col", YUP);
05773    if (tmp1) SUMA_free(tmp1); tmp1 = NULL;
05774    if (tmp2) SUMA_free(tmp2); tmp2 = NULL;
05775    
05776    /* add a .xyz extension */
05777    if (newname) SUMA_free(newname); newname = NULL;
05778    newname = SUMA_Extension(newprefix, ".1D.xyz", NOPE); 
05779    if (!newname) {
05780       SUMA_SL_Err("Invalid filename");
05781       if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
05782       SUMA_RETURNe;
05783    }
05784    SUMA_LH(newname);
05785    /* check for filename existence */
05786    if (SUMA_filexists (newname)) {
05787       answer = SUMA_ForceUser_YesNo (SUMAg_SVv[0].X->TOPLEVEL, 
05788                                     "Prefix exists, overwrite?", 
05789                                     SUMA_NO, SWP_DONT_CARE);
05790       if (answer == SUMA_NO ||answer == SUMA_NO_ALL) {
05791          if (newname) SUMA_free(newname); newname = NULL;
05792          if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
05793          SUMA_RETURNe; 
05794       }
05795    } 
05796 
05797    /* add a .tri extension */
05798    if (answer != SUMA_YES_ALL && answer != SUMA_YES) {
05799       if (newname) SUMA_free(newname);newname = NULL;
05800       newname = SUMA_Extension(newprefix, ".1D.tri", NOPE); 
05801       if (!newname) {
05802          SUMA_SL_Err("Invalid filename");
05803          if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
05804          SUMA_RETURNe;
05805       }
05806       SUMA_LH(newname);
05807       /* check for filename existence */
05808       if (SUMA_filexists (newname)) {
05809          answer = SUMA_ForceUser_YesNo (SUMAg_SVv[0].X->TOPLEVEL, 
05810                                        "Prefix exists, overwrite?", 
05811                                        SUMA_NO, SWP_DONT_CARE);
05812          if (answer == SUMA_NO ||answer == SUMA_NO_ALL) {
05813             if (newname) SUMA_free(newname);newname = NULL;
05814             if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
05815             SUMA_RETURNe; 
05816          }
05817       } 
05818    }
05819    
05820    /* add a .col extension */
05821    if (answer != SUMA_YES_ALL  && answer != SUMA_YES) {
05822       if (newname) SUMA_free(newname); newname = NULL;
05823       newname = SUMA_Extension(newprefix, ".1D.col", NOPE); 
05824       if (!newname) {
05825          SUMA_SL_Err("Invalid filename");
05826          if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
05827          SUMA_RETURNe;
05828       }
05829       SUMA_LH(newname);
05830       /* check for filename existence */
05831       if (SUMA_filexists (newname)) {
05832          answer = SUMA_ForceUser_YesNo (SUMAg_SVv[0].X->TOPLEVEL, 
05833                                        "Prefix exists, overwrite?", 
05834                                        SUMA_NO, SWP_DONT_CARE);
05835          if (answer == SUMA_NO ||answer == SUMA_NO_ALL) {
05836             if (newname) SUMA_free(newname);newname = NULL;
05837             if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
05838             SUMA_RETURNe; 
05839          }
05840       } 
05841    }
05842    
05843    /* OK, names are acceptable, proceed */
05844    ND = SaveSO_data->SO->NodeDim;
05845    NP = SaveSO_data->SO->FaceSetDim;
05846 
05847    if (newname) SUMA_free(newname);newname = NULL;
05848    newname = SUMA_Extension(newprefix, ".1D.xyz", NOPE);  
05849    if (LocalHead) fprintf (SUMA_STDERR,"%s: Preparing to write .1D.xyz %s.\n", FuncName, newname); 
05850    Fout = fopen(newname, "w");
05851    if (Fout == NULL) {
05852       fprintf(SUMA_STDERR, "Error %s: Could not open file %s for writing.\n", FuncName, newname);
05853       if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
05854       SUMA_RETURNe;
05855    }
05856 
05857    fprintf(Fout, "#FileContents = Node coordinates\n#RowFormat = X Y Z\n#N_Nodes = %d\n#Source = SUMA, surface %s (idcode: %s)\n",
05858           SaveSO_data->SO->N_Node, SaveSO_data->SO->Label, SaveSO_data->SO->idcode_str);
05859    for (ii=0; ii < SaveSO_data->SO->N_Node; ++ii) {
05860       id = ND * ii;
05861       fprintf(Fout, "%f\t%f\t%f\n", \
05862          SaveSO_data->SO->NodeList[id], SaveSO_data->SO->NodeList[id+1],SaveSO_data->SO->NodeList[id+2]);
05863    }
05864    fclose (Fout);
05865 
05866    if (newname) SUMA_free(newname);newname = NULL;
05867    newname = SUMA_Extension(newprefix, ".1D.tri", NOPE);  
05868    if (LocalHead) fprintf (SUMA_STDERR,"%s: Preparing to write .1D.tri %s.\n", FuncName, newname); 
05869    Fout = fopen(newname, "w");
05870    if (Fout == NULL) {
05871       fprintf(SUMA_STDERR, "Error %s: Could not open file %s for writing.\n", FuncName, newname);
05872       if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
05873       SUMA_RETURNe;
05874    }
05875    
05876    fprintf(Fout, "#FileContents = Triangles\n#RowFormat = n1 n2 n3\n#N_Tri = %d\n#Source = SUMA, surface %s (idcode: %s)\n",
05877           SaveSO_data->SO->N_FaceSet, SaveSO_data->SO->Label, SaveSO_data->SO->idcode_str);
05878    for (ii=0; ii < SaveSO_data->SO->N_FaceSet; ++ii) {
05879       ip = NP * ii;
05880       fprintf(Fout, "%d\t%d\t%d\n", \
05881          SaveSO_data->SO->FaceSetList[ip], SaveSO_data->SO->FaceSetList[ip+1],SaveSO_data->SO->FaceSetList[ip+2]);
05882    }
05883    fclose (Fout);
05884 
05885    if (newname) SUMA_free(newname);newname = NULL;
05886    newname = SUMA_Extension(newprefix, ".1D.col", NOPE);  
05887    if (LocalHead) fprintf (SUMA_STDERR,"%s: Preparing to write .1D.col %s.\n", FuncName, newname); 
05888    Fout = fopen(newname, "w");
05889    if (Fout == NULL) {
05890       fprintf(SUMA_STDERR, "Error %s: Could not open file %s for writing.\n", FuncName, newname);
05891       if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
05892       SUMA_RETURNe;
05893    }
05894     glar_ColorList = SUMA_GetColorList (SaveSO_data->sv, SaveSO_data->SO->idcode_str);
05895     if (!glar_ColorList) {
05896       fprintf(SUMA_STDERR, "Error %s: NULL glar_ColorList. BAD.\n", FuncName);
05897       if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
05898       SUMA_RETURNe;
05899     }
05900    fprintf(Fout, "#FileContents = Node Colors\n#RowFormat = n R G B\n#N_Nodes = %d\n#Source = SUMA, surface %s (idcode: %s)\n",
05901           SaveSO_data->SO->N_Node, SaveSO_data->SO->Label, SaveSO_data->SO->idcode_str);
05902    for (ii=0; ii < SaveSO_data->SO->N_Node; ++ii) {
05903       ip = 4 * ii;
05904       fprintf(Fout, "%d\t%f\t%f\t%f\n", \
05905          ii, glar_ColorList[ip], glar_ColorList[ip+1], glar_ColorList[ip+2]);
05906    }
05907    fclose (Fout);
05908 
05909    if (LocalHead) fprintf(SUMA_STDERR, "%s: Wrote files to disk.\n", 
05910       FuncName);
05911 
05912    if (newname) SUMA_free(newname);newname = NULL;
05913    if (SaveSO_data) SUMA_free(SaveSO_data); SaveSO_data = NULL;
05914    if (newprefix) SUMA_free(newprefix); 
05915    SUMA_RETURNe;
05916 }
05917 
05918 /*!
05919    \brief handles saving ROI to filename.
05920    
05921    \param filename (char *)
05922    \param data(void *) pointer to DrawnROI stucture to be saved.
05923           If you pass null then SUMAg_CF->X->DrawROI->curDrawnROI is used.
05924 */
05925 void SUMA_SaveDrawnROI (char *filename, void *data)
05926 {
05927    static char FuncName[]={"SUMA_SaveDrawnROI"};
05928    SUMA_DRAWN_ROI *DrawnROI=NULL;
05929    SUMA_SurfaceObject *SO= NULL;
05930    SUMA_Boolean LocalHead = NOPE;
05931    
05932    SUMA_ENTRY;
05933 
05934    SUMA_LH("Called");   
05935    if (!data) {
05936       DrawnROI = SUMAg_CF->X->DrawROI->curDrawnROI;
05937    } else {
05938       DrawnROI = (SUMA_DRAWN_ROI *)data;
05939    }
05940    
05941    /* is there a DrawnROI to work with ? */
05942    if (!DrawnROI) {
05943       SUMA_SLP_Err("No ROI selected.");
05944       SUMA_RETURNe;
05945    }
05946    
05947    /* Find the parent SO of that ROI */
05948    SO = SUMA_findSOp_inDOv(DrawnROI->Parent_idcode_str, SUMAg_DOv, SUMAg_N_DOv);
05949    if (!SO) {
05950       SUMA_SLP_Err("No Parent surface found.");
05951       SUMA_RETURNe;
05952    }
05953    
05954    /* switch the type of saving */
05955    switch (SUMAg_CF->X->DrawROI->SaveMode) {
05956       case SW_DrawROI_SaveMode1D:
05957          if (!SUMA_SaveDrawnROI_1D (filename, SO, DrawnROI, SUMAg_CF->X->DrawROI->SaveWhat)) {
05958             SUMA_SLP_Err("Failed to save ROI to disk");
05959             SUMA_RETURNe;
05960          }   
05961          break;
05962       case SW_DrawROI_SaveModeNIML:
05963          if (!SUMA_SaveDrawnROINIML (filename, SO, DrawnROI, SUMAg_CF->X->DrawROI->SaveWhat, SUMA_ASCII)) {
05964             SUMA_SLP_Err("Failed to save ROI to disk");
05965             SUMA_RETURNe;
05966          }
05967          break;
05968       case SW_DrawROI_SaveMode:
05969       case SW_N_DrawROI_SaveMode:
05970       default:
05971          SUMA_SL_Err("WhatYouTalkinAbout?");
05972          SUMA_RETURNe;
05973          break;
05974    }
05975    
05976    SUMA_RETURNe;
05977 } 
05978 
05979 SUMA_Boolean SUMA_SaveDrawnROI_1D (char *filename, SUMA_SurfaceObject *SO, SUMA_DRAWN_ROI *DrawnROI, int SaveWhat) 
05980 {
05981    static char FuncName[]={"SUMA_SaveDrawnROI_1D"};
05982    char stmp[SUMA_MAX_NAME_LENGTH+20];
05983    SUMA_DRAWN_ROI **ROIv = NULL;
05984    int N_ROI=0;
05985    SUMA_Boolean LocalHead = NOPE;
05986    
05987    SUMA_ENTRY;
05988    SUMA_LH("Called");   
05989 
05990    if (SaveWhat == SW_DrawROI_SaveWhatThis) {
05991       if (!SUMA_Write_DrawnROI_1D (&DrawnROI, 1, filename)) {
05992          sprintf(stmp,"Failed to write %s", filename);
05993          SUMA_SLP_Err(stmp);
05994          SUMA_RETURN(NOPE);
05995       }
05996    }else if (SaveWhat == SW_DrawROI_SaveWhatRelated){
05997       /* get the pointers to the ROIs that are related to SO*/
05998       if (!(ROIv = SUMA_Find_ROIrelatedtoSO (SO, SUMAg_DOv, SUMAg_N_DOv, &N_ROI))) {
05999          SUMA_SLP_Err("Failed to write ROIs related to SO.");
06000          SUMA_RETURN(NOPE);
06001       }
06002       if (!SUMA_Write_DrawnROI_1D (ROIv, N_ROI, filename)) {
06003          sprintf(stmp,"Failed to write %s", filename);
06004          SUMA_SLP_Err(stmp);
06005          SUMA_RETURN(NOPE);
06006       }
06007         
06008       if (ROIv) SUMA_free(ROIv);    
06009    } else {
06010       SUMA_SLP_Err("SaveWhat option not nderstood");
06011       SUMA_RETURN(NOPE);
06012    }
06013    
06014    
06015 
06016    SUMA_RETURN(YUP);
06017 }
06018 
06019 SUMA_Boolean SUMA_SaveDrawnROINIML (char *filename, SUMA_SurfaceObject *SO, SUMA_DRAWN_ROI *DrawnROI, int SaveWhat, int Format) 
06020 {
06021    static char FuncName[]={"SaveDrawnROINIML"};
06022    char stmp[SUMA_MAX_NAME_LENGTH+20];
06023    SUMA_DRAWN_ROI **ROIv = NULL;
06024    int N_ROI=0;
06025    SUMA_Boolean LocalHead = NOPE;
06026    
06027    SUMA_ENTRY;
06028    SUMA_LH("Called");   
06029 
06030    if (SaveWhat == SW_DrawROI_SaveWhatThis) {
06031       if (!SUMA_Write_DrawnROI_NIML (&DrawnROI, 1, filename, Format)) {
06032          sprintf(stmp,"Failed to write %s", filename);
06033          SUMA_SLP_Err(stmp);
06034          SUMA_RETURN(NOPE);
06035       }
06036    }else if (SaveWhat == SW_DrawROI_SaveWhatRelated){
06037       /* get the pointers to the ROIs that are related to SO*/
06038       if (!(ROIv = SUMA_Find_ROIrelatedtoSO (SO, SUMAg_DOv, SUMAg_N_DOv, &N_ROI))) {
06039          SUMA_SLP_Err("Failed to write ROIs related to SO.");
06040          SUMA_RETURN(NOPE);
06041       }
06042       if (!SUMA_Write_DrawnROI_NIML (ROIv, N_ROI, filename, Format)) {
06043          sprintf(stmp,"Failed to write %s", filename);
06044          SUMA_SLP_Err(stmp);
06045          SUMA_RETURN(NOPE);
06046       }
06047         
06048       if (ROIv) SUMA_free(ROIv);    
06049    } else {
06050       SUMA_SLP_Err("SaveWhat option not nderstood");
06051       SUMA_RETURN(NOPE);
06052    }
06053   
06054    SUMA_RETURN(YUP);
06055 }
06056 
06057 /*!
06058    \brief writes a vector of SUMA_DRAWN_ROI * to disk in NIML format
06059 */
06060 
06061 SUMA_Boolean SUMA_Write_DrawnROI_NIML (SUMA_DRAWN_ROI **ROIv, int N_ROI, char *filename, int Format) 
06062 {
06063    static char FuncName[]={"SUMA_Write_DrawnROI_NIML"};
06064    char stmp[SUMA_MAX_NAME_LENGTH+20];
06065    char *newname=NULL;
06066    int i;
06067    NI_element *nel ;
06068    NI_stream ns ;
06069    SUMA_NIML_DRAWN_ROI *niml_ROI = NULL;
06070    SUMA_DRAWN_ROI *ROI = NULL;
06071    SUMA_Boolean WriteBin = NOPE, LocalHead = NOPE;
06072 
06073    SUMA_ENTRY;
06074 
06075    if (Format == SUMA_ASCII) WriteBin = NOPE;
06076    else if (Format == SUMA_BINARY) WriteBin = YUP;
06077    else {
06078       SUMA_SL_Err("Wrong format");
06079       SUMA_RETURN(NOPE);
06080    }
06081    
06082    if (SUMAg_CF->nimlROI_Datum_type < 0) {
06083       SUMA_SL_Err("Bad niml type code");
06084       SUMA_RETURN(NOPE);
06085    }
06086    if (LocalHead) fprintf(SUMA_STDERR, "%s: roi_type code = %d\n", FuncName, SUMAg_CF->nimlROI_Datum_type) ;
06087 
06088    /* add a .niml.roi extension */
06089    if (strlen(filename) >= SUMA_MAX_NAME_LENGTH-20) {
06090       SUMA_SLP_Err("Give me a break, what kind of a filename is this ?");
06091       SUMA_RETURN(NOPE);
06092    }
06093 
06094    sprintf(stmp,"file:%s", filename);
06095    newname = SUMA_Extension(stmp, ".niml.roi", NOPE); 
06096    SUMA_LH(newname);
06097    ns = NI_stream_open( newname , "w" ) ;
06098 
06099    /* write the various ROIs */
06100    for (i=0; i < N_ROI; ++i) {
06101       ROI = ROIv[i];
06102       if (!ROI) {
06103          SUMA_SL_Err("NULL ROI!");
06104          NI_stream_close( ns ) ; 
06105          SUMA_RETURN(NOPE);
06106       }
06107       /* Transform the ROI to niml friendly structure */
06108       if (!(niml_ROI = SUMA_DrawnROI_to_NIMLDrawnROI (ROI))) {
06109          SUMA_SL_Err("NULL niml_ROI!");
06110          NI_stream_close( ns ) ; 
06111          SUMA_RETURN(NOPE);
06112       }
06113  
06114       /* Now create a ni element */
06115       if (LocalHead) fprintf(SUMA_STDERR,"%s: Creating new element of %d segments\n", FuncName, niml_ROI->N_ROI_datum);
06116       nel = NI_new_data_element(SUMA_Dset_Type_Name(SUMA_NODE_ROI),  niml_ROI->N_ROI_datum);
06117 
06118       SUMA_LH("Adding column...");
06119       NI_add_column( nel , SUMAg_CF->nimlROI_Datum_type, niml_ROI->ROI_datum );
06120 
06121       SUMA_LH("Setting attributes...");
06122       NI_set_attribute (nel, "Object_ID", niml_ROI->idcode_str);
06123       NI_set_attribute (nel, "Parent_ID", niml_ROI->Parent_idcode_str);
06124       NI_set_attribute (nel, "Label", niml_ROI->Label);
06125       sprintf(stmp,"%d", niml_ROI->iLabel);
06126       NI_set_attribute (nel, "iLabel", stmp);
06127       sprintf(stmp,"%d", niml_ROI->Type);
06128       NI_set_attribute (nel, "Type", stmp);
06129       NI_set_attribute (nel, "ColPlaneName", niml_ROI->ColPlaneName);
06130       sprintf(stmp,"%f %f %f", niml_ROI->FillColor[0], niml_ROI->FillColor[1],
06131                               niml_ROI->FillColor[2]);
06132       NI_set_attribute (nel, "FillColor",stmp);
06133       sprintf(stmp,"%f %f %f", niml_ROI->EdgeColor[0], niml_ROI->EdgeColor[1],
06134                               niml_ROI->EdgeColor[2]);
06135       NI_set_attribute (nel, "EdgeColor",stmp);
06136       sprintf(stmp,"%d", niml_ROI->EdgeThickness);
06137       NI_set_attribute (nel, "EdgeThickness", stmp);                   
06138       
06139       if (LocalHead) SUMA_nel_stdout (nel);
06140 
06141       if (!WriteBin) {
06142          SUMA_LH ("Writing element, Text mode.");
06143          if (NI_write_element( ns , nel , NI_TEXT_MODE | NI_HEADERSHARP_FLAG ) < 0) {
06144            SUMA_SL_Err("Badness, failed to write nel");
06145            NI_stream_close( ns ) ; 
06146            SUMA_RETURN(NOPE);
06147          }
06148       } else {
06149          SUMA_LH ("Writing element, Binary mode.");
06150          if (NI_write_element( ns , nel , NI_BINARY_MODE) < 0) {
06151            SUMA_SL_Err("Badness, failed to write nel");
06152            NI_stream_close( ns ) ; 
06153            SUMA_RETURN(NOPE);
06154          }
06155       } 
06156 
06157       /* free nel */
06158       NI_free_element(nel) ; nel = NULL;
06159 
06160       /* free the niml_ROI structure */
06161       niml_ROI = SUMA_Free_NIMLDrawROI (niml_ROI); niml_ROI = NULL;
06162       
06163    }
06164    
06165    NI_stream_close( ns ) ; 
06166    
06167    if (newname) SUMA_free(newname);
06168    
06169    SUMA_RETURN(YUP);
06170 }
06171 
06172 
06173 /*!
06174    \brief A function to take a SUMA_DRAWN_ROI struct and return an equivalent
06175    SUMA_1D_DRAWN_ROI struct. 
06176    
06177    - Do not free SUMA_1D_DRAWN_ROI manually, many of its fields are 
06178    pointer copies of values in SUMA_DRAWN_ROI.
06179    
06180    \sa SUMA_Free_1DDrawROI
06181 */
06182 SUMA_1D_DRAWN_ROI * SUMA_DrawnROI_to_1DDrawROI (SUMA_DRAWN_ROI *ROI)
06183 {
06184    static char FuncName[]={"SUMA_DrawnROI_to_1DDrawROI"};
06185    SUMA_1D_DRAWN_ROI *ROI_1D=NULL;
06186    SUMA_ROI_DATUM *ROI_Datum=NULL;
06187    DListElmt *Elm = NULL;
06188    int i = -1, cnt = 0, *isort=NULL, *iLabel=NULL, *iNode=NULL;
06189    SUMA_Boolean LocalHead = NOPE;
06190 
06191    SUMA_ENTRY;
06192 
06193    if (!ROI) {
06194       SUMA_SL_Err("Null ROI");
06195       SUMA_RETURN(NULL);
06196    }
06197    
06198    /* count the total number of nodes in ROI */
06199    
06200    /* allocate for nimlROI */
06201    ROI_1D = (SUMA_1D_DRAWN_ROI *)SUMA_malloc(sizeof(SUMA_1D_DRAWN_ROI));
06202    Elm = NULL;
06203    ROI_1D->N = 0;
06204    do {
06205       if (!Elm) Elm = dlist_head(ROI->ROIstrokelist); 
06206       else Elm = Elm->next;
06207       ROI_Datum = (SUMA_ROI_DATUM *)Elm->data;
06208       ROI_1D->N += ROI_Datum->N_n;
06209    } while (Elm != dlist_tail(ROI->ROIstrokelist));
06210       
06211    ROI_1D->Type = (int)ROI->Type;
06212    ROI_1D->idcode_str = ROI->idcode_str;
06213    ROI_1D->Parent_idcode_str = ROI->Parent_idcode_str;
06214    ROI_1D->Label = ROI->Label;
06215    ROI_1D->iNode = NULL;
06216    ROI_1D->iLabel = NULL;
06217    iNode = (int *) SUMA_calloc(ROI_1D->N, sizeof(int));
06218    iLabel = (int *) SUMA_calloc(ROI_1D->N, sizeof(int));
06219    if (!iNode || !iLabel) {
06220       SUMA_SL_Err("Failed to allocate");
06221       SUMA_RETURN(NULL);
06222    }
06223    
06224    /* now fill the node indices and the node values */
06225    Elm = NULL;
06226    cnt = 0;
06227    do {
06228       if (!Elm) Elm = dlist_head(ROI->ROIstrokelist);
06229       else Elm = Elm->next;
06230       ROI_Datum = (SUMA_ROI_DATUM *)Elm->data;
06231       for (i=0; i < ROI_Datum->N_n; ++i) {
06232          iNode[cnt] = ROI_Datum->nPath[i];
06233          iLabel[cnt] = ROI->iLabel;
06234          ++cnt;
06235       }
06236    } while (Elm != dlist_tail(ROI->ROIstrokelist));
06237    
06238    /* some node entries are redundant, clear those up */
06239    /* first sort iNode */
06240    isort = SUMA_z_dqsort( iNode, ROI_1D->N);
06241 
06242    /* Now sort the labels accordingly */
06243    ROI_1D->iLabel = (int *) SUMA_calloc(ROI_1D->N, sizeof(int));
06244    ROI_1D->iNode = (int *) SUMA_calloc(ROI_1D->N, sizeof(int));
06245    if (!ROI_1D->iNode || !ROI_1D->iLabel) {
06246       SUMA_SL_Err("Failed to allocate");
06247       SUMA_RETURN(NULL);
06248    }
06249    
06250    for (i=0; i < ROI_1D->N; ++i) {
06251       ROI_1D->iLabel[i] = iLabel[isort[i]];
06252    }
06253    if (iLabel) SUMA_free(iLabel); iLabel = NULL; /* done with unsorted version of iLabel */
06254    
06255    /* Now remove redundant entries */
06256    cnt = 0;
06257    ROI_1D->iNode[cnt] = iNode[0]; 
06258    ROI_1D->iLabel[cnt] = ROI_1D->iLabel[0];
06259    ++cnt;
06260    for (i=1;i<ROI_1D->N;++i)
06261     {
06262       if ((iNode[i] != iNode[i- 1]))
06263          {
06264             ROI_1D->iNode[cnt] = iNode[i];
06265             ROI_1D->iLabel[cnt] = ROI_1D->iLabel[i]; 
06266             ++cnt;   
06267          }
06268    }
06269 
06270    
06271    /* you would reallocate here, because cnt is always <= ROI_1D->N,
06272    but it is not worth the effort because cnt is only slightly
06273    less than ROI_1D->N */
06274    
06275    /* just update ROI_1D->N */
06276    ROI_1D->N = cnt;
06277    
06278    if (isort) SUMA_free(isort); isort = NULL;
06279    if (iNode) SUMA_free(iNode); iNode = NULL;
06280    
06281    SUMA_RETURN(ROI_1D);
06282 }
06283 
06284 /*!
06285    \brief frees a ROI_1D structure. These structures are created by
06286     the likes of SUMA_DrawnROI_to_1DDrawROI
06287     
06288     \sa SUMA_DrawnROI_to_1DDrawROI
06289 */
06290 SUMA_1D_DRAWN_ROI * SUMA_Free_1DDrawROI (SUMA_1D_DRAWN_ROI *ROI_1D)
06291 {
06292    static char FuncName[]={"SUMA_Free_1DDrawROI"};
06293    SUMA_Boolean LocalHead = NOPE;
06294    
06295    SUMA_ENTRY;
06296 
06297    if (!ROI_1D) SUMA_RETURN(NULL);
06298    
06299    if (ROI_1D->iLabel) SUMA_free(ROI_1D->iLabel); 
06300    if (ROI_1D->iNode) SUMA_free(ROI_1D->iNode);
06301    
06302    SUMA_free(ROI_1D);
06303    
06304    SUMA_RETURN(NULL);
06305 }
06306 
06307 
06308 /*!
06309    \brief writes a vector of SUMA_DRAWN_ROI * to disk in afni's 1D ascii format
06310 */
06311 
06312 SUMA_Boolean SUMA_Write_DrawnROI_1D (SUMA_DRAWN_ROI **ROIv, int N_ROI, char *filename) 
06313 {
06314    static char FuncName[]={"SUMA_Write_DrawnROI_1D"};
06315    char *newname=NULL;
06316    int i,j;
06317    SUMA_1D_DRAWN_ROI *ROI_1D = NULL;
06318    SUMA_DRAWN_ROI *ROI = NULL;
06319    FILE *fout=NULL;
06320    SUMA_Boolean LocalHead = NOPE;
06321 
06322    SUMA_ENTRY;
06323 
06324    /* add a .1D.roi extension */
06325    newname = SUMA_Extension(filename, ".1D.roi", NOPE); 
06326    if (!newname) {
06327       SUMA_SL_Err("Invalid filename");
06328       SUMA_RETURN(NOPE);
06329    }
06330    
06331    SUMA_LH(newname);
06332 
06333    fout = fopen(newname,"w");
06334    if (!fout) {
06335       SUMA_SL_Err("Failed to open file for writing.");
06336       SUMA_RETURN(NOPE);
06337    }
06338 
06339    /* write the various ROIs */
06340    for (i=0; i < N_ROI; ++i) {
06341       ROI = ROIv[i];
06342       if (!ROI) {
06343          SUMA_SL_Err("NULL ROI!");
06344          fclose(fout);
06345          SUMA_RETURN(NOPE);
06346       }
06347       /* Transform the ROI to niml friendly structure */
06348       if (!(ROI_1D = SUMA_DrawnROI_to_1DDrawROI (ROI))) {
06349          SUMA_SL_Err("NULL niml_ROI!");
06350          fclose(fout);
06351          SUMA_RETURN(NOPE);
06352       }
06353 
06354       /* write it out in a NIML friendly format */
06355       /* begin with attributes */
06356       fprintf (fout,"# %s\n", SUMA_Dset_Type_Name(SUMA_NODE_ROI));
06357       fprintf (fout,"#  ni_type = \"SUMA_1D_ROI_DATUMorint,int?\"\n");
06358       fprintf (fout,"#  ni_dimen = \"%d\"\n",  ROI_1D->N);
06359       fprintf (fout,"#  ni_datasize = \"???\"\n");
06360       fprintf (fout,"#  idcode_str = \"%s\"\n", ROI_1D->idcode_str);
06361       fprintf (fout,"#  Parent_idcode_str = \"%s\"\n", ROI_1D->Parent_idcode_str);
06362       fprintf (fout,"#  Label = \"%s\"\n", ROI_1D->Label);
06363       fprintf (fout,"# >\n");
06364       for (j=0; j < ROI_1D->N; ++j) 
06365          fprintf (fout," %d %d\n", ROI_1D->iNode[j], ROI_1D->iLabel[j]);
06366       fprintf (fout,"# </%s>\n", SUMA_Dset_Type_Name(SUMA_NODE_ROI));
06367       fprintf (fout,"\n");
06368        
06369       /* free the ROI_1D structure */
06370       ROI_1D = SUMA_Free_1DDrawROI (ROI_1D); ROI_1D = NULL;
06371    }
06372    
06373    fclose(fout) ; 
06374    if (newname) SUMA_free(newname);
06375    
06376    SUMA_RETURN(YUP);
06377 }
06378 
06379 
06380 SUMA_FORM_AFNI_DSET_STRUCT *SUMA_New_FormAfniDset_Opt(void)
06381 {
06382    static char FuncName[]={"SUMA_New_FormAfniDset_Opt"};
06383    SUMA_FORM_AFNI_DSET_STRUCT *Opt=NULL;
06384    
06385    SUMA_ENTRY;
06386    
06387    Opt = (SUMA_FORM_AFNI_DSET_STRUCT*)SUMA_malloc(sizeof(SUMA_FORM_AFNI_DSET_STRUCT));
06388    
06389    Opt->master = NULL;
06390    Opt->mset = NULL;
06391    Opt->mask = NULL;
06392    Opt->prefix = NULL;
06393    Opt->prefix_path = NULL;
06394    Opt->orcode = NULL;
06395    Opt->do_ijk = 1;
06396    Opt->dimen_ii=0;
06397    Opt->dimen_jj=0;
06398    Opt->dimen_kk=0;
06399    Opt->datum=MRI_short;
06400    Opt->dval=1.0;
06401    Opt->fval=0.0;
06402    Opt->mmask=NULL;
06403    Opt->full_list = 0;
06404    
06405    SUMA_RETURN(Opt);
06406 }
06407 
06408 SUMA_FORM_AFNI_DSET_STRUCT *SUMA_Free_FormAfniDset_Opt(SUMA_FORM_AFNI_DSET_STRUCT *Opt)
06409 {
06410    static char FuncName[]={"SUMA_Free_FormAfniDset_Opt"};
06411    SUMA_ENTRY;
06412    
06413    if (!Opt) SUMA_RETURN(NULL);
06414    
06415    if (Opt->master) SUMA_free(Opt->master);
06416    if (Opt->mask) SUMA_free(Opt->mask);  
06417    if (Opt->mset) {
06418       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");
06419    } 
06420    if (Opt->prefix) SUMA_free(Opt->prefix);
06421    if (Opt->prefix_path) SUMA_free(Opt->prefix_path);
06422    if (Opt->mmask) SUMA_free(Opt->mmask);
06423    if (Opt->orcode) SUMA_free(Opt->orcode);
06424    SUMA_free(Opt);
06425    
06426    SUMA_RETURN(NULL);
06427 }
06428 
06429 /*!
06430    (stolen from 3dUndump)
06431    \param NodeList (float *) (3*N_valsx1) XYZ or IJK coordinates. 
06432                              Can be NULL if Opt->full_list = 1.
06433                              &(NodeList[3*n]) is the pointer for the coordinates of entry ni  
06434    \param vals     (float *) (N_valsx1) vector of values. Can be NULL, in which case the
06435                              default value in Opt is used.
06436    \param N_vals   (int) number of values. If Opt->full_list then N_vals must be equal to the 
06437                              number of voxels in the data set (dimen_ii*dimen_jj*dimen_kk) 
06438                              as specified by Opt's fields or the master set.
06439    \param Opt (SUMA_FORM_AFNI_DSET_STRUCT *) The famed options structure:
06440       master: Name of master dset. NULL if none
06441       mask: Name of mask dset. NULL if none. 
06442       prefix: Prefix of output. Must have.
06443       orcode: Orientation string. NULL if none, like RAI, LPI, etc.
06444       do_ijk: 1 = coordinates in NodeList are voxel indices (i j k)
06445               0 = coordinates in NodeList are voxel dicomm coordinates (x y z)
06446       dimen_ii(_jj, _kk): Number of voxels in ii (jj, kk) directions. 
06447                           Do not use with master option
06448                           Must use either master or dimen options.
06449       datum: output data type: MRI_short(default), MRI_byte, MRI_float only.
06450       dval: Default data value (default 1). Used if vals is NULL
06451       fval: Default fill value (default 0). 
06452       mmask: (byte *) mask of (dimen_ii*dimen_jj*dimen_kk x 1) values always. This can
06453                       be used to pass a predefined mask. NULL if not
06454                       interested in it. Cannot specify it along with mask
06455                       option above. If both NodeList and Vals are null, then
06456                       mmask is used as data, replaces vals in a way. If mmask points
06457                       to non NULL, the memory at that pointer is freed when Opt is freed.
06458       full_list: 1 = full list, coordinates are inferred from 1D index of array.
06459                      N_vals == dimen_ii*dimen_jj*dimen_kk. Requires NodeList == NULL
06460                  0 = not a full list NodeList != NULL
06461    - See  SUMA_Free_FormAfniDset_Opt for freeing Opt and its contents
06462    
06463    \return dset (THD_3dim_dataset *) output dset.
06464                                      Write it to disk with :   DSET_write(dset) ;
06465                                      Delete it with: DSET_delete(dset); dset = NULL;
06466 
06467    - FUNCTION NOT FULLY TESTED for all options, USE WITH CARE : Feb 08 05
06468 */
06469 THD_3dim_dataset *SUMA_FormAfnidset (float *NodeList, float *vals, int N_vals, SUMA_FORM_AFNI_DSET_STRUCT *Opt)
06470 {
06471    static char FuncName[]={"SUMA_FormAfnidset"};
06472    THD_coorder cord;
06473    int ii=0,jj=0,kk=0,ll=0,ijk=0 , nx=0,ny=0,nz=0 , nxyz=0 ;
06474    float      xx,yy,zz,vv=0.0 , dx,dy,dz;
06475    short               sv=0   ;
06476    byte                bv=0   ;
06477    float *fbr=NULL, fval_float, dval_float;
06478    byte *bbr=NULL, *mmask=NULL, fval_byte, dval_byte;
06479    short *sbr=NULL, fval_short, dval_short;
06480    char *orcode=NULL;
06481    float xxdown =0.0,xxup=0.0 , yydown=0.0,yyup=0.0 , zzdown=0.0,zzup=0.0 ;
06482    
06483    THD_3dim_dataset *dset=NULL, *mset=NULL, *maskset=NULL;
06484 
06485    /* check for badiosity */
06486    if( Opt->do_ijk == 0 && Opt->master == NULL ) {
06487       SUMA_SL_Err("Can't use mm coords without master.") ;
06488       SUMA_RETURN(NULL);
06489    }
06490    if( (Opt->master == NULL && Opt->mset == NULL) && Opt->dimen_ii < 2 ) {
06491       SUMA_SL_Err("Must use exactly one of Opt->master or Opt->dimen options");
06492       SUMA_RETURN(NULL);
06493    }
06494    if (Opt->master && Opt->mset) {
06495       SUMA_SL_Err("Cannot use Opt->master and Opt->mset");
06496       SUMA_RETURN(NULL);
06497    }
06498    
06499    fval_byte = (byte)Opt->fval;
06500    fval_short = (short)Opt->fval;
06501    fval_float = (float)Opt->fval;
06502    dval_byte = (byte)Opt->dval;
06503    dval_short = (short)Opt->dval;
06504    dval_float = (float)Opt->dval;
06505    
06506    if( (Opt->datum == MRI_short && dval_short == fval_short) ||
06507     (Opt->datum == MRI_float && dval_float == fval_float) ||
06508     (Opt->datum == MRI_byte  && dval_byte  == fval_byte )   ){
06509 
06510       SUMA_SL_Warn("dval and fval are the same!") ;
06511    }
06512 
06513    if (Opt->full_list && NodeList) {
06514       SUMA_SL_Err("Opt->full_list && NodeList");
06515       SUMA_RETURN(NULL);
06516    }
06517    if (!Opt->full_list && !NodeList &&!Opt->mmask) {
06518       SUMA_SL_Err("!Opt->full_list && !NodeList && !Opt->mmask");
06519       SUMA_RETURN(NULL);
06520    }
06521 
06522    if (!Opt->prefix || !Opt->prefix_path) {
06523       SUMA_SL_Err("Need a prefix and a prefix_path Joe.");
06524       SUMA_RETURN(NULL);
06525    }
06526 
06527    if (!NodeList && !vals && !Opt->mmask) {
06528       SUMA_SL_Warn("Creating a dataset of constants. (!NodeList && !vals && !Opt->mmask)");
06529    }
06530    
06531    if (Opt->master) {
06532       mset = THD_open_dataset(Opt->master);
06533       if( mset == NULL ) {
06534          SUMA_SL_Err("-master: can't open dataset" ) ; 
06535          SUMA_RETURN(dset);
06536       }
06537    }
06538    if (Opt->mset) mset = Opt->mset;
06539    
06540    if ((Opt->master || Opt->mset) && Opt->orcode) {
06541       SUMA_SL_Err("Cannot have bothpt->master && Opt->orcode");
06542       SUMA_RETURN(dset);      
06543    }
06544    
06545    if (Opt->mask && Opt->mmask) {
06546       SUMA_SL_Err("Cannot have both Opt->mask && Opt->mmask");
06547       SUMA_RETURN(dset);
06548    }
06549 
06550    if (Opt->mask) {
06551       maskset = THD_open_dataset( Opt->mask) ;
06552       if( maskset == NULL ) {
06553          SUMA_SL_Err("-mask: can't open dataset" ) ; 
06554          if (mset) {  DSET_delete(mset); mset = NULL; }
06555          SUMA_RETURN(dset);
06556       }
06557    }
06558    
06559    
06560   /*-- set orcode to value from -master, if this is needed --*/
06561 
06562   if( mset != NULL ){
06563       orcode = malloc(4) ;
06564       orcode[0] = ORIENT_typestr[mset->daxes->xxorient][0] ;
06565       orcode[1] = ORIENT_typestr[mset->daxes->yyorient][0] ;
06566       orcode[2] = ORIENT_typestr[mset->daxes->zzorient][0] ;
06567       orcode[3] = '\0' ;
06568    } else if (Opt->orcode) {
06569       orcode = malloc(4) ; orcode = strcpy(orcode, Opt->orcode);
06570    } else {
06571       SUMA_SL_Err("Huh?");
06572       if (mset) {  DSET_delete(mset); mset = NULL; }
06573       if (maskset) {  DSET_delete(maskset); maskset = NULL; }
06574       SUMA_RETURN(dset);
06575    }
06576 
06577    THD_coorder_fill( orcode , &cord ) ;  /* setup coordinate order */ 
06578 
06579    /*-- make empty dataset --*/
06580    if( mset != NULL ){                 /* from -master */
06581 
06582       dset = EDIT_empty_copy( mset ) ;
06583       EDIT_dset_items( dset ,
06584                           ADN_prefix    , Opt->prefix ,
06585                           ADN_datum_all , Opt->datum ,
06586                           ADN_nvals     , 1 ,
06587                           ADN_ntt       , 0 ,
06588                           ADN_func_type , ISANAT(mset) ? mset->func_type
06589                                                        : FUNC_FIM_TYPE ,
06590 
06591                           ADN_directory_name , Opt->prefix_path ,
06592                           ADN_none ) ;
06593 
06594    } else {                            /* from nothing */
06595      THD_ivec3 iv_nxyz   , iv_xyzorient ;
06596      THD_fvec3 fv_xyzorg , fv_xyzdel ;
06597 
06598      LOAD_IVEC3( iv_nxyz , Opt->dimen_ii , Opt->dimen_jj , Opt->dimen_kk ) ;
06599      LOAD_IVEC3( iv_xyzorient , cord.xxor , cord.yyor , cord.zzor ) ;
06600      LOAD_FVEC3( fv_xyzdel ,
06601                  ORIENT_sign[iv_xyzorient.ijk[0]]=='+' ? 1.0 : -1.0 ,
06602                  ORIENT_sign[iv_xyzorient.ijk[1]]=='+' ? 1.0 : -1.0 ,
06603                  ORIENT_sign[iv_xyzorient.ijk[2]]=='+' ? 1.0 : -1.0  ) ;
06604      LOAD_FVEC3( fv_xyzorg ,
06605                  ORIENT_sign[iv_xyzorient.ijk[0]]=='+' ? -0.5*Opt->dimen_ii : 0.5*Opt->dimen_ii,
06606                  ORIENT_sign[iv_xyzorient.ijk[1]]=='+' ? -0.5*Opt->dimen_jj : 0.5*Opt->dimen_jj,
06607                  ORIENT_sign[iv_xyzorient.ijk[2]]=='+' ? -0.5*Opt->dimen_kk : 0.5*Opt->dimen_kk ) ;
06608 
06609      dset = EDIT_empty_copy( NULL ) ;
06610 
06611      EDIT_dset_items( dset ,
06612                        ADN_nxyz      , iv_nxyz ,
06613                        ADN_xyzdel    , fv_xyzdel ,
06614                        ADN_xyzorg    , fv_xyzorg ,
06615                        ADN_xyzorient , iv_xyzorient ,
06616                        ADN_prefix    , Opt->prefix ,
06617                        ADN_datum_all , Opt->datum ,
06618                        ADN_nvals     , 1 ,
06619                        ADN_ntt       , 0 ,
06620                        ADN_type      , HEAD_FUNC_TYPE ,
06621                        ADN_func_type , FUNC_FIM_TYPE ,
06622                        ADN_directory_name , Opt->prefix_path ,
06623                     ADN_none ) ;
06624 
06625    }
06626 
06627    if( THD_is_file(DSET_HEADNAME(dset)) ) {
06628       SUMA_SL_Err("Output dataset already exists -- can't overwrite") ;
06629       exit(1);
06630    }
06631    /*-- make empty brick array for dataset --*/
06632 
06633    EDIT_substitute_brick( dset , 0 , Opt->datum , NULL ) ;  /* will make array */
06634 
06635    nx = DSET_NX(dset); ny = DSET_NY(dset); nz = DSET_NZ(dset); nxyz = nx*ny*nz;
06636 
06637    if (Opt->full_list && N_vals != nxyz) {
06638       SUMA_SL_Err("Opt->full_list && N_vals != nx*ny*nz");
06639       SUMA_RETURN(NULL);
06640    }
06641    /* 19 Feb 2004: check and make mask if desired */
06642 
06643    if( maskset != NULL &&
06644        ( DSET_NX(maskset) != nx ||
06645          DSET_NY(maskset) != ny ||
06646          DSET_NZ(maskset) != nz   ) ) {
06647      SUMA_SL_Err("mask dataset doesn't match dimension of output dataset") ;
06648      if (mset) {  DSET_delete(mset); mset = NULL; }
06649      if (maskset) {  DSET_delete(maskset); maskset = NULL; }
06650      SUMA_RETURN(NULL);
06651    }
06652 
06653    if( maskset != NULL ){
06654      mmask = THD_makemask( maskset , 0 , 1.0,-1.0 ) ;
06655      SUMA_SL_Warn("can't create mask for some reason!") ;
06656      DSET_delete(maskset) ;
06657    } else mmask = Opt->mmask;
06658 
06659    if( mmask == NULL ){
06660    } else {
06661       int nmask = THD_countmask( nxyz , mmask ) ;
06662       if( nmask == 0 ){
06663          SUMA_SL_Warn("0 voxels in mask -- ignoring it!") ;
06664          if (!Opt->mmask) free((void *)mmask) ; mmask = NULL ;
06665       } else {
06666          fprintf(SUMA_STDERR,"%s:++ %d voxels found in mask\n", FuncName, nmask) ;
06667       }
06668    }
06669 
06670    /*-- fill new dataset brick with the -fval value --*/
06671    switch( Opt->datum ){
06672       case MRI_short:
06673          if (0) fprintf(SUMA_STDERR,"%s: Filling with %d\n", FuncName, fval_short);
06674          sbr = (short *) DSET_BRICK_ARRAY(dset,0) ;
06675          for( ii=0 ; ii < nxyz ; ii++ ) sbr[ii] = fval_short ;
06676       break ;
06677 
06678       case MRI_float:
06679          fbr = (float *) DSET_BRICK_ARRAY(dset,0) ;
06680          for( ii=0 ; ii < nxyz ; ii++ ) fbr[ii] = fval_float ;
06681       break ;
06682 
06683       case MRI_byte:
06684          bbr = (byte *) DSET_BRICK_ARRAY(dset,0) ;
06685          for( ii=0 ; ii < nxyz ; ii++ ) bbr[ii] = fval_byte ;
06686       break ;
06687    }
06688 
06689    /* 24 Nov 2000: get the bounding box for the dataset */
06690 
06691    dx = fabs(dset->daxes->xxdel) ; if( dx <= 0.0 ) dx = 1.0 ;
06692    dy = fabs(dset->daxes->yydel) ; if( dy <= 0.0 ) dy = 1.0 ;
06693    dz = fabs(dset->daxes->zzdel) ; if( dz <= 0.0 ) dz = 1.0 ;
06694 
06695    if( !Opt->do_ijk ){
06696 #ifndef EXTEND_BBOX
06697       xxdown = dset->daxes->xxmin - 0.501 * dx ;
06698       xxup   = dset->daxes->xxmax + 0.501 * dx ;
06699       yydown = dset->daxes->yymin - 0.501 * dy ;
06700       yyup   = dset->daxes->yymax + 0.501 * dy ;
06701       zzdown = dset->daxes->zzmin - 0.501 * dz ;
06702       zzup   = dset->daxes->zzmax + 0.501 * dz ;
06703 #else
06704       xxdown = dset->daxes->xxmin ;
06705       xxup   = dset->daxes->xxmax ;
06706       yydown = dset->daxes->yymin ;
06707       yyup   = dset->daxes->yymax ;
06708       zzdown = dset->daxes->zzmin ;
06709       zzup   = dset->daxes->zzmax ;
06710 #endif
06711    }
06712 
06713    for (ll=0; ll<N_vals; ++ll) {
06714       /* stick 'em in */
06715       if (!Opt->full_list) {
06716          xx = NodeList[3*ll]; yy = NodeList[3*ll+1]; zz = NodeList[3*ll+2]; 
06717          if (Opt->do_ijk) {
06718             ii = (int) rint(xx) ; jj = (int) rint(yy) ; kk = (int) rint(zz) ;
06719             if( ii < 0 || ii >= nx ){
06720                fprintf(stderr,
06721                        "Warning %s: entry %d: i index=%d is invalid, ignoring...\n",
06722                        FuncName,ll,ii) ;
06723                continue ;
06724             }
06725             if( jj < 0 || jj >= ny ){
06726                fprintf(stderr,
06727                        "Warning %s: entry %d: j index=%d is invalid, ignoring...\n",
06728                        FuncName, ll,jj) ;
06729                continue ;
06730             }
06731             if( kk < 0 || kk >= nz ){
06732                fprintf(stderr,
06733                        "Warning %s: entry %d: k index=%d is invalid\n",
06734                        FuncName,ll,kk) ;
06735                continue ;
06736             }
06737          } else {   /* inputs are coordinates => must convert to index */
06738 
06739             THD_fvec3 mv , dv ;                              /* temp vectors */
06740             THD_ivec3 iv ;
06741 
06742             THD_coorder_to_dicom( &cord , &xx,&yy,&zz ) ;    /* to Dicom order */
06743             LOAD_FVEC3( dv , xx,yy,zz ) ;
06744             mv = THD_dicomm_to_3dmm( dset , dv ) ;           /* to Dataset order */
06745 
06746             /* 24 Nov 2000: check (xx,yy,zz) for being inside the box */
06747 
06748             if( mv.xyz[0] < xxdown || mv.xyz[0] > xxup ){
06749                fprintf(stderr,"+++ Warning %s: line %d: x coord=%g is outside %g .. %g\n" ,
06750                        FuncName,ll,mv.xyz[0] , xxdown,xxup ) ;
06751                continue ;
06752             }
06753             if( mv.xyz[1] < yydown || mv.xyz[1] > yyup ){
06754                fprintf(stderr,"+++ Warning %s: line %d: y coord=%g is outside %g .. %g\n" ,
06755                        FuncName,ll,mv.xyz[1] , yydown , yyup ) ;
06756                continue ;
06757             }
06758             if( mv.xyz[2] < zzdown || mv.xyz[2] > zzup ){
06759                fprintf(stderr,"+++ Warning %s: line %d: z coord=%g is outside %g .. %g\n" ,
06760                        FuncName,ll,mv.xyz[2] , zzdown , zzup ) ;
06761                continue ;
06762             }
06763 
06764             iv = THD_3dmm_to_3dind( dset , mv ) ;            /* to Dataset index */
06765             ii = iv.ijk[0]; jj = iv.ijk[1]; kk = iv.ijk[2];  /* save */
06766          }
06767 
06768          ijk = ii + jj*nx + kk*nx*ny ;
06769       } else {
06770          ijk = ll; 
06771       }
06772 
06773       if (vals) vv = vals[ll];
06774       else vv = dval_float ;   
06775 
06776       if( mmask == NULL || mmask[ijk] ){
06777          switch( Opt->datum ){
06778             case MRI_float:{
06779               if( fbr[ijk] != fval_float && fbr[ijk] != vv )
06780                 fprintf(stderr,"Overwrite voxel %d %d %d\n",ii,jj,kk) ;
06781               fbr[ijk] = vv ;
06782             }
06783             break ;
06784             case MRI_short:{
06785               sv = SHORTIZE(vv) ;
06786               if( sbr[ijk] != fval_short && sbr[ijk] != sv )
06787                 fprintf(stderr,"Overwrite voxel %d %d %d\n",ii,jj,kk) ;
06788               sbr[ijk] = sv ;
06789             }
06790             break ;
06791             case MRI_byte:{
06792               bv = BYTEIZE(vv) ;
06793               if( bbr[ijk] != fval_byte && bbr[ijk] != bv )
06794                 fprintf(stderr,"Overwrite voxel %d %d %d\n",ii,jj,kk) ;
06795               bbr[ijk] = bv ;
06796             }
06797             break ;
06798          }
06799       }
06800 
06801    }
06802    
06803    if (orcode) free(orcode); orcode = NULL;
06804    if (mmask && !Opt->mmask) free(mmask); mmask = NULL;
06805    if (mset && !Opt->mset) DSET_delete(mset); mset = NULL; 
06806 
06807    SUMA_RETURN(dset);      
06808 }
06809 
06810 /*! 
06811    \brief A function to change a SurfaceObject to niml format 
06812    \param SO (SUMA_SurfaceObject *)
06813    \param optlist (char *) string indicating what parts of SO to put in ngr
06814                            choose any combination of: NodeList, FaceSetList, 
06815                            EdgeList, MemberFace, NodeNeighb, VolPar, facenormals, 
06816                            NodeNormals, PolyArea, 
06817    \param No_LinksExternalElements (int) 1: Do not include IDs of elements not 
06818                            created inside this group, i.e. not mentioned in optlist
06819                                        0: So include IDs of elements that may reside 
06820                                        on disk.
06821    \return ngr (NI_group *) a NI group element formed from SO. 
06822                            NOTE: That element has the SAME ID as SO!
06823    \sa SUMA_nimlSO2SO
06824 */
06825 NI_group *SUMA_SO2nimlSO(SUMA_SurfaceObject *SO, char *optlist, int nlee) 
06826 {
06827    static char FuncName[]={"SUMA_SO2nimlSO"};
06828    NI_group *ngr = NULL;
06829    NI_element *nel = NULL;
06830    char stmp[500];
06831    SUMA_Boolean LocalHead = NOPE;
06832    
06833    SUMA_ENTRY;
06834    
06835    if (!SO) { 
06836       SUMA_SL_Err("Null SO"); SUMA_RETURN(ngr);
06837    }
06838    
06839    /* create group and name it */
06840    ngr = NI_new_group_element();
06841    NI_rename_group(ngr, "SurfaceObject");
06842    
06843    /** BEGIN ATTRIBUTES COMMON TO ALL OBJECTS **/ 
06844    
06845    /* set the object type attribute */
06846    switch (SO->FaceSetDim) {
06847       case 3:
06848          NI_set_attribute(ngr, "Object_Type", "Triangulated_Surface");
06849          break;
06850       default:
06851          NI_set_attribute(ngr, "Object_Type", SUMA_EMPTY_ATTR);
06852          SUMA_SL_Warn("FaceSetDim not supported");
06853          break;
06854    }      
06855    
06856    /* set the object ID */
06857    if (SO->idcode_str) {
06858       NI_set_attribute(ngr, "Object_ID", SO->idcode_str);
06859    } else {
06860       NI_set_attribute(ngr, "Object_ID", SUMA_EMPTY_ATTR);
06861    }  
06862    
06863    /* set the object Label */
06864    if (SO->Label) {
06865       NI_set_attribute(ngr, "Object_Label", SO->Label);
06866    } else {
06867       NI_set_attribute(ngr, "Object_Label", SUMA_EMPTY_ATTR);
06868    }
06869    
06870    
06871    /* set the parent ID */
06872    if (SO->LocalDomainParentID) {
06873       NI_set_attribute(ngr, "Parent_ID", SO->LocalDomainParentID);
06874    } else {
06875       NI_set_attribute(ngr, "Parent_ID", SUMA_EMPTY_ATTR);
06876    }
06877    
06878    /* set the grand parent ID */
06879    if (SO->DomainGrandParentID) {
06880       NI_set_attribute(ngr, "Grand_Parent_ID", SO->DomainGrandParentID);
06881    } else {
06882       NI_set_attribute(ngr, "Grand_Parent_ID", SUMA_EMPTY_ATTR);
06883    }
06884    
06885    /** END ATTRIBUTES COMMON TO ALL OBJECTS **/      
06886    
06887    /** BEGIN ATTRIBUTES specific to Surfaces**/
06888    if (SO->Group_idcode_str) {
06889       NI_set_attribute(ngr, "Subject_ID", SO->Group_idcode_str);
06890    } else {
06891       NI_set_attribute(ngr, "Subject_ID", SUMA_EMPTY_ATTR);
06892    }
06893    
06894    if (SO->Group) {
06895       NI_set_attribute(ngr, "Subject_Label", SO->Group);
06896    } else {
06897       NI_set_attribute(ngr, "Subject_Label", SUMA_EMPTY_ATTR);
06898    }
06899    
06900    if (SO->OriginatorID) {
06901       NI_set_attribute(ngr, "Instance_ID", SO->OriginatorID);
06902    } else {
06903       NI_set_attribute(ngr, "Instance_ID", SUMA_EMPTY_ATTR);
06904    }
06905    
06906    if (SO->OriginatorLabel) {
06907       NI_set_attribute(ngr, "Instance_Label", SO->OriginatorLabel);
06908    } else {
06909       NI_set_attribute(ngr, "Instance_Label", SUMA_EMPTY_ATTR);
06910    }
06911    
06912    if (SO->ModelName) {
06913       NI_set_attribute(ngr, "Model_Name", SO->ModelName);
06914    } else {
06915       NI_set_attribute(ngr, "Model_Name", SUMA_EMPTY_ATTR);
06916    }
06917    
06918    switch (SO->Side) {
06919       case SUMA_NO_SIDE:
06920          NI_set_attribute(ngr, "Side", "none");
06921          break;
06922       case SUMA_LEFT:
06923          NI_set_attribute(ngr, "Side", "left");
06924          break;
06925       case SUMA_RIGHT:
06926          NI_set_attribute(ngr, "Side", "right");
06927          break;
06928       default:
06929          NI_set_attribute(ngr, "Side", SUMA_EMPTY_ATTR);
06930          break;
06931    }
06932    
06933    if (SO->State) {
06934       NI_set_attribute(ngr, "Layer_Name", SO->State);
06935    } else {
06936       NI_set_attribute(ngr, "Layer_Name", SUMA_EMPTY_ATTR);
06937    }
06938    
06939    if (SO->AnatCorrect) {
06940       NI_set_attribute(ngr, "Anatomically_Correct", "yes");
06941    } else {
06942       NI_set_attribute(ngr, "Anatomically_Correct", "no");
06943    }
06944    
06945    sprintf(stmp,"%d", SO->EmbedDim);
06946    NI_set_attribute(ngr, "Embedding_Dimension", stmp);
06947    
06948    if (SO->FileType >=0) {
06949       sprintf(stmp,"%s", SUMA_SurfaceTypeString(SO->FileType));
06950       NI_set_attribute(ngr, "Surface_Creation_Software",  stmp);
06951    } else {
06952       NI_set_attribute(ngr, "Surface_Creation_Software", SUMA_EMPTY_ATTR);
06953    }
06954    
06955    NI_set_attribute(ngr, "Surface_Creation_History", SUMA_EMPTY_ATTR); 
06956    
06957    if (SO->StandardSpace) {
06958       NI_set_attribute(ngr, "Standard_Space", SO->StandardSpace);
06959    } else {
06960       NI_set_attribute(ngr, "Standard_Space", SUMA_EMPTY_ATTR);
06961    }
06962    
06963    if (!nlee || SUMA_iswordin(optlist,"FaceSetList")) {
06964       if (SO->facesetlist_idcode_str) {
06965          NI_set_attribute(ngr, "Mesh_Element_ID", SO->facesetlist_idcode_str);
06966       } else {
06967          if (SO->idcode_str) {
06968             sprintf(stmp, "facesetlist_idcode_str_%s", SO->idcode_str);
06969             SUMA_NEW_ID(SO->facesetlist_idcode_str, stmp);
06970             NI_set_attribute(ngr, "Mesh_Element_ID", SO->facesetlist_idcode_str);
06971          } else  {
06972             NI_set_attribute(ngr, "Mesh_Element_ID", SUMA_EMPTY_ATTR);
06973          }
06974       }
06975    }
06976    
06977    if (!nlee || SUMA_iswordin(optlist,"NodeList")) {
06978       if (SO->nodelist_idcode_str) {
06979          NI_set_attribute(ngr, "NodeList_Element_ID", SO->nodelist_idcode_str);
06980       } else {
06981          if (SO->idcode_str) {
06982             sprintf(stmp, "nodelist_idcode_str_%s", SO->idcode_str);
06983             SUMA_NEW_ID(SO->nodelist_idcode_str, stmp);
06984             NI_set_attribute(ngr, "NodeList_Element_ID", SO->nodelist_idcode_str);
06985          } else  {
06986             NI_set_attribute(ngr, "NodeList_Element_ID", SUMA_EMPTY_ATTR);
06987          }
06988       }
06989    }
06990    if (!nlee || SUMA_iswordin(optlist,"facenormals")) {
06991       if (SO->facenormals_idcode_str) {
06992          NI_set_attribute(ngr, "Polygon_Normals_Element_ID", SO->facenormals_idcode_str);
06993       } else {
06994          if (SO->idcode_str) {
06995             sprintf(stmp, "facenormals_idcode_str_%s", SO->idcode_str);
06996             SUMA_NEW_ID(SO->facenormals_idcode_str, stmp);
06997             NI_set_attribute(ngr, "Polygon_Normals_Element_ID", SO->facenormals_idcode_str);
06998          } else  {
06999             NI_set_attribute(ngr, "Polygon_Normals_Element_ID", SUMA_EMPTY_ATTR);
07000          }
07001       }
07002    }
07003    
07004    if (!nlee || SUMA_iswordin(optlist,"NodeNormals")) {
07005       if (SO->nodenormals_idcode_str) {
07006          NI_set_attribute(ngr, "Node_Normals_Element_ID", SO->nodenormals_idcode_str);
07007       } else {
07008          if (SO->idcode_str) {
07009             sprintf(stmp, "nodenormals_idcode_str_%s", SO->idcode_str);
07010             SUMA_NEW_ID(SO->nodenormals_idcode_str, stmp);
07011             NI_set_attribute(ngr, "Node_Normals_Element_ID", SO->nodenormals_idcode_str);
07012          } else  {
07013             NI_set_attribute(ngr, "Node_Normals_Element_ID", SUMA_EMPTY_ATTR);
07014          }
07015       }
07016    }
07017    
07018    if (!nlee || SUMA_iswordin(optlist,"PolyArea")) {
07019       if (SO->polyarea_idcode_str) {
07020          NI_set_attribute(ngr, "Polygon_Area_Element_ID", SO->polyarea_idcode_str);
07021       } else {
07022          if (SO->idcode_str) {
07023             sprintf(stmp, "polyarea_idcode_str_%s", SO->idcode_str);
07024             SUMA_NEW_ID(SO->polyarea_idcode_str, stmp);
07025             NI_set_attribute(ngr, "Polygon_Area_Element_ID", SO->polyarea_idcode_str);
07026          } else  {
07027             NI_set_attribute(ngr, "Polygon_Area_Element_ID", SUMA_EMPTY_ATTR);
07028          }
07029       }
07030    }
07031 
07032    if (!nlee || SUMA_iswordin(optlist,"EdgeList")) {
07033       /* add here the edge list, the node neighbor list and the face neighbor list IDs*/
07034       if (SO->EL && SO->EL->idcode_str) {
07035          NI_set_attribute(ngr, "SUMA_Edge_List_Element_ID", SO->EL->idcode_str);
07036       } else {
07037          NI_set_attribute(ngr, "SUMA_Edge_List_Element_ID", SUMA_EMPTY_ATTR);
07038       }
07039    }
07040    
07041    if (!nlee || SUMA_iswordin(optlist,"MemberFace")) {
07042       if (SO->MF && SO->MF->idcode_str) {
07043          NI_set_attribute(ngr, "SUMA_Node_Face_Member_Element_ID", SO->MF->idcode_str);
07044       } else {
07045          NI_set_attribute(ngr, "SUMA_Node_Face_Member_Element_ID", SUMA_EMPTY_ATTR);
07046       }
07047    }
07048    
07049    if (!nlee || SUMA_iswordin(optlist,"NodeNeighb")) {
07050       if (SO->FN && SO->FN->idcode_str) {
07051          NI_set_attribute(ngr, "SUMA_Node_First_Neighb_Element_ID", SO->FN->idcode_str);
07052       } else {
07053          NI_set_attribute(ngr, "SUMA_Node_First_Neighb_Element_ID", SUMA_EMPTY_ATTR);
07054       }
07055    }
07056 
07057    if (!nlee) {
07058       /* add the parent volume (SurfVol, NOT SurfVol_AlndExp) IDcode if present. 
07059         That ID does not usually refer to the volume from which VolPar is created. Except in the case 
07060         where you are viewing the surfaces on the orignal volume (SurfVol) then this field and
07061         SurfVol (afni dset *) ->idcode.str and VolPar->vol_idcode_str should be identical */
07062       if (SO->parent_vol_idcode_str) {
07063          NI_set_attribute(ngr, "SUMA_Afni_Parent_Vol_ID", SO->parent_vol_idcode_str);
07064       } else {
07065          NI_set_attribute(ngr, "SUMA_Afni_Parent_Vol_ID", SUMA_EMPTY_ATTR);
07066       }
07067    }
07068    
07069    /** END ATTRIBUTES specific to Surfaces**/ 
07070    
07071    /** BEGIN Adding data elements **/
07072    
07073    /* add the node list */
07074    if (SUMA_iswordin(optlist,"NodeList")) {
07075       SUMA_LH("Adding Nodelist nel...");
07076       nel = SUMA_NodeXYZ2NodeXYZ_nel (SO, SO->NodeList, 0, SUMA_NEW_NODE_XYZ);
07077       if (!nel) { SUMA_SL_Err("Failed to create nel"); NI_free_element(ngr); SUMA_RETURN(NULL); }
07078       NI_add_to_group( ngr, nel); 
07079    }
07080    
07081    /* add the faceset list */
07082    if (SUMA_iswordin(optlist,"FaceSetList")) {
07083       SUMA_LH("Adding Nodelist nel...");
07084       nel = SUMA_Mesh_IJK2Mesh_IJK_nel (SO, SO->FaceSetList, 0, SUMA_NEW_MESH_IJK);
07085       if (!nel) { SUMA_SL_Err("Failed to create nel"); NI_free_element(ngr); SUMA_RETURN(NULL); }
07086       NI_add_to_group( ngr, nel); 
07087    }   
07088    
07089    /* add the edge list */
07090    if (SUMA_iswordin(optlist,"EdgeList")) {
07091       SUMA_LH("Adding EdgeList nel...");
07092       SUMA_SL_Warn("Option not implemented yet.");
07093       if (SO->EL) {
07094          /* if (!nel) { SUMA_SL_Err("Failed to create nel"); NI_free_element(ngr); SUMA_RETURN(NULL); } 
07095          NI_add_to_group( ngr, nel); */
07096       }
07097    }
07098    
07099    /* add the member face list */
07100    if (SUMA_iswordin(optlist,"MemberFace")) {
07101       SUMA_LH("Adding Member of FaceSet nel...");
07102       SUMA_SL_Warn("Option not implemented yet.");
07103       if (SO->MF) {
07104          /* if (!nel) { SUMA_SL_Err("Failed to create nel"); NI_free_element(ngr); SUMA_RETURN(NULL); } 
07105          NI_add_to_group( ngr, nel); */
07106       }
07107    }
07108    
07109    /* add the node neighbor list */
07110    if (SUMA_iswordin(optlist,"NodeNeighb")) {
07111       SUMA_LH("Adding node neighbors nel...");
07112       SUMA_SL_Warn("Option not implemented yet.");
07113       if (SO->FN) {
07114          /* if (!nel) { SUMA_SL_Err("Failed to create nel"); NI_free_element(ngr); SUMA_RETURN(NULL); } 
07115          NI_add_to_group( ngr, nel); */
07116       }
07117    }
07118    
07119    /* add the VolPar element */
07120    if (SUMA_iswordin(optlist,"VolPar")) {
07121       SUMA_LH("Adding VolPar nel ...");
07122       if (SO->VolPar) {
07123          nel = SUMA_SOVolPar2VolPar_nel (SO, SO->VolPar, SUMA_SURFACE_VOLUME_PARENT);
07124          if (!nel) { SUMA_SL_Err("Failed to create nel"); NI_free_element(ngr); SUMA_RETURN(NULL); } 
07125          NI_add_to_group( ngr, nel); 
07126       }
07127    }
07128    
07129    /** END Adding data elements **/ 
07130    if (1) {
07131       int suc;
07132       SUMA_SL_Warn("writing SO group to DISK!");
07133       NEL_WRITE_TX(ngr, "file:Test_SO2NIML_write_asc_1D", suc);
07134    }
07135    
07136    SUMA_RETURN(ngr);
07137 }
07138 
07139 SUMA_SurfaceObject *SUMA_nimlSO2SO(NI_group *ngr) 
07140 {
07141    static char FuncName[]={"SUMA_nimlSO2SO"};
07142    NI_element *nel = NULL;
07143    char stmp[500], *tmp;
07144    int ip;
07145    SUMA_SurfaceObject *SO=NULL;
07146    SUMA_Boolean LocalHead = NOPE;
07147    
07148    SUMA_ENTRY;
07149    
07150    if (!ngr) {  SUMA_SL_Err("Null ngr"); SUMA_RETURN(SO); }
07151    
07152    if (strcmp(ngr->name, "SurfaceObject")) {
07153       fprintf (SUMA_STDERR,"Error %s: group name (%s) is not (SUMA_SurfaceObject)\nObject does not appear to be a surface.", FuncName, ngr->name);
07154    }
07155    
07156    /* a new surface */
07157    SO = SUMA_Alloc_SurfObject_Struct(1); 
07158    if (!SO) { SUMA_SL_Err("Failed to create SO."); SUMA_RETURN(SO); }
07159    
07160    /** BEGIN ATTRIBUTES COMMON TO ALL OBJECTS **/ 
07161    tmp = SUMA_copy_string(NI_get_attribute(ngr,"Object_ID"));
07162    if (SUMA_IS_EMPTY_STR_ATTR(tmp)) { 
07163       SUMA_SL_Warn("No ID in nel.\nThat's not cool yall.\n I'll be adding a new one now."); SUMA_NEW_ID(SO->idcode_str, NULL); 
07164       NI_set_attribute(ngr, "Group_ID", SO->idcode_str);
07165    } else SO->idcode_str = SUMA_copy_string(tmp);
07166    
07167    tmp = NI_get_attribute(ngr, "Object_Type");
07168    if (SUMA_IS_EMPTY_STR_ATTR(tmp)) { SUMA_SL_Err("Missing Object Type."); SUMA_Free_Surface_Object(SO); SO = NULL; SUMA_RETURN(SO); }
07169    if (!strcmp(tmp, "Triangulated_Surface")) SO->FaceSetDim = 3;
07170    else {
07171       fprintf (SUMA_STDERR,"Error %s: Object_Type %s not recognized.\n", FuncName, tmp);
07172       SUMA_Free_Surface_Object(SO); SO = NULL; SUMA_RETURN(SO); 
07173    }   
07174    
07175    tmp = NI_get_attribute(ngr, "Object_Label");
07176    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->Label = SUMA_copy_string(tmp);  
07177    
07178    /* set the parent ID */
07179    tmp = NI_get_attribute(ngr, "Parent_ID");
07180    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->LocalDomainParentID = SUMA_copy_string(tmp);  
07181    
07182    
07183    /* set the grand parent ID */
07184    tmp = NI_get_attribute(ngr, "Grand_Parent_ID");
07185    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->DomainGrandParentID = SUMA_copy_string(tmp);  
07186    
07187    
07188    /** END ATTRIBUTES COMMON TO ALL OBJECTS **/      
07189    
07190    /** BEGIN ATTRIBUTES specific to Surfaces**/
07191    tmp = NI_get_attribute(ngr, "Subject_ID");
07192    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->Group_idcode_str = SUMA_copy_string(tmp); 
07193    
07194    tmp = NI_get_attribute(ngr, "Subject_Label");
07195    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->Group = SUMA_copy_string(tmp); 
07196    
07197    tmp = NI_get_attribute(ngr, "Instance_ID");
07198    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->OriginatorID = SUMA_copy_string(tmp);    
07199    
07200    tmp = NI_get_attribute(ngr, "Instance_Label");
07201    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->OriginatorLabel = SUMA_copy_string(tmp); 
07202    
07203    tmp = NI_get_attribute(ngr, "Model_Name");
07204    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->ModelName = SUMA_copy_string(tmp); 
07205    
07206    tmp = NI_get_attribute(ngr, "Side");
07207    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) {
07208       if (!strcmp(tmp,"none")) SO->Side = SUMA_NO_SIDE;
07209       else if (!strcmp(tmp,"left")) SO->Side = SUMA_LEFT;
07210       else if (!strcmp(tmp,"right")) SO->Side = SUMA_RIGHT;
07211    } 
07212 
07213    tmp = NI_get_attribute(ngr, "Layer_Name");
07214    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->State = SUMA_copy_string(tmp); 
07215 
07216    tmp = NI_get_attribute(ngr, "Anatomically_Correct");
07217    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) {
07218       if (!strcmp(tmp,"yes")) SO->AnatCorrect = 1; 
07219       else SO->AnatCorrect = 0; 
07220    }
07221     
07222    tmp = NI_get_attribute(ngr, "Embedding_Dimension");
07223    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->EmbedDim = atoi(tmp); 
07224    
07225    tmp = NI_get_attribute(ngr, "Surface_Creation_Software");
07226    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->FileType = SUMA_SurfaceTypeCode(tmp); 
07227    
07228    tmp = NI_get_attribute(ngr, "Standard_Space");
07229    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->StandardSpace = SUMA_copy_string(tmp); 
07230    
07231    tmp = NI_get_attribute(ngr, "SUMA_Afni_Parent_Vol_ID");
07232    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->parent_vol_idcode_str = SUMA_copy_string(tmp); 
07233       
07234    
07235    /** END ATTRIBUTES specific to Surfaces**/ 
07236    
07237    /* now read the elements in this group */
07238    for( ip=0 ; ip < ngr->part_num ; ip++ ){ /* do not free elements as you process them, free with group at end */
07239       switch( ngr->part_typ[ip] ){
07240          /*-- a sub-group ==> recursion! --*/
07241          case NI_GROUP_TYPE:
07242             SUMA_SL_Err("Not ready from groups inside surface group. Group ignored"); 
07243             break ;
07244          case NI_ELEMENT_TYPE:
07245             nel = (NI_element *)ngr->part[ip] ;
07246             if (LocalHead)  {
07247                fprintf(SUMA_STDERR,"%s:     name=%s vec_len=%d vec_filled=%d, vec_num=%d\n", FuncName,\
07248                         nel->name, nel->vec_len, nel->vec_filled, nel->vec_num );
07249             }
07250 
07251             /*--- NodeList ---*/
07252             if( strcmp(nel->name,"Node_XYZ") == 0 || strcmp(nel->name,"NewNode_XYZ") == 0) { /* Get Da NodeList */
07253                if (LocalHead) fprintf (SUMA_STDERR,"%s:\nGetting NodeList...\n", 
07254                                              FuncName);
07255                if (!SUMA_NodeXYZ_nel2NodeXYZ(SO, nel)) {
07256                   SUMA_SL_Err("Failed in SUMA_NodeXYZ_nel2NodeXYZ");
07257                   SUMA_Free_Surface_Object(SO); SO = NULL; SUMA_RETURN(SO);
07258                }
07259             } else if ( strcmp(nel->name,"Mesh_IJK") == 0 || strcmp(nel->name,"NewMesh_IJK") == 0) { /* Get Da FaceSetList */ 
07260                if (LocalHead) fprintf (SUMA_STDERR,"%s:\nGetting FaceSetList...\n", 
07261                                              FuncName);
07262                if (!SUMA_Mesh_IJK_nel2Mesh_IJK(SO, nel)) {
07263                   SUMA_SL_Err("Failed in SUMA_Mesh_IJK_nel2Mesh_IJK");
07264                   SUMA_Free_Surface_Object(SO); SO = NULL; SUMA_RETURN(SO);
07265                }
07266             } else if ( strcmp(nel->name,"SurfaceVolumeParent") == 0) { /* Get Da FaceSetList */ 
07267                if (LocalHead) fprintf (SUMA_STDERR,"%s:\nGetting VolPar...\n", 
07268                                              FuncName);
07269                if (!SUMA_VolPar_nel2SOVolPar(SO, nel)) {
07270                   SUMA_SL_Err("Failed in SUMA_VolPar_nel2SOVolPar");
07271                   SUMA_Free_Surface_Object(SO); SO = NULL; SUMA_RETURN(SO);
07272                }
07273             } else {
07274                fprintf (SUMA_STDERR,"Warning %s:\n nel (%s) unknown, ignoring it.\n", FuncName, nel->name);
07275             }
07276             break;
07277          default:
07278             SUMA_SL_Err("Don't know what to make of this group element, ignoring.");
07279             break;
07280       }
07281    }
07282    
07283    if (!SO->NodeList || !SO->FaceSetList) { /* perhaps you'll remove this condition in the future ...*/
07284       SUMA_SL_Err("Looks like NodeList and/or FaceSetList not in group. Balking.\n");
07285       SUMA_Free_Surface_Object(SO); SO = NULL; SUMA_RETURN(SO);
07286    }
07287    
07288    /* check on all elements that need to be loaded */   
07289    tmp = NI_get_attribute(ngr, "Mesh_Element_ID");
07290    if (!SUMA_IS_EMPTY_STR_ATTR(tmp))  { 
07291       if (!SO->FaceSetList) { /* element was not part of this group, usually recover from other files on disk, for the moment, warning */
07292          fprintf (SUMA_STDERR,"Warning %s:\n group %s called for FaceSetList element_ID %s which was not found.\n", FuncName, ngr->name, tmp);  
07293          /* 
07294          in the future, try to load from separate file
07295          nel = SUMA_Find_nel_File(tmp); (for example) SUMA_Mesh_IJK_nel2Mesh_IJK(SO, nel) ;  NI_free_nel(nel); nel = NULL; 
07296          */     
07297       }
07298    }
07299 
07300    tmp = NI_get_attribute(ngr, "NodeList_Element_ID");
07301    if (!SUMA_IS_EMPTY_STR_ATTR(tmp))  { 
07302       if (!SO->NodeList) { /* element was not part of this group, usually recover from other files on disk, for the moment, warning */
07303          fprintf (SUMA_STDERR,"Warning %s:\n group %s called for NodeList element_ID %s which was not found.\n", FuncName, ngr->name, tmp);  
07304          /* 
07305          in the future, try to load from separate file
07306          nel = SUMA_Find_nel_File(tmp); (for example) SUMA_NodeXYZ_nel2NodeXYZ(SO, nel) ;  NI_free_nel(nel); nel = NULL; 
07307          */     
07308       }
07309    }
07310    
07311    tmp = NI_get_attribute(ngr, "facenormals_idcode_str");
07312    if (!SUMA_IS_EMPTY_STR_ATTR(tmp))  { 
07313       if (!SO->FaceNormList) { /* element was not part of this group, usually recover from other files on disk, for the moment, warning */
07314          fprintf (SUMA_STDERR,"Warning %s:\n group %s called for facenormals element_ID %s which was not found.\n", FuncName, ngr->name, tmp);  
07315          /* 
07316          in the future, try to load from separate file
07317          nel = SUMA_Find_nel_File(tmp); (for example) xxxxxx(SO, nel) ;  NI_free_nel(nel); nel = NULL; 
07318          */     
07319       }
07320    }
07321      
07322    tmp = NI_get_attribute(ngr, "Node_Normals_Element_ID");
07323    if (!SUMA_IS_EMPTY_STR_ATTR(tmp))  { 
07324       if (!SO->NodeNormList) { /* element was not part of this group, usually recover from other files on disk, for the moment, warning */
07325          fprintf (SUMA_STDERR,"Warning %s:\n group %s called for Node_Normals element_ID %s which was not found.\n", FuncName, ngr->name, tmp);  
07326          /* 
07327          in the future, try to load from separate file
07328          nel = SUMA_Find_nel_File(tmp); (for example) xxxxxx(SO, nel) ;  NI_free_nel(nel); nel = NULL; 
07329          */     
07330       }
07331    }
07332    
07333    tmp = NI_get_attribute(ngr, "Polygon_Area_Element_ID");
07334    if (!SUMA_IS_EMPTY_STR_ATTR(tmp))  { 
07335       if (!SO->PolyArea) { /* element was not part of this group, usually recover from other files on disk, for the moment, warning */
07336          fprintf (SUMA_STDERR,"Warning %s:\n group %s called for Polygon_Area element_ID %s which was not found.\n", FuncName, ngr->name, tmp);  
07337          /* 
07338          in the future, try to load from separate file
07339          nel = SUMA_Find_nel_File(tmp); (for example) xxxxxx(SO, nel) ;  NI_free_nel(nel); nel = NULL; 
07340          */     
07341       }
07342    }
07343    
07344    tmp = NI_get_attribute(ngr, "SUMA_Edge_List_Element_ID");
07345    if (!SUMA_IS_EMPTY_STR_ATTR(tmp))  { 
07346       if (!SO->EL) { /* element was not part of this group, usually recover from other files on disk, for the moment, warning */
07347          fprintf (SUMA_STDERR,"Warning %s:\n group %s called for Edge_List element_ID %s which was not found.\n", FuncName, ngr->name, tmp);  
07348          /* 
07349          in the future, try to load from separate file
07350          nel = SUMA_Find_nel_File(tmp); (for example) xxxxxx(SO, nel) ;  NI_free_nel(nel); nel = NULL; 
07351          */     
07352       }
07353    }
07354 
07355    tmp = NI_get_attribute(ngr, "SUMA_Node_Face_Member_Element_ID");
07356    if (!SUMA_IS_EMPTY_STR_ATTR(tmp))  { 
07357       if (!SO->MF) { /* element was not part of this group, usually recover from other files on disk, for the moment, warning */
07358          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);  
07359          /* 
07360          in the future, try to load from separate file
07361          nel = SUMA_Find_nel_File(tmp); (for example) xxxxxx(SO, nel) ;  NI_free_nel(nel); nel = NULL; 
07362          */     
07363       }
07364    }
07365    
07366    tmp = NI_get_attribute(ngr, "SUMA_Node_First_Neighb_Element_ID");
07367    if (!SUMA_IS_EMPTY_STR_ATTR(tmp))  { 
07368       if (!SO->FN) { /* element was not part of this group, usually recover from other files on disk, for the moment, warning */
07369          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);  
07370          /* 
07371          in the future, try to load from separate file
07372          nel = SUMA_Find_nel_File(tmp); (for example) xxxxxx(SO, nel) ;  NI_free_nel(nel); nel = NULL; 
07373          */     
07374       }
07375    }
07376    
07377    
07378    if (SO->MF && SO->MF->idcode_str) {
07379       NI_set_attribute(ngr, "SUMA_Node_Face_Member_Element_ID", SO->MF->idcode_str);
07380    } else {
07381       NI_set_attribute(ngr, "SUMA_Node_Face_Member_Element_ID", SUMA_EMPTY_ATTR);
07382    }
07383    
07384    if (SO->FN && SO->FN->idcode_str) {
07385       NI_set_attribute(ngr, "SUMA_Node_First_Neighb_Element_ID", SO->FN->idcode_str);
07386    } else {
07387       NI_set_attribute(ngr, "SUMA_Node_First_Neighb_Element_ID", SUMA_EMPTY_ATTR);
07388    }
07389    
07390 
07391     
07392    SUMA_RETURN(SO);
07393 }
07394 
07395 /*  >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Begin OpenDX functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
07396 
07397 SUMA_OPEN_DX_STRUCT *SUMA_Alloc_OpenDX_Struct(void)
07398 {
07399    static char FuncName[]={"SUMA_Alloc_OpenDX_Struct"};
07400    int i;
07401    SUMA_OPEN_DX_STRUCT *dx = NULL;
07402    
07403    SUMA_ENTRY;
07404    
07405    dx = (SUMA_OPEN_DX_STRUCT *)SUMA_malloc(sizeof(SUMA_OPEN_DX_STRUCT));
07406    dx->rank = 0;
07407    dx->shape = 0;
07408    dx->items = 0;
07409    dx->bad_data = 0;
07410    dx->object = NULL;
07411    dx->class = NULL;
07412    dx->type = NULL;
07413    dx->data = NULL;
07414    dx->data_format = 0;
07415    dx->data_off = NULL;
07416    dx->datap = NULL;
07417    dx->n_comp = 0;
07418    dx->counts = NULL;
07419    dx->n_counts = 0;
07420    dx->origin = NULL;
07421    dx->n_origin = 0;
07422    dx->delta = NULL;
07423    dx->n_delta = 0;
07424    for (i=0; i<SUMA_MAX_OPEN_DX_FIELD_COMPONENTS; ++i) { dx->comp_name[i] = dx->comp_value[i] =NULL; }
07425    dx->n_attr = 0;
07426    for (i=0; i<SUMA_MAX_OPEN_DX_FIELD_ATTRIBUTES; ++i) { dx->attr_name[i] = dx->attr_string[i] =NULL; }
07427    SUMA_RETURN(dx);
07428 }
07429 
07430 SUMA_OPEN_DX_STRUCT ** SUMA_Free_OpenDX_StructVec(SUMA_OPEN_DX_STRUCT **dxv, int nobj)
07431 {
07432    static char FuncName[]={"SUMA_Free_OpenDX_StructVec"};
07433    int i;
07434    
07435    SUMA_ENTRY;
07436    
07437    if (!dxv) SUMA_RETURN(NULL);
07438    for (i=0; i<nobj; ++i) {
07439       dxv[i] = SUMA_Free_OpenDX_Struct(dxv[i]);
07440    }
07441    SUMA_free(dxv); 
07442    SUMA_RETURN(NULL);
07443 }
07444 
07445 SUMA_OPEN_DX_STRUCT *SUMA_Free_OpenDX_Struct(SUMA_OPEN_DX_STRUCT *dx)
07446 {
07447    static char FuncName[]={"SUMA_Free_OpenDX_Struct"};
07448    int i;
07449    
07450    SUMA_ENTRY;
07451    
07452    if (!dx) SUMA_RETURN(dx);
07453    if (dx->object) SUMA_free(dx->object); dx->object = NULL;
07454    if (dx->class) SUMA_free(dx->class); dx->class = NULL;
07455    if (dx->data) SUMA_free(dx->data); dx->data = NULL;
07456    if (dx->data_off) SUMA_free(dx->data_off); dx->data_off = NULL;
07457    if (dx->datap) {
07458       if ( SUMA_OK_OPENDX_DATA_TYPE(SUMA_VarType2TypeCast (dx->type)) ) {
07459          SUMA_free(dx->datap); dx->datap = NULL;
07460       } else {
07461          SUMA_SL_Warn("Do not know how to free datap.\nYou now possibly have a leak on your hands.");
07462       }
07463    }
07464    if (dx->type) SUMA_free(dx->type); dx->type = NULL;
07465    for (i=0; i<SUMA_MAX_OPEN_DX_FIELD_COMPONENTS; ++i) { 
07466       if (dx->comp_name[i]) SUMA_free(dx->comp_name[i]); dx->comp_name[i] = NULL;
07467       if (dx->comp_value[i]) SUMA_free(dx->comp_value[i]); dx->comp_value[i] =NULL; 
07468    }
07469    for (i=0; i<SUMA_MAX_OPEN_DX_FIELD_ATTRIBUTES; ++i) { 
07470       if (dx->attr_name[i]) SUMA_free(dx->attr_name[i]); dx->attr_name[i] = NULL;
07471       if (dx->attr_string[i]) SUMA_free(dx->attr_string[i]); dx->attr_string[i] =NULL; 
07472    }
07473    if (dx->origin) SUMA_free(dx->origin); 
07474    if (dx->delta) SUMA_free(dx->delta);
07475    if (dx->counts) SUMA_free(dx->counts);
07476    SUMA_free(dx); dx = NULL;
07477    SUMA_RETURN(dx);
07478 }
07479 
07480 void SUMA_Show_OpenDX_Struct(SUMA_OPEN_DX_STRUCT **dxv, int N_dxv, FILE *out)
07481 {
07482    static char FuncName[]={"SUMA_Show_OpenDX_Struct"};
07483    int i, idx;
07484    SUMA_STRING *SS=NULL;
07485    char *s = NULL;
07486    SUMA_OPEN_DX_STRUCT *dx=NULL;
07487    
07488    SUMA_ENTRY;
07489    
07490    SS = SUMA_StringAppend(NULL, NULL);  
07491    if (!dxv) SS = SUMA_StringAppend(SS, "NULL dxv\n");
07492    for (idx = 0; idx < N_dxv; ++idx) {
07493       dx = dxv[idx];
07494       SS = SUMA_StringAppend_va(SS, "Object Struct %d/%d\n", idx+1, N_dxv);
07495       if (!dx) SS = SUMA_StringAppend(SS, "NULL dx\n");
07496       else {
07497          if (dx->object) SS = SUMA_StringAppend_va(SS, "object: %s\n", dx->object);
07498          else SS = SUMA_StringAppend_va(SS, "object: NULL\n"); 
07499          if (dx->class) SS = SUMA_StringAppend_va(SS, "class: %s\n", dx->class);
07500          else SS = SUMA_StringAppend_va(SS, "class: NULL\n"); 
07501          if (dx->type) SS = SUMA_StringAppend_va(SS, "type: %s\n", dx->type);
07502          else SS = SUMA_StringAppend_va(SS, "type: NULL\n"); 
07503          if (dx->rank) SS = SUMA_StringAppend_va(SS, "rank: %d\n", dx->rank);
07504          else SS = SUMA_StringAppend_va(SS, "rank: 0\n"); 
07505          if (dx->shape) SS = SUMA_StringAppend_va(SS, "shape: %d\n", dx->shape);
07506          else SS = SUMA_StringAppend_va(SS, "shape: 0\n"); 
07507          if (dx->items) SS = SUMA_StringAppend_va(SS, "items: %d\n", dx->items);
07508          else SS = SUMA_StringAppend_va(SS, "items: 0\n"); 
07509          if (dx->counts) {
07510             SS = SUMA_StringAppend_va(SS, "counts: (%d vals)\n", dx->n_counts);
07511             s = SUMA_ShowMeSome(dx->counts, SUMA_int, dx->n_counts, 5);
07512             SS = SUMA_StringAppend_va(SS, "\t%s\n", s); SUMA_free(s); s = NULL;
07513          } else SS = SUMA_StringAppend_va(SS, "counts: NULL\n");
07514          if (dx->origin) {
07515             SS = SUMA_StringAppend_va(SS, "origin: (%d vals)\n", dx->n_origin);
07516             s = SUMA_ShowMeSome(dx->origin, SUMA_float, dx->n_origin, 5);
07517             SS = SUMA_StringAppend_va(SS, "\t%s\n", s); SUMA_free(s); s = NULL;
07518          } else SS = SUMA_StringAppend_va(SS, "origin: NULL\n");
07519          if (dx->delta) {
07520             SS = SUMA_StringAppend_va(SS, "delta: (%d vals)\n", dx->n_delta);
07521             s = SUMA_ShowMeSome(dx->delta, SUMA_float, dx->n_delta, 9);
07522             SS = SUMA_StringAppend_va(SS, "\t%s\n", s); SUMA_free(s); s = NULL;
07523          }else SS = SUMA_StringAppend_va(SS, "delta: NULL\n");
07524          
07525          if (dx->data) SS = SUMA_StringAppend_va(SS, "data: %s (Data load error %d)\n", dx->data, dx->bad_data);
07526          else SS = SUMA_StringAppend_va(SS, "data: NULL\n"); 
07527          if (dx->data_off) SS = SUMA_StringAppend_va(SS, "data_off: %s \n", dx->data_off);
07528          else SS = SUMA_StringAppend_va(SS, "data_off: NULL\n"); 
07529          SS = SUMA_StringAppend_va(SS, "data_format: %d \n", dx->data_format);
07530          if (dx->datap) {
07531             s = SUMA_ShowMeSome(dx->datap, SUMA_VarType2TypeCast(dx->type), dx->items * SUMA_NCOL_OPENDX(dx), 5);
07532             SS = SUMA_StringAppend_va(SS, "\t%s\n", s); SUMA_free(s); s = NULL;
07533          }
07534          if (dx->n_comp) {
07535             SS = SUMA_StringAppend_va(SS, "components: %d\n", dx->n_comp);
07536             for (i=0; i<dx->n_comp; ++i) {  
07537                if (dx->comp_name[i]) SS = SUMA_StringAppend_va(SS, "\tname: %s\t", dx->comp_name[i]);
07538                else SS = SUMA_StringAppend_va(SS, "\tname: NULL\t"); 
07539                if (dx->comp_value[i]) SS = SUMA_StringAppend_va(SS, "\ttype: %s\n", dx->comp_value[i]);
07540                else SS = SUMA_StringAppend_va(SS, "\ttype: NULL\n"); 
07541             }    
07542          } else {
07543             SS = SUMA_StringAppend_va(SS, "components: %d\n", dx->n_comp); 
07544          }
07545          if (dx->n_attr) {
07546             SS = SUMA_StringAppend_va(SS, "attributes: %d\n", dx->n_attr);
07547             for (i=0; i<dx->n_attr; ++i) {  
07548                if (dx->attr_name[i]) SS = SUMA_StringAppend_va(SS, "\tname: %s\t", dx->attr_name[i]);
07549                else SS = SUMA_StringAppend_va(SS, "\tname: NULL\t"); 
07550                if (dx->attr_string[i]) SS = SUMA_StringAppend_va(SS, "\tstring: %s\n", dx->attr_string[i]);
07551                else SS = SUMA_StringAppend_va(SS, "\tstring: NULL\n"); 
07552             }    
07553          } else {
07554             SS = SUMA_StringAppend_va(SS, "attributes: %d\n", dx->n_attr); 
07555          }
07556       }
07557    }
07558    
07559    SUMA_SS2S(SS,s);
07560    if (!out) fprintf(stdout, "%s", s);
07561    else fprintf(out, "%s", s);
07562    
07563    SUMA_free(s); s = NULL;
07564    
07565    SUMA_RETURNe;
07566 }
07567 
07568 SUMA_Boolean SUMA_OpenDX_Write(char *fname, SUMA_SurfaceObject *SO)
07569 {
07570    static char FuncName[]={"SUMA_OpenDX_Write"};
07571    
07572    SUMA_ENTRY;
07573    
07574    SUMA_SL_Err("Not supported yet");
07575    
07576    SUMA_RETURN(NOPE);
07577 }
07578 
07579 
07580 /*!
07581    \brief get the data values 
07582 */
07583 SUMA_Boolean SUMA_OpenDx_Object_Data(char *op, int nchar, SUMA_OPEN_DX_STRUCT *dx)
07584 {
07585    static char FuncName[]={"SUMA_OpenDx_Object_Data"};
07586    int i, Found = 0, ival;
07587    char *op_end, cend, *op2, *sval;
07588    char *op_orig;
07589    SUMA_Boolean LocalHead = NOPE;
07590    
07591    SUMA_ENTRY;
07592    
07593    /* get the data */
07594    op_orig = op; /* hide this pointer from the evils that will befall it */
07595    cend = op_orig[nchar-1]; op_orig[nchar-1] = '\0';
07596    op_end = op_orig + nchar - 1; 
07597    if (LocalHead) { /* potential for huge dump if you set show to nchar! */
07598          int j, show;
07599          show = 500; /* could also use nchar */
07600          fprintf(SUMA_STDERR,"%s Object\n", FuncName);
07601          j=0; while (op[j] && j<500) { fprintf(SUMA_STDERR,"%c", op[j]); ++j; }
07602          fprintf(SUMA_STDERR,"\n");
07603    }
07604    SUMA_ADVANCE_PAST(op,op_end,"data",Found,1);
07605    sval = NULL;
07606    if (Found) {
07607       /* get the data's info */
07608       SUMA_GET_BETWEEN_BLANKS(op, op_end, op2);
07609       if (op2 == op) {
07610          SUMA_LH("Empty data?");
07611          dx->data=NULL;
07612       } else {
07613          SUMA_COPY_TO_STRING(op, op2, sval);
07614          dx->data = sval; sval = NULL;
07615       }
07616       op = op2;
07617       /* now fill datap if possible*/
07618       if (dx->data && strstr(dx->data,"follows")){
07619          int nread=0;
07620          SUMA_LH("data inside");
07621          if (LocalHead) { /* potential for huge dump! */
07622             int j, show;
07623             show = 500; /* could also use nchar */
07624             fprintf(SUMA_STDERR,"%s Object\n", FuncName);
07625             j=0; while (op[j] && j<500) { fprintf(SUMA_STDERR,"%c", op[j]); ++j; }
07626             fprintf(SUMA_STDERR,"\n");
07627          }  
07628          dx->datap = SUMA_strtol_vec(op, dx->items*SUMA_NCOL_OPENDX(dx), &nread, SUMA_VarType2TypeCast (dx->type));
07629          if (LocalHead) {
07630             fprintf(SUMA_STDERR,"%s: Read %d/%d values\n", FuncName, nread, dx->items*SUMA_NCOL_OPENDX(dx));
07631          }
07632          if (nread != dx->items*SUMA_NCOL_OPENDX(dx)) {
07633             fprintf(SUMA_STDERR,"Error %s: read in %d values, expected %d \n", FuncName, nread, dx->items*SUMA_NCOL_OPENDX(dx));
07634             op_orig[nchar-1] =  cend;
07635             SUMA_RETURN(NOPE);
07636          }
07637       }else {
07638          SUMA_LH("data does not follow");
07639          if (LocalHead) {
07640             for (i=0; i < 500; ++i) { fprintf(SUMA_STDERR,"%c", op[i]); } fprintf(SUMA_STDERR,"\n"); fflush(SUMA_STDERR);
07641          }
07642          /* ? have file name ? */
07643          if (strstr(dx->data,"file")) {
07644             SUMA_GET_BETWEEN_BLANKS(op, op_end, op2);
07645             if (op2 > op) {
07646                SUMA_free(dx->data); /* free the "file" string */
07647                SUMA_COPY_TO_STRING(op, op2, sval);
07648                dx->data = sval; sval = NULL;
07649                /* search backwards for a comma */
07650                i=strlen(dx->data)-1; Found = -1;
07651                while(i>=0 && Found <0) { if (dx->data[i] == ',') Found = i; --i; }
07652                if (Found >= 0) { 
07653                   dx->data_off = SUMA_copy_string(&(dx->data[Found+1]));
07654                   dx->data[Found]='\0';
07655                }  
07656                /* see if you have some byte order or binary business */
07657                dx->data_format = 0; /* ascii, default*/
07658                op = op_orig; SUMA_ADVANCE_PAST(op,op_end,"binary",Found,1);
07659                if (Found) {
07660                   dx->data_format = MSB_FIRST; /* default */
07661                }
07662                /* endianness, regardless of what was above, "binary" might not occur */
07663                op = op_orig; SUMA_ADVANCE_PAST(op,op_end,"msb",Found,1);
07664                if (Found) { dx->data_format = MSB_FIRST; }
07665                else {
07666                   op = op_orig; SUMA_ADVANCE_PAST(op,op_end,"lsb",Found,1);
07667                   if (Found) { dx->data_format = LSB_FIRST; }
07668                }
07669             }
07670          }
07671       }
07672    } else {
07673       SUMA_LH("No data for this object");
07674    }
07675       
07676    op_orig[nchar-1] =  cend;
07677    SUMA_RETURN(YUP);
07678 }
07679 
07680 
07681 /*!
07682    \brief return values of an attribute from an OpenDX object string
07683 */  
07684 SUMA_Boolean SUMA_OpenDx_Object_Attr(char *op, int nchar, SUMA_OPEN_DX_STRUCT *dx)
07685 {
07686    static char FuncName[]={"SUMA_OpenDx_Object_Attr"};
07687    int i, Found, ival,imax;
07688    char *op_end, cend, *op2, *sval;
07689    char *op_orig;
07690    SUMA_Boolean LocalHead = NOPE;
07691    
07692    SUMA_ENTRY;
07693    
07694    /* get the attributes */
07695    
07696    op_orig = op; /* hide this pointer from the evils that will befall it */
07697    cend = op_orig[nchar-1]; op_orig[nchar-1] = '\0';
07698    op_end = op_orig + nchar - 1; 
07699    
07700    SUMA_ADVANCE_PAST(op,op_end,"attribute",Found, 1);
07701    sval = NULL;
07702    while (Found) {
07703       /* get the attribute's name */
07704       SUMA_GET_BETWEEN_BLANKS(op, op_end, op2);
07705       if (op2 == op) {
07706          SUMA_LH("Empty attribute?");
07707       } else {
07708          imax = op2 - op;
07709          if (imax > 5000) {
07710             SUMA_SL_Err("Unexpectedly large field!");
07711             op_orig[nchar-1] =  cend;
07712             SUMA_RETURN(NOPE);
07713          }else if (imax < 0) {
07714             SUMA_SL_Err("Negative imax!");
07715             op_orig[nchar-1] =  cend;
07716             SUMA_RETURN(NOPE);
07717          }
07718          sval = (char *)SUMA_calloc(imax + 2, sizeof(char));
07719 
07720          for (i=0; i < imax; ++i) sval[i] = op[i];
07721          sval[imax] = '\0';
07722          dx->attr_name[dx->n_attr] = sval;
07723       }
07724       op = op2;
07725       /* look for attribute string */
07726       SUMA_ADVANCE_PAST(op,op_end,"string",Found,1);
07727       if (Found) {
07728          SUMA_GET_BETWEEN_BLANKS(op, op_end, op2);
07729          if (op2 == op) {
07730             SUMA_LH("Empty string?");
07731          } else {
07732             imax = op2 - op;
07733             if (imax > 5000) {
07734                SUMA_SL_Err("Unexpectedly large field!");
07735                op_orig[nchar-1] =  cend;
07736                SUMA_RETURN(NOPE);
07737             }else if (imax < 0) {
07738                SUMA_SL_Err("Negative imax!");
07739                op_orig[nchar-1] =  cend;
07740                SUMA_RETURN(NOPE);
07741             }
07742             sval = (char *)SUMA_calloc(imax + 2, sizeof(char));
07743 
07744             for (i=0; i < imax; ++i) sval[i] = op[i];
07745             sval[imax] = '\0';
07746             dx->attr_string[dx->n_attr] = sval;
07747          }   
07748       }
07749       ++dx->n_attr;
07750       /* look for next attribute */
07751       op = op2;
07752       SUMA_ADVANCE_PAST(op,op_end,"attribute",Found,1);
07753    }
07754       
07755    op_orig[nchar-1] =  cend;
07756    SUMA_RETURN(YUP);
07757 }
07758 /*!
07759    \brief return values of an attribute from an OpenDX object string
07760 */  
07761 SUMA_Boolean SUMA_OpenDx_Object_Components(char *op, int nchar, SUMA_OPEN_DX_STRUCT *dx)
07762 {
07763    static char FuncName[]={"SUMA_OpenDx_Object_Components"};
07764    int i, Found, ival,imax;
07765    char *op_end, cend, *op2, *sval;
07766    char *op_orig;
07767    SUMA_Boolean LocalHead = NOPE;
07768    
07769    SUMA_ENTRY;
07770    
07771    /* get the attributes */
07772    
07773    op_orig = op; /* hide this pointer from the evils that will befall it */
07774    cend = op_orig[nchar-1]; op_orig[nchar-1] = '\0';
07775    op_end = op_orig + nchar - 1; 
07776    
07777    SUMA_ADVANCE_PAST(op,op_end,"component",Found,1);
07778    while (Found) {
07779       /* get the attribute's name */
07780       SUMA_GET_BETWEEN_BLANKS(op, op_end, op2);
07781       if (op2 == op) {
07782          SUMA_LH("Empty component?");
07783       } else {
07784          imax = op2 - op;
07785          if (imax > 5000) {
07786             SUMA_SL_Err("Unexpectedly large field!");
07787             op_orig[nchar-1] =  cend;
07788             SUMA_RETURN(NOPE);
07789          }else if (imax < 0) {
07790             SUMA_SL_Err("Negative imax!");
07791             op_orig[nchar-1] =  cend;
07792             SUMA_RETURN(NOPE);
07793          }
07794          sval = (char *)SUMA_calloc(imax + 2, sizeof(char));
07795 
07796          for (i=0; i < imax; ++i) sval[i] = op[i];
07797          sval[imax] = '\0';
07798          dx->comp_name[dx->n_comp] = sval;
07799       }
07800       op = op2;
07801       /* look for attribute string */
07802       SUMA_ADVANCE_PAST(op,op_end,"value",Found,1);
07803       if (Found) {
07804          SUMA_GET_BETWEEN_BLANKS(op, op_end, op2);
07805          if (op2 == op) {
07806             SUMA_SL_Err("No value!");
07807          } else {
07808             imax = op2 - op;
07809             if (imax > 5000) {
07810                SUMA_SL_Err("Unexpectedly large field!");
07811                op_orig[nchar-1] =  cend;
07812                SUMA_RETURN(NOPE);
07813             }else if (imax < 0) {
07814                SUMA_SL_Err("Negative imax!");
07815                op_orig[nchar-1] =  cend;
07816                SUMA_RETURN(NOPE);
07817             }
07818             sval = (char *)SUMA_calloc(imax + 2, sizeof(char));
07819 
07820             for (i=0; i < imax; ++i) sval[i] = op[i];
07821             sval[imax] = '\0';
07822             dx->comp_value[dx->n_comp] = sval;
07823          }   
07824       }else { /* try for non-existing "value" */
07825          SUMA_GET_BETWEEN_BLANKS(op, op_end, op2);
07826          if (op2 == op) {
07827             SUMA_SL_Err("No value at all");
07828          } else {
07829             imax = op2 - op;
07830             if (imax > 5000) {
07831                SUMA_SL_Err("Unexpectedly large field!");
07832                op_orig[nchar-1] =  cend;
07833                SUMA_RETURN(NOPE);
07834             }else if (imax < 0) {
07835                SUMA_SL_Err("Negative imax!");
07836                op_orig[nchar-1] =  cend;
07837                SUMA_RETURN(NOPE);
07838             }
07839             sval = (char *)SUMA_calloc(imax + 2, sizeof(char));
07840 
07841             for (i=0; i < imax; ++i) sval[i] = op[i];
07842             sval[imax] = '\0';
07843             dx->comp_value[dx->n_comp] = sval;
07844          }   
07845       }
07846       ++dx->n_comp;
07847       /* look for next component */
07848       op = op2;
07849       SUMA_ADVANCE_PAST(op,op_end,"component",Found,1);
07850    }
07851       
07852    op_orig[nchar-1] =  cend;
07853    SUMA_RETURN(YUP);
07854 }
07855 
07856 /*!
07857    \brief return values of a header field from an OpenDX object string
07858    If you expect an int back like when attr is "rank" or "shape"
07859       ans should be type cast to (int *) before use: int ival; ival = *((int *)ans); 
07860    If you expect a bunch of numbers like for "counts" "origin" "delta"
07861       then ans is (SUMA_IVEC *) or (SUMA_FVEC*) or (SUMA_DVEC *)
07862       These are freed with SUMA_free(ans->v); SUMA_free(ans);
07863    else ans should be type cast to (char **) before use: 
07864       char *sval; sval = *((char **)ans); then free sval with SUMA_free(sval); 
07865       
07866 */  
07867 void * SUMA_OpenDx_Object_Header_Field(char *op, int nchar, const char *attr, char **opeofield)
07868 {
07869    static char FuncName[]={"SUMA_OpenDx_Object_Header_Field"};
07870    void *ans=NULL;
07871    int i, Found, ival, imax, nread;
07872    char *op_end = NULL, cend, *op2, *sval, *pp1, *pp2;
07873    char *op_orig;
07874    SUMA_Boolean LocalHead = NOPE;
07875    
07876    SUMA_ENTRY;
07877    
07878    if (opeofield) *opeofield = op;
07879    
07880    if (!attr) SUMA_RETURN(ans);
07881    op_orig = op; /* hide this pointer from the evils that will befall it */
07882    cend = op_orig[nchar-1]; op_orig[nchar-1] = '\0';
07883    /* do we have a data section to signal end of header? */
07884    op_end = NULL;
07885    pp1 = strstr(op, "data"); 
07886    if (pp1) {
07887       pp2 = strstr(op, "follows");
07888       if (pp2) op_end = pp2;
07889    }
07890    if (!op_end) op_end = op_orig + nchar - 1; /* op_end all the way at end */
07891    
07892    if (LocalHead) {
07893       fprintf(SUMA_STDERR,"%s: Object of %d chars, looking for >>>%s<<<\n", FuncName, nchar, attr );
07894    }
07895    
07896   /* get the header field's value name */
07897    SUMA_ADVANCE_PAST(op,op_end,attr,Found,1);
07898    if (Found) {
07899       SUMA_GET_BETWEEN_BLANKS(op, op_end, op2);
07900       if (op2 == op) {
07901          SUMA_LH("No field");
07902       } else {
07903          /* get the numeric fields changed*/
07904          if (strstr(attr,"rank") || strstr(attr,"shape") || strstr(attr,"items")) { /* rank, shape (matrix's second dim) are integer vals */
07905             ival = (int)strtol(op, NULL , 10);
07906             ans = (void*)&ival;
07907          } else if (strstr(attr,"counts")) { /* are a series integer vals */
07908             ans = SUMA_AdvancePastNumbers(op, &op2, SUMA_int);
07909          } else if (strstr(attr,"origin") || strstr(attr,"delta")) { /* are integer vals */
07910             ans = SUMA_AdvancePastNumbers(op, &op2, SUMA_float);
07911          } else  { /* strings*/
07912             imax = op2 - op;
07913             if (imax > 5000) {
07914                SUMA_SL_Err("Unexpectedly large field!");
07915                op_orig[nchar-1] =  cend;
07916                SUMA_RETURN(ans);
07917             }else if (imax < 0) {
07918                SUMA_SL_Err("Negative imax!");
07919                op_orig[nchar-1] =  cend;
07920                SUMA_RETURN(ans);
07921             }
07922             sval = (char *)SUMA_calloc(imax + 2, sizeof(char));
07923             
07924             for (i=0; i < imax; ++i) sval[i] = op[i];
07925             sval[imax] = '\0';
07926             ans = (void*)&sval;
07927          }    
07928          if (LocalHead) {
07929             fprintf(SUMA_STDERR,"%s: attribute >>>%s<<< is:\n", FuncName, attr);
07930             i = 0;
07931             while (op[i] && op+i != op2) {
07932                fprintf(SUMA_STDERR,"%c", op[i]); 
07933                ++i;   
07934             }
07935             fprintf(SUMA_STDERR,"\n");
07936          }
07937          
07938       }
07939       op = op2; /* advance op */
07940    } else {
07941       if (strstr(attr,"class")) {
07942          /* it looks like "class" is sometimes omitted, look for string field, which is a class */
07943          SUMA_ADVANCE_PAST(op,op_end,"field", Found,1);
07944          if (Found) sval = SUMA_copy_string("field");
07945          ans = (void*)&sval;
07946       } else {
07947          SUMA_LH("No such attribute");
07948       }
07949    }
07950       
07951    op_orig[nchar-1] =  cend;
07952    if (opeofield) *opeofield = op; 
07953    SUMA_RETURN(ans);
07954 }
07955 /*!
07956    \sa http://opendx.npaci.edu/docs/html/pages/usrgu068.htm#Header_417
07957 */
07958 SUMA_OPEN_DX_STRUCT **SUMA_OpenDX_Read(char *fname, int *nobj)
07959 {
07960    static char FuncName[]={"SUMA_OpenDX_Read"};
07961    int nread = 0, i = 0,  iop, *ivalp=NULL, shft=0;
07962    char *fl=NULL, **opv = NULL, *op = NULL,*sbuf=NULL, **svalp=NULL, *ope;
07963    int *nchar = NULL;
07964    SUMA_OPEN_DX_STRUCT **dxv=NULL;
07965    SUMA_FVEC *fvec=NULL;
07966    SUMA_IVEC *ivec=NULL;
07967    SUMA_Boolean LocalHead = NOPE;
07968    
07969    SUMA_ENTRY;
07970    
07971    *nobj = 0;
07972    
07973    SUMA_LH("Sucking file");
07974    nread = SUMA_suck_file( fname , &fl ) ;
07975    if (!fl) {
07976       SUMA_SL_Err("Failed to read file.");
07977       SUMA_RETURN(dxv);
07978    }
07979 
07980    if (LocalHead) fprintf(SUMA_STDERR,"%s: Read in %d chars\n", FuncName, nread);
07981    
07982    opv = (char **)SUMA_calloc(SUMA_MAX_OPEN_DX_OBJECTS, sizeof(char*));
07983    nchar = (int*)SUMA_calloc(SUMA_MAX_OPEN_DX_OBJECTS, sizeof(int));
07984    dxv = (SUMA_OPEN_DX_STRUCT **)SUMA_calloc(SUMA_MAX_OPEN_DX_OBJECTS, sizeof(SUMA_OPEN_DX_STRUCT *));
07985    
07986    /* now search for the first "object" */
07987    op = fl;
07988    iop = 0;
07989    shft = 0;
07990    do {
07991       op = strstr((op+shft), "object");
07992       if (op) {
07993          opv[iop] = op;
07994          if (iop) nchar[iop-1] = opv[iop] - opv[iop-1];
07995          if (LocalHead) {
07996             fprintf(SUMA_STDERR,"%s: Object found.\n", FuncName);
07997             i = 0;
07998             while (i<20 && op[i] !='\0') { fprintf(SUMA_STDERR,"%c",op[i]); ++i; } fprintf(SUMA_STDERR,"\n"); 
07999          }
08000          
08001          /* must skip beyond first "object" for next pass*/
08002          shft = strlen("object");
08003          ++iop;
08004       }
08005    } while (op && iop < SUMA_MAX_OPEN_DX_OBJECTS);
08006    if (iop >= SUMA_MAX_OPEN_DX_OBJECTS) {
08007       SUMA_SL_Warn("Too many objects, processing first SUMA_MAX_OPEN_DX_OBJECTS only"); 
08008    }
08009    
08010    if (iop) {/* find the length of the last object */
08011       op = opv[iop-1];
08012       while (*op !='\0') { ++op; }
08013       nchar[iop-1] = op - opv[iop-1];
08014    }
08015    
08016    if (LocalHead) {
08017       fprintf(SUMA_STDERR,"%s: %d Objects found.\n", FuncName, iop);
08018    }
08019    
08020    for (i=0; i<iop; ++i) { /* process each object's header field and data*/
08021       if ( 0 && LocalHead) { /* potentially huge dump if nmax is not controlled*/
08022          int j, nmax;
08023          nmax = 500; /* could also use nchar[i]*/
08024          fprintf(SUMA_STDERR,"%s Object %d\n", FuncName, i);
08025          op = opv[i]; for (j=0; j<nmax; ++j) fprintf(SUMA_STDERR,"%c", op[j]);
08026          fprintf(SUMA_STDERR,"\n");
08027       }
08028       /* get the class */
08029       dxv[i] = SUMA_Alloc_OpenDX_Struct();
08030       ivalp = (int *)SUMA_OpenDx_Object_Header_Field(opv[i], nchar[i], "rank", NULL);
08031       if (ivalp) dxv[i]->rank = *ivalp;
08032       ivalp = (int *)SUMA_OpenDx_Object_Header_Field(opv[i], nchar[i], "shape", NULL);
08033       if (ivalp) dxv[i]->shape = *ivalp;
08034       ivalp = (int *)SUMA_OpenDx_Object_Header_Field(opv[i], nchar[i], "items", NULL);
08035       if (ivalp) dxv[i]->items = *ivalp;
08036       svalp = (char **)SUMA_OpenDx_Object_Header_Field(opv[i], nchar[i], "object", NULL);
08037       if (svalp) dxv[i]->object = *svalp;
08038       svalp = (char **)SUMA_OpenDx_Object_Header_Field(opv[i], nchar[i], "class", NULL);
08039       if (svalp) dxv[i]->class = *svalp;
08040       svalp = (char **)SUMA_OpenDx_Object_Header_Field(opv[i], nchar[i], "type", NULL);
08041       if (svalp) dxv[i]->type = *svalp;
08042       ivec = (SUMA_IVEC*)SUMA_OpenDx_Object_Header_Field(opv[i], nchar[i], "counts", NULL);
08043       if (ivec) { dxv[i]->counts = ivec->v; dxv[i]->n_counts = ivec->n; SUMA_free(ivec); ivec = NULL;} 
08044       fvec = (SUMA_FVEC*)SUMA_OpenDx_Object_Header_Field(opv[i], nchar[i], "origin", NULL);
08045       if (fvec) { dxv[i]->origin = fvec->v; dxv[i]->n_origin = fvec->n; SUMA_free(fvec); fvec = NULL;} 
08046       { /* get the deltas */
08047          int j, k;
08048          char *rf=opv[i];
08049          j=0; 
08050          while (j<dxv[i]->n_counts) {
08051             fvec = (SUMA_FVEC*)SUMA_OpenDx_Object_Header_Field(rf, nchar[i], "delta", &ope);
08052             if (fvec && fvec->v) { 
08053                if (fvec->n < dxv[i]->n_counts) { SUMA_SL_Warn("Bad assumption about delta field.\nExpect disasters!"); }
08054                if (fvec->n > dxv[i]->n_counts) { 
08055                   SUMA_SL_Err("More values in delta that counts! Limiting to counts.\nExpect tragedy."); 
08056                   fvec->n = dxv[i]->n_counts;
08057                }
08058                if (j==0) { /* allocate */ 
08059                   dxv[i]->n_delta = dxv[i]->n_counts*dxv[i]->n_counts; 
08060                   dxv[i]->delta = (float *)SUMA_calloc(dxv[i]->n_delta, sizeof(float));
08061                }
08062                for (k=0; k<fvec->n; ++k) { 
08063                   dxv[i]->delta[(j*dxv[i]->n_counts) + k] = fvec->v[k];  
08064                }
08065                SUMA_free(fvec->v); SUMA_free(fvec); fvec = NULL;
08066             } else { /* get out */
08067                if (j) {
08068                   SUMA_SL_Warn("Expect as many deltas as counts!\nThat was not the case.");
08069                } else { /* OK, no deltas at all */ }
08070                j = dxv[i]->n_counts;
08071             }
08072             ++j; rf = ope;
08073          }
08074       } 
08075       /* now for the data */
08076       if (!SUMA_OpenDx_Object_Data(opv[i], nchar[i], dxv[i])) {
08077          SUMA_SL_Err("Failed to get data");
08078          dxv[i]->bad_data = 1;
08079       }
08080    }
08081 
08082    for (i=0; i<iop; ++i) { /* process each object's attributes*/
08083       if (!SUMA_OpenDx_Object_Attr(opv[i], nchar[i], dxv[i])) {
08084          SUMA_SL_Err("Failed in SUMA_OpenDx_Object_Attr");
08085       }
08086       if (!SUMA_OpenDx_Object_Components(opv[i], nchar[i], dxv[i])) {
08087          SUMA_SL_Err("Failed in SUMA_OpenDx_Object_Components");
08088       }
08089    }
08090 
08091    if (LocalHead) {
08092          SUMA_Show_OpenDX_Struct(dxv, iop, NULL); fflush(stdout);
08093    }
08094    
08095    if (opv) SUMA_free(opv); opv = NULL;
08096    if (nchar) SUMA_free(nchar); nchar = NULL;
08097    if (fl) SUMA_free(fl); fl = NULL; /* added Mon May 9 05, ZSS */
08098    *nobj = iop;
08099    SUMA_RETURN(dxv); 
08100 }
08101 
08102 /*!
08103    \brief returns structure containing object of a certain name in dxv
08104    do not free returned structure since it is a copy of pointer in dxv
08105 */
08106 SUMA_OPEN_DX_STRUCT *SUMA_Find_OpenDX_Object_Name(SUMA_OPEN_DX_STRUCT **dxv, int iop, char *nm, int *nf)
08107 {
08108    static char FuncName[]={"SUMA_Find_OpenDX_Object_Name"};
08109    int i;
08110    SUMA_OPEN_DX_STRUCT *dx = NULL;
08111    SUMA_Boolean LocalHead = NOPE;
08112    
08113    SUMA_ENTRY;
08114    
08115    *nf = 0;
08116    for (i=0; i<iop; ++i) {
08117       if (strstr(dxv[i]->object, nm)) { 
08118          if (!dx) dx = dxv[i]; 
08119          ++ (*nf);
08120       }
08121    }
08122    
08123    if (LocalHead) fprintf(SUMA_STDERR,"%s: Found %d objects\n", FuncName, *nf);
08124    SUMA_RETURN(dx);
08125 }
08126 /*!
08127    \brief returns structure containing object of a certain class in dxv
08128    do not free returned structure since it is a copy of pointer in dxv
08129 */
08130 SUMA_OPEN_DX_STRUCT *SUMA_Find_OpenDX_Object_Class(SUMA_OPEN_DX_STRUCT **dxv, int iop, char *nm, int *nf)
08131 {
08132    static char FuncName[]={"SUMA_Find_OpenDX_Object_Class"};
08133    int i;
08134    SUMA_OPEN_DX_STRUCT *dx = NULL;
08135    SUMA_Boolean LocalHead = NOPE;
08136    
08137    SUMA_ENTRY;
08138    
08139    *nf = 0;
08140    for (i=0; i<iop; ++i) {
08141       if (strstr(dxv[i]->class, nm)) { 
08142          if (!dx) dx = dxv[i]; 
08143          ++ (*nf);
08144       }
08145    }
08146    
08147    if (LocalHead) fprintf(SUMA_STDERR,"%s: Found %d objects\n", FuncName, *nf);
08148    SUMA_RETURN(dx);
08149 }
08150 
08151 
08152 char * SUMA_OpenDX_Read_CruiseVolHead(char *fname, THD_3dim_dataset *dset, int LoadData)
08153 {
08154    static char FuncName[]={"SUMA_OpenDX_Read_CruiseVolHead"};
08155    int i = 0, nf, iop, chunk, End, bs, doff, data_type=SUMA_notypeset;
08156    THD_ivec3 iv3;
08157    THD_mat33 m33;
08158    THD_ivec3 orixyz , nxyz ;
08159    THD_fvec3 dxyz , orgxyz ;
08160    float ep[3], sp[3];
08161    char *scom=NULL, form[10], swp[10], orstr[10], xfov[100], yfov[100], zfov[100], *prefix = NULL, *dsetheadname = NULL;
08162    SUMA_OPEN_DX_STRUCT **dxv=NULL, *dxp=NULL, *dxc=NULL, *dxf=NULL, *dxa=NULL;
08163    SUMA_Boolean LocalHead = NOPE;
08164    
08165    SUMA_ENTRY;
08166    
08167    if (!dset || !fname) {
08168       SUMA_SL_Err("NULL fname || NULL dset!");
08169       SUMA_RETURN(NOPE);
08170    }
08171    
08172    prefix = SUMA_AfniPrefix(fname, NULL, NULL, NULL);
08173    if( !THD_filename_ok(prefix) ) {
08174       SUMA_SL_Err("Bad prefix");
08175       SUMA_RETURN(NOPE);
08176    } 
08177    dsetheadname = SUMA_append_string(prefix,"+orig.HEAD");
08178    if (SUMA_filexists(dsetheadname)) {
08179       SUMA_SL_Err("Bad prefix, output dset exists");
08180       SUMA_RETURN(NOPE);
08181    }
08182    SUMA_free(dsetheadname); dsetheadname = NULL;
08183    
08184    SUMA_LH("Reading objects");
08185    dxv = SUMA_OpenDX_Read(fname, &iop);
08186    if (!dxv) {
08187       SUMA_SL_Err("Failed to read DX file.");
08188       SUMA_RETURN(NOPE);
08189    }
08190    
08191    SUMA_LH("Checking for field object");
08192    dxf = SUMA_Find_OpenDX_Object_Class(dxv, iop, "field", &nf);
08193    if (!dxf || nf != 1) { SUMA_SL_Err("Failed to find one and only one field object"); goto CLEAN_EXIT; }
08194    dxp = dxc = NULL;   
08195    for (i=0; i<dxf->n_comp; ++i) {
08196       if (strstr(dxf->comp_name[i],"positions")) {
08197          dxp = SUMA_Find_OpenDX_Object_Name(dxv, iop, dxf->comp_value[i], &nf); 
08198          if (!dxp || nf != 1) { SUMA_SL_Err("Failed to find one and only one positions object"); goto CLEAN_EXIT; }
08199       }
08200       if (strstr(dxf->comp_name[i],"connections")) {
08201          dxc = SUMA_Find_OpenDX_Object_Name(dxv, iop, dxf->comp_value[i], &nf); 
08202          if (!dxc || nf != 1) { SUMA_SL_Err("Failed to find one and only one connections object"); goto CLEAN_EXIT; }
08203       }
08204       if (strstr(dxf->comp_name[i],"data")) {
08205          dxa = SUMA_Find_OpenDX_Object_Name(dxv, iop, dxf->comp_value[i], &nf); 
08206          if (!dxa || nf != 1) { SUMA_SL_Err("Failed to find one and only one data object"); goto CLEAN_EXIT; }
08207       }
08208    }
08209    
08210    if (!dxp || !dxv || !dxa) {
08211       SUMA_SL_Err("Failed to find necessary objects"); SUMA_RETURN(NOPE);
08212    }
08213    
08214    /* sanity */
08215    SUMA_LH("Sanity checks");
08216    if (!dxa->data_format) {
08217       SUMA_SL_Err("Not a binary data file!");
08218       goto CLEAN_EXIT; 
08219    }
08220    if (!dxa->data) {
08221       SUMA_SL_Err("No data file!");
08222       goto CLEAN_EXIT; 
08223    }
08224    if (dxp->n_counts != 3) {
08225       SUMA_SL_Err("counts field must have 3 values");
08226       goto CLEAN_EXIT; 
08227    }
08228    if (dxp->n_delta != 9) {
08229       SUMA_SL_Err("delta must contain 9 elements!");
08230       goto CLEAN_EXIT; 
08231    }
08232    
08233    /* form the command */
08234    SUMA_LH("Forming command");
08235    /* 3d what? */
08236    chunk = 0;
08237    form[0] = '\0';
08238    data_type = SUMA_VarType2TypeCast(dxa->type);
08239    switch (data_type) {
08240       case SUMA_float:
08241          sprintf(form,"3Df");
08242          chunk = sizeof(float);
08243          break;
08244       case SUMA_double:
08245          sprintf(form,"3Dd");
08246          chunk = sizeof(double);
08247          break;
08248       case SUMA_int:
08249          sprintf(form,"3Di");
08250          chunk = sizeof(int);
08251          break;
08252       case SUMA_short:
08253          sprintf(form,"3Ds");
08254          chunk = sizeof(short);
08255          break;
08256       case SUMA_byte:
08257          sprintf(form,"3Db");
08258          chunk = sizeof(byte);
08259          break;
08260       default:
08261          SUMA_SL_Err("No support for this type");
08262          goto CLEAN_EXIT; 
08263          break;
08264    }
08265    /* byte ordering */
08266    SUMA_WHAT_ENDIAN(End);
08267    bs = 0;
08268    swp[0] = '\0';
08269    if (End != dxa->data_format) {
08270       SUMA_LH("swapping needed");
08271       bs = 1;
08272       switch (chunk) {
08273          case 1:
08274             break;
08275          case 2:
08276             sprintf(swp,"-2swap");
08277             break;
08278          case 4:
08279             sprintf(swp,"-4swap");
08280             break;
08281          case 8:
08282             sprintf(swp,"-8swap");
08283             break;
08284          default:
08285             SUMA_SL_Err("Patchunk!");
08286             break;
08287       }
08288    }
08289    if (dxa->data_off)  doff = (int)strtol(dxa->data_off,NULL, 10);
08290    else doff = 0;
08291    
08292    /* direction that varies the fastest (x) is in the last delta
08293       count is ordered like delta. I do not know about origin yet,
08294       I assume that origin follows the ordering of count
08295       see http://opendx.npaci.edu/docs/html/pages/usrgu068.htm 
08296       for reference, someday....*/
08297    
08298    /* number of voxels */
08299    LOAD_IVEC3( nxyz   , dxp->counts[2]    , dxp->counts[1]    , dxp->counts[0] ) ;
08300    
08301    /* orientation */
08302    /* find closest orientation in RAI, delta matrix does allow for obliqueness (non diagonal matrix) but we ignore it */
08303    LOAD_MAT(m33, 
08304                dxp->delta[6], dxp->delta[7], dxp->delta[8], 
08305                dxp->delta[3], dxp->delta[4], dxp->delta[5],
08306                dxp->delta[0], dxp->delta[1], dxp->delta[2] );
08307    orixyz = THD_matrix_to_orientation( m33 );
08308 
08309    /* dimensions */
08310    {  
08311       float fb[3]; 
08312       SUMA_NORM_VEC((&(dxp->delta[6])),3, fb[0]);
08313       SUMA_NORM_VEC((&(dxp->delta[3])),3, fb[1]);
08314       SUMA_NORM_VEC((&(dxp->delta[0])),3, fb[2]);
08315       LOAD_FVEC3( dxyz   , fb[0]    , fb[1]    , fb[2]    ) ;
08316       SUMA_sizeto3d_2_deltaHEAD(orixyz, &dxyz);
08317    }
08318    
08319    /* origin , assumed to be center of first voxel*/
08320    LOAD_FVEC3( orgxyz , dxp->origin[2]    , dxp->origin[1] , dxp->origin[0]  ) ;
08321    SUMA_originto3d_2_originHEAD(orixyz, &orgxyz);
08322     
08323    /* start point (edge of origin voxel) and end point (opposite to start ) */
08324    sp[0] = dxp->origin[2] + SUMA_ABS(dxyz.xyz[0]) / 2.0;
08325    sp[1] = dxp->origin[1] + SUMA_ABS(dxyz.xyz[1]) / 2.0;
08326    sp[2] = dxp->origin[0] + SUMA_ABS(dxyz.xyz[2]) / 2.0;
08327    ep[0] = dxp->origin[2] + (nxyz.ijk[0] - 0.5) * SUMA_ABS(dxyz.xyz[0]);
08328    ep[1] = dxp->origin[1] + (nxyz.ijk[1] - 0.5) * SUMA_ABS(dxyz.xyz[1]);
08329    ep[2] = dxp->origin[0] + (nxyz.ijk[2] - 0.5) * SUMA_ABS(dxyz.xyz[2]);
08330    SUMA_orcode_to_orstring (orixyz.ijk[0], orixyz.ijk[1], orixyz.ijk[2], orstr);
08331    sprintf(xfov," -xFOV %.2f%c-%.2f%c", sp[0], orstr[0], ep[0], orstr[3]);
08332    sprintf(yfov," -yFOV %.2f%c-%.2f%c", sp[1], orstr[1], ep[1], orstr[4]);
08333    sprintf(zfov," -zFOV %.2f%c-%.2f%c", sp[2], orstr[2], ep[2], orstr[5]);
08334   
08335    
08336    scom = (char *)SUMA_calloc((strlen(dxa->data)+500), sizeof(char));
08337    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);
08338    
08339    
08340    if (dset) { /* form the dset header */
08341          int nvals_read = 0;
08342          EDIT_dset_items( dset ,
08343                             ADN_prefix      , prefix ,
08344                             ADN_datum_all   , data_type ,
08345                             ADN_nxyz        , nxyz ,
08346                             ADN_xyzdel      , dxyz ,
08347                             ADN_xyzorg      , orgxyz ,
08348                             ADN_xyzorient   , orixyz ,
08349                             ADN_malloc_type , DATABLOCK_MEM_MALLOC ,
08350                             ADN_view_type   , VIEW_ORIGINAL_TYPE ,
08351                             ADN_type        , HEAD_ANAT_TYPE ,
08352                             ADN_func_type   , ANAT_BUCK_TYPE ,
08353                           ADN_none ) ;
08354 
08355          if (LoadData) {
08356             void *vec=NULL;
08357             if (!(vec = SUMA_BinarySuck(dxa->data, data_type, dxa->data_format, doff, -1, &nvals_read))) {
08358                SUMA_SL_Err("Failed to read data file"); goto CLEAN_EXIT;
08359             }
08360             EDIT_substitute_brick( dset , 0 , data_type , vec) ;      
08361             if (LocalHead) fprintf(SUMA_STDERR,"%s: Read %d values from file.\n", FuncName, nvals_read);
08362             /* DSET_write(dset) ; */
08363          }
08364    }
08365    
08366 
08367    
08368    CLEAN_EXIT:
08369    dxv = SUMA_Free_OpenDX_StructVec(dxv, iop);
08370    if (prefix) SUMA_free(prefix); prefix = NULL;
08371    
08372    SUMA_RETURN(scom);
08373 }
08374 
08375 /*!
08376    \brief reads an OpenDX surface. Sample surfaces provided by Aaron Carass
08377    
08378    The following fields are set in SO:
08379    SO->NodeDim
08380    SO->FaceSetDim
08381    SO->NodeList
08382    SO->FaceSetList
08383    SO->N_Node;
08384    SO->N_FaceSet;
08385    SO->Name;
08386    SO->FileType;
08387    SO->FileFormat
08388 
08389 */
08390 SUMA_Boolean SUMA_OpenDX_Read_SO(char *fname, SUMA_SurfaceObject *SO)
08391 {
08392    static char FuncName[]={"SUMA_OpenDX_Read_SO"};
08393    int i = 0, nf, iop;
08394    SUMA_OPEN_DX_STRUCT **dxv=NULL, *dxp=NULL, *dxc = NULL, *dxf = NULL, *dxo = NULL;
08395    SUMA_Boolean ans = NOPE;
08396    SUMA_Boolean LocalHead = NOPE;
08397    
08398    SUMA_ENTRY;
08399    
08400    if (!SO || !fname) {
08401       SUMA_SL_Err("NULL fname || NULL SO!");
08402       SUMA_RETURN(NOPE);
08403    }
08404    
08405    SUMA_LH("Reading objects");
08406    dxv = SUMA_OpenDX_Read(fname, &iop);
08407    if (!dxv) {
08408       SUMA_SL_Err("Failed to read DX file.");
08409       SUMA_RETURN(NOPE);
08410    }
08411    
08412    
08413    SUMA_LH("Checking for field object");
08414    dxf = SUMA_Find_OpenDX_Object_Class(dxv, iop, "field", &nf);
08415    if (!dxf || nf != 1) { SUMA_SL_Err("Failed to find one and only one field object"); goto CLEAN_EXIT; }
08416    /* get names of objects that contain positions and connections */
08417    dxp = dxc = dxo = NULL;   
08418    for (i=0; i<dxf->n_comp; ++i) {
08419       if (strstr(dxf->comp_name[i],"positions")) {
08420          dxp = SUMA_Find_OpenDX_Object_Name(dxv, iop, dxf->comp_value[i], &nf); 
08421          if (!dxp || nf != 1) { SUMA_SL_Err("Failed to find one and only one positions object"); goto CLEAN_EXIT; }
08422       }
08423       if (strstr(dxf->comp_name[i],"connections")) {
08424          dxc = SUMA_Find_OpenDX_Object_Name(dxv, iop, dxf->comp_value[i], &nf); 
08425          if (!dxc || nf != 1) { SUMA_SL_Err("Failed to find one and only one connections object"); goto CLEAN_EXIT; }
08426       }
08427       if (strstr(dxf->comp_name[i],"origin")) {
08428          dxo = SUMA_Find_OpenDX_Object_Name(dxv, iop, dxf->comp_value[i], &nf); 
08429          if (!dxo || nf != 1) { SUMA_SL_Err("Failed to find one and only one origin object.\nOrigin ignored"); }
08430       }
08431    }
08432    
08433    if (!dxp || !dxv) {
08434       SUMA_SL_Err("Failed to find necessary objects"); goto CLEAN_EXIT;
08435    }
08436    
08437    SUMA_LH("checking...");
08438    if (SUMA_VarType2TypeCast (dxp->type) != SUMA_float) {
08439       SUMA_SL_Err("Expected floats for positions"); goto CLEAN_EXIT;
08440    }
08441    if (dxp->bad_data) {
08442       SUMA_SL_Err("Problem reading data for positions"); goto CLEAN_EXIT;
08443    }
08444    if (dxp->rank != 1) {
08445       SUMA_SL_Err("Expected rank of 1 for positions"); goto CLEAN_EXIT;
08446    }
08447    if (dxp->shape != 3) {
08448       SUMA_SL_Err("Expected rank of 3 for positions"); goto CLEAN_EXIT;
08449    }
08450    if (SUMA_VarType2TypeCast (dxc->type) != SUMA_int) {
08451       SUMA_SL_Err("Expected ints for connections"); goto CLEAN_EXIT;
08452    }
08453    if (dxc->bad_data) {
08454       SUMA_SL_Err("Problem reading data for connections"); goto CLEAN_EXIT;
08455    }   
08456    if (dxc->rank != 1) {
08457       SUMA_SL_Err("Expected rank of 1 for connections"); goto CLEAN_EXIT;
08458    }
08459    if (dxc->shape != 3) {
08460       SUMA_SL_Err("Expected rank of 3 for connections"); goto CLEAN_EXIT;
08461    }
08462    /* if dxo */
08463    if (dxo) {
08464       if (SUMA_VarType2TypeCast (dxo->type) != SUMA_float) {
08465          SUMA_SL_Err("Expected floats for origin.\nOrigin ignored"); dxo = NULL;
08466       }
08467       if (!dxo->datap || dxo->shape * dxo->items != 3) {
08468          SUMA_SL_Err("Unknown origin format, ignoring origin"); dxo = NULL;
08469       }  
08470    }
08471    
08472    SUMA_LH("Take the gold");
08473    SO->FileType = SUMA_OPENDX_MESH;
08474    SO->FileFormat = SUMA_ASCII;
08475    
08476    SO->NodeDim = dxp->shape;
08477    SO->NodeList = (float *)dxp->datap; dxp->datap = NULL; /* datap will not be freed at end anymore */
08478    SO->N_Node = dxp->items;
08479    
08480    SO->FaceSetDim = dxc->shape;
08481    SO->FaceSetList = (int *)dxc->datap; dxc->datap = NULL; /* datap will not be freed at end anymore */
08482    SO->N_FaceSet = dxc->items;;
08483    SO->Name = SUMA_StripPath(fname);
08484    
08485    if (dxo) {
08486       float *fvec=(float*)dxo->datap;
08487       SUMA_LH("Adding origin");
08488       i = 0;
08489       while (i < dxp->items*dxp->shape) {
08490          SO->NodeList[i] += fvec[0]; ++i;
08491          SO->NodeList[i] += fvec[1]; ++i;
08492          SO->NodeList[i] += fvec[2]; ++i;
08493       }
08494    }
08495    
08496    /* all is well here */
08497    ans = YUP;
08498 
08499    CLEAN_EXIT:
08500    SUMA_LH("Frenching dxv");
08501    for (i=0; i<iop; ++i) {
08502       dxv[i] = SUMA_Free_OpenDX_Struct(dxv[i]);
08503    }
08504    if (dxv) SUMA_free(dxv); dxv = NULL;
08505    SUMA_RETURN(YUP);
08506 }
08507 /*  >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> END OpenDX functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
 

Powered by Plone

This site conforms to the following standards: