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_Load_Surface_Object.c

Go to the documentation of this file.
00001 
00002 /*----------------------------------------------------------------------
00003  * history:
00004  *
00005  * 11 Dec 2003  [rickr]
00006  *   - added functions:
00007  *       o  SUMA_spec_select_surfs      - restrict spec struct from name list
00008  *       o  SUMA_swap_spec_entries      - swap 2 entries in spec struct
00009  *       o  SUMA_unique_name_ind        - verify unique surf name in spec
00010  *       o  SUMA_coord_file             - get file name, based on surf type
00011  *       o  swap_strings                - swap 2 strings via 3rd
00012  *----------------------------------------------------------------------
00013 */
00014     
00015 /* Header FILES */
00016    
00017 #include "SUMA_suma.h"
00018 
00019 
00020 /*#define  DO_SCALE_RANGE   *//*!< scale node coordinates to 0 <--> 100. DO NOT USE IT, OBSOLETE*/
00021 #ifndef DO_SCALE_RANGE
00022    #define DO_SCALE 319.7   /*!< scale node coordinates by specified factor. Useful for tesscon coordinate system in iv files*/
00023 #endif
00024 
00025 #undef STAND_ALONE
00026 
00027 #if defined SUMA_Read_SpecFile_STAND_ALONE
00028 #define STAND_ALONE
00029 #elif defined SUMA_Load_Surface_Object_STAND_ALONE
00030 #define STAND_ALONE
00031 #elif defined SUMA_SurfaceMetrics_STAND_ALONE
00032 #define STAND_ALONE 
00033 #elif defined SUMA_inspec_STAND_ALONE
00034 #define STAND_ALONE 
00035 #elif defined SUMA_quickspec_STAND_ALONE
00036 #define STAND_ALONE 
00037 #endif
00038 
00039 #ifdef STAND_ALONE
00040 /* these global variables must be declared even if they will not be used by this main */
00041 SUMA_SurfaceViewer *SUMAg_cSV; /*!< Global pointer to current Surface Viewer structure*/
00042 SUMA_SurfaceViewer *SUMAg_SVv; /*!< Global pointer to the vector containing the various Surface Viewer Structures 
00043                                     SUMAg_SVv contains SUMA_MAX_SURF_VIEWERS structures */
00044 int SUMAg_N_SVv = 0; /*!< Number of SVs realized by X */
00045 SUMA_DO *SUMAg_DOv;   /*!< Global pointer to Displayable Object structure vector*/
00046 int SUMAg_N_DOv = 0; /*!< Number of DOs stored in DOv */
00047 SUMA_CommonFields *SUMAg_CF; /*!< Global pointer to structure containing info common to all viewers */
00048 #else
00049 extern SUMA_CommonFields *SUMAg_CF;
00050 extern SUMA_DO *SUMAg_DOv;
00051 extern SUMA_SurfaceViewer *SUMAg_SVv;
00052 extern int SUMAg_N_SVv; 
00053 extern int SUMAg_N_DOv;  
00054 #endif
00055 
00056 /* CODE */
00057 
00058    
00059 /*!
00060    \brief Function to write surface objects to disk in various formats
00061    ans = SUMA_Save_Surface_Object (void * F_name, SUMA_SurfaceObject *SO, SUMA_SO_File_Type SO_FT, 
00062                               SUMA_SO_File_Format SO_FF, void *someparam);
00063    \param F_name (void *)
00064          For SUMA_INVENTOR_GENERIC F_name is (char *) containing path (if any) and filename of surface
00065          For SUMA_SUREFIT F_name is (SUMA_SFname *) containing full topo and coord names, with path (if any)
00066          For SUMA_FREE_SURFER F_name is  (char *) name of .asc file (with path)
00067          For SUMA_VEC (a dumb ascii format), F_name is (SUMA_SFname *) containing the nodelist file in name_coord 
00068           and facesetlist file in name_topo (path included).
00069          For SUMA_PLY (char *) name of .ply file (with path)
00070          For SUMA_OPENDX_MESH (char *) name of .dx file (with path)
00071    \param   SO_FT (SUMA_SO_File_Type) file type to be read (inventor, free surfer , Surefit )
00072    \param   SO_FF (SUMA_SO_File_Format) Ascii or Binary (only ascii at the moment, except for .ply files)
00073    \param someparam (void *) a pointer used to pass extra parameters. At the moment, used for passing a parent
00074                            surface when writing FreeSurferPatches
00075    \sa SUMA_Load_Surface_Object()
00076    
00077    NOTE:
00078    Vertex coordinates are written as in SO->NodeList
00079    The Volume Parent transformation is not undone. 
00080    For SureFit surfaces, the volume param shift is not undone.
00081 */
00082 SUMA_Boolean SUMA_Save_Surface_Object (void * F_name, SUMA_SurfaceObject *SO, SUMA_SO_File_Type SO_FT, SUMA_SO_File_Format SO_FF, void *someparam)
00083 {/*SUMA_Save_Surface_Object*/
00084    static char FuncName[]={"SUMA_Save_Surface_Object"};
00085    
00086    SUMA_ENTRY;
00087    
00088    if (!F_name) {
00089       SUMA_S_Err("Null filename!");
00090       SUMA_RETURN(NOPE);
00091    }
00092    
00093    switch (SO_FT) {
00094       case SUMA_OPENDX_MESH:
00095          if (!SUMA_OpenDX_Write ((char *)F_name, SO)) {
00096             fprintf (SUMA_STDERR, "Error %s: Failed to write SUMA_OPENDX_MESH surface.\n", FuncName);
00097             SUMA_RETURN (NOPE);
00098          }
00099          break;
00100       case SUMA_PLY:
00101          if (!SUMA_Ply_Write ((char *)F_name, SO)) {
00102             fprintf (SUMA_STDERR, "Error %s: Failed to write PLY surface.\n", FuncName);
00103             SUMA_RETURN (NOPE);
00104          }
00105          break;
00106       case SUMA_FREE_SURFER:
00107          if (SO_FF != SUMA_ASCII) {
00108             fprintf (SUMA_STDERR, "Warning %s: Only ASCII supported for Free Surfer surfaces.\n", FuncName);
00109          }
00110          if (!SUMA_FS_Write ((char *)F_name, SO, "#Output of SUMA_SurfaceConvert")) {
00111             fprintf (SUMA_STDERR, "Error %s: Failed to write FreeSurfer surface.\n", FuncName);
00112             SUMA_RETURN (NOPE);
00113          }
00114          break;
00115       case SUMA_FREE_SURFER_PATCH:
00116          if (SO_FF != SUMA_ASCII) {
00117             fprintf (SUMA_STDERR, "Warning %s: Only ASCII supported for Free Surfer surface patches.\n", FuncName);
00118          }
00119          if (!SUMA_FreeSurfer_WritePatch ((char *)F_name, SO, NULL, (SUMA_SurfaceObject *)someparam)) {
00120             fprintf (SUMA_STDERR, "Error %s: Failed to write FreeSurfer surface.\n", FuncName);
00121             SUMA_RETURN (NOPE);
00122          }
00123          break;
00124       case SUMA_SUREFIT:
00125          if (SO_FF != SUMA_ASCII) {
00126             fprintf (SUMA_STDERR, "Warning %s: Only ASCII supported for SureFit surfaces.\n", FuncName);
00127          }
00128          if (!SUMA_SureFit_Write ((SUMA_SFname *)F_name, SO)) {
00129             fprintf (SUMA_STDERR, "Error %s: Failed to write SureFit surface.\n", FuncName);
00130             SUMA_RETURN (NOPE);
00131          }
00132          break;
00133       case SUMA_VEC:
00134          if (SO_FF != SUMA_ASCII) {
00135             fprintf (SUMA_STDERR, "Warning %s: Only ASCII supported for vec surfaces.\n", FuncName);
00136          }
00137          if (!SUMA_VEC_Write ((SUMA_SFname *)F_name, SO)) {
00138             fprintf (SUMA_STDERR, "Error %s: Failed to write vec surface.\n", FuncName);
00139             SUMA_RETURN (NOPE);
00140          }
00141          break;
00142       case SUMA_INVENTOR_GENERIC:
00143          fprintf (SUMA_STDERR, "Error %s: Not ready to deal with inventor surfaces.\n", FuncName);
00144          SUMA_RETURN (NOPE);
00145          break;
00146       case SUMA_FT_NOT_SPECIFIED:
00147       default:
00148          fprintf (SUMA_STDERR, "Error %s: Bad surface type.\n", FuncName);
00149          SUMA_RETURN (NOPE);
00150    
00151    }
00152    
00153    SUMA_RETURN (YUP);
00154 }
00155 
00156 /*!
00157    \brief for a new SO, calculate the following:
00158    Normals, dimensions, SUMA's NodeMarker FaceSetMarker, etc.
00159 */
00160 SUMA_Boolean SUMA_PrepSO_GeomProp_GL(SUMA_SurfaceObject *SO)
00161 {
00162    static char FuncName[]={"SUMA_PrepSO_GeomProp_GL"};
00163    int k, ND, id;
00164    SUMA_SURF_NORM SN;
00165    SUMA_Boolean *PatchNodeMask=NULL;
00166    SUMA_Boolean LocalHead = NOPE;
00167    
00168    /* Calculate Min, Max, Mean */
00169    
00170    SUMA_MIN_MAX_SUM_VECMAT_COL (SO->NodeList, SO->N_Node, SO->NodeDim, SO->MinDims, SO->MaxDims, SO->Center);
00171      
00172    SO->Center[0] /= SO->N_Node;
00173    SO->Center[1] /= SO->N_Node;
00174    SO->Center[2] /= SO->N_Node;
00175 
00176    SUMA_MIN_VEC (SO->MinDims, 3, SO->aMinDims );
00177    SUMA_MAX_VEC (SO->MaxDims, 3, SO->aMaxDims);
00178 
00179    /* calculate the center and dimensions for the nodes in the patch only */
00180    PatchNodeMask = SUMA_MaskOfNodesInPatch(SO, &(SO->N_patchNode));
00181    if (!SO->N_patchNode || SO->N_patchNode == SO->N_Node) { 
00182       if (!PatchNodeMask ) { SUMA_SL_Err("Faied in SUMA_MaskOfNodesInPatch.\nUsing values from all nodes."); }
00183       SUMA_COPY_VEC(SO->Center, SO->patchCenter, 3, float, float);
00184       SUMA_COPY_VEC(SO->MinDims, SO->patchMinDims, 3, float, float);
00185       SUMA_COPY_VEC(SO->MaxDims, SO->patchMaxDims, 3, float, float);
00186       SO->patchaMaxDims = SO->aMaxDims;
00187       SO->patchaMinDims = SO->aMinDims;
00188    }else {
00189       SUMA_MIN_MAX_SUM_VECMAT_MASK_COL (SO->NodeList, SO->N_Node, SO->NodeDim, PatchNodeMask, SO->patchMinDims, SO->patchMaxDims, SO->patchCenter);
00190       SO->patchCenter[0] /= SO->N_patchNode;
00191       SO->patchCenter[1] /= SO->N_patchNode;
00192       SO->patchCenter[2] /= SO->N_patchNode;
00193       SUMA_MIN_VEC (SO->patchMinDims, 3, SO->patchaMinDims );
00194       SUMA_MAX_VEC (SO->patchMaxDims, 3, SO->patchaMaxDims);
00195       SUMA_free(PatchNodeMask) ; PatchNodeMask = NULL;
00196    }
00197    
00198    #ifdef DO_SCALE_RANGE
00199    { float tmpfact;
00200    /* Now do some scaling */
00201    tmpfact = (SO->aMaxDims - SO->aMinDims)/100;
00202    ND = SO->NodeDim;
00203    for (k=0; k < SO->N_Node; k++)
00204    {
00205       id = NodeDim * k;
00206       SO->NodeList[k] = (SO->NodeList[k] - SO->aMinDims)/tmpfact;
00207       SO->NodeList[k+1] = (SO->NodeList[k+1] - SO->aMinDims)/tmpfact;
00208       SO->NodeList[k+2] = (SO->NodeList[k+2] - SO->aMinDims)/tmpfact;
00209    }
00210    
00211    SO->Center[0] = (SO->Center[0] - SO->aMinDims)/tmpfact;
00212    SO->Center[1] = (SO->Center[1] - SO->aMinDims)/tmpfact;
00213    SO->Center[2] = (SO->Center[2] - SO->aMinDims)/tmpfact;
00214 
00215    SO->MinDims[0] = (SO->MinDims[0] - SO->aMinDims)/tmpfact;
00216    SO->MinDims[1] = (SO->MinDims[1] - SO->aMinDims)/tmpfact;
00217    SO->MinDims[2] = (SO->MinDims[2] - SO->aMinDims)/tmpfact;
00218 
00219    SO->MaxDims[0] = (SO->MaxDims[0] - SO->aMinDims)/tmpfact;
00220    SO->MaxDims[1] = (SO->MaxDims[1] - SO->aMinDims)/tmpfact;
00221    SO->MaxDims[2] = (SO->MaxDims[2] - SO->aMinDims)/tmpfact;
00222 
00223    SO->aMinDims = 0.0;
00224    SO->aMaxDims = 100.0;
00225    }
00226    #endif
00227    #ifdef DO_SCALE
00228    /* Now do some scaling */
00229    if ((SO->aMaxDims - SO->aMinDims) > SUMA_TESSCON_DIFF_FLAG) {
00230       fprintf (stdout,"\n\nWARNING %s:\n Assuming surface to be in tesscon units, scaling down by %f.\n\aYou might have abnormally large or small freakish vertex coordinates\n\n",\
00231          FuncName, SUMA_TESSCON_TO_MM);
00232       ND = SO->NodeDim;
00233       for (k=0; k < SO->N_Node; k++)
00234       {
00235          id = ND * k;
00236          SO->NodeList[id] /= SUMA_TESSCON_TO_MM;
00237          SO->NodeList[id+1] /= SUMA_TESSCON_TO_MM;
00238          SO->NodeList[id+2] /= SUMA_TESSCON_TO_MM;
00239       }
00240 
00241       SO->Center[0] /= SUMA_TESSCON_TO_MM;
00242       SO->Center[1] /= SUMA_TESSCON_TO_MM;
00243       SO->Center[2] /= SUMA_TESSCON_TO_MM;
00244 
00245       SO->MinDims[0] /= SUMA_TESSCON_TO_MM;
00246       SO->MinDims[1] /= SUMA_TESSCON_TO_MM;
00247       SO->MinDims[2] /= SUMA_TESSCON_TO_MM;
00248 
00249       SO->MaxDims[0] /= SUMA_TESSCON_TO_MM;
00250       SO->MaxDims[1] /= SUMA_TESSCON_TO_MM;
00251       SO->MaxDims[2] /= SUMA_TESSCON_TO_MM;
00252 
00253       SO->aMinDims /= SUMA_TESSCON_TO_MM;
00254       SO->aMaxDims /= SUMA_TESSCON_TO_MM;
00255    } 
00256    #endif
00257     
00258    
00259    /* Calculate SurfaceNormals */
00260    if (SO->NodeNormList && SO->FaceNormList) {
00261       SUMA_LH("Node normals already computed, skipping...");
00262    } else {
00263       SN = SUMA_SurfNorm(SO->NodeList,  SO->N_Node, SO->FaceSetList, SO->N_FaceSet );
00264       SO->NodeNormList = SN.NodeNormList;
00265       SO->FaceNormList = SN.FaceNormList;
00266    }
00267    
00268    /*create the structures for GL rendering */
00269    /*The data is being duplicated at the moment and perhaps I should just stick with the 1D stuf */
00270    if (sizeof(GLfloat) != sizeof(float)) { SUMA_SL_Crit("GLfloat and float have differing sizes!\n"); SUMA_RETURN(NOPE); }
00271    if (sizeof(GLint) != sizeof(int)) { SUMA_SL_Crit("GLint and int have differing sizes!\n"); SUMA_RETURN(NOPE); }
00272    
00273    SO->glar_NodeList = (GLfloat *) SO->NodeList; /* just copy the pointer, not the data */
00274    SO->glar_FaceSetList = (GLint *) SO->FaceSetList; /* just copy the pointer, not the data */
00275    SO->glar_FaceNormList = (GLfloat *) SO->FaceNormList; /* just copy the pointer, not the data */
00276    SO->glar_NodeNormList = (GLfloat *) SO->NodeNormList; /* just copy the pointer, not the data */
00277 
00278    /* a surface object does contribute to the rotation center of the viewer displaying it */
00279    SO->RotationWeight = SO->N_Node;
00280    SO->ViewCenterWeight = SO->N_Node;
00281    
00282    /* No selections yet, but make the preps */
00283       SO->ShowSelectedNode = YUP;
00284       SO->ShowSelectedFaceSet = YUP;
00285       SO->SelectedFaceSet = -1;
00286       SO->SelectedNode = -1;
00287       /* create the ball object*/
00288       if (SO->NodeMarker) {
00289          SUMA_LH("NodeMarker already present. Skipping");
00290       } else {
00291          SO->NodeMarker = SUMA_Alloc_SphereMarker ();
00292       }
00293       if (SO->NodeMarker == NULL) {
00294          fprintf(SUMA_STDERR,"Error%s: Could not allocate for SO->NodeMarker\n", FuncName);
00295          SUMA_Free_Surface_Object (SO);
00296          SUMA_RETURN (NOPE);
00297       }
00298       /* create the FaceSetMarker object */
00299       if (SO->FaceSetMarker) {
00300          SUMA_LH("FaceSetMarker already present. Skipping");
00301       } else {
00302          SO->FaceSetMarker = SUMA_Alloc_FaceSetMarker();
00303       }
00304       if (SO->FaceSetMarker == NULL) {
00305          fprintf(SUMA_STDERR,"Error%s: Could not allocate for SO->FaceSetMarker\n", FuncName);
00306          SUMA_Free_Surface_Object (SO);
00307          SUMA_RETURN (NOPE);
00308       }
00309    
00310          
00311    SUMA_RETURN(YUP);
00312 }
00313    
00314    
00315 /*! 
00316    Call the function engine, with debug turned on.      20 Oct 2003 [rickr]
00317 */
00318 SUMA_SurfaceObject * SUMA_Load_Surface_Object (void *SO_FileName_vp, SUMA_SO_File_Type SO_FT, SUMA_SO_File_Format SO_FF, char *VolParName)
00319 {/*SUMA_Load_Surface_Object*/
00320    static char FuncName[]={"SUMA_Load_Surface_Object"};
00321 
00322    SUMA_ENTRY;
00323 
00324    SUMA_RETURN( SUMA_Load_Surface_Object_eng( SO_FileName_vp, SO_FT, SO_FF,
00325                                               VolParName, 1) );
00326 }/*SUMA_Load_Surface_Object*/
00327 
00328 
00329 /* - appended _eng to engine function name             20 Oct 2003 [rickr]
00330  * - added debug parmeter
00331  * - only print non-error info when debug flag is set
00332 */
00333 /*!
00334 \brief
00335       SO = SUMA_Load_Surface_Object_eng ( SO_FileName, SO_FT, SO_FF, char *VolParName, int debug)
00336    
00337    
00338 Input paramters : 
00339 \param   (void *) SO_FileName 
00340          For SUMA_INVENTOR_GENERIC SO_FileName is (char *) containing path (if any) and filename of surface
00341          For SUMA_SUREFIT SO_FileName is (SUMA_SFname *) containing full topo and coord names, with path (if any)
00342          For SUMA_FREE_SURFER SO_FileName is  (char *) name of .asc file (with path)
00343          For SUMA_VEC (a dumb ascii format), SO_FileName is (SUMA_SFname *) containing the nodelist file in name_coord 
00344           and facesetlist file in name_topo (path included).
00345          For SUMA_PLY (char *) name of .ply file (with path)
00346          For SUMA_OPENDX_MESH (char *) name of .dx file (with path)
00347 \param   SO_FT (SUMA_SO_File_Type) file type to be read (inventor, free surfer , Surefit )
00348 \param   SO_FF (SUMA_SO_File_Format) Ascii or Binary (only ascii at the moment, except for .ply files)
00349 \param   VolParName (char *) filename (+path) of parent volume, pass NULL for none
00350          If you pass NULL, no transformation is applied to the coordinates read.
00351 \param   debug (int) flag specifying whether to output surface object info
00352    
00353 \return   SO (SUMA_SurfaceObject *) Surface Object pointer
00354    The following fields are set (or initialized):
00355    SO->NodeDim
00356    SO->FaceSetDim
00357    SO->NodeList
00358    SO->FaceSetList
00359    SO->N_Node;
00360    SO->N_FaceSet;
00361    SO->Name;
00362    SO->FileType;
00363    SO->FileFormat
00364    SO->idcode_str
00365    SO->Center
00366    SO->aMaxDims
00367    SO->aMinDims
00368    SO->NodeNormList
00369    SO->FaceNormList
00370    SO->glar_NodeList
00371    SO->glar_FaceSetList
00372    SO->glar_FaceNormList
00373    SO->glar_NodeNormList
00374    SO->RotationWeight
00375    SO->ViewCenterWeight
00376    SO->ShowSelectedNode
00377    SO->ShowSelectedFaceSet
00378    SO->SelectedFaceSet
00379    SO->SelectedNode
00380    SO->NodeMarker
00381    SO->FaceSetMarker
00382    SO->VolPar
00383    SO->SUMA_VolPar_Aligned   
00384    
00385 \sa SUMA_IV*
00386 \sa SUMA_Save_Surface_Object()
00387 \sa SUMA_Align_to_VolPar()   
00388    
00389 ***/
00390 SUMA_SurfaceObject * SUMA_Load_Surface_Object_eng (void *SO_FileName_vp, SUMA_SO_File_Type SO_FT, SUMA_SO_File_Format SO_FF, char *VolParName, int debug)
00391 {/*SUMA_Load_Surface_Object_eng*/
00392    static char FuncName[]={"SUMA_Load_Surface_Object_eng"};
00393    char stmp[1000], *SO_FileName=NULL;
00394    SUMA_SFname *SF_FileName; 
00395    SUMA_SureFit_struct *SF;
00396    SUMA_FreeSurfer_struct *FS;
00397    SUMA_SurfaceObject *SO;
00398    SUMA_Boolean LocalHead = NOPE;
00399    
00400    SUMA_ENTRY;
00401 
00402    /* Allocate and initialize SUMA_SurfaceObject Pointer */
00403    SO = SUMA_Alloc_SurfObject_Struct(1);
00404    
00405    /* check if recognizable type */
00406    switch (SO_FT) {
00407       case SUMA_INVENTOR_GENERIC:
00408          break;
00409       case SUMA_SUREFIT:
00410          break;
00411       case SUMA_FREE_SURFER:
00412       case SUMA_FREE_SURFER_PATCH:
00413          break;
00414       case SUMA_PLY:
00415          break;
00416       case SUMA_OPENDX_MESH:
00417          break;
00418       case SUMA_VEC:
00419          break;
00420       case SUMA_BRAIN_VOYAGER:
00421          break;
00422       default:
00423          SUMA_error_message(FuncName, "SO_FileType not supported", 0);
00424          SUMA_RETURN (NULL);
00425          break;
00426    } /* SO_FT*/
00427 
00428    
00429    /* proceed for reading */
00430    switch (SO_FT) {
00431       case SUMA_CMAP_SO:
00432          /* nothing to do here */
00433          SUMA_SL_Err("Don't know how to read those from disk:");
00434          SUMA_RETURN(NULL);
00435       
00436       case SUMA_FT_NOT_SPECIFIED:
00437          fprintf (SUMA_STDERR,"Error %s: No File Type specified.\n", FuncName);
00438          SUMA_RETURN(NULL);
00439       
00440       case SUMA_N_SO_FILE_TYPE:
00441          fprintf (SUMA_STDERR,"Error %s: This should not happen (SUMA_N_SO_FILE_TYPE)\n", FuncName);
00442          SUMA_RETURN(NULL);
00443       
00444       case SUMA_PLY:
00445          if (!SUMA_Ply_Read ((char *)SO_FileName_vp, SO)) {
00446             fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_Ply_Read.\n", FuncName);
00447             SUMA_RETURN(NULL);
00448          }
00449          SUMA_NEW_ID(SO->idcode_str,(char *)SO_FileName_vp); 
00450          
00451          /* change coordinates to align them with volparent data set, if possible */
00452          if (VolParName != NULL) {
00453             SO->VolPar = SUMA_VolPar_Attr (VolParName);
00454             if (SO->VolPar == NULL) {
00455                fprintf(SUMA_STDERR,"Error %s: Failed to load parent volume attributes.\n", FuncName);
00456             } else {
00457 
00458             if (!SUMA_Align_to_VolPar (SO, NULL)) SO->SUMA_VolPar_Aligned = NOPE;
00459                else {
00460                   SO->SUMA_VolPar_Aligned = YUP;
00461                   /*SUMA_Show_VolPar(SO->VolPar, NULL);*/
00462                }
00463          }
00464          } else { 
00465             SO->SUMA_VolPar_Aligned = NOPE;
00466          }
00467 
00468          break;
00469       case SUMA_OPENDX_MESH:
00470          if (!SUMA_OpenDX_Read_SO ((char *)SO_FileName_vp, SO)) {
00471             fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_OpenDX_Read_SO.\n", FuncName);
00472             SUMA_RETURN(NULL);
00473          }
00474          SUMA_NEW_ID(SO->idcode_str,(char *)SO_FileName_vp); 
00475          
00476          /* change coordinates to align them with volparent data set, if possible */
00477          if (VolParName != NULL) {
00478             SO->VolPar = SUMA_VolPar_Attr (VolParName);
00479             if (SO->VolPar == NULL) {
00480                fprintf(SUMA_STDERR,"Error %s: Failed to load parent volume attributes.\n", FuncName);
00481             } else {
00482 
00483             if (!SUMA_Align_to_VolPar (SO, NULL)) SO->SUMA_VolPar_Aligned = NOPE;
00484                else {
00485                   SO->SUMA_VolPar_Aligned = YUP;
00486                   /*SUMA_Show_VolPar(SO->VolPar, NULL);*/
00487                }
00488          }
00489          } else { 
00490             SO->SUMA_VolPar_Aligned = NOPE;
00491          }
00492 
00493          break;
00494      case SUMA_BRAIN_VOYAGER:
00495          if (!SUMA_BrainVoyager_Read ((char *)SO_FileName_vp, SO, 1)) {
00496             fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_Ply_Read.\n", FuncName);
00497             SUMA_RETURN(NULL);
00498          }
00499          SUMA_NEW_ID(SO->idcode_str,(char *)SO_FileName_vp); 
00500          
00501          /* change coordinates to align them with volparent data set, if possible */
00502          if (VolParName != NULL) {
00503             SO->VolPar = SUMA_VolPar_Attr (VolParName);
00504             if (SO->VolPar == NULL) {
00505                fprintf(SUMA_STDERR,"Error %s: Failed to load parent volume attributes.\n", FuncName);
00506             } else {
00507 
00508             if (!SUMA_Align_to_VolPar (SO, NULL)) SO->SUMA_VolPar_Aligned = NOPE;
00509                else {
00510                   SO->SUMA_VolPar_Aligned = YUP;
00511                   /*SUMA_Show_VolPar(SO->VolPar, NULL);*/
00512                }
00513          }
00514          } else { 
00515             SO->SUMA_VolPar_Aligned = NOPE;
00516          }
00517          break;
00518             
00519       case SUMA_INVENTOR_GENERIC:
00520          SO_FileName = (char *)SO_FileName_vp;
00521          /* You need to split name into path and name ... */
00522          if ( debug )
00523             fprintf(stdout,"%s\n", SO_FileName);
00524          SO->Name = SUMA_StripPath(SO_FileName);
00525          /* check for file existence  */
00526          if (!SUMA_filexists(SO_FileName)) {
00527             sprintf(stmp,"File %s not found!", SO_FileName);
00528             SUMA_error_message(FuncName, stmp, 0);
00529             SUMA_RETURN (NULL);
00530          }
00531          SO->FileType = SO_FT;
00532          SO->FileFormat = SO_FF;
00533          SO->NodeDim = 3; /* This must be automated */
00534          SO->NodeList = SUMA_IV_XYZextract (SO_FileName, &(SO->N_Node), 0);
00535          if (SO->NodeList == NULL) {
00536             SUMA_error_message(FuncName,"SUMA_IV_XYZextract failed!",0);
00537             SUMA_RETURN(NULL);
00538          }
00539          SO->FaceSetList = SUMA_IV_FaceSetsextract (SO_FileName, &(SO->N_FaceSet));
00540          if (SO->FaceSetList == NULL) {
00541             SUMA_error_message(FuncName,"SUMA_IV_FaceSetsextract failed!",0);
00542             SUMA_RETURN(NULL);
00543          }
00544          SO->FaceSetDim = 3; /*This must also be automated */
00545          SUMA_NEW_ID(SO->idcode_str,SO_FileName); 
00546          break;
00547          
00548       case SUMA_FREE_SURFER:
00549       case SUMA_FREE_SURFER_PATCH:
00550          /* Allocate for FS */
00551          FS = (SUMA_FreeSurfer_struct *) SUMA_malloc(sizeof(SUMA_FreeSurfer_struct));   
00552          if (FS == NULL) {
00553             fprintf(SUMA_STDERR,"Error %s: Failed to allocate for FS\n", FuncName);
00554             SUMA_RETURN (NULL);
00555          }
00556          SO->Name = SUMA_StripPath((char*)SO_FileName_vp);
00557          SO->FileType = SO_FT;
00558          SO->FileFormat = SO_FF;
00559          SO->NodeDim = 3; /* This must be automated */
00560          /*read the surface file */
00561          if (SO->FileFormat == SUMA_ASCII) {
00562             if (!SUMA_FreeSurfer_Read_eng((char*)SO_FileName_vp, FS, debug)) {
00563                fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_FreeSurfer_Read.\n", FuncName);
00564                SUMA_RETURN (NULL);
00565             }
00566          } else if (SO->FileFormat == SUMA_BINARY_BE) {
00567             if (!SUMA_FreeSurfer_ReadBin_eng((char*)SO_FileName_vp, FS, debug)) {
00568                fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_FreeSurfer_Read.\n", FuncName);
00569                SUMA_RETURN (NULL);
00570             }
00571          } else {
00572             SUMA_SL_Err("Format not supported.");
00573             SUMA_RETURN (NULL);
00574          }
00575          if ( debug > 1)
00576             SUMA_Show_FreeSurfer (FS, NULL);
00577          /* save the juice and clean up the rest */
00578          SO->N_Node = FS->N_Node;
00579          /* Save the pointers to NodeList and FaceSetList and clear what is left of FS structure at the end */
00580          SO->NodeList = FS->NodeList;
00581          FS->NodeList = NULL;
00582          SO->FaceSetList = FS->FaceSetList;
00583          SO->N_FaceSet = FS->N_FaceSet;
00584          FS->FaceSetList = NULL;
00585          SO->FaceSetDim = 3; /*This must also be automated */
00586          
00587          
00588          /* change coordinates to align them with volparent data set, if possible */
00589          if (VolParName != NULL) {
00590             SO->VolPar = SUMA_VolPar_Attr (VolParName);
00591             if (SO->VolPar == NULL) {
00592                fprintf(SUMA_STDERR,"Error %s: Failed to load parent volume attributes.\n", FuncName);
00593             } else {
00594 
00595                if (!SUMA_Align_to_VolPar (SO, (void*)FS)) SO->SUMA_VolPar_Aligned = NOPE;
00596                   else {
00597                      SO->SUMA_VolPar_Aligned = YUP;
00598                      /*SUMA_Show_VolPar(SO->VolPar, NULL);*/
00599                   }
00600          }
00601          } else { 
00602             SO->SUMA_VolPar_Aligned = NOPE;
00603          }
00604          
00605          /* free FS */
00606          if (!SUMA_Free_FreeSurfer (FS)) {
00607             fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_Free_FreeSurfer.\n", FuncName);
00608             SUMA_RETURN (NULL);
00609          }
00610          
00611          /* create the IDcode */
00612          SUMA_NEW_ID(SO->idcode_str,SO_FileName_vp);
00613          if (LocalHead) fprintf (SUMA_STDERR, "%s: Assigned idcode_str:%s:.\n", FuncName, SO->idcode_str);
00614          break;
00615          
00616       case SUMA_VEC:
00617          /* naming is with two files, similar to SureFit */
00618          SF_FileName = (SUMA_SFname *)SO_FileName_vp;      
00619          /* form the topo and the coord names */
00620          SO->Name_coord = SUMA_StripPath(SF_FileName->name_coord);
00621          SO->Name_topo = SUMA_StripPath(SF_FileName->name_topo);
00622          SO->FileType = SO_FT;
00623          SO->FileFormat = SO_FF;
00624          SO->NodeDim = 3; /* This must be automated */
00625          /* check for files */
00626          if (!SUMA_filexists(SF_FileName->name_coord)) {
00627             fprintf(SUMA_STDERR,"Error %s: Could not find %s\n", FuncName, SF_FileName->name_coord);
00628             SUMA_RETURN (NULL);
00629          }
00630          if (!SUMA_filexists(SF_FileName->name_topo)) {
00631             fprintf(SUMA_STDERR,"Error %s: Could not find %s\n", FuncName, SF_FileName->name_topo);
00632             SUMA_RETURN (NULL);
00633          }
00634          
00635          #if 0
00636          /* THE OLDE WAY */
00637          /* check number of elements */
00638          SO->N_Node = SUMA_float_file_size (SF_FileName->name_coord);
00639          if ((SO->N_Node %3)) {
00640             fprintf(SUMA_STDERR,"Error %s: Number of elements (%d) in vertex file %s is not multiple of 3.\n", 
00641                FuncName, SO->N_Node, SF_FileName->name_coord);
00642             SUMA_RETURN (NULL);
00643          }
00644          SO->N_Node /= 3;
00645          SO->N_FaceSet = SUMA_float_file_size (SF_FileName->name_topo);
00646          if ((SO->N_FaceSet % 3)) {
00647             fprintf(SUMA_STDERR,"Error %s: Number of elements (%d) in faceset file %s is not multiple of 3.\n", 
00648                FuncName, SO->N_Node, SF_FileName->name_topo);
00649             SUMA_RETURN (NULL);
00650          }
00651          SO->N_FaceSet /= 3;
00652          SO->FaceSetDim = 3;
00653          
00654          SO->NodeList = (float *)SUMA_calloc (SO->N_Node*SO->NodeDim, sizeof(float));
00655          SO->FaceSetList = (int *) SUMA_calloc (SO->N_FaceSet*SO->FaceSetDim, sizeof(int));
00656          if (!SO->NodeList || !SO->FaceSetList) {
00657             fprintf(SUMA_STDERR,"Error %s: Failed to allocate for NodeList or FaceSetList.\n", FuncName);
00658             if (SO->NodeList) SUMA_free(SO->NodeList);
00659             if (SO->FaceSetList) SUMA_free(SO->FaceSetList);
00660             SUMA_RETURN (NULL);
00661          }
00662          SUMA_Read_file (SO->NodeList, SF_FileName->name_coord, SO->N_Node*SO->NodeDim);
00663          SUMA_Read_dfile (SO->FaceSetList, SF_FileName->name_topo, SO->N_FaceSet*SO->FaceSetDim);
00664         
00665          #else
00666          if (0){
00667             /* the local im_read_1D way */
00668             MRI_IMAGE *im = NULL;
00669             float *far=NULL;
00670             int icnt;
00671             
00672             im = mri_read_1D (SF_FileName->name_coord);
00673             if (!im) {
00674                SUMA_SLP_Err("Failed to read 1D file");
00675                SUMA_RETURN(NULL);
00676             }
00677             far = MRI_FLOAT_PTR(im);
00678             SO->N_Node = im->nx;
00679             SO->NodeDim = im->ny;
00680             if (!SO->N_Node) {
00681                SUMA_SL_Err("Empty file");
00682                SUMA_RETURN(NULL);
00683             }
00684             if (SO->NodeDim !=  3 ) {
00685                SUMA_SL_Err("File must have\n"
00686                            "3 columns.");
00687                mri_free(im); im = NULL;   /* done with that baby */
00688                SUMA_RETURN(NULL);
00689             }
00690             
00691             SO->NodeList = (float *)SUMA_calloc (SO->N_Node*SO->NodeDim, sizeof(float));
00692             if (!SO->NodeList) {
00693                fprintf(SUMA_STDERR,"Error %s: Failed to allocate for NodeList.\n", FuncName);
00694                if (SO->NodeList) SUMA_free(SO->NodeList);
00695                if (SO->FaceSetList) SUMA_free(SO->FaceSetList);
00696                SUMA_RETURN (NULL);
00697             }
00698             
00699             for (icnt=0; icnt < SO->N_Node; ++icnt) {
00700                SO->NodeList[3*icnt] = far[icnt];
00701                SO->NodeList[3*icnt+1] = far[icnt+SO->N_Node];
00702                SO->NodeList[3*icnt+2] = far[icnt+2*SO->N_Node];
00703             }   
00704             if (LocalHead) {
00705                fprintf (SUMA_STDERR,"%s: SO->NodeList\n Node 0: %f, %f, %f \n Node %d: %f, %f, %f \n",
00706                   FuncName,
00707                   SO->NodeList[0], SO->NodeList[1], SO->NodeList[2], SO->N_Node -1, 
00708                   SO->NodeList[3*(SO->N_Node-1)], SO->NodeList[3*(SO->N_Node-1)+1], SO->NodeList[3*(SO->N_Node-1)+2]);
00709             }
00710             mri_free(im); im = NULL;
00711             
00712             im = mri_read_1D (SF_FileName->name_topo);
00713             if (!im) {
00714                SUMA_SLP_Err("Failed to read 1D file");
00715                SUMA_RETURN(NULL);
00716             }
00717             far = MRI_FLOAT_PTR(im);
00718             SO->N_FaceSet = im->nx;
00719             SO->FaceSetDim = im->ny;
00720             if (!SO->N_FaceSet) {
00721                SUMA_SL_Err("Empty file");
00722                SUMA_RETURN(NULL);
00723             }
00724             if (SO->FaceSetDim !=  3 ) {
00725                SUMA_SL_Err("File must have\n"
00726                            "3 columns.");
00727                mri_free(im); im = NULL;   /* done with that baby */
00728                SUMA_RETURN(NULL);
00729             }
00730             
00731             SO->FaceSetList = (int *)SUMA_calloc (SO->N_FaceSet*SO->FaceSetDim, sizeof(int));
00732             if (!SO->FaceSetList) {
00733                fprintf(SUMA_STDERR,"Error %s: Failed to allocate for FaceSetList.\n", FuncName);
00734                if (SO->NodeList) SUMA_free(SO->NodeList);
00735                if (SO->FaceSetList) SUMA_free(SO->FaceSetList);
00736                SUMA_RETURN (NULL);
00737             }
00738             
00739             for (icnt=0; icnt < SO->N_FaceSet; ++icnt) {
00740                SO->FaceSetList[3*icnt] = (int)far[icnt];
00741                SO->FaceSetList[3*icnt+1] = (int)far[icnt+SO->N_FaceSet];
00742                SO->FaceSetList[3*icnt+2] = (int)far[icnt+2*SO->N_FaceSet];
00743             }   
00744             
00745             if (LocalHead) {
00746                fprintf (SUMA_STDERR,"%s: SO->FaceSetList\n Node 0: %d, %d, %d \n Node %d: %d, %d, %d \n",
00747                   FuncName,
00748                   SO->FaceSetList[0], SO->FaceSetList[1], SO->FaceSetList[2], SO->N_FaceSet -1, 
00749                   SO->FaceSetList[3*(SO->N_FaceSet-1)], SO->FaceSetList[3*(SO->N_FaceSet-1)+1], SO->FaceSetList[3*(SO->N_FaceSet-1)+2]);
00750             } 
00751             mri_free(im); im = NULL;
00752             
00753          } else {
00754             if (!SUMA_VEC_Read(SF_FileName, SO)) {
00755                SUMA_SLP_Err("Failed to read 1D file");
00756                if (SO->NodeList) SUMA_free(SO->NodeList);
00757                if (SO->FaceSetList) SUMA_free(SO->FaceSetList);
00758                SUMA_RETURN (NULL);
00759             }
00760          }
00761          #endif
00762                   
00763          sprintf (stmp, "%s%s", SF_FileName->name_coord, SF_FileName->name_topo);
00764          SUMA_NEW_ID(SO->idcode_str,stmp);
00765          
00766          /* change coordinates to align them with volparent data set, if possible */
00767          if (VolParName != NULL) {
00768             SO->VolPar = SUMA_VolPar_Attr (VolParName);
00769             if (SO->VolPar == NULL) {
00770                fprintf(SUMA_STDERR,"Error %s: Failed to load parent volume attributes.\n", FuncName);
00771             } else {
00772 
00773             if (!SUMA_Align_to_VolPar (SO, NULL)) SO->SUMA_VolPar_Aligned = NOPE;
00774                else {
00775                   SO->SUMA_VolPar_Aligned = YUP;
00776                   /*SUMA_Show_VolPar(SO->VolPar, NULL);*/
00777                }
00778          }
00779          } else { 
00780             SO->SUMA_VolPar_Aligned = NOPE;
00781          }
00782 
00783          break;
00784          
00785       case SUMA_FT_ERROR:
00786          SUMA_SL_Err("Error specifying file type.");
00787          break;
00788          
00789       case SUMA_SUREFIT:
00790          /* Allocate for SF */
00791          SF = (SUMA_SureFit_struct *) SUMA_malloc(sizeof(SUMA_SureFit_struct));   
00792          if (SF == NULL) {
00793             fprintf(SUMA_STDERR,"Error %s: Failed to allocate for SF\n", FuncName);
00794             SUMA_RETURN (NULL);
00795          }
00796          SF_FileName = (SUMA_SFname *)SO_FileName_vp;
00797          /* form the topo and the coord names */
00798          SO->Name_coord = SUMA_StripPath(SF_FileName->name_coord);
00799          SO->Name_topo = SUMA_StripPath(SF_FileName->name_topo);
00800          SO->FileType = SO_FT;
00801          SO->FileFormat = SO_FF;
00802          SO->NodeDim = 3; /* This must be automated */
00803          /*read the coordinate file */
00804          if (!SUMA_SureFit_Read_Coord (SF_FileName->name_coord, SF)) {
00805             fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_SureFit_Read_Coord.\n", FuncName);
00806             SUMA_RETURN (NULL);
00807          }
00808          /* copy the pertinent data to SO */
00809          SO->N_Node = SF->N_Node;
00810          /* Save the pointers to NodeList and FaceSetList and clear what is left of SF structure at the end */
00811          SO->NodeList = SF->NodeList;
00812          SF->NodeList = NULL;
00813          
00814          /*read the topology file */
00815          if (!SUMA_SureFit_Read_Topo (SF_FileName->name_topo, SF)) {
00816             fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_SureFit_Read_Topo.\n", FuncName);
00817             SUMA_RETURN (NULL);
00818          }
00819          /* read the param file */
00820          if (strlen(SF_FileName->name_param)){
00821             if (!SUMA_Read_SureFit_Param(SF_FileName->name_param, SF)) {
00822                fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_Read_SureFit_Param.\n", FuncName);
00823             }
00824          } else {
00825             if (VolParName != NULL) {
00826                fprintf(SUMA_STDERR,"Error %s: Volume Parent specified without .param file.\nParent Volume Alignment will not be done.", FuncName);
00827             }
00828          }
00829          
00830          /* copy the pertinent data to SO */
00831          SO->FaceSetList = SF->FaceSetList;
00832          SO->N_FaceSet = SF->N_FaceSet;
00833          SF->FaceSetList = NULL;
00834          SO->FaceSetDim = 3; /*This must also be automated */
00835 
00836          /* change coordinates to align them with volparent data set, if possible */
00837          if (VolParName != NULL && strlen(SF_FileName->name_param)) {
00838             SO->VolPar = SUMA_VolPar_Attr (VolParName);
00839             if (SO->VolPar == NULL) {
00840                fprintf(SUMA_STDERR,"Error %s: Failed to load parent volume attributes.\n", FuncName);
00841             } else {
00842                /*SUMA_Show_VolPar(SO->VolPar, NULL);*/
00843 
00844                if (!SUMA_Align_to_VolPar (SO, (void *)SF)) SO->SUMA_VolPar_Aligned = NOPE;
00845                   else SO->SUMA_VolPar_Aligned = YUP;
00846                }
00847          } else { 
00848             SO->SUMA_VolPar_Aligned = NOPE;
00849          }
00850          
00851          /* free SF */
00852          if (!SUMA_Free_SureFit (SF)) {
00853             fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_Free_SureFit.\n", FuncName);
00854             SUMA_RETURN (NULL);
00855          }
00856          
00857          sprintf (stmp, "%s%s", SF_FileName->name_coord, SF_FileName->name_topo);
00858          SUMA_NEW_ID(SO->idcode_str, stmp);
00859          break;
00860    } /* SO_FileType*/
00861    
00862    /* sanity check (this one's here for a reason) */
00863    if (SO->N_Node <=0 || SO->N_FaceSet<=0) {
00864       SUMA_SL_Crit("0 nodes or 0 facesets.\nProceed I will not.\n");
00865       SUMA_Free_Surface_Object (SO);
00866       SUMA_RETURN (NULL);
00867    }
00868 
00869 
00870    if (!SUMA_PrepSO_GeomProp_GL (SO)) {
00871       SUMA_SL_Err("Failed to set surface's properties");
00872       SUMA_RETURN (NULL);
00873    }
00874       
00875    SUMA_RETURN (SO);
00876    
00877 }/*SUMA_Load_Surface_Object_eng*/
00878 
00879  
00880 /*!
00881    SUMA_Boolean SUMA_ParseLHS_RHS (char *s, char *lhs, char *rhs)
00882    
00883    Parses S of the form "lhs = rhs" 
00884    blanks are necessary around the = sign
00885    s, lhs and rhs must be allocated for
00886    
00887    \param s (char *) "joe = fred"
00888    \param lhs (char *) "joe"
00889    \param rhs (char *) returned "fred"
00890    \ret YUP/NOPE for goodness, badness
00891    
00892 */
00893 SUMA_Boolean SUMA_ParseLHS_RHS (char *s, char *lhs, char *rhs)
00894 {
00895    static char FuncName[]={"SUMA_ParseLHS_RHS"};
00896    char *st;
00897 
00898    SUMA_ENTRY;
00899 
00900    if (s == NULL) {
00901       fprintf(SUMA_STDERR,"Error %s: NULL s\n", FuncName);
00902       SUMA_RETURN (NOPE);
00903    }
00904    st = strtok(s, " \0=");
00905    if (SUMA_iswordin (st,"=") == 1) { /* no blanks it seems */
00906       /*fprintf(SUMA_STDERR,"NO BLANK, st:%s\n", st);*/
00907       fprintf(SUMA_STDERR,"Error %s: Bad file format. Perhaps no blanks before = sign after LHS argument %s.\n", FuncName, lhs);
00908       SUMA_RETURN (NOPE);
00909    } else { /* skip the next blank to = */
00910       st = strtok(NULL, " \0=");
00911       if (SUMA_iswordin (st,"=")!=1) {
00912          fprintf(SUMA_STDERR,"Error %s: Bad file format. Perhaps no blanks around = after LHS argument %s.\n", FuncName, lhs);
00913          SUMA_RETURN (NOPE);
00914       }
00915    }
00916    /* get the rhs */
00917    st = strtok(NULL, " \0=");
00918    if (st == NULL) {
00919       fprintf(SUMA_STDERR,"Error %s: Bad file format. Perhaps no blanks after = after LHS argument %s.\n", FuncName, lhs);
00920       SUMA_RETURN (NOPE);
00921    } else {
00922       sprintf(rhs,"%s", st);
00923       /*fprintf(SUMA_STDERR,"RHS: %s\n", rhs);*/
00924    }
00925    SUMA_RETURN (YUP); 
00926 }
00927 
00928 /*! 
00929    Function to read the surface specs file.
00930    \param fname (char *) name of the specs file
00931    \param Spec (SUMA_SurfSpecFile *) pre-allocated pointer to SUMA_SurfSpecFile structure )
00932    \ret YUP, good, NOPE, not good
00933 */
00934 SUMA_Boolean SUMA_Read_SpecFile (char *f_name, SUMA_SurfSpecFile * Spec)
00935 {/* SUMA_Read_SpecFile */
00936    static char FuncName[]={"SUMA_Read_SpecFile"};
00937    char s[SUMA_MAX_DIR_LENGTH], stmp[SUMA_MAX_DIR_LENGTH],  stmp2[SUMA_MAX_DIR_LENGTH], c;
00938    int ex, skp, evl, i;
00939    FILE *sf_file;
00940    SUMA_FileName SpecName;
00941    SUMA_Boolean OKread_SurfaceFormat, OKread_SurfaceType, OKread_TopoFile, OKread_CoordFile;
00942    SUMA_Boolean OKread_MappingRef, OKread_SureFitVolParam, OKread_FreeSurferSurface, OKread_InventorSurface;
00943    SUMA_Boolean OKread_Group, OKread_State, OKread_EmbedDim, OKread_SurfaceVolume, OKread_SurfaceLabel;
00944    SUMA_Boolean OKread_AnatCorrect, OKread_Hemisphere, OKread_DomainGrandParentID, OKread_OriginatorID;
00945    SUMA_Boolean OKread_LocalCurvatureParent, OKread_LocalDomainParent;
00946    char DupWarn[]={"Bad format in specfile (you may need a NewSurface line). Duplicate specification of"};
00947    char NewSurfWarn[]={"Bad format in specfile. You must start with NewSurface line before any other field."};
00948 
00949    SUMA_ENTRY;
00950 
00951    /*make sure file is there */
00952    if (!SUMA_filexists(f_name)) {
00953       fprintf(SUMA_STDERR,"Error %s: File %s does not exist or cannot be read.\n", FuncName, f_name);
00954       SUMA_RETURN (NOPE);
00955    }
00956    Spec->N_Surfs = 0;
00957    
00958    /* set the path for the spec file */
00959    SpecName = SUMA_StripPath (f_name);
00960    if (strlen(SpecName.Path) > SUMA_MAX_DIR_LENGTH-1) {
00961       fprintf(SUMA_STDERR,"Error %s: Path of specfile > %d charcters.\n", FuncName, SUMA_MAX_DIR_LENGTH-1);
00962       SUMA_RETURN (NOPE);
00963    }
00964    if (strlen(SpecName.FileName) > SUMA_MAX_NAME_LENGTH-1) {
00965       fprintf(SUMA_STDERR,"Error %s: Name of specfile > %d charcters.\n", FuncName, SUMA_MAX_NAME_LENGTH-1);
00966       SUMA_RETURN (NOPE);
00967    }
00968    snprintf(Spec->SpecFilePath,SUMA_MAX_DIR_LENGTH*sizeof(char), "%s", SpecName.Path);
00969    snprintf(Spec->SpecFileName,SUMA_MAX_NAME_LENGTH*sizeof(char), "%s", SpecName.FileName);
00970    
00971    /* free SpecName since it's not used elsewhere */
00972    if (SpecName.Path) SUMA_free(SpecName.Path);
00973    if (SpecName.FileName) SUMA_free(SpecName.FileName);
00974 
00975    /*read the thing*/
00976    sf_file = fopen (f_name,"r");
00977    if (sf_file == NULL)
00978       {
00979          fprintf(SUMA_STDERR,"Error %s: Could not open file for read\n", FuncName);
00980          SUMA_RETURN (NOPE);
00981       }
00982    
00983    /*read until you find not a comment */
00984  
00985    /* read the first line, skipping leading space */
00986    do {
00987       ex = fscanf (sf_file,"%c",&c);
00988    } while (ex != EOF && isspace(c));
00989    
00990    i=0;
00991    while (ex != EOF && c != '\n') {   
00992          s[i] = c; ++i;
00993       ex = fscanf (sf_file,"%c",&c);
00994    }
00995    s[i] = '\0';
00996    /*fprintf(SUMA_STDERR,"Read %s\n", s);*/
00997    OKread_Group = YUP; /* it is OK to read a group before a new surface is declared */
00998    OKread_SurfaceFormat = OKread_SurfaceType = OKread_TopoFile = OKread_CoordFile = NOPE;
00999    OKread_MappingRef = OKread_SureFitVolParam = OKread_FreeSurferSurface = OKread_InventorSurface = NOPE;
01000    OKread_State = OKread_EmbedDim = OKread_SurfaceVolume = OKread_SurfaceLabel = NOPE ;
01001    OKread_AnatCorrect = OKread_Hemisphere = OKread_DomainGrandParentID = OKread_OriginatorID = NOPE;
01002    OKread_LocalCurvatureParent = OKread_LocalDomainParent = NOPE;
01003    
01004    Spec->StateList[0] = '\0';
01005    Spec->Group[0][0] = '\0';
01006    Spec->N_Surfs = Spec->N_States = Spec->N_Groups = 0;
01007    while (ex !=EOF) {
01008       evl = SUMA_iswordin (s,"#");
01009       if (evl != 1) { /* not a comment */
01010          /*fprintf(SUMA_STDERR,"Not a comment: %s\n", s);*/
01011          skp = 0;
01012          sprintf(stmp,"NewSurface");
01013          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01014             if(Spec->N_Surfs >= SUMA_MAX_N_SURFACE_SPEC) {
01015                fprintf(SUMA_STDERR,"Error %s: Cannot read in more than %d new surfaces.\n", FuncName, SUMA_MAX_N_SURFACE_SPEC);
01016                SUMA_RETURN (NOPE);
01017             }
01018             Spec->N_Surfs += 1;
01019             /*fprintf(SUMA_STDERR,"Found New Surface, N = %d\n", Spec->N_Surfs);*/
01020             /* initialize some of the fields */
01021             if (Spec->N_Surfs == 1) { /* first surface, initialize to empty */
01022                sprintf(Spec->SurfaceFormat[Spec->N_Surfs-1],"ASCII");
01023                Spec->SurfaceType[Spec->N_Surfs-1][0] = '\0';
01024                Spec->TopoFile[Spec->N_Surfs-1][0] = Spec->CoordFile[Spec->N_Surfs-1][0] = '\0';
01025                Spec->MappingRef[Spec->N_Surfs-1][0] = '\0';  /* Should become obsolete, ZSS Jan 02 03 */
01026                Spec->SureFitVolParam[Spec->N_Surfs-1][0] = '\0';
01027                Spec->SurfaceFile[Spec->N_Surfs-1][0] = '\0';
01028                Spec->State[Spec->N_Surfs-1][0] = '\0';
01029                Spec->IDcode[Spec->N_Surfs-1] = NULL; /* this field is set in LoadSpec function */
01030                Spec->EmbedDim[Spec->N_Surfs-1] = 3;
01031                Spec->VolParName[Spec->N_Surfs-1][0] = '\0';
01032                Spec->SurfaceLabel[Spec->N_Surfs-1][0] = '\0';
01033                Spec->AnatCorrect[Spec->N_Surfs-1][0] = '\0';
01034                Spec->Hemisphere[Spec->N_Surfs-1][0] = '\0';
01035                Spec->DomainGrandParentID[Spec->N_Surfs-1][0] = '\0';
01036                Spec->OriginatorID[Spec->N_Surfs-1][0] = '\0';
01037                Spec->LocalCurvatureParent[Spec->N_Surfs-1][0] = '\0'; 
01038                Spec->LocalDomainParent[Spec->N_Surfs-1][0] = '\0';
01039             } else { 
01040                /* make sure important fields have been filled */
01041                if (Spec->SurfaceType[Spec->N_Surfs-2][0] == '\0') {
01042                   fprintf(SUMA_STDERR,"Error %s: Failed to specify surface type for surface %d\n", FuncName, Spec->N_Surfs-2);
01043                   SUMA_RETURN (NOPE);
01044                }
01045                /* initilize SOME of the fields to previous one */
01046                Spec->CoordFile[Spec->N_Surfs-1][0] = '\0';  /* *** BA, Dec 03 */
01047                Spec->SurfaceFile[Spec->N_Surfs-1][0] = '\0'; /* *** BA, Dec 03 */
01048                
01049                strcpy(Spec->SurfaceFormat[Spec->N_Surfs-1], Spec->SurfaceFormat[Spec->N_Surfs-2]);
01050                strcpy(Spec->SurfaceType[Spec->N_Surfs-1], Spec->SurfaceType[Spec->N_Surfs-2]);
01051                strcpy(Spec->TopoFile[Spec->N_Surfs-1], Spec->TopoFile[Spec->N_Surfs-2]);
01052                strcpy(Spec->MappingRef[Spec->N_Surfs-1], Spec->MappingRef[Spec->N_Surfs-2]);   /* Should become obsolete, ZSS Jan 02 03 */
01053                strcpy(Spec->SureFitVolParam[Spec->N_Surfs-1], Spec->SureFitVolParam[Spec->N_Surfs-2]);
01054                Spec->VolParName[Spec->N_Surfs-1][0] = '\0'; /* it is confusing to users to inherit this one from the pervious, keep it separate.*/
01055                Spec->IDcode[Spec->N_Surfs-1] = NULL; /* this field is set in LoadSpec function */
01056                Spec->SurfaceLabel[Spec->N_Surfs-1][0] = '\0';
01057                strcpy(Spec->Group[Spec->N_Surfs-1], Spec->Group[Spec->N_Surfs-2]);
01058                strcpy(Spec->State[Spec->N_Surfs-1], Spec->State[Spec->N_Surfs-2]);
01059                Spec->EmbedDim[Spec->N_Surfs-1] = Spec->EmbedDim[Spec->N_Surfs-2];
01060                /* perhaps make these inheritable from previous */
01061                Spec->AnatCorrect[Spec->N_Surfs-1][0] = '\0';
01062                Spec->Hemisphere[Spec->N_Surfs-1][0] = '\0';
01063                Spec->DomainGrandParentID[Spec->N_Surfs-1][0] = '\0';
01064                Spec->OriginatorID[Spec->N_Surfs-1][0] = '\0';
01065                Spec->LocalCurvatureParent[Spec->N_Surfs-1][0] = '\0'; 
01066                Spec->LocalDomainParent[Spec->N_Surfs-1][0] = '\0';
01067               /* only Spec->CoordFile, Spec->SurfaceFile MUST be specified with a new surface */
01068             } 
01069             OKread_SurfaceFormat = OKread_SurfaceType = OKread_TopoFile = OKread_CoordFile = YUP;
01070             OKread_MappingRef = OKread_SureFitVolParam = OKread_FreeSurferSurface = OKread_InventorSurface = YUP;
01071             OKread_Group = OKread_State = OKread_EmbedDim = OKread_SurfaceLabel = OKread_SurfaceVolume = YUP;
01072             OKread_AnatCorrect = OKread_Hemisphere = OKread_DomainGrandParentID = OKread_OriginatorID = YUP;
01073             OKread_LocalCurvatureParent = OKread_LocalDomainParent = YUP;
01074             skp = 1;
01075          }
01076          
01077          sprintf(stmp,"StateDef");
01078          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01079             /* found a state definition, parse it */
01080             if (!SUMA_ParseLHS_RHS (s, stmp, Spec->State[Spec->N_Surfs-1])) {
01081                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01082                SUMA_RETURN (NOPE);
01083             }
01084             if (Spec->N_States == 0) {
01085                /* first state, add it to the list of states */
01086                sprintf(Spec->StateList, "%s|", Spec->State[Spec->N_Surfs-1]);
01087                Spec->N_States += 1;
01088             } else  {
01089                if (strcmp(Spec->StateList, Spec->State[Spec->N_Surfs-1]) == 0) {
01090                   /* it's a duplicate, complain and get outa here */
01091                   fprintf(SUMA_STDERR,"Error %s: Duplicate StateDef (%s).\n", FuncName, Spec->State[Spec->N_Surfs-1]);
01092                   SUMA_RETURN (NOPE);
01093                } else {
01094                   /* a new one, add it to the list and increment States counter */
01095                   sprintf(Spec->StateList, "%s%s|", Spec->StateList, Spec->State[Spec->N_Surfs-1]);
01096                   Spec->N_States += 1;
01097                }
01098             }
01099             skp = 1;
01100          }
01101          
01102          sprintf(stmp,"Group");
01103          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01104             /* found a state definition, parse it */
01105             /*fprintf(SUMA_STDERR,"%s: Found %s.\n", FuncName, stmp);*/
01106             if (Spec->N_Surfs < 1) { /* no surfaces have been defined yet, group goes for all */
01107                if (!SUMA_ParseLHS_RHS (s, stmp, Spec->Group[0])) {
01108                   fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01109                   SUMA_RETURN (NOPE);
01110                }
01111             }
01112             else {
01113                if (!SUMA_ParseLHS_RHS (s, stmp, Spec->Group[Spec->N_Surfs-1])) {
01114                   fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01115                   SUMA_RETURN (NOPE);
01116                }
01117             }
01118 
01119             Spec->N_Groups += 1;
01120             
01121             if (!OKread_Group) {
01122                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01123                SUMA_RETURN (NOPE);
01124             } else {
01125                OKread_Group = NOPE;
01126             }
01127             skp = 1;
01128          }
01129          
01130          sprintf(stmp,"Anatomical");
01131          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01132             /* found Anatomically Correct field, parse it */
01133             if (!SUMA_ParseLHS_RHS (s, stmp, Spec->AnatCorrect[Spec->N_Surfs-1])) {
01134                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01135                SUMA_RETURN (NOPE);
01136             }
01137             if ( strcmp(Spec->AnatCorrect[Spec->N_Surfs-1],"Y") && strcmp(Spec->AnatCorrect[Spec->N_Surfs-1],"N")) {
01138                SUMA_SL_Err("Anatomical can only be Y ot N");
01139                SUMA_RETURN (NOPE);
01140             }
01141             if (!OKread_AnatCorrect) {
01142                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01143                SUMA_RETURN (NOPE);
01144             } else  {
01145                OKread_AnatCorrect = NOPE;
01146             }
01147             skp = 1;
01148          } 
01149          
01150          sprintf(stmp,"Hemisphere");
01151          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01152             /* found Hemisphere field, parse it */
01153             if (!SUMA_ParseLHS_RHS (s, stmp, Spec->Hemisphere[Spec->N_Surfs-1])) {
01154                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01155                SUMA_RETURN (NOPE);
01156             }
01157             if ( strcmp(Spec->Hemisphere[Spec->N_Surfs-1],"L") && strcmp(Spec->Hemisphere[Spec->N_Surfs-1],"R")) {
01158                SUMA_SL_Err("Hemisphere can only be L ot R");
01159                SUMA_RETURN (NOPE);
01160             }
01161             if (!OKread_Hemisphere) {
01162                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01163                SUMA_RETURN (NOPE);
01164             } else  {
01165                OKread_Hemisphere = NOPE;
01166             }
01167             skp = 1;
01168          }
01169          
01170          sprintf(stmp,"DomainGrandParentID");
01171          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01172             /* found DomainGrandParentID field, parse it */
01173             if (!SUMA_ParseLHS_RHS (s, stmp, Spec->DomainGrandParentID[Spec->N_Surfs-1])) {
01174                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01175                SUMA_RETURN (NOPE);
01176             }
01177             
01178             if (!OKread_DomainGrandParentID) {
01179                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01180                SUMA_RETURN (NOPE);
01181             } else  {
01182                OKread_DomainGrandParentID = NOPE;
01183             }
01184             skp = 1;
01185          }
01186          
01187          sprintf(stmp,"OriginatorID");
01188          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01189             /* found OriginatorID  field, parse it */
01190             if (!SUMA_ParseLHS_RHS (s, stmp, Spec->OriginatorID[Spec->N_Surfs-1])) {
01191                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01192                SUMA_RETURN (NOPE);
01193             }
01194             
01195             if (!OKread_OriginatorID) {
01196                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01197                SUMA_RETURN (NOPE);
01198             } else  {
01199                OKread_OriginatorID = NOPE;
01200             }
01201             skp = 1;
01202          }
01203 
01204          sprintf(stmp,"LocalCurvatureParent");
01205          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01206             /* found LocalCurvatureParent  field, parse it */
01207             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
01208                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01209                SUMA_RETURN (NOPE);
01210             }
01211             snprintf (Spec->LocalCurvatureParent[Spec->N_Surfs-1], SUMA_MAX_FP_NAME_LENGTH * sizeof(char), 
01212                      "%s%s", Spec->SpecFilePath, stmp2);
01213                      
01214             if (!OKread_LocalCurvatureParent) {
01215                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01216                SUMA_RETURN (NOPE);
01217             } else  {
01218                OKread_LocalCurvatureParent = NOPE;
01219             }
01220             skp = 1;
01221          }
01222 
01223          sprintf(stmp,"LocalDomainParent");
01224          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01225             /* found LocalDomainParent  field, parse it */
01226             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
01227                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01228                SUMA_RETURN (NOPE);
01229             }
01230             
01231             snprintf (Spec->LocalDomainParent[Spec->N_Surfs-1], SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
01232                "%s%s", Spec->SpecFilePath, stmp2);
01233             
01234             if (!OKread_LocalDomainParent) {
01235                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01236                SUMA_RETURN (NOPE);
01237             } else  {
01238                OKread_LocalDomainParent = NOPE;
01239             }
01240             skp = 1;
01241          }
01242 
01243          
01244          sprintf(stmp,"EmbedDimension");
01245          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01246             /* found surface embedding dimension, parse it */
01247             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
01248                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01249                SUMA_RETURN (NOPE);
01250             }
01251             Spec->EmbedDim[Spec->N_Surfs-1] = atoi(stmp2);
01252             if (Spec->EmbedDim[Spec->N_Surfs-1] < 2 || Spec->EmbedDim[Spec->N_Surfs-1] > 3) {
01253                fprintf(SUMA_STDERR,"Error %s: Bad Embedding dimension %d. Only 2 and 3 allowed.\n", \
01254                   FuncName, Spec->EmbedDim[Spec->N_Surfs-1]);
01255                SUMA_RETURN (NOPE); 
01256             }
01257             if (!OKread_EmbedDim) {
01258                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01259                SUMA_RETURN (NOPE);
01260             } else  {
01261                OKread_EmbedDim = NOPE;
01262             }
01263             skp = 1;
01264          }
01265             
01266          sprintf(stmp,"SurfaceState");
01267          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01268             /* found surface state, parse it */
01269             if (!SUMA_ParseLHS_RHS (s, stmp, Spec->State[Spec->N_Surfs-1])) {
01270                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01271                SUMA_RETURN (NOPE);
01272             }
01273             /* make sure it is in the StateList */
01274             if (SUMA_iswordin (Spec->StateList, Spec->State[Spec->N_Surfs-1]) != 1) {
01275                fprintf(SUMA_STDERR,"Error %s: State %s was not predefined in StateDef.\nStateDef List (| delimited) = %s \n",\
01276                 FuncName, Spec->State[Spec->N_Surfs-1], Spec->StateList);
01277                SUMA_RETURN (NOPE);
01278             }
01279             if (!OKread_State) {
01280                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01281                SUMA_RETURN (NOPE);
01282             } else  {
01283                OKread_State = NOPE;
01284             }
01285             skp = 1;
01286          }
01287          
01288          sprintf(stmp,"SurfaceFormat");
01289          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01290             if (Spec->N_Surfs < 1) {
01291                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
01292                SUMA_RETURN (NOPE);
01293             }
01294             /*fprintf(SUMA_STDERR,"Found %s: ", stmp);*/
01295             
01296             if (!SUMA_ParseLHS_RHS (s, stmp, Spec->SurfaceFormat[Spec->N_Surfs-1])) {
01297                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01298                SUMA_RETURN (NOPE);
01299             }
01300             
01301             if (!OKread_SurfaceFormat) {
01302                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01303                SUMA_RETURN (NOPE);
01304             } else {
01305                OKread_SurfaceFormat = NOPE;
01306             }
01307             skp = 1;
01308             /*fprintf(SUMA_STDERR,"%s\n", Spec->SurfaceFormat[Spec->N_Surfs-1]);*/
01309          }
01310          
01311          sprintf(stmp,"SurfaceType");
01312          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01313             if (Spec->N_Surfs < 1) {
01314                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
01315                SUMA_RETURN (NOPE);
01316             }
01317             /*fprintf(SUMA_STDERR,"Found %s\n", stmp);*/
01318             if (!SUMA_ParseLHS_RHS (s, stmp, Spec->SurfaceType[Spec->N_Surfs-1])) {
01319                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01320                SUMA_RETURN (NOPE);
01321             }
01322             if (!OKread_SurfaceType) {
01323                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01324                SUMA_RETURN (NOPE);
01325             } else {
01326                OKread_SurfaceType = NOPE;
01327             }
01328             skp = 1;
01329          }
01330          
01331          sprintf(stmp,"TopoFile");
01332          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01333             /*fprintf(SUMA_STDERR,"Found %s\n", stmp);*/
01334             if (Spec->N_Surfs < 1) {
01335                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
01336                SUMA_RETURN (NOPE);
01337             }
01338             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
01339                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01340                SUMA_RETURN (NOPE);
01341             }
01342             snprintf(Spec->TopoFile[Spec->N_Surfs-1], SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
01343                "%s%s", Spec->SpecFilePath, stmp2);
01344             
01345             if (!OKread_TopoFile) {
01346                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01347                SUMA_RETURN (NOPE);
01348             } else {
01349                OKread_TopoFile = NOPE;
01350             }
01351             skp = 1;
01352          }
01353          
01354          sprintf(stmp,"SureFitTopo");
01355          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01356             /*fprintf(SUMA_STDERR,"Found %s\n", stmp);*/
01357             if (Spec->N_Surfs < 1) {
01358                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
01359                SUMA_RETURN (NOPE);
01360             }
01361             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
01362                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01363                SUMA_RETURN (NOPE);
01364             }
01365             snprintf(Spec->TopoFile[Spec->N_Surfs-1], SUMA_MAX_FP_NAME_LENGTH * sizeof(char),"%s%s", 
01366                Spec->SpecFilePath, stmp2);
01367             
01368             if (!OKread_TopoFile) {
01369                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01370                SUMA_RETURN (NOPE);
01371             } else {
01372                OKread_TopoFile = NOPE;
01373             }
01374             skp = 1;
01375          }
01376          
01377          sprintf(stmp,"CoordFile");
01378          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01379             /*fprintf(SUMA_STDERR,"Found %s\n", stmp);*/
01380             if (Spec->N_Surfs < 1) {
01381                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
01382                SUMA_RETURN (NOPE);
01383             }
01384             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
01385                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01386                SUMA_RETURN (NOPE);
01387             }
01388             snprintf (Spec->CoordFile[Spec->N_Surfs-1], SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
01389                "%s%s", Spec->SpecFilePath, stmp2);
01390             
01391             if (!OKread_CoordFile) {
01392                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01393                SUMA_RETURN (NOPE);
01394             } else {
01395                OKread_CoordFile = NOPE;
01396             }
01397             skp = 1;
01398          }
01399          
01400          sprintf(stmp,"SureFitCoord");
01401          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01402             /*fprintf(SUMA_STDERR,"Found %s\n", stmp);*/
01403             if (Spec->N_Surfs < 1) {
01404                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
01405                SUMA_RETURN (NOPE);
01406             }
01407             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
01408                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01409                SUMA_RETURN (NOPE);
01410             }
01411             snprintf (Spec->CoordFile[Spec->N_Surfs-1], SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
01412                "%s%s", Spec->SpecFilePath, stmp2);
01413             
01414             if (!OKread_CoordFile) {
01415                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01416                SUMA_RETURN (NOPE);
01417             } else {
01418                OKread_CoordFile = NOPE;
01419             }
01420             skp = 1;
01421          }
01422          
01423          sprintf(stmp,"MappingRef");
01424          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01425             /*fprintf(SUMA_STDERR,"Found %s\n", stmp);*/
01426             if (Spec->N_Surfs < 1) {
01427                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
01428                SUMA_RETURN (NOPE);
01429             }
01430             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
01431                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01432                SUMA_RETURN (NOPE);
01433             }
01434             snprintf (Spec->MappingRef[Spec->N_Surfs-1], SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
01435                "%s%s", Spec->SpecFilePath, stmp2);
01436             if (!OKread_MappingRef) {
01437                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01438                SUMA_RETURN (NOPE);
01439             } else {
01440                OKread_MappingRef = NOPE;
01441             }
01442             skp = 1;
01443          }
01444          /* Should become obsolete, ZSS Jan 02 03 */
01445          
01446          sprintf(stmp,"SureFitVolParam");
01447          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01448             /*fprintf(SUMA_STDERR,"Found %s\n", stmp);*/
01449             if (Spec->N_Surfs < 1) {
01450                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
01451                SUMA_RETURN (NOPE);
01452             }
01453             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
01454                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01455                SUMA_RETURN (NOPE);
01456             }
01457             snprintf (Spec->SureFitVolParam[Spec->N_Surfs-1], SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
01458                "%s%s", Spec->SpecFilePath, stmp2);
01459             
01460             if (!OKread_SureFitVolParam) {
01461                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01462                SUMA_RETURN (NOPE);
01463             } else {
01464                OKread_SureFitVolParam = NOPE;
01465             }
01466             skp = 1;
01467          }
01468          
01469          sprintf(stmp,"FreeSurferSurface");
01470          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01471             /*fprintf(SUMA_STDERR,"Found %s\n", stmp);*/
01472             if (Spec->N_Surfs < 1) {
01473                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
01474                SUMA_RETURN (NOPE);
01475             }
01476             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
01477                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01478                SUMA_RETURN (NOPE);
01479             }
01480             snprintf (Spec->SurfaceFile[Spec->N_Surfs-1], SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
01481                "%s%s", Spec->SpecFilePath, stmp2);
01482             if (!OKread_FreeSurferSurface) {
01483                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01484                SUMA_RETURN (NOPE);
01485             } else {
01486                OKread_FreeSurferSurface = NOPE;
01487             }
01488             skp = 1;
01489          }
01490          
01491          sprintf(stmp,"SurfaceName");
01492          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01493             /*fprintf(SUMA_STDERR,"Found %s\n", stmp);*/
01494             if (Spec->N_Surfs < 1) {
01495                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
01496                SUMA_RETURN (NOPE);
01497             }
01498             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
01499                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01500                SUMA_RETURN (NOPE);
01501             }
01502             snprintf (Spec->SurfaceFile[Spec->N_Surfs-1], SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
01503                "%s%s", Spec->SpecFilePath, stmp2);
01504             if (!OKread_FreeSurferSurface) {
01505                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01506                SUMA_RETURN (NOPE);
01507             } else {
01508                OKread_FreeSurferSurface = NOPE;
01509             }
01510             skp = 1;
01511          }
01512          
01513          sprintf(stmp,"InventorSurface");
01514          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01515             /*fprintf(SUMA_STDERR,"Found %s\n", stmp);*/
01516             if (Spec->N_Surfs < 1) {
01517                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
01518                SUMA_RETURN (NOPE);
01519             }
01520             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
01521                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01522                SUMA_RETURN (NOPE);
01523             }
01524             snprintf(Spec->SurfaceFile[Spec->N_Surfs-1], SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
01525                "%s%s", Spec->SpecFilePath, stmp2);
01526             
01527             if (!OKread_InventorSurface) {
01528                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01529                SUMA_RETURN (NOPE);
01530             } else {
01531                OKread_InventorSurface = NOPE;
01532             }
01533             skp = 1;
01534          }
01535 
01536          sprintf(stmp,"SurfaceVolume");
01537          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01538             /*fprintf(SUMA_STDERR,"Found %s\n", stmp);*/
01539             if (Spec->N_Surfs < 1) {
01540                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
01541                SUMA_RETURN (NOPE);
01542             }
01543             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
01544                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01545                SUMA_RETURN (NOPE);
01546             }
01547             
01548             fprintf(SUMA_STDOUT,"Warning %s: Found SurfaceVolume in Spec File, Name must include path to volume.\n", FuncName);
01549             
01550             sprintf(Spec->VolParName[Spec->N_Surfs-1], "%s",  stmp2);
01551             
01552             if (!OKread_SurfaceVolume) {
01553                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01554                SUMA_RETURN (NOPE);
01555             } else {
01556                OKread_SurfaceVolume = NOPE;
01557             }
01558             skp = 1;
01559          }
01560          
01561          sprintf(stmp,"SurfaceLabel");
01562          if (!skp && SUMA_iswordin (s, stmp) == 1) {
01563             /*fprintf(SUMA_STDERR,"Found %s\n", stmp);*/
01564             if (Spec->N_Surfs < 1) {
01565                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
01566                SUMA_RETURN (NOPE);
01567             }
01568             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
01569                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
01570                SUMA_RETURN (NOPE);
01571             }
01572                         
01573             sprintf(Spec->SurfaceLabel[Spec->N_Surfs-1], "%s",  stmp2);
01574             
01575             if (!OKread_SurfaceLabel) {
01576                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
01577                SUMA_RETURN (NOPE);
01578             } else {
01579                OKread_SurfaceLabel = NOPE;
01580             }
01581             skp = 1;
01582          }
01583          
01584          if (!skp) {
01585             fprintf(SUMA_STDERR,"Error %s: Your spec file contains uncommented gibberish:\n%s\nPlease deal with it.\n", \
01586             FuncName, s);
01587             SUMA_RETURN (NOPE);
01588          }
01589       } else {/* not not a comment */
01590          /*fprintf(SUMA_STDERR,"A comment: %s\n", s);*/
01591       }
01592 
01593       /* read the next line */
01594       do {
01595          ex = fscanf (sf_file,"%c",&c);
01596       } while (ex!=EOF && isspace(c));
01597       i=0;
01598       while (ex != EOF && c != '\n') {   
01599          s[i] = c; ++i;
01600          ex = fscanf (sf_file,"%c",&c);
01601       }
01602       s[i] = '\0';
01603       /*fprintf(SUMA_STDERR,"Read %s\n", s); */
01604    }
01605    fclose (sf_file);
01606    /* make sure last entry was good */
01607    if (Spec->SurfaceType[Spec->N_Surfs-1][0] == '\0') {
01608       fprintf(SUMA_STDERR,"Error %s: Failed to specify surface type for surface %d\n", FuncName, Spec->N_Surfs-1);
01609       SUMA_RETURN (NOPE);
01610    }
01611 
01612    if (!SUMA_CheckOnSpecFile (Spec)) {
01613       SUMA_SL_Err("Badness in the spec file.\n");
01614       SUMA_RETURN(NOPE);
01615    }
01616    
01617    SUMA_RETURN (YUP); 
01618 }/* SUMA_Read_SpecFile */
01619 
01620 /*!
01621    \brief more checksums on the contents of the specfile
01622 */
01623 SUMA_Boolean SUMA_CheckOnSpecFile (SUMA_SurfSpecFile *Spec)
01624 {
01625    static char FuncName[]={"SUMA_CheckOnSpecFile"};
01626    static int ob_warn = 0;
01627    int i;
01628    SUMA_Boolean LocalHead = NOPE;
01629    
01630    SUMA_ENTRY;
01631    
01632    for (i=0; i<Spec->N_Surfs; ++i) {
01633       if (  Spec->MappingRef[i][0] && 
01634            (Spec->LocalDomainParent[i][0] || 
01635             Spec->LocalCurvatureParent[i][0] || 
01636             Spec->OriginatorID[i][0] || 
01637             Spec->DomainGrandParentID[i][0]) ) {
01638          SUMA_SL_Err("You cannont mix MappingRef with\n"
01639                      "newer fields such as:\n"
01640                      "LocalDomainParent, LocalCurvatureParent\n"
01641                      "OriginatorID or DomainGrandParentID  ");
01642          SUMA_RETURN(NOPE);            
01643       }
01644       if (  Spec->MappingRef[i][0] ) {
01645          
01646          if (LocalHead && !ob_warn) { 
01647             fprintf(SUMA_STDERR, "Warning:\n"
01648                                  "The field MappingRef in the spec file \n"
01649                                  "is obsolete. Consider replacing: \n"
01650                                  "  MappingRef = %s\n"
01651                                  "  with\n"
01652                                  "  LocalDomainParent = %s\n"
01653                                  "Similar warnings will be muted.\n",
01654                                  Spec->MappingRef[i], Spec->MappingRef[i]);
01655          }
01656          strcpy(Spec->LocalDomainParent[i], Spec->MappingRef[i]);
01657          strcpy(Spec->LocalCurvatureParent[i], Spec->MappingRef[i]);
01658          Spec->MappingRef[i][0] = '\0';
01659          ++ob_warn;
01660       }
01661       if ( strlen(Spec->LocalCurvatureParent[i]) ) {
01662          if ( ! strstr(Spec->LocalCurvatureParent[i], Spec->LocalDomainParent[i]) ) {
01663             SUMA_SL_Err("Fields LocalCurvatureParent and LocalDomainParent must be identical.\n");
01664             SUMA_RETURN(NOPE);
01665          }
01666       } else {
01667          sprintf(Spec->LocalCurvatureParent[i], "%s", Spec->LocalDomainParent[i]);
01668       }
01669    }
01670    
01671    SUMA_RETURN(YUP);
01672 }
01673 
01674 SUMA_Boolean SUMA_ShowSpecStruct (SUMA_SurfSpecFile *Spec, FILE *Out, int detail)
01675 {
01676    static char FuncName[]={"SUMA_ShowSpecStruct"};
01677    FILE *Outp;
01678    char *s;
01679    
01680    SUMA_ENTRY;
01681    
01682    if (!Spec) {
01683       SUMA_SL_Err("NULL Spec");
01684       SUMA_RETURN(NOPE);
01685    }
01686    
01687    if (!Out) Outp = stdout;
01688    else Outp = Out;
01689    
01690    s = SUMA_SpecStructInfo (Spec, detail);
01691    
01692    if (!s) {
01693       SUMA_SL_Err("Failed in   SUMA_SpecStructInfo");
01694       SUMA_RETURN(NOPE);
01695    }
01696    
01697    fprintf(Outp, "%s", s);
01698    
01699    SUMA_free(s); s = NULL;
01700    
01701    SUMA_RETURN(YUP);
01702 }
01703 /*!
01704    \brief show the contents of Spec structure 
01705    ans = SUMA_ShowSpecStruct (Spec, Out, detail);
01706    
01707    \param Spec (SUMA_SurfSpecFile *)
01708    \param Out (FILE *)  Pointer to output file
01709                         If NULL then output is to stdout
01710    \param detail (int) 1:  only surface name or coord file 
01711                            name if surface file is split to coord. 
01712                            and topo. files
01713                        2:  surface name and BOTH coord and topo files 
01714                            whenever applicable
01715                        3:  The whole nine yards.
01716    \return ans (YUP = good, NOPE = bad)
01717    \sa SUMA_Read_SpecFile
01718 */
01719 char* SUMA_SpecStructInfo (SUMA_SurfSpecFile *Spec, int detail)
01720 {
01721    static char FuncName[]={"SUMA_ShowSpecStruct"};
01722    char name_coord[SUMA_MAX_LABEL_LENGTH];
01723    char name_topo[SUMA_MAX_LABEL_LENGTH], *s = NULL;
01724    SUMA_STRING *SS = NULL;
01725    char stmp[1000];
01726    int i;
01727    SUMA_Boolean ShowCoord, ShowTopo, ShowRest;
01728    
01729    SUMA_ENTRY;
01730    
01731    ShowCoord = ShowTopo = ShowRest = NOPE;
01732    
01733    if (detail == 1) ShowCoord = YUP;
01734    else if (detail == 2) { ShowCoord = YUP; ShowTopo = YUP; }
01735    else if (detail == 3) { ShowCoord = YUP; ShowTopo = YUP; ShowRest = YUP; }
01736    else {
01737       SUMA_SL_Err("Bad value for detail, 0 < detail < 4");
01738       SUMA_RETURN(NULL);
01739    }
01740    
01741    SS = SUMA_StringAppend (NULL, NULL);
01742    
01743    if (Spec->SpecFilePath) SS = SUMA_StringAppend_va (SS,"SpecFilePath: %s\n", Spec->SpecFilePath);
01744    else SS = SUMA_StringAppend_va (SS,"SpecFilePath: NULL\n");
01745    if (Spec->SpecFileName) SS = SUMA_StringAppend_va (SS,"SpecFileName: %s\n", Spec->SpecFileName);
01746    else SS = SUMA_StringAppend_va (SS,"SpecFileName: NULL\n");
01747 
01748    if (!Spec->N_Surfs) {
01749       SS = SUMA_StringAppend (SS,"No surfaces in Spec.\n");
01750    } else {
01751       
01752       sprintf (stmp, "%d surfaces in Spec, %d defined states, %d groups\n", 
01753                         Spec->N_Surfs, Spec->N_States, Spec->N_Groups);
01754       SS = SUMA_StringAppend (SS, stmp);
01755       
01756       for (i=0; i < Spec->N_Surfs; ++i) {
01757          name_coord[0] ='\0';
01758          name_topo[0] = '\0';
01759          if (  (SUMA_iswordin(Spec->SurfaceType[i], "SureFit") == 1) || 
01760                (SUMA_iswordin(Spec->SurfaceType[i], "1D") == 1)         ) {
01761             sprintf(name_coord, "%s ", Spec->CoordFile[i]);
01762             sprintf(name_topo,"%s ", Spec->TopoFile[i]);
01763          } else if ( (SUMA_iswordin(Spec->SurfaceType[i], "FreeSurfer") == 1) ||
01764                      (SUMA_iswordin(Spec->SurfaceType[i], "Ply") == 1)        ||
01765                      (SUMA_iswordin(Spec->SurfaceType[i], "GenericInventor") == 1) ||
01766                      (SUMA_iswordin(Spec->SurfaceType[i], "OpenDX") == 1) ) {
01767             sprintf(name_coord, "%s ", Spec->SurfaceFile[i]);
01768          }
01769          SS = SUMA_StringAppend_va (SS, "%d) ", i);/* print the index */
01770          
01771          if (ShowCoord)  SS = SUMA_StringAppend (SS, name_coord);
01772          if (ShowTopo &&name_topo[0]) SS = SUMA_StringAppend (SS,  name_topo);
01773          SS = SUMA_StringAppend (SS, "\n");
01774          
01775          if (ShowRest) {
01776             SS = SUMA_StringAppend_va (SS, "\tMappingRef: %s\n", Spec->MappingRef[i]);   /* Should become obsolete, ZSS Jan 02 03 */
01777             SS = SUMA_StringAppend_va (SS, "\tType: %s\n", Spec->SurfaceType[i]);
01778             SS = SUMA_StringAppend_va (SS, "\tFormat: %s\n", Spec->SurfaceFormat[i]);
01779             SS = SUMA_StringAppend_va (SS, "\tEmbedDim: %d\n", Spec->EmbedDim[i]);
01780             SS = SUMA_StringAppend_va (SS, "\tState: %s, Group %s\n", Spec->State[i], Spec->Group[i]);
01781             
01782             if (strlen(Spec->SureFitVolParam[i])) {
01783                SS = SUMA_StringAppend_va (SS, "\tSureFitVolParam: %s\n", Spec->SureFitVolParam[i]);
01784             } else  SS = SUMA_StringAppend_va (SS, "\tSureFitVolParam: (empty)\n");
01785             
01786             if (strlen(Spec->VolParName[i]))  {
01787                SS = SUMA_StringAppend_va (SS, "\tVolParName: %s\n", Spec->VolParName[i]);
01788             } else SS = SUMA_StringAppend_va (SS, "\tVolParName: (empty)\n");
01789             
01790             if (Spec->IDcode[i])  {
01791                SS = SUMA_StringAppend_va (SS, "\tIDcode: %s\n", Spec->IDcode[i]);
01792             } else SS = SUMA_StringAppend_va (SS, "\tIDcode: (empty)\n");
01793             
01794             if (strlen(Spec->AnatCorrect[i])) {
01795                SS = SUMA_StringAppend_va (SS, "\tAnatCorrect: %s\n", Spec->AnatCorrect[i]);
01796             } else SS = SUMA_StringAppend_va (SS, "\tAnatCorrect: (empty)\n");
01797             
01798             if (strlen(Spec->Hemisphere[i])) {
01799                SS = SUMA_StringAppend_va (SS, "\tHemisphere: %s\n", Spec->Hemisphere[i]);
01800             } else SS = SUMA_StringAppend_va (SS, "\tHemisphere: (empty)\n");
01801             
01802             if (strlen(Spec->DomainGrandParentID[i])) {
01803                SS = SUMA_StringAppend_va (SS, "\tDomainGrandParentID: %s\n", Spec->DomainGrandParentID[i]);
01804             } else SS = SUMA_StringAppend_va (SS, "\tDomainGrandParentID: (empty)\n");
01805             
01806             if (strlen(Spec->OriginatorID[i])) {
01807                SS = SUMA_StringAppend_va (SS, "\tOriginatorID: %s\n", Spec->OriginatorID[i]);
01808             } else SS = SUMA_StringAppend_va (SS, "\tOriginatorID: (empty)\n");
01809             
01810             if (strlen(Spec->LocalCurvatureParent[i])) {
01811                SS = SUMA_StringAppend_va (SS, "\tLocalCurvatureParent: %s\n", Spec->LocalCurvatureParent[i]);
01812             } else SS = SUMA_StringAppend_va (SS, "\tLocalCurvatureParent: (empty)\n");
01813             
01814             if (strlen(Spec->LocalDomainParent[i])) {
01815                SS = SUMA_StringAppend_va (SS, "\tLocalDomainParent: %s\n", Spec->LocalDomainParent[i]);
01816             } else SS = SUMA_StringAppend_va (SS, "\tLocalDomainParent: (empty)\n");
01817             
01818             /*
01819             if (strlen(Spec->[i])) {
01820                SS = SUMA_StringAppend_va (SS, "\t: %s\n", Spec->[i]);
01821             } else SS = SUMA_StringAppend_va (SS, "\t: (empty)\n");
01822             */
01823          }   
01824       }
01825    }
01826       
01827    /* clean SS */
01828    SS = SUMA_StringAppend (SS, NULL);
01829    /* copy s pointer and free SS */
01830    s = SS->s;
01831    SUMA_free(SS); 
01832    
01833    SUMA_RETURN (s);
01834 }
01835 
01836 /*!
01837    \brief loads a surface object specified in Spec[i]
01838    
01839    - NOTABLE SO fields filled in this function are:
01840    SO->NodeList, SO->N_NodeList, SO->FaceSetList, SO->N_FaceSet
01841    SO->Group, SO->idcode_str,
01842    SO->State
01843    SO->EmbedDim
01844    SO->Side
01845    SO->OriginatorID
01846    SO->DomainGrandParentID
01847    SO->LocalCurvatureParent
01848    SO->LocalDomainParent
01849    SO->AnatCorrect
01850    SO->SpecFile
01851    \returns SO (SUMA_SurfaceObject *)
01852 */
01853 SUMA_SurfaceObject * SUMA_Load_Spec_Surf(SUMA_SurfSpecFile *Spec, int i, char *tmpVolParName, int debug)
01854 {  /* start SUMA_Load_Spec_Surf */
01855    static char FuncName[]={"SUMA_Load_Spec_Surf"};
01856    SUMA_SFname *SF_name;
01857    SUMA_SurfaceObject *SO=NULL;
01858    SUMA_Boolean brk, SurfIn=NOPE;
01859    SUMA_Boolean LocalHead = NOPE;
01860    
01861    SUMA_ENTRY;
01862    
01863    brk = NOPE;
01864 
01865    if (!brk && SUMA_iswordin(Spec->SurfaceType[i], "SureFit") == 1) {/* load surefit surface */
01866       SF_name = (SUMA_SFname *) SUMA_malloc(sizeof(SUMA_SFname));
01867       sprintf(SF_name->name_coord,"%s", Spec->CoordFile[i]); 
01868       sprintf(SF_name->name_topo,"%s", Spec->TopoFile[i]); 
01869       if (!strlen(Spec->SureFitVolParam[i])) { /* initialize to empty string */
01870          SF_name->name_param[0] = '\0'; 
01871       }
01872       else {
01873          sprintf(SF_name->name_param,"%s", Spec->SureFitVolParam[i]);
01874       }
01875 
01876       /* Load The Surface */
01877       if (SUMA_iswordin(Spec->SurfaceFormat[i], "ASCII") == 1) {
01878          SO = SUMA_Load_Surface_Object_eng ((void *)SF_name, SUMA_SUREFIT, SUMA_ASCII, tmpVolParName, debug);
01879       } else {
01880          fprintf(SUMA_STDERR,"Error %s: Only ASCII surfaces can be read for now.\n", FuncName);
01881          SUMA_RETURN (NULL);
01882       }
01883       if (SO == NULL)   {
01884          fprintf(SUMA_STDERR,"Error %s: could not load SO\n", FuncName);
01885          SUMA_RETURN(NULL);
01886       }
01887 
01888       SUMA_free(SF_name); 
01889 
01890       SurfIn = YUP;         
01891       brk = YUP;
01892    }/* load surefit surface */ 
01893                   
01894    if (!brk && SUMA_iswordin(Spec->SurfaceType[i], "1D") == 1) {/* load 1D surface */
01895       SF_name = (SUMA_SFname *) SUMA_malloc(sizeof(SUMA_SFname));
01896       sprintf(SF_name->name_coord,"%s", Spec->CoordFile[i]); ;
01897       sprintf(SF_name->name_topo,"%s", Spec->TopoFile[i]); 
01898       SF_name->name_param[0] = '\0';
01899 
01900 
01901       /* Load The Surface */
01902       if (SUMA_iswordin(Spec->SurfaceFormat[i], "ASCII") == 1) {
01903          SO = SUMA_Load_Surface_Object_eng ((void *)SF_name, SUMA_VEC, SUMA_ASCII, tmpVolParName, debug);
01904       } else {
01905          fprintf(SUMA_STDERR,"Error %s: Only ASCII allowed for 1D files.\n", FuncName);
01906          SUMA_RETURN (NULL);
01907       }
01908       if (SO == NULL)   {
01909          fprintf(SUMA_STDERR,"Error %s: could not load SO\n", FuncName);
01910          SUMA_RETURN(NULL);
01911       }
01912 
01913       SUMA_free(SF_name); 
01914 
01915       SurfIn = YUP;         
01916       brk = YUP;
01917    }/* load 1D surface */
01918 
01919    if (!brk && SUMA_iswordin(Spec->SurfaceType[i], "FreeSurfer") == 1) {/* load FreeSurfer surface */
01920 
01921       if (SUMA_iswordin(Spec->SurfaceFormat[i], "ASCII") == 1)
01922          SO = SUMA_Load_Surface_Object_eng ((void *)Spec->SurfaceFile[i], SUMA_FREE_SURFER, SUMA_ASCII, tmpVolParName, debug);
01923       else if (SUMA_iswordin(Spec->SurfaceFormat[i], "BINARY") == 1)
01924          SO = SUMA_Load_Surface_Object_eng ((void *)Spec->SurfaceFile[i], SUMA_FREE_SURFER, SUMA_BINARY_BE, tmpVolParName, debug);
01925       if (SO == NULL)   {
01926          fprintf(SUMA_STDERR,"Error %s: could not load SO\n", FuncName);
01927          SUMA_RETURN(NULL);
01928       }
01929       SurfIn = YUP;
01930       brk = YUP;
01931    } /* load FreeSurfer surface */
01932 
01933    if (!brk && SUMA_iswordin(Spec->SurfaceType[i], "Ply") == 1) {/* load Ply format surface */
01934 
01935       SO = SUMA_Load_Surface_Object_eng ((void *)Spec->SurfaceFile[i], SUMA_PLY, SUMA_FF_NOT_SPECIFIED, tmpVolParName, debug);
01936 
01937       if (SO == NULL)   {
01938          fprintf(SUMA_STDERR,"Error %s: could not load SO\n", FuncName);
01939          SUMA_RETURN(NULL);
01940       }
01941       SurfIn = YUP;
01942       brk = YUP;
01943    } /* load Ply format surface */
01944 
01945    if (!brk && SUMA_iswordin(Spec->SurfaceType[i], "OpenDX") == 1) {/* load SUMA_OPENDX_MESH format surface */
01946 
01947       SO = SUMA_Load_Surface_Object_eng ((void *)Spec->SurfaceFile[i], SUMA_OPENDX_MESH, SUMA_ASCII, tmpVolParName, debug);
01948 
01949       if (SO == NULL)   {
01950          fprintf(SUMA_STDERR,"Error %s: could not load SO\n", FuncName);
01951          SUMA_RETURN(NULL);
01952       }
01953       SurfIn = YUP;
01954       brk = YUP;
01955    } /* load Ply format surface */
01956    
01957    if (!brk && SUMA_iswordin(Spec->SurfaceType[i], "BrainVoyager") == 1) {/* load BrainVoyager format surface */
01958 
01959       SO = SUMA_Load_Surface_Object_eng ((void *)Spec->SurfaceFile[i], SUMA_BRAIN_VOYAGER, SUMA_FF_NOT_SPECIFIED, tmpVolParName, debug);
01960 
01961       if (SO == NULL)   {
01962          fprintf(SUMA_STDERR,"Error %s: could not load SO\n", FuncName);
01963          SUMA_RETURN(NULL);
01964       }
01965       SurfIn = YUP;
01966       brk = YUP;
01967    } /* load Ply format surface */
01968    
01969    if (!brk && SUMA_iswordin(Spec->SurfaceType[i], "GenericInventor") == 1) {/* load generic inventor format surface */
01970       if (tmpVolParName != NULL) {
01971          fprintf(SUMA_STDERR,"Error %s: Sorry, but Parent volumes are not supported for generic inventor surfaces.\n", FuncName);
01972          SUMA_RETURN (NULL);
01973       }
01974       if (SUMA_iswordin(Spec->SurfaceFormat[i], "ASCII") == 1)
01975          SO = SUMA_Load_Surface_Object_eng ((void *)Spec->SurfaceFile[i], SUMA_INVENTOR_GENERIC, SUMA_ASCII, NULL, debug);
01976       else {
01977          fprintf(SUMA_STDERR,"Error %s: Only ASCII surfaces can be read for now.\n", FuncName);
01978          SUMA_RETURN(NULL);
01979       }
01980       if (SO == NULL)   {
01981          fprintf(SUMA_STDERR,"Error %s: could not load SO\n", FuncName);
01982          SUMA_RETURN(NULL);
01983       }
01984       SurfIn = YUP;
01985 
01986       brk = YUP;
01987    }
01988 
01989    if (!brk) {
01990       fprintf(SUMA_STDERR,"Error %s: Unknown SurfaceFormat %s.\n(Format syntax is case sensitive)\n", FuncName, Spec->SurfaceType[i]);
01991       SUMA_RETURN(NULL);
01992    }
01993 
01994    if (!SurfIn) {
01995       fprintf(SUMA_STDERR,"Error %s: Failed to read input surface.\n", FuncName);
01996       SUMA_RETURN(NULL);
01997    }
01998 
01999    /* assign its Group and State and Side*/
02000    SO->Group = (char *)SUMA_calloc(strlen(Spec->Group[i])+1, sizeof(char));
02001    SO->State = (char *)SUMA_calloc(strlen(Spec->State[i])+1, sizeof(char));
02002    if (Spec->SurfaceLabel[i][0] == '\0') {
02003       SO->Label = SUMA_SurfaceFileName (SO, NOPE);
02004    } else {
02005       SO->Label = SUMA_copy_string(Spec->SurfaceLabel[i]);
02006    }
02007 
02008 
02009    if (!SO->Group || !SO->State || !SO->Label) {
02010       fprintf(SUMA_STDERR,"Error %s: Error allocating lameness.\n", FuncName);
02011       SUMA_RETURN (NULL);
02012    }
02013          
02014    SO->Group = strcpy(SO->Group, Spec->Group[i]);
02015    SO->State = strcpy(SO->State, Spec->State[i]);
02016    SO->EmbedDim = Spec->EmbedDim[i];
02017    if (Spec->Hemisphere[i][0] == 'L') {
02018       SO->Side = SUMA_LEFT;
02019    } else if (Spec->Hemisphere[i][0] == 'R') {
02020       SO->Side = SUMA_RIGHT;
02021    } else SO->Side = SUMA_GuessSide (SO);
02022 
02023    if (Spec->OriginatorID[i][0]) SO->OriginatorID = SUMA_copy_string(Spec->OriginatorID[i]);
02024    if (Spec->DomainGrandParentID[i][0]) SO->DomainGrandParentID = SUMA_copy_string(Spec->DomainGrandParentID[i]);
02025    if (Spec->LocalCurvatureParent[i][0]) SO->LocalCurvatureParent = SUMA_copy_string(Spec->LocalCurvatureParent[i]);
02026    if (Spec->LocalDomainParent[i][0]) SO->LocalDomainParent = SUMA_copy_string(Spec->LocalDomainParent[i]);
02027    if (Spec->AnatCorrect[i][0] == '\0') Spec->AnatCorrect[i][0] = SUMA_GuessAnatCorrect(SO);
02028    SO->AnatCorrect = NOPE;
02029    if (Spec->AnatCorrect[i][0] == 'Y')  SO->AnatCorrect = YUP;
02030    else SO->AnatCorrect = NOPE;
02031    
02032    if (Spec->SpecFilePath) SO->SpecFile.Path = SUMA_copy_string(Spec->SpecFilePath);
02033    if (Spec->SpecFileName) SO->SpecFile.FileName = SUMA_copy_string(Spec->SpecFileName);
02034    
02035    SUMA_RETURN(SO);
02036 
02037 } /* end SUMA_Load_Spec_Surf */
02038 
02039 /*!
02040    Take a mappable SO , loaded as it would be out of, say, SUMA_Load_Spec_Surf, 
02041    find its metrics, initialize suma structures and add it to DOv
02042 */
02043 SUMA_Boolean SUMA_PrepAddmappableSO(SUMA_SurfaceObject *SO, SUMA_DO *dov, int *N_dov, int debug, DList *DsetList)
02044 { /* begin SUMA_PrepAddmappableSO */
02045    static char FuncName[]={"SUMA_PrepAddmappableSO"};
02046    SUMA_OVERLAYS *NewColPlane=NULL;
02047    SUMA_Boolean SurfIn = NOPE;
02048    char DoThis[100];
02049    SUMA_Boolean LocalHead = NOPE;
02050 
02051    SUMA_ENTRY;
02052    
02053    SurfIn = YUP;
02054    
02055    /* set its MappingRef id to its own */
02056       SO->LocalDomainParentID = (char *)SUMA_calloc(strlen(SO->idcode_str)+1, sizeof(char));
02057       if (SO->LocalDomainParentID == NULL) {
02058          fprintf(SUMA_STDERR,"Error %s: Failed to allocate for SO->LocalDomainParentID. That is pretty bad.\n", FuncName);
02059          SUMA_RETURN (NOPE);
02060       }
02061       SO->LocalDomainParentID = strcpy(SO->LocalDomainParentID, SO->idcode_str);
02062 
02063    
02064 
02065    /* if the surface is loaded OK, and it has not been loaded previously, register it */
02066    if (SurfIn) {
02067       sprintf(DoThis,"Convexity");
02068       if (!SO->EL || !SO->FN) sprintf(DoThis,"%s, EdgeList", DoThis);
02069       if (!SO->MF) sprintf(DoThis,"%s, MemberFace", DoThis);
02070       if (!SUMA_SurfaceMetrics_eng (SO, DoThis, NULL, debug, DsetList)) {
02071          fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_SurfaceMetrics.\n", FuncName);
02072          SUMA_RETURN (NOPE);
02073       }
02074 
02075       #if SUMA_CHECK_WINDING
02076       /* if you have surfaces that are not consistent, you should fix them ahead of time
02077       because orientation affects calculations of normals, areas (signed), convexity 
02078       etc.... */
02079       if (!SUMA_SurfaceMetrics_eng (SO, "CheckWind", NULL, debug, DsetList)) {
02080          fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_SurfaceMetrics.\n", FuncName);
02081          SUMA_RETURN (NOPE);
02082       }
02083       #endif
02084 
02085       /* create the surface controller */
02086       SO->SurfCont = SUMA_CreateSurfContStruct(SO->idcode_str);
02087 
02088       {
02089          SUMA_DSET *dset=NULL;/* create the color plane for Convexity*/
02090 
02091        /* create an overlay plane */
02092          if (!(dset = (SUMA_DSET *)SUMA_GetCx(SO->idcode_str, DsetList, 1))) {
02093             SUMA_SL_Err("Failed to find dset!");
02094             SUMA_RETURN (NOPE);
02095          }
02096          NewColPlane = SUMA_CreateOverlayPointer (SO->N_Node, "Convexity", dset, SO->idcode_str);
02097          if (!NewColPlane) {
02098             fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_CreateOverlayPointer.\n", FuncName);
02099             SUMA_RETURN (NOPE);
02100          } 
02101 
02102          /* Add this plane to SO->Overlays */
02103          if (!SUMA_AddNewPlane (SO, NewColPlane, NULL, -1, 1)) { /* duplicate planes will be ignored! */
02104             SUMA_SL_Err("Failed in SUMA_AddNewPlane");
02105             SUMA_FreeOverlayPointer(NewColPlane);
02106             SUMA_RETURN (NOPE);
02107          }
02108 
02109          if (!SUMAg_CF->scm) {   
02110             SUMAg_CF->scm = SUMA_Build_Color_maps();
02111             if (!SUMAg_CF->scm) {
02112                SUMA_SL_Err("Failed to build color maps.\n");
02113                SUMA_RETURN(NOPE);            
02114             }
02115          }
02116          if (!SUMA_SetConvexityPlaneDefaults(SO, DsetList)) {
02117             SUMA_SL_Err("Failed to set plane defaults."); SUMA_RETURN(NOPE);
02118          }
02119 
02120          /* colorize the plane */
02121          SUMA_ColorizePlane(NewColPlane);
02122       }
02123 
02124       /* Create a Mesh Axis for the surface */
02125       SO->MeshAxis = SUMA_Alloc_Axis ("Surface Mesh Axis");
02126       if (SO->MeshAxis == NULL) {
02127          fprintf(SUMA_STDERR,"Error %s: Error Allocating axis\n", FuncName);
02128          SUMA_RETURN(NOPE);
02129       }
02130       /* Change the defaults of Mesh axis to fit standard  */
02131       /* For the moment, use Box Axis */
02132       SO->MeshAxis->type = SUMA_SCALE_BOX;
02133       SUMA_MeshAxisStandard (SO->MeshAxis, SO);
02134       /*turn on the viewing for the axis */
02135       SO->ShowMeshAxis = NOPE;
02136 
02137       /* Store it into dov, if not there already */
02138       if (SUMA_whichDO(SO->idcode_str, dov, *N_dov) < 0) {
02139          if (!SUMA_AddDO(dov, N_dov, (void *)SO,  SO_type, SUMA_LOCAL)) {
02140             fprintf(SUMA_STDERR,"Error %s: Error Adding DO\n", FuncName);
02141             SUMA_RETURN(NOPE);
02142          }
02143       }
02144 
02145    }
02146    SUMA_RETURN(YUP);
02147 
02148 } /* end SUMA_PrepAddmappableSO */
02149 
02150 /*! 
02151    Call the function engine, with debug turned on.      20 Oct 2003 [rickr]
02152 */
02153 SUMA_Boolean SUMA_LoadSpec (SUMA_SurfSpecFile *Spec, SUMA_DO *dov, int *N_dov, char *VolParName)
02154 {/* SUMA_LoadSpec */
02155    static char FuncName[]={"SUMA_LoadSpec"};
02156 
02157    SUMA_ENTRY;
02158 
02159    SUMA_RETURN( SUMA_LoadSpec_eng(Spec, dov, N_dov, VolParName, 1, SUMAg_CF->DsetList) );
02160 
02161 }/* SUMA_LoadSpec */
02162 
02163 /* - appended _eng to engine function name             20 Oct 2003 [rickr]
02164  * - added debug parameter
02165  * - only output non-error info when debug flag is set
02166  * - debug level 1, slight detail, level 2 more detail
02167 */
02168 /*! 
02169    Loads the surfaces specified in Spec and stores them in DOv
02170 */
02171 SUMA_Boolean SUMA_LoadSpec_eng (SUMA_SurfSpecFile *Spec, SUMA_DO *dov, int *N_dov, char *VolParName, int debug, DList *DsetList)
02172 {/* SUMA_LoadSpec_eng */
02173    static char FuncName[]={"SUMA_LoadSpec_eng"};
02174    int i, k;
02175    char *tmpid, *tmpVolParName = NULL;
02176    SUMA_SurfaceObject *SO=NULL;
02177    SUMA_Axis *EyeAxis;
02178    SUMA_OVERLAYS *NewColPlane=NULL;
02179    SUMA_Boolean SurfIn = NOPE;
02180    SUMA_Boolean LocalHead = NOPE; 
02181 
02182    SUMA_ENTRY;
02183    
02184    if ( debug )
02185        fprintf (SUMA_STDERR, "Expecting to read %d surfaces.\n", Spec->N_Surfs);
02186    for (i=0; i<Spec->N_Surfs; ++i) { /* first loop across mappable surfaces */
02187       /*locate and load all Mappable surfaces */
02188       if (SUMA_iswordin(Spec->LocalDomainParent[i],"SAME") == 1) { /* Mappable surfaces */
02189          if ( debug || 1) { /* turned this back on as a pacifier */
02190             fprintf (SUMA_STDERR,"\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv");
02191             fprintf (SUMA_STDERR,
02192                      "Surface #%d/%d(Local Domain Parent), loading ...\n",i+1, Spec->N_Surfs );
02193          }
02194 
02195          if (Spec->VolParName[i][0] != '\0') {
02196             fprintf (SUMA_STDOUT, "Warning %s: Using Volume Parent Specified in Spec File. This overrides -sv option.\n", FuncName);
02197             tmpVolParName = Spec->VolParName[i];
02198          }else {
02199             tmpVolParName = VolParName;
02200          }
02201          
02202          SO = SUMA_Load_Spec_Surf(Spec, i, tmpVolParName, debug);
02203          if (SO) SurfIn = YUP;
02204          else {
02205             SurfIn = NOPE;
02206             SUMA_SL_Err("Failed to read surface.");
02207             SUMA_RETURN(NOPE);
02208          }
02209          
02210          /* store the surface's idcode pointer for use in non mappable bloc below */
02211             Spec->IDcode[i] = SO->idcode_str;
02212          
02213          /* check if surface read was unique 
02214          it's inefficient to check after the surface is read, but idcode is generated in the read routine 
02215          and users should not be making this mistake too often */
02216          if (SUMA_existSO (SO->idcode_str, dov, *N_dov)) {
02217             fprintf(SUMA_STDERR,"Note %s: Surface is specifed more than once, multiple copies ignored.\n", FuncName);
02218             /* free SO */
02219             if (!SUMA_Free_Surface_Object (SO)) {
02220                fprintf(SUMA_STDERR,"Error %s: Error freeing SO.\n", FuncName);
02221                SUMA_RETURN (NOPE);
02222             }
02223             SurfIn = NOPE;
02224          } else {
02225             if (!SUMA_PrepAddmappableSO(SO, dov, N_dov, debug, DsetList)) {
02226                SUMA_SL_Err("Failed in SUMA_PrepAddmappableSO.");
02227                SUMA_RETURN(NOPE);
02228             }
02229          }  
02230             SurfIn = NOPE;
02231       }/* Mappable surfaces */
02232    }/* first loop across mappable surfaces */
02233 
02234    for (i=0; i<Spec->N_Surfs; ++i) { /* Now locate and load all NON Mappable surfaces */
02235 
02236       if (Spec->VolParName[i][0] != '\0') {
02237          if (VolParName) {
02238             fprintf (SUMA_STDOUT, "Warning %s: Using Volume Parent Specified in Spec File.\nThis overrides -sv option.\n", FuncName);
02239          }
02240          tmpVolParName = Spec->VolParName[i];
02241       }else {
02242          tmpVolParName = VolParName;
02243       }
02244 
02245       if (SUMA_iswordin(Spec->LocalDomainParent[i],"SAME") != 1) { /* Non Mappable surfaces */
02246          if ( debug  || 1) { /* turned this back on as a pacifier */
02247             fprintf (SUMA_STDERR,"\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv");
02248             fprintf (SUMA_STDERR,
02249                      "Surface #%d/%d (mappable via Local Domain Parent), loading ...\n",i+1, Spec->N_Surfs);
02250          }
02251          
02252          SO = SUMA_Load_Spec_Surf(Spec, i, tmpVolParName, debug);
02253          if (SO) SurfIn = YUP;
02254          else {
02255             SurfIn = NOPE;
02256             SUMA_SL_Err("Failed to read surface.");
02257             SUMA_RETURN(NOPE);
02258          }
02259          
02260 
02261 
02262          /* check if surface read was unique 
02263             it's inefficient to check after the surface is read, but idcode is generated in the read routine 
02264             and users should not be making this mistake too often */
02265             if (SUMA_existSO (SO->idcode_str, dov, *N_dov)) {
02266                fprintf(SUMA_STDERR,"Error %s: Surface %d is specifed more than once, multiple copies ignored.\n", FuncName, i);
02267                /* free SO */
02268                if (!SUMA_Free_Surface_Object (SO)) {
02269                   fprintf(SUMA_STDERR,"Error %s: Error freeing SO.\n", FuncName);
02270                   SUMA_RETURN (NOPE);
02271                }
02272                SurfIn = NOPE;
02273             }
02274 
02275          /* if the surface is loaded OK, and it has not been loaded previously, register it */
02276          if (SurfIn) {
02277             /* Create a Mesh Axis for the surface */
02278             SO->MeshAxis = SUMA_Alloc_Axis ("Surface Mesh Axis");
02279             if (SO->MeshAxis == NULL) {
02280                fprintf(SUMA_STDERR,"Error %s: Error Allocating axis\n", FuncName);
02281                SUMA_RETURN(NOPE);
02282             }
02283             /* Change the defaults of Mesh axis to fit standard  */
02284             SUMA_MeshAxisStandard (SO->MeshAxis, SO);
02285             /*turn on the viewing for the axis */
02286             SO->ShowMeshAxis = NOPE;
02287 
02288             /* Store it into dov */
02289             if (!SUMA_AddDO(dov, N_dov, (void *)SO,  SO_type, SUMA_LOCAL)) {
02290                fprintf(SUMA_STDERR,"Error %s: Error Adding DO\n", FuncName);
02291                SUMA_RETURN(NOPE);
02292             }
02293             
02294          /* set its MappingRef id to NULL if none is specified */
02295             if (Spec->LocalDomainParent[i][0] == '\0') {
02296                SO->LocalDomainParentID = NULL; /* no known MapRef_idcode */
02297                fprintf(SUMA_STDERR,"No Mapping Ref specified.\n");
02298             } else {
02299                /* make sure that specified Mapping ref had been loaded */
02300                   int j = 0, ifound = -1;
02301                   while (j < Spec->N_Surfs) {
02302                      if (LocalHead) { fprintf(SUMA_STDERR,"%s-voila%d/%d:\n%s\n%s\n%s\n%s\n", FuncName, j, Spec->N_Surfs,\
02303                         Spec->LocalDomainParent[i], Spec->CoordFile[j], Spec->TopoFile[j],\
02304                          Spec->SurfaceFile[j]); }
02305                      if (strcmp(Spec->LocalDomainParent[i], Spec->CoordFile[j]) == 0 || \
02306                          strcmp(Spec->LocalDomainParent[i], Spec->TopoFile[j]) == 0 ||  \
02307                          strcmp(Spec->LocalDomainParent[i], Spec->SurfaceFile[j]) == 0) {
02308                         /* found a match */
02309                         ifound = j;
02310                         j = Spec->N_Surfs + 1;   
02311                      }
02312                      ++j;
02313                   }
02314                if (ifound >= 0) { /* found */
02315                   if (LocalHead) fprintf (SUMA_STDERR,"ifound = %d, i = %d\nSpec->LocalDomainParent[i]:->%s<-\n", ifound, i, Spec->LocalDomainParent[i]);
02316                   if (!SUMA_existSO (Spec->IDcode[ifound], dov, *N_dov)) {
02317                      fprintf(SUMA_STDERR,"MappingRef unavailable, that should not happen here.\n");
02318                      SO->LocalDomainParentID = NULL;
02319                      /* showme the contents */
02320                      if (!SUMA_ShowSpecStruct (Spec, NULL, 3)) {
02321                         SUMA_SL_Err("Failed in SUMA_ShowSpecStruct\n");
02322                         exit(1);
02323                      }
02324                   } else {
02325                      /*fprintf(SUMA_STDERR,"MappingRef found in mappable surfaces\n");*/
02326                      SO->LocalDomainParentID = (char *)SUMA_calloc(strlen(Spec->IDcode[ifound])+1, sizeof(char));
02327                      if (SO->LocalDomainParentID == NULL) {
02328                         fprintf(SUMA_STDERR,"Error %s: Failed to allocate for SO->LocalDomainParentID. That is pretty bad.\n", FuncName);
02329                         SUMA_RETURN (NOPE);
02330                      }
02331                      SO->LocalDomainParentID = strcpy(SO->LocalDomainParentID, Spec->IDcode[ifound]);
02332                   }
02333                } else {
02334                   fprintf(SUMA_STDERR,"MappingRef unavailable, you won't be able to link to afni.\n");
02335                   SO->LocalDomainParentID = NULL;
02336                }
02337             }
02338             
02339             /* create the colorlist vector and calculate the surface metrics with the possibility of inheriting from the mapping reference */
02340             {
02341                SUMA_SurfaceObject *SOinh = NULL;
02342                int ifound = -1; 
02343                
02344                if (SO->LocalDomainParentID) {   
02345                   ifound =  SUMA_findSO_inDOv (SO->LocalDomainParentID, dov, *N_dov);
02346                   if (ifound < 0) {
02347                      SOinh = NULL;
02348                   }else {
02349                      SOinh = (SUMA_SurfaceObject *)(dov[ifound].OP);
02350                   }
02351                } else SOinh = NULL;
02352                
02353                /* deal with surface controller */
02354                if (SOinh) {
02355                   #if SUMA_SEPARATE_SURF_CONTROLLERS
02356                   /* leave controllers separate */ 
02357                   SO->SurfCont = SUMA_CreateSurfContStruct(SO->idcode_str); 
02358                   #else
02359                   /* create a link to the surface controller pointer */
02360                   SO->SurfCont = (SUMA_X_SurfCont*)SUMA_LinkToPointer((void *)SOinh->SurfCont);
02361                   #endif
02362                } else {
02363                   /* brand new one */
02364                   SO->SurfCont = SUMA_CreateSurfContStruct(SO->idcode_str);
02365                }
02366 
02367                
02368                if (!SUMA_SurfaceMetrics_eng (SO, "EdgeList, MemberFace", SOinh, debug, DsetList)) {
02369                   fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_SurfaceMetrics.\n", FuncName);
02370                   SUMA_RETURN (NOPE);
02371                }
02372             }  
02373                
02374             
02375 
02376             SurfIn = NOPE;
02377          }
02378       }/* Non Mappable surfaces */
02379 
02380    }/*locate and load all NON Mappable surfaces */
02381 
02382    SUMA_RETURN (YUP);
02383 }/* SUMA_LoadSpec_eng */
02384 
02385 
02386 /*!
02387    SUMA_SurfaceMetrics - call the engine with debug set    20 Oct 2003 [rickr]
02388 */
02389 SUMA_Boolean SUMA_SurfaceMetrics(SUMA_SurfaceObject *SO, const char *Metrics, SUMA_SurfaceObject *SOinh)
02390 {
02391    static char FuncName[]={"SUMA_SurfaceMetrics"};
02392    
02393    SUMA_ENTRY;
02394 
02395    SUMA_RETURN(SUMA_SurfaceMetrics_eng(SO, Metrics, SOinh, 1, SUMAg_CF->DsetList));
02396 }
02397 
02398 
02399 /* - appended _eng to engine function name                 20 Oct 2003 [rickr]
02400  * - added debug parameter
02401  * - only output non-error info when debug flag is set
02402 */
02403 /*!
02404    calculate surface properties
02405    
02406    ans = SUMA_SurfaceMetrics_eng (SO, Metrics, SOinh, debug, DList *DsetList)
02407    \param SO (SUMA_SurfaceObject *)
02408    \param Metrics (const char *) list of parameters to compute. Supported parameters are (case sensitive):
02409       "Convexity", "PolyArea", "Curvature", "EdgeList", "MemberFace", "CheckWind"
02410       You can specify more than one parameter "Convexity, PolyArea"
02411       if the field of a certain parameter is not NULL then it is assumed that 
02412       this parameter was computed at an earlier time and will not be recalculated.
02413       Some parameters require the computation of others and that's done automatically.
02414    \param SOinh (SUMA_SurfaceObject *) Some of the metrics can be inherited from SOinh (done through inodes)
02415       if things make sense. SOinh is typically the Mapping Reference SO. Pass NULL not to use this feature.
02416       Currently, only EL and FN can use this feature if the number of nodes, facesets match and SOinh is the 
02417       mapping reference of SO
02418    \param debug (int) flag specifying whether to output non-error info
02419    \param DsetList (DList *)  pointer to list where computed elements are to be stored
02420                               as datasets. For the moment, this pointer can be NULL and
02421                               if that is the case then nothing will get stored as a dataset.
02422    \return ans (SUMA_Boolean) NOPE = failure
02423    
02424    Convexity : Fills Cx field in SO, An inode is also created
02425    
02426    EdgeList also runs SUMA_Build_FirstNeighb
02427    
02428    Curvature requires also PolyArea, FaceNeighb and EdgeList
02429    CheckWind requires EdgeList
02430    
02431       
02432 */
02433 SUMA_Boolean SUMA_SurfaceMetrics_eng (SUMA_SurfaceObject *SO, const char *Metrics, SUMA_SurfaceObject *SOinh, int debug, 
02434                                        DList *DsetList)
02435 {
02436    static char FuncName[]={"SUMA_SurfaceMetrics_eng"};
02437    float *Cx=NULL, *SOCx = NULL;
02438    SUMA_Boolean DoConv, DoArea, DoCurv, DoEL, DoMF, DoWind, LocalHead = NOPE;
02439    int i = 0;
02440    
02441    SUMA_ENTRY;
02442 
02443    if (debug > 1)
02444       fprintf (SUMA_STDERR,"%s: Calculating surface metrics, please be patient...\n", FuncName);
02445    
02446    if (!DsetList) {
02447       SUMA_SL_Err("DsetList now is a must.");
02448       SUMA_RETURN(NOPE);
02449    }
02450    DoConv = DoArea = DoCurv = DoEL = DoMF = DoWind = NOPE;
02451    
02452    if (SUMA_iswordin (Metrics, "Convexity")) DoConv = YUP;
02453    if (SUMA_iswordin (Metrics, "PolyArea")) DoArea = YUP;
02454    if (SUMA_iswordin (Metrics, "Curvature")) DoCurv = YUP;
02455    if (SUMA_iswordin (Metrics, "EdgeList")) DoEL = YUP;
02456    if (SUMA_iswordin (Metrics, "MemberFace")) DoMF = YUP;
02457    if (SUMA_iswordin (Metrics, "CheckWind")) DoWind = YUP;
02458    
02459    /* check for input inconsistencies and warn */
02460    if (!DoConv && !DoArea && !DoCurv && !DoEL  && !DoMF && !DoWind) {
02461       fprintf (SUMA_STDERR,"Warning %s: Nothing to do.\n", FuncName);
02462       SUMA_RETURN (YUP);
02463    }
02464    
02465    SOCx = (float *)SUMA_GetCx (SO->idcode_str, DsetList, 0); 
02466    if (DoConv && SOCx) {
02467       fprintf (SUMA_STDERR,"Warning %s: SOCx != NULL and thus appears to have been precomputed.\n", FuncName);
02468       DoConv = NOPE;
02469    }
02470    
02471    if (DoArea && SO->PolyArea != NULL) {
02472       fprintf (SUMA_STDERR,"Warning %s: SO->PolyArea != NULL and thus appears to have been precomputed.\n", FuncName);
02473       DoArea = NOPE;
02474    }
02475    
02476    if (DoCurv && SO->SC != NULL) {
02477       fprintf (SUMA_STDERR,"Warning %s: SO->SC != NULL and thus appears to have been precomputed.\n", FuncName);
02478       DoCurv = NOPE;
02479    }
02480    
02481    if (DoMF && SO->MF != NULL) {
02482       fprintf (SUMA_STDERR,"Warning %s: SO->MF != NULL and thus appears to have been precomputed.\n", FuncName);
02483       DoMF = NOPE;
02484    }
02485    
02486    if (DoEL && (SO->EL != NULL || SO->FN != NULL)) {
02487       fprintf (SUMA_STDERR,"Warning %s: SO->EL != NULL || SO->FN != NULL and thus appears to have been precomputed.\n", FuncName);
02488       DoEL = NOPE;
02489    }
02490    
02491    if (DoEL && SOinh) {
02492       if (strcmp(SO->LocalDomainParentID, SOinh->idcode_str)) {
02493          SUMA_SL_Warn(  "Cannot inherit Edge List\n"
02494                         "and First Neightbor.\n"
02495                         "Cause: idcode mismatch.\n"
02496                         "Independent lists will\n"
02497                         "be created." );
02498          SOinh = NULL;
02499       }else if (SO->N_Node != SOinh->N_Node || SO->N_FaceSet != SOinh->N_FaceSet) {
02500          SUMA_SL_Warn(  "(IGNORE for surface patches)\n"
02501                         "Cannot inherit Edge List\n"
02502                         "and First Neightbor.\n"
02503                         "Cause: Node number mismatch.\n"
02504                         "Independent lists will\n"
02505                         "be created.");
02506          SOinh = NULL;      
02507       }
02508    }
02509    
02510    if (DoMF && SOinh) {
02511       if (strcmp(SO->LocalDomainParentID, SOinh->idcode_str)) {
02512          SUMA_SL_Warn(  "Cannot inherit MemberFaceSet\n"
02513                         "Cause: idcode mismatch.\n"
02514                         "Independent lists will\n"
02515                         "be created." );
02516          SOinh = NULL;
02517       }else if (SO->N_Node != SOinh->N_Node || SO->N_FaceSet != SOinh->N_FaceSet) {
02518          SUMA_SL_Warn(  "(IGNORE for surface patches)\n"
02519                         "Cannot inherit MemberFaceSet\n"
02520                         "Cause: Node number mismatch.\n"
02521                         "Independent lists will\n"
02522                         "be created.");
02523          SOinh = NULL;      
02524       }
02525    }
02526     
02527    /* prerequisits */
02528    if (DoCurv) {
02529       DoArea = YUP;
02530       DoEL = YUP;
02531    }
02532    
02533    if (DoWind) {
02534       DoEL = YUP;
02535    }
02536 
02537    if (DoConv && (!SO->EL || !SO->FN)) {
02538       DoEL = YUP;
02539    }
02540    
02541    /* the computations */
02542    if (DoArea) {
02543       /* create the triangle Area  */
02544       if (SO->NodeDim == 3) {
02545          if (debug) fprintf(SUMA_STDOUT, "%s: Calculating triangle areas ...\n", FuncName); fflush(SUMA_STDOUT); 
02546          SO->PolyArea = SUMA_TriSurf3v (SO->NodeList, SO->FaceSetList, SO->N_FaceSet);
02547       } else {
02548          if (debug) fprintf(SUMA_STDOUT, "%s: Calculating polygon areas ...\n", FuncName); fflush(SUMA_STDOUT); 
02549          SO->PolyArea = SUMA_PolySurf3 (SO->NodeList, SO->N_Node, SO->FaceSetList, SO->N_FaceSet, SO->NodeDim, SO->FaceNormList, NOPE);
02550          #if 0
02551             /* a test of the functions for calculating areas */
02552             {
02553                int ji, in0, in1, in2;
02554                float *n0, *n1, *n2, A;
02555                for (ji=0; ji<SO->N_FaceSet; ++ji) {
02556                   in0 = SO->FaceSetList[3*ji];
02557                   in1 = SO->FaceSetList[3*ji+1];
02558                   in2 = SO->FaceSetList[3*ji+2];
02559                   n0 = &(SO->NodeList[3*in0]);
02560                   n1 = &(SO->NodeList[3*in1]);
02561                   n2 = &(SO->NodeList[3*in2]);
02562                   A = SUMA_TriSurf3 (n0, n1, n2);
02563                   if (abs(A - SO->PolyArea[ji]) > 0.00001) {
02564                      fprintf (SUMA_STDERR, "Error %s: Failed comparing SUMA_TriSurf3 to SUMA_PolySurf3. A = %f vs %f.\nTri = [ %f, %f, %f; %f, %f, %f; %f, %f, %f]\n", 
02565                         FuncName, A, SO->PolyArea[ji], n0[0], n0[1], n0[2], n1[0], n1[1], n1[2], n2[0], n2[1], n2[2]);
02566                   }else fprintf (SUMA_STDERR, "-");
02567 
02568                   SUMA_TRI_AREA (n0, n1, n2, A);
02569                   if (abs(A - SO->PolyArea[ji]) > 0.00001) {
02570                      fprintf (SUMA_STDERR, "Error %s: Failed comparing SUMA_TRI_AREA to SUMA_PolySurf3. %f vs %f Exiting.\n", 
02571                         FuncName, A, SO->PolyArea[ji]);
02572                   }else fprintf (SUMA_STDERR, ".");
02573                }  
02574             }
02575          #endif
02576 
02577       }
02578       if (SO->PolyArea == NULL) {
02579          fprintf(SUMA_STDERR,"Error %s: Error in SUMA_PolySurf3 or SUMA_TriSurf3v\n", FuncName);
02580       }
02581    }
02582    
02583    if (DoEL) {
02584       if (!SOinh) {
02585          /* create the edge list, it's nice and dandy */
02586          if (LocalHead) fprintf(SUMA_STDOUT, "%s: Making Edge list ....\n", FuncName); 
02587          if (SO->EL) {
02588             fprintf (SUMA_STDERR,"Warning %s: SO->FN appears to have been computed before. \n", FuncName); 
02589          } else {
02590             SO->EL = SUMA_Make_Edge_List_eng (SO->FaceSetList, SO->N_FaceSet, SO->N_Node, SO->NodeList, debug, SO->idcode_str);
02591             if (SO->EL == NULL) {
02592                fprintf(SUMA_STDERR, "Error %s: Failed in SUMA_Make_Edge_List. Neighbor list will not be created\n", FuncName);
02593             } else {
02594                if (LocalHead) fprintf(SUMA_STDOUT, "%s: Making Node Neighbor list ....\n", FuncName); 
02595                /* create the node neighbor list */
02596                if (SO->FN) {
02597                   fprintf (SUMA_STDERR,"Warning %s: SO->FN appears to have been computed before. \n", FuncName); 
02598                } else {
02599                   SO->FN = SUMA_Build_FirstNeighb (SO->EL, SO->N_Node, SO->idcode_str);   
02600                   if (SO->FN == NULL) {
02601                      fprintf(SUMA_STDERR, "Error %s: Failed in SUMA_Build_FirstNeighb.\n", FuncName);
02602                   }
02603                } 
02604             }
02605          }
02606       } else {
02607          if (LocalHead) fprintf(SUMA_STDOUT, "%s: Linking Edge List and First Neighbor Lits ...\n", FuncName);
02608          SO->FN = (SUMA_NODE_FIRST_NEIGHB*)SUMA_LinkToPointer((void *)SOinh->FN);
02609          SO->EL = (SUMA_EDGE_LIST*)SUMA_LinkToPointer((void *)SOinh->EL);
02610       }
02611    }
02612    
02613    if (DoConv) {
02614       /* calculate convexity */
02615       if (LocalHead) fprintf(SUMA_STDOUT, "%s: Calculating convexity ...\n", FuncName);
02616       Cx = SUMA_Convexity   (SO->NodeList, SO->N_Node, SO->NodeNormList, SO->FN);
02617       if (Cx == NULL) {
02618          fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_Convexity\n", FuncName);
02619       }   
02620             
02621       /* flip sign of convexity if it's a SureFit Surface */
02622       if (SO->FileType == SUMA_SUREFIT) {
02623          for (i=0; i < SO->N_Node; ++i) {
02624             Cx[i] = -Cx[i];
02625          }
02626       }
02627       
02628       #if 0
02629       { 
02630          /* smooth the estimate twice*/
02631          float *attr_sm;
02632          attr_sm = SUMA_SmoothAttr_Neighb (Cx, SO->N_Node, NULL, SO->FN, 1);
02633          if (attr_sm == NULL) {
02634                fprintf(stderr,"Error %s: Failed in SUMA_SmoothAttr_Neighb\n", FuncName);
02635          }   else {
02636             Cx = SUMA_SmoothAttr_Neighb (attr_sm, SO->N_Node, Cx, SO->FN, 1);
02637             if (attr_sm) SUMA_free(attr_sm);
02638          }
02639       }
02640       #else 
02641          /* smooth the estimate as much as specified*/
02642          {
02643             char *eee = getenv("SUMA_NumConvSmooth");
02644             if (eee) {
02645                int N_smooth = (int)strtod(eee, NULL);
02646                if (N_smooth > 1) {
02647                   Cx = SUMA_SmoothAttr_Neighb_Rec (Cx, SO->N_Node, Cx, SO->FN, 1, N_smooth);
02648                } else {
02649                   Cx = SUMA_SmoothAttr_Neighb_Rec (Cx, SO->N_Node, Cx, SO->FN, 1, 5);
02650                }
02651             }   
02652          }
02653       #endif
02654       
02655       if (Cx == NULL) {
02656          fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_SmoothAttr_Neighb\n", FuncName);
02657       } 
02658       
02659       /* create a dataset of the convexity */
02660       if (DsetList){ /* put the convexity as a DataSet */
02661          SUMA_DSET *dset = NULL;
02662          char *name_tmp=NULL;
02663          if (SO->Label) {
02664             name_tmp = SUMA_append_string("Convexity_",SO->Label);
02665          } else {
02666             name_tmp = SUMA_append_string("Convexity_",SO->idcode_str);
02667          }
02668          dset = SUMA_CreateDsetPointer(name_tmp, /* no file name, but specify a name anyway _COD is computed on demand*/
02669                                        SUMA_NODE_CONVEXITY,
02670                                        NULL, /* let function create ID code */
02671                                        SO->idcode_str,   /* that's the domain owner */
02672                                        SO->N_Node);
02673          SUMA_free(name_tmp); name_tmp = NULL;
02674          if (!SUMA_InsertDsetPointer(dset, DsetList)) {
02675             SUMA_SL_Err("Failed to insert dset into list");
02676             SUMA_RETURN(NOPE);
02677          }
02678          if (!SUMA_AddDsetNelCol (dset, "convexity", SUMA_NODE_CX, (void *)Cx, NULL ,1)) {
02679             SUMA_SL_Err("Failed in SUMA_AddNelCol");
02680             SUMA_RETURN(NOPE);
02681          }
02682          
02683          SUMA_free(Cx); Cx = NULL; /* Cx is safe and sound in DsetList */
02684          
02685       }
02686    } /* DoConv */
02687    
02688    
02689    if (DoWind){   
02690       int trouble;
02691       /* make sure winding is consistent */
02692       if (!SUMA_MakeConsistent (SO->FaceSetList, SO->N_FaceSet, SO->EL, 1, &trouble)) {
02693          fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_MakeConsistent.\n", FuncName);
02694       }else {
02695          if (LocalHead) fprintf(SUMA_STDERR,"%s: Eeeexcellent.\n", FuncName);
02696       }
02697       if (trouble) {
02698          SUMA_SL_Note(  "Even if winding was made consistent,\n"
02699                         "Pre-computed normals and normals-related\n"
02700                         "measures and edge lists will need to be\n"
02701                         "recalculated.\n"
02702                         "See also SurfQual and \n"
02703                         "ConvertSurface's -make_consistent option.\n");
02704       }
02705    }
02706 
02707    
02708    if (DoCurv) {
02709       /* calculate the curvature */
02710       if (LocalHead) fprintf(SUMA_STDOUT, "%s: Calculating curvature ...\n", FuncName);
02711       SO->SC = SUMA_Surface_Curvature (SO->NodeList, SO->N_Node, SO->NodeNormList, SO->PolyArea, SO->N_FaceSet, SO->FN, SO->EL);
02712    }
02713    
02714    
02715    if (DoMF) {
02716       if (!SOinh) {
02717          /* determine the MemberFaceSets */
02718          if (LocalHead) fprintf(SUMA_STDOUT, "%s: Determining MemberFaceSets  ...\n", FuncName);
02719          SO->MF = SUMA_MemberFaceSets(SO->N_Node, SO->FaceSetList, SO->N_FaceSet, SO->FaceSetDim, SO->idcode_str);
02720          if (SO->MF->NodeMemberOfFaceSet == NULL) {
02721             fprintf(SUMA_STDERR,"Error %s: Error in SUMA_MemberFaceSets\n", FuncName);
02722             SUMA_RETURN (NOPE); /* do not free MF, that is done when SO is freed */
02723          }else {
02724          }
02725       } else { /* inherit */
02726          if (LocalHead) fprintf(SUMA_STDOUT, "%s: Linking Member Facesets ...\n", FuncName);
02727          SO->MF = (SUMA_MEMBER_FACE_SETS*)SUMA_LinkToPointer((void*)SOinh->MF);
02728       }
02729    }
02730 
02731    SUMA_RETURN (YUP);
02732 }
02733 
02734 #ifdef SUMA_inspec_STAND_ALONE
02735 void usage_SUMA_inspec()
02736 {
02737    static char FuncName[]={"usage_SUMA_inspec"};
02738    char * s = NULL;
02739    printf ( "\n"
02740             "Usage: inspec <-spec specfile> [-detail d] [-h/-help]\n"
02741             "Outputs information found from specfile.\n" 
02742             "    -spec specfile: specfile to be read\n"
02743             "    -detail d: level of output detail default is 1.\n"
02744             "               Available levels are 1, 2 and 3.\n"
02745             "    -h or -help: This message here.\n" );
02746    s = SUMA_New_Additions(0, 1); printf("%s\n", s);SUMA_free(s); s = NULL;
02747    printf ( "      Ziad S. Saad SSCC/NIMH/NIH ziad@nih.gov \n     Dec 2 03\n"
02748             "\n");   
02749 }
02750 int main (int argc,char *argv[])
02751 {/* Main */
02752    char FuncName[]={"inspec"};
02753    int detail, kar;
02754    char *spec_name;
02755    SUMA_SurfSpecFile Spec;   
02756    SUMA_Boolean brk;
02757    
02758         /* allocate space for CommonFields structure */
02759         SUMAg_CF = SUMA_Create_CommonFields ();
02760         if (SUMAg_CF == NULL) {
02761                 fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_Create_CommonFields\n", FuncName);
02762                 exit(1);
02763         }
02764    
02765    if (argc < 3)
02766        {
02767           usage_SUMA_inspec ();
02768           exit (1);
02769        }
02770    
02771    kar = 1;
02772         brk = NOPE;
02773    detail = 1;
02774    spec_name = NULL;
02775         while (kar < argc) { /* loop accross command ine options */
02776                 /*fprintf(stdout, "%s verbose: Parsing command line...\n", FuncName);*/
02777                 if (strcmp(argv[kar], "-h") == 0 || strcmp(argv[kar], "-help") == 0) {
02778                          usage_SUMA_inspec();
02779           exit (1);
02780                 }
02781                 if (!brk && (strcmp(argv[kar], "-spec") == 0)) {
02782          kar ++;
02783                         if (kar >= argc)  {
02784                                 fprintf (SUMA_STDERR, "need argument after -spec ");
02785                                 exit (1);
02786                         }
02787          spec_name = argv[kar];
02788                         if (!SUMA_filexists(spec_name)) {
02789             fprintf (SUMA_STDERR, "File %s not found or not readable.\n", spec_name);
02790             exit(1);
02791          }
02792                         brk = YUP;
02793                 }
02794       if (!brk && (strcmp(argv[kar], "-detail") == 0)) {
02795          kar ++;
02796                         if (kar >= argc)  {
02797                                 fprintf (SUMA_STDERR, "need argument after -detail ");
02798                                 exit (1);
02799                         }
02800                         detail = atoi(argv[kar]);
02801          if (detail < 1 || detail > 3) {
02802             SUMA_SL_Err("detail is < 1 or > 3");
02803             exit (1);
02804          }
02805                         brk = YUP;
02806                 }
02807       
02808       if (!brk) {
02809                         fprintf (SUMA_STDERR,"Error %s: Option %s not understood. Try -help for usage\n", FuncName, argv[kar]);
02810                         exit (1);
02811                 } else {        
02812                         brk = NOPE;
02813                         kar ++;
02814                 }
02815    }
02816    
02817    if (!spec_name) {
02818       SUMA_SL_Err("-spec option must be specified.\n");
02819       exit(1);
02820    }
02821    /* load spec file */
02822    if (!SUMA_Read_SpecFile (spec_name, &Spec)) {
02823       SUMA_SL_Err("Error in SUMA_Read_SpecFile\n");
02824       exit(1);
02825    }
02826    
02827    /* showme the contents */
02828    if (!SUMA_ShowSpecStruct (&Spec, NULL, detail)) {
02829       SUMA_SL_Err("Failed in SUMA_ShowSpecStruct\n");
02830       exit(1);
02831    }
02832    
02833    if (!SUMA_Free_CommonFields(SUMAg_CF)) {
02834       fprintf(SUMA_STDERR,"Error %s: SUMAg_CF Cleanup Failed!\n", FuncName);
02835       exit(1);
02836    }
02837    
02838    SUMA_RETURN(0);
02839 }/* main inspec */
02840 #endif
02841 
02842 
02843 #ifdef SUMA_quickspec_STAND_ALONE
02844 void usage_SUMA_quickspec()
02845 {
02846    static char FuncName[]={"usage_SUMA_quickspec"};
02847    char * s = NULL;
02848    printf ( "\nUsage:  quickspec \n"
02849             "        <-tn TYPE NAME> ...\n"
02850             "        <-tsn TYPE STATE NAME> ...\n"
02851             "        [<-spec specfile>] [-h/-help]\n"
02852             "  Use this spec file for quick and dirty way of \n"
02853             "  loading a surface into SUMA or the command line programs.\n"
02854             "\n"
02855             "Options:\n"
02856             "   -tn TYPE NAME: specify surface type and name.\n"
02857             "                  See below for help on the parameters.\n"
02858             "   -tsn TYPE STATE NAME: specify surface type state and name.\n"
02859                  "        TYPE: Choose from the following (case sensitive):\n"
02860             "           1D: 1D format\n"
02861             "           FS: FreeSurfer ascii format\n"
02862             "           PLY: ply format\n"
02863             "           SF: Caret/SureFit format\n"
02864             "           BV: BrainVoyager format\n"
02865             "        NAME: Name of surface file. \n"
02866             "           For SF and 1D formats, NAME is composed of two names\n"
02867             "           the coord file followed by the topo file\n"
02868             "        STATE: State of the surface.\n"
02869             "           Default is S1, S2.... for each surface.\n"
02870             "   -spec specfile: Name of spec file output.\n"
02871             "                   Default is quick.spec\n"
02872             "                   The program will only overwrite \n"
02873             "                   quick.spec (the default) spec file.\n"
02874             "   -h or -help: This message here.\n" 
02875             "\n"
02876             "  You can use any combinaton of -tn and -tsn options.\n"
02877             "  Fields in the spec file that are (or cannot) be specified\n"
02878             "  by this program are set to default values.\n"
02879             "\n   This program was written to ward off righteous whiners and is\n"
02880             "  not meant to replace the venerable @SUMA_Make_Spec_XX scripts.\n"
02881             "\n");
02882      s = SUMA_New_Additions(0, 1); printf("%s\n", s);SUMA_free(s); s = NULL;
02883      printf("      Ziad S. Saad SSCC/NIMH/NIH ziad@nih.gov \n\t\t Tue Dec 30\n"
02884             "\n");   
02885 }
02886 int main (int argc,char *argv[])
02887 {/* Main */
02888    char FuncName[]={"quickspec"};
02889    int detail, kar, i, N_surf, N_name, idefstate;
02890    FILE *fid = NULL;
02891    char *spec_name, stmp[500], *Unique_st;
02892    SUMA_SO_File_Type TypeC[SUMA_MAX_N_SURFACE_SPEC];
02893    char  *State[SUMA_MAX_N_SURFACE_SPEC],
02894          *Name_coord[SUMA_MAX_N_SURFACE_SPEC], *Name_topo[SUMA_MAX_N_SURFACE_SPEC];
02895    SUMA_Boolean brk;
02896    
02897         /* allocate space for CommonFields structure */
02898         SUMAg_CF = SUMA_Create_CommonFields ();
02899         if (SUMAg_CF == NULL) {
02900                 fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_Create_CommonFields\n", FuncName);
02901                 exit(1);
02902         }
02903    
02904    if (argc < 3)
02905        {
02906           usage_SUMA_quickspec ();
02907           exit (1);
02908        }
02909    
02910    kar = 1;
02911         brk = NOPE;
02912    detail = 1;
02913    N_surf = 0;
02914    N_name = 0;
02915    spec_name = NULL;
02916         while (kar < argc) { /* loop accross command ine options */
02917                 /*fprintf(stdout, "%s verbose: Parsing command line...\n", FuncName);*/
02918                 if (strcmp(argv[kar], "-h") == 0 || strcmp(argv[kar], "-help") == 0) {
02919                          usage_SUMA_quickspec();
02920           exit (1);
02921                 }
02922                 if (!brk && (strcmp(argv[kar], "-spec") == 0)) {
02923          kar ++;
02924                         if (kar >= argc)  {
02925                                 fprintf (SUMA_STDERR, "need argument after -spec \n");
02926                                 exit (1);
02927                         }
02928          spec_name = argv[kar];
02929                         if (SUMA_filexists(spec_name)) {
02930             fprintf (SUMA_STDERR, "File %s exists, choose another one.\n", spec_name);
02931             exit(1);
02932          }
02933                         brk = YUP;
02934                 }
02935       if (!brk && (strcmp(argv[kar], "-tn") == 0)) {
02936          if (N_surf >= SUMA_MAX_N_SURFACE_SPEC) {
02937             SUMA_SL_Err("Exceeding maximum number of allowed surfaces...");
02938             exit(1);   
02939          }
02940          /* get the type */
02941          kar ++;
02942                         if (kar >= argc)  {
02943                                 fprintf (SUMA_STDERR, "Type argument must follow -tn \n");
02944                                 exit (1);
02945                         }
02946          TypeC[N_surf] = SUMA_SurfaceTypeCode(argv[kar]);
02947          if (TypeC[N_surf] == SUMA_FT_ERROR || TypeC[N_surf] == SUMA_FT_NOT_SPECIFIED) {
02948             fprintf (SUMA_STDERR, "%s is a bad file type.\n", argv[kar]);
02949             exit(1);
02950          }
02951          /* get the name */
02952          if (TypeC[N_surf] == SUMA_SUREFIT || TypeC[N_surf] == SUMA_VEC) N_name = 2;
02953          else N_name = 1;
02954          if (kar+N_name >= argc)  {
02955                                 fprintf (SUMA_STDERR, "need %d elements for NAME \n", N_name);
02956                                 exit (1);
02957                         }
02958          kar ++; Name_coord[N_surf] = argv[kar];
02959          if (N_name == 2) {
02960             kar ++; Name_topo[N_surf] = argv[kar];
02961          } else { 
02962             Name_topo[N_surf] = NULL;
02963          }
02964          State[N_surf] = NULL;
02965          
02966          ++N_surf; 
02967                         brk = YUP;
02968                 }
02969       if (!brk && (strcmp(argv[kar], "-tsn") == 0)) {
02970          if (N_surf >= SUMA_MAX_N_SURFACE_SPEC) {
02971             SUMA_SL_Err("Exceeding maximum number of allowed surfaces...");
02972             exit(1);   
02973          }
02974          /* get the type */
02975          kar ++;
02976                         if (kar >= argc)  {
02977                                 fprintf (SUMA_STDERR, "TYPE argument must follow -tsn \n");
02978                                 exit (1);
02979                         }
02980          TypeC[N_surf] = SUMA_SurfaceTypeCode(argv[kar]);
02981          if (TypeC[N_surf] == SUMA_FT_ERROR || TypeC[N_surf] == SUMA_FT_NOT_SPECIFIED) {
02982             fprintf (SUMA_STDERR, "%s is a bad file TYPE.\n", argv[kar]);
02983             exit(1);
02984          }
02985          /* get the state */
02986          kar ++;
02987                         if (kar >= argc)  {
02988                                 fprintf (SUMA_STDERR, "STATE argument must follow TYPE with -tsn \n");
02989                                 exit (1);
02990                         }
02991          State[N_surf] = argv[kar];
02992          
02993          /* get the name */
02994          if (TypeC[N_surf] == SUMA_SUREFIT || TypeC[N_surf] == SUMA_VEC) N_name = 2;
02995          else N_name = 1;
02996          if (kar+N_name >= argc)  {
02997                                 fprintf (SUMA_STDERR, "need %d elements for NAME \n", N_name);
02998                                 exit (1);
02999                         }
03000          kar ++; Name_coord[N_surf] = argv[kar];
03001          if (N_name == 2) {
03002             kar ++; Name_topo[N_surf] = argv[kar];
03003          } else { 
03004             Name_topo[N_surf] = NULL;
03005          }
03006          
03007          ++N_surf; 
03008                         brk = YUP;
03009                 }
03010       
03011       if (!brk) {
03012                         fprintf (SUMA_STDERR,"Error %s: Option %s not understood. Try -help for usage\n", FuncName, argv[kar]);
03013                         exit (1);
03014                 } else {        
03015                         brk = NOPE;
03016                         kar ++;
03017                 }
03018    }
03019    
03020    /* write out the comments */
03021    if (!spec_name) {
03022       fid = fopen("quick.spec", "w");
03023    } else {
03024       fid = fopen(spec_name,"w");
03025    }
03026    if (!fid){
03027       SUMA_SL_Err("Failed to open file for output");
03028       exit(1);
03029    }
03030    fprintf(fid,"# define the group\n");
03031    fprintf(fid,"\tGroup = QuickSpec\n");
03032    
03033    
03034    /* now create a list of unique states */
03035    idefstate = 0;
03036    if (!State[0]) {
03037       Unique_st = SUMA_copy_string ("\tStateDef = S_1\n");
03038       idefstate = 1;
03039    } else {
03040       sprintf(stmp, "\tStateDef = %s\n", State[0]);
03041       Unique_st = SUMA_copy_string (stmp);
03042    }
03043    for (i=1; i < N_surf; ++i) {
03044       if (!State[i]) { 
03045          ++idefstate;
03046          sprintf(stmp,"\tStateDef = S_%d\n", idefstate);
03047          Unique_st = SUMA_append_replace_string (Unique_st, stmp, "", 1);
03048       } else { 
03049          if (SUMA_iswordin(Unique_st, State[i]) != 1) {
03050             sprintf(stmp, "\tStateDef = %s\n", State[i]);
03051             Unique_st = SUMA_append_replace_string(Unique_st, stmp, "", 1);
03052          }
03053       }
03054    }
03055    fprintf (fid, "# define the various States\n");
03056    fprintf (fid, "%s\n", Unique_st);
03057    
03058    /* now loop accross surfaces and write out the results */
03059    idefstate = 0;
03060    for (i=0; i < N_surf; ++i) {
03061       fprintf(fid, "\nNewSurface\n");
03062       fprintf(fid, "\tSurfaceType = %s\n", SUMA_SurfaceTypeString(TypeC[i]));
03063       if (!State[i]) { 
03064          ++idefstate;
03065          fprintf(fid, "\tSurfaceState = S_%d\n", idefstate);
03066       } else fprintf(fid, "\tSurfaceState = %s\n", State[i]);
03067       if (Name_topo[i]) {
03068          fprintf(fid, "\tCoordFile = %s\n", Name_coord[i]);
03069          fprintf(fid, "\tTopoFile = %s\n", Name_topo[i]);
03070       } else {
03071          fprintf(fid, "\tSurfaceName = %s\n", Name_coord[i]); 
03072       }
03073       /* add LocalDomainParent */
03074       fprintf(fid, "\tLocalDomainParent = SAME\n");
03075       /* binary ? */
03076       switch (TypeC[i]) {
03077          case SUMA_FREE_SURFER:
03078             if (!SUMA_isExtension(Name_coord[i], ".asc")) {
03079                fprintf(fid, "\tSurfaceFormat = BINARY\n");
03080             }
03081             break;
03082          default:
03083             break;
03084       }
03085    }
03086    
03087    fclose(fid); fid = NULL;
03088    
03089    if (Unique_st) SUMA_free(Unique_st); Unique_st = NULL;
03090    
03091    if (!SUMA_Free_CommonFields(SUMAg_CF)) {
03092       fprintf(SUMA_STDERR,"Error %s: SUMAg_CF Cleanup Failed!\n", FuncName);
03093       exit(1);
03094    }
03095    
03096    SUMA_RETURN(0);
03097    
03098 }/* main quickspec */
03099 #endif
03100 
03101 
03102 #ifdef SUMA_SurfaceMetrics_STAND_ALONE
03103 
03104 void usage_SUMA_SurfaceMetrics ()
03105    {
03106       static char FuncName[]={"usage_SUMA_SurfaceMetrics"};
03107       char * s = NULL;
03108       s = SUMA_help_basics();
03109       printf ( "\n"
03110                "Usage: SurfaceMetrics <-Metric1> [[-Metric2] ...] \n"
03111                "                  <-spec SpecFile> <-surf_A insurf> \n"
03112                "                  [<-sv SurfaceVolume [VolParam for sf surfaces]>]\n"
03113                "                  [-tlrc] [<-prefix prefix>]\n"
03114                "\n"
03115                "Outputs information about a surface's mesh\n"
03116                "\n"
03117                "   -Metric1: Replace -Metric1 with the following:\n"
03118                "      -vol: calculates the volume of a surface.\n"
03119                "            Volume unit is the cube of your surface's\n"
03120                "            coordinates unit, obviously.\n"
03121                "            Volume's sign depends on the orientation\n"
03122                "            of the surface's mesh.\n" 
03123                "            Make sure your surface is a closed one\n"
03124                "            and that winding is consistent.\n"
03125                "            Use SurfQual to check the surface.\n"
03126                "            If your surface's mesh has problems,\n"
03127                "            the result is incorrect. \n"
03128                "            Volume is calculated using Gauss's theorem,\n"
03129                "            see [Hughes, S.W. et al. 'Application of a new \n"
03130                "            discreet form of Gauss's theorem for measuring \n"
03131                "            volume' in Phys. Med. Biol. 1996].\n"
03132                "      -conv: output surface convexity at each node.\n"
03133                "         Output file is prefix.conv. Results in two columns:\n"
03134                "         Col.0: Node Index\n"
03135                "         Col.1: Convexity\n"
03136                "         This is the measure used to shade sulci and gyri in SUMA.\n"
03137                "         C[i] = Sum(dj/dij) over all neighbors j of i\n"
03138                "         dj is the distance of neighboring node j to the tangent plane at i\n"
03139                "         dij is the length of the segment ij\n"
03140                "      -area: output area of each triangle. \n"
03141                "         Output file is prefix.area. Results in two columns:\n"
03142                "         Col.0: Triangle Index\n"
03143                "         Col.1: Triangle Area\n"
03144                "      -curv: output curvature at each node.\n"
03145                "         Output file is prefix.curv. Results in nine columns:\n"
03146                "         Col.0: Node Index\n"
03147                "         Col.1-3: vector of 1st principal direction of surface\n"
03148                "         Col.4-6: vector of 2nd principal direction of surface\n"
03149                "         Col.7: Curvature along T1\n"
03150                "         Col.8: Curvature along T2\n"
03151                "         Curvature algorithm by G. Taubin from: \n"
03152                "         'Estimating the tensor of curvature of surface \n"
03153                "         from a polyhedral approximation.'\n"
03154                "      -edges: outputs info on each edge. \n"
03155                "         Output file is prefix.edges. Results in five columns:\n"
03156                "         Col.0: Edge Index (into a SUMA structure).\n"
03157                "         Col.1: Index of the first node forming the edge\n"
03158                "         Col.2: Index of the second node forming the edge\n"
03159                "         Col.3: Number of triangles containing edge\n"
03160                "         Col.4: Length of edge.\n"
03161                "      -node_normals: Outputs segments along node normals.\n"
03162                "                     Segments begin at node and have a default\n"
03163                "                     magnitude of 1. See option 'Alt+Ctrl+s' in \n"
03164                "                     SUMA for visualization.\n"
03165                "      -face_normals: Outputs segments along triangle normals.\n"
03166                "                     Segments begin at centroid of triangles and \n"
03167                "                     have a default magnitude of 1. See option \n"
03168                "                     'Alt+Ctrl+s' in SUMA for visualization.\n"
03169                "      -normals_scale SCALE: Scale the normals by SCALE (1.0 default)\n"
03170                "                     For use with options -node_normals and -face_normals\n"
03171                "      -coords: Output coords of each node after any transformation \n"
03172                "         that is normally carried out by SUMA on such a surface.\n"
03173                "         Col. 0: Node Index\n"
03174                "         Col. 1: X\n"
03175                "         Col. 2: Y\n"
03176                "         Col. 3: Z\n"     
03177                "      -sph_coords: Output spherical coords of each node.\n"
03178                "      -sph_coords_center x y z: Shift each node by  x y z\n"
03179                "                                before calculating spherical\n"
03180                "                                coordinates. Default is the\n"
03181                "                                center of the surface.\n"
03182                "          Both sph_coords options output the following:\n"
03183                "          Col. 0: Node Index\n"
03184                "          Col. 1: R (radius)\n"
03185                "          Col. 2: T (azimuth)\n"
03186                "          Col. 3: P (elevation)\n" 
03187                "\n"
03188                "      You can use any or all of these metrics simultaneously.\n"
03189                "\n"
03190                "   -spec SpecFile: Name of specfile containing surface of interest.\n"
03191                "                   If the surface does not have a spec file, use the \n"
03192                "                   program quickspec to create one.\n"
03193                "   -surf_A insurf: Name of surface of interest. \n"
03194                "                   NOTE: i_TYPE inSurf option is now obsolete.\n"
03195                "\n"
03196                "   -sv SurfaceVolume [VolParam for sf surfaces]: Specify a surface volume\n"
03197                "                   for surface alignment. See ConvertSurface -help for more info.\n"
03198                "\n"
03199                "   -tlrc: Apply Talairach transform to surface.\n"
03200                "                   See ConvertSurface -help for more info.\n"
03201                "\n"
03202                "   -prefix prefix: Use prefix for output files. (default is prefix of inSurf)\n"
03203                "%s"
03204                "\n", s);
03205       SUMA_free(s); s = NULL;
03206       s = SUMA_New_Additions(0, 1); printf("%s\n", s);SUMA_free(s); s = NULL;
03207       printf ( "       Ziad S. Saad SSCC/NIMH/NIH ziad@nih.gov \n"
03208                "       Mon May 19 15:41:12 EDT 2003\n"
03209                "\n");   
03210    }
03211 #define SURFACEMETRICS_MAX_SURF 10
03212 
03213 int main (int argc,char *argv[])
03214 {/* Main */
03215    static char FuncName[]={"Main_SUMA_SurfaceMetrics"};
03216    char  *OutName=NULL, *OutPrefix = NULL, *if_name = NULL, 
03217          *if_name2 = NULL, *sv_name = NULL, *vp_name = NULL,
03218          *tlrc_name = NULL;
03219    float *Cx = NULL, sph_center[3], NormScale;
03220    SUMA_STRING *MetricList = NULL;
03221    int i, n1, n2, n1_3, n2_3, kar, nt, SO_read;
03222    double edgeL2;
03223    FILE *fout=NULL;
03224    SUMA_SO_File_Type iType = SUMA_FT_NOT_SPECIFIED;
03225    SUMA_SurfaceObject *SO = NULL;   
03226    SUMA_SFname *SF_name = NULL;
03227    void *SO_name = NULL;   
03228    SUMA_SurfSpecFile Spec;
03229    THD_warp *warp=NULL ;
03230    THD_3dim_dataset *aset=NULL;
03231    char *surf_names[SURFACEMETRICS_MAX_SURF];
03232    char *spec_file, *histnote;
03233    int insurf_method = 0, N_surf = 0, ind = 0;
03234    SUMA_Boolean   brk, Do_tlrc, Do_conv, Do_curv, 
03235                   Do_area, Do_edges, Do_vol, Do_sph, NewCent, Do_cord, Do_TriNorm, Do_NodeNorm, LocalHead = NOPE;  
03236    
03237    SUMA_mainENTRY;
03238    
03239         SUMA_STANDALONE_INIT;
03240    
03241         /* Allocate space for DO structure */
03242         SUMAg_DOv = SUMA_Alloc_DisplayObject_Struct (SUMA_MAX_DISPLAYABLE_OBJECTS);
03243 
03244    if (argc < 4)
03245        {
03246           SUMA_S_Err("Too few parameters");
03247           usage_SUMA_SurfaceMetrics ();
03248           exit (1);
03249        }
03250    
03251    MetricList = SUMA_StringAppend (NULL, NULL);
03252    kar = 1;
03253         brk = NOPE;
03254    Do_cord = NOPE;
03255    Do_sph = NOPE;
03256    Do_vol = NOPE;
03257    Do_tlrc = NOPE;
03258    Do_conv = NOPE;
03259    Do_area = NOPE;
03260    Do_curv = NOPE;
03261    Do_edges = NOPE;
03262    Do_TriNorm = NOPE;
03263    Do_NodeNorm = NOPE;
03264    NormScale = 5.0;
03265    NewCent = NOPE;
03266    OutPrefix = NULL;
03267    for (i=0; i<SURFACEMETRICS_MAX_SURF; ++i) { surf_names[i] = NULL; }   
03268    spec_file = NULL;
03269 
03270         while (kar < argc) { /* loop accross command ine options */
03271                 /* fprintf(stdout, "%s verbose: Parsing command line...\n", FuncName); */
03272                 if (strcmp(argv[kar], "-h") == 0 || strcmp(argv[kar], "-help") == 0) {
03273                          usage_SUMA_SurfaceMetrics();
03274           exit (1);
03275                 }
03276                 
03277       SUMA_SKIP_COMMON_OPTIONS(brk, kar);
03278       
03279                 if (!brk && (strcmp(argv[kar], "-i_fs") == 0)) {
03280          SUMA_SL_Err("Option -i_fs is obsolete.\nUse -spec and -surf_A instead.\n");
03281          exit(1);
03282          kar ++;
03283                         if (kar >= argc)  {
03284                                 fprintf (SUMA_STDERR, "need argument after -i_fs ");
03285                                 exit (1);
03286                         }
03287                         if_name = argv[kar];
03288          iType = SUMA_FREE_SURFER;
03289                         brk = YUP;
03290                 }
03291       
03292       if (!brk && (strcmp(argv[kar], "-i_sf") == 0)) {
03293          SUMA_SL_Err("Option -i_sf is obsolete.\nUse -spec and -surf_A instead.\n");
03294          exit(1);
03295          kar ++;
03296                         if (kar+1 >= argc)  {
03297                                 fprintf (SUMA_STDERR, "need 2 argument after -i_sf");
03298                                 exit (1);
03299                         }
03300                         if_name = argv[kar]; kar ++;
03301          if_name2 = argv[kar];
03302          iType = SUMA_SUREFIT;
03303                         brk = YUP;
03304                 }
03305       
03306       if (!brk && (strcmp(argv[kar], "-i_vec") == 0)) {
03307          SUMA_SL_Err("Option -i_vec is obsolete.\nUse -spec and -surf_A instead.\n");
03308          exit(1);
03309          kar ++;
03310                         if (kar+1 >= argc)  {
03311                                 fprintf (SUMA_STDERR, "need 2 argument after -i_vec");
03312                                 exit (1);
03313                         }
03314                         if_name = argv[kar]; kar ++;
03315          if_name2 = argv[kar];
03316          iType = SUMA_VEC;
03317                         brk = YUP;
03318                 }
03319       
03320       if (!brk && (strcmp(argv[kar], "-i_ply") == 0)) {
03321          SUMA_SL_Err("Option -i_ply is obsolete.\nUse -spec and -surf_A instead.\n");
03322          exit(1);
03323          kar ++;
03324                         if (kar >= argc)  {
03325                                 fprintf (SUMA_STDERR, "need argument after -i_ply ");
03326                                 exit (1);
03327                         }
03328                         if_name = argv[kar];
03329          iType = SUMA_PLY;
03330                         brk = YUP;
03331                 }
03332       
03333       if (!brk && (strcmp(argv[kar], "-spec") == 0)) {
03334          kar ++;
03335                         if (kar >= argc)  {
03336                                 fprintf (SUMA_STDERR, "need argument after -spec \n");
03337                                 exit (1);
03338                         }
03339                         spec_file = argv[kar];
03340          if (!insurf_method) insurf_method = 2;
03341          else {
03342             fprintf (SUMA_STDERR, "already specified spec file.\n");
03343             exit(1);
03344          }
03345                         brk = YUP;
03346                 }
03347       
03348       if (!brk && (strncmp(argv[kar], "-surf_", 6) == 0)) {
03349                         if (kar + 1>= argc)  {
03350                                 fprintf (SUMA_STDERR, "need argument after -surf_X SURF_NAME \n");
03351                                 exit (1);
03352                         }
03353                         ind = argv[kar][6] - 'A';
03354          if (ind < 0 || ind >= SURFACEMETRICS_MAX_SURF) {
03355             fprintf (SUMA_STDERR, "-surf_X SURF_NAME option is out of range,\n"
03356                                   "   only surf_A allowed.\n");
03357                                 exit (1);
03358          }
03359          kar ++;
03360          surf_names[ind] = argv[kar];
03361          N_surf = ind+1;
03362                         if (insurf_method != 2) {
03363             fprintf (SUMA_STDERR, "-surf_X SURF_NAME option must be used with -spec option.\n");
03364             exit(1);
03365          }
03366          brk = YUP;
03367                 }
03368       
03369       if (!brk && (strcmp(argv[kar], "-sph_coords_center") == 0)) {
03370          kar ++;
03371                         if (kar+2 >= argc)  {
03372                                 fprintf (SUMA_STDERR, "need 3 arguments after -sph_coords_center \n");
03373                                 exit (1);
03374                         }
03375                         sph_center[0] = atof(argv[kar]); kar ++;
03376          sph_center[1] = atof(argv[kar]); kar ++;
03377          sph_center[2] = atof(argv[kar]);
03378          NewCent = YUP;
03379          Do_sph = YUP;
03380                         brk = YUP;
03381                 }
03382       
03383       if (!brk && (strcmp(argv[kar], "-sph_coords") == 0)) {
03384          Do_sph = YUP;
03385                         brk = YUP;
03386                 }
03387       
03388       if (!brk && (strcmp(argv[kar], "-coords") == 0)) {
03389          Do_cord = YUP;
03390                         brk = YUP;
03391                 }
03392       
03393       if (!brk && (strcmp(argv[kar], "-prefix") == 0)) {
03394          kar ++;
03395                         if (kar >= argc)  {
03396                                 fprintf (SUMA_STDERR, "need argument after -prefix ");
03397                                 exit (1);
03398                         }
03399                         OutPrefix = SUMA_copy_string(argv[kar]);
03400                         brk = YUP;
03401                 }
03402       
03403       if (!brk && (strcmp(argv[kar], "-sv") == 0)) {
03404          if (iType == SUMA_FT_NOT_SPECIFIED) {
03405             fprintf (SUMA_STDERR, " -sv option must be preceeded by -i_TYPE option.");
03406             exit(1);
03407          }
03408          kar ++;
03409                         if (iType == SUMA_SUREFIT) {
03410             if (kar+1 >= argc)  {
03411                                    fprintf (SUMA_STDERR, "need 2 argument after -sv (SurfaceVolume and VolumeParent)");
03412                                    exit (1);
03413                            }
03414             sv_name = argv[kar]; kar ++;
03415             vp_name = argv[kar];
03416          } else {
03417             if (kar >= argc)  {
03418                                    fprintf (SUMA_STDERR, "need argument after -sv ");
03419                                    exit (1);
03420                            }
03421                            sv_name = argv[kar];
03422          }
03423                         brk = YUP;
03424                 }
03425 
03426       if (!brk && (strcmp(argv[kar], "-tlrc") == 0)) {
03427          Do_tlrc = YUP;
03428          brk = YUP;
03429       }
03430       if (!brk && (strcmp(argv[kar], "-node_normals") == 0)) {
03431          Do_NodeNorm = YUP;
03432          brk = YUP;
03433       }
03434       if (!brk && (strcmp(argv[kar], "-face_normals") == 0)) {
03435          Do_TriNorm = YUP;
03436          brk = YUP;
03437       }
03438       if (!brk && (strcmp(argv[kar], "-normals_scale") == 0)) {
03439          kar ++;
03440                         if (kar >= argc)  {
03441                                 fprintf (SUMA_STDERR, "need argument after -normals_scale ");
03442                                 exit (1);
03443                         }
03444          NormScale = atof(argv[kar]);
03445          brk = YUP;
03446       }
03447       
03448       if (!brk && (strcmp(argv[kar], "-conv") == 0)) {
03449          Do_conv = YUP;
03450          MetricList = SUMA_StringAppend (MetricList, "Convexity "); 
03451          brk = YUP;
03452       }
03453       
03454       if (!brk && (strcmp(argv[kar], "-area") == 0)) {
03455          Do_area = YUP;
03456          MetricList = SUMA_StringAppend (MetricList, "PolyArea "); 
03457          brk = YUP;
03458       }
03459 
03460       if (!brk && (strcmp(argv[kar], "-curv") == 0)) {
03461          Do_curv = YUP;
03462          MetricList = SUMA_StringAppend (MetricList, "Curvature "); 
03463          brk = YUP;
03464       }
03465       
03466       if (!brk && (strcmp(argv[kar], "-edges") == 0)) {
03467          Do_edges = YUP;
03468          MetricList = SUMA_StringAppend (MetricList, "EdgeList "); 
03469          brk = YUP;
03470       }
03471       
03472       if (!brk && (strcmp(argv[kar], "-vol") == 0)) {
03473          Do_vol = YUP;
03474          brk = YUP;
03475       }
03476       
03477       if (!brk) {
03478                         fprintf (SUMA_STDERR,"Error %s: Option %s not understood. Try -help for usage\n", FuncName, argv[kar]);
03479                         exit (1);
03480                 } else {        
03481                         brk = NOPE;
03482                         kar ++;
03483                 }
03484    }
03485    
03486    if (N_surf < 1) {
03487       SUMA_SL_Err("No surface specified.");
03488       exit(1);
03489    }
03490 
03491    /* clean MetricList */
03492    MetricList = SUMA_StringAppend (MetricList, NULL); 
03493    
03494    /* sanity checks */
03495    if (!strlen(MetricList->s) && !Do_vol && !Do_sph && !Do_cord && !Do_TriNorm && !Do_NodeNorm) {
03496       SUMA_S_Err("No Metrics specified.\nNothing to do.\n");
03497       exit(1);
03498    }
03499    
03500    if (sv_name) {
03501       if (!SUMA_filexists(sv_name)) {
03502          fprintf (SUMA_STDERR,"Error %s: %s not found.\n", FuncName, sv_name);
03503          exit(1);
03504       }
03505    }
03506    
03507    if (Do_tlrc && !sv_name) {
03508       fprintf (SUMA_STDERR,"Error %s: -tlrc must be used with -sv option.\n", FuncName);
03509       exit(1);
03510    }
03511    
03512    if (vp_name) {
03513       if (!SUMA_filexists(vp_name)) {
03514          fprintf (SUMA_STDERR,"Error %s: %s not found.\n", FuncName, vp_name);
03515          exit(1);
03516       }
03517    }
03518 
03519    
03520    /* read all surfaces */
03521    if (!SUMA_Read_SpecFile (spec_file, &Spec)) {
03522                 fprintf(SUMA_STDERR,"Error %s: Error in SUMA_Read_SpecFile\n", FuncName);
03523                 exit(1);
03524         }
03525    SO_read = SUMA_spec_select_surfs(&Spec, surf_names, SURFACEMETRICS_MAX_SURF, 0);
03526    if ( SO_read != N_surf )
03527    {
03528            if (SO_read >=0 )
03529          fprintf(SUMA_STDERR,"Error %s:\nFound %d surfaces, expected %d.\n", FuncName,  SO_read, N_surf);
03530       exit(1);
03531    }
03532    
03533    /* now read into SUMAg_DOv */
03534    if (!SUMA_LoadSpec_eng(&Spec, SUMAg_DOv, &SUMAg_N_DOv, sv_name, 0, SUMAg_CF->DsetList) ) {
03535            fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_LoadSpec_eng\n", FuncName);
03536       exit(1);
03537    }   SO = SUMA_find_named_SOp_inDOv(surf_names[0], SUMAg_DOv, SUMAg_N_DOv);
03538    if (!SO) {
03539       fprintf (SUMA_STDERR,"Error %s: Failed to read input surface.\n", FuncName);
03540       exit (1);
03541    }
03542    
03543    if (Do_tlrc) {
03544       fprintf (SUMA_STDOUT,"Performing talairach transform...\n");
03545 
03546       /* form the tlrc version of the surface volume */
03547       tlrc_name = (char *) SUMA_calloc (strlen(SO->VolPar->dirname)+strlen(SO->VolPar->prefix)+60, sizeof(char));
03548       sprintf (tlrc_name, "%s%s+tlrc.HEAD", SO->VolPar->dirname, SO->VolPar->prefix);
03549       if (!SUMA_filexists(tlrc_name)) {
03550          fprintf (SUMA_STDERR,"Error %s: %s not found.\n", FuncName, tlrc_name);
03551          exit(1);
03552       }
03553       
03554       /* read the tlrc header */
03555       aset = THD_open_dataset(tlrc_name) ;
03556       if( !ISVALID_DSET(aset) ){
03557          fprintf (SUMA_STDERR,"Error %s: %s is not a valid data set.\n", FuncName, tlrc_name) ;
03558          exit(1);
03559       }
03560       if( aset->warp == NULL ){
03561          fprintf (SUMA_STDERR,"Error %s: tlrc_name does not contain a talairach transform.\n", FuncName);
03562          exit(1);
03563       }
03564       
03565       warp = aset->warp ;
03566       
03567       /* now warp the coordinates, one node at a time */
03568       if (!SUMA_AFNI_forward_warp_xyz(warp, SO->NodeList, SO->N_Node)) {
03569          fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_AFNI_forward_warp_xyz.\n", FuncName);
03570          exit(1);
03571       }
03572 
03573       
03574       
03575    }
03576    
03577    /* check on normals */
03578    if ((Do_TriNorm || Do_NodeNorm) && (!SO->NodeNormList || !SO->FaceNormList)) {
03579       SUMA_RECOMPUTE_NORMALS(SO);
03580    }
03581    
03582    /* create the surface label*/
03583    SO->Label = SUMA_SurfaceFileName (SO, NOPE);
03584    if (!SO->Label) {
03585       SUMA_S_Err("Failed to create Label");
03586       exit(1);
03587    }
03588 
03589    if (LocalHead) SUMA_Print_Surface_Object (SO, stderr);
03590    
03591    /* Now do the deed */
03592    SUMA_LH (MetricList->s);
03593    if (strlen(MetricList->s)) {
03594       if (!SUMA_SurfaceMetrics (SO, MetricList->s, NULL)) {
03595          fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_SurfaceMetrics.\n", FuncName);
03596          exit(1);
03597       }
03598    }
03599 
03600    SUMA_LH ("Done with Metrics");
03601    
03602    /* output time */
03603    if (!OutPrefix) {
03604       OutPrefix = SUMA_copy_string(SO->Label);
03605    }
03606    
03607    OutName = (char*) SUMA_malloc((strlen(OutPrefix) + 30) * sizeof(char));
03608    histnote = SUMA_HistString (NULL, argc, argv, NULL);
03609    
03610    if (Do_sph) {
03611       float *sph=NULL;
03612       sprintf(OutName, "%s.sphcoord.1D.dset", OutPrefix);
03613       if (SUMA_filexists(OutName)) {
03614          SUMA_S_Err("Edge output file exists.\nWill not overwrite.");
03615          exit(1);
03616       }
03617       if (NewCent) ;
03618       else if (SO->Center) { SUMA_COPY_VEC(SO->Center, sph_center, 3, float, float); }
03619       else {
03620          SUMA_SL_Err("SO has no center");
03621          exit(1);
03622       }
03623       sph = SUMA_Cart2Sph(SO->NodeList, SO->N_Node, sph_center);
03624 
03625       fout = fopen(OutName,"w");
03626       if (!fout) {
03627          SUMA_S_Err("Failed to open file for writing.\nCheck your permissions.\n");
03628          exit(1);
03629       }
03630       
03631       fprintf (fout,"#Spherical coords, \n");
03632       fprintf (fout,"#  cartesian coords shifted by [%f %f %f] prior to xform\n", sph_center[0], sph_center[1], sph_center[2]);
03633       fprintf (fout,"#nI = Node Index\n");
03634       fprintf (fout,"#r  = Rho (radius)\n");
03635       fprintf (fout,"#t  = theta(azimuth)\n");
03636       fprintf (fout,"#p  = phi(elevation)\n");
03637       fprintf (fout,"#nI\tr\tt\tp\n\n");
03638       if (histnote) fprintf (fout,"#History:%s\n", histnote);
03639       
03640       for (i=0; i < SO->N_Node; ++i) {
03641             fprintf (fout,"%d\t%f\t%f\t%f\n",
03642                   i, sph[3*i], sph[3*i+1],sph[3*i+2]);
03643       }
03644       
03645       fclose(fout); fout = NULL;
03646       
03647       if (sph) SUMA_free(sph); sph = NULL;
03648    }  
03649    
03650    if (Do_NodeNorm) {
03651       float norm[3];
03652       sprintf(OutName, "%s.NodeNormSeg.1D", OutPrefix);
03653       if (SUMA_filexists(OutName)) {
03654          SUMA_S_Err("Node normals output file exists.\nWill not overwrite.");
03655          exit(1);
03656       }
03657       fout = fopen(OutName,"w");
03658       if (!fout) {
03659          SUMA_S_Err("Failed to open file for writing.\nCheck your permissions.\n");
03660          exit(1);
03661       }
03662       
03663       fprintf (fout,"#Node normals.\n");
03664       fprintf (fout,"#  Segments from node along the direction of the normal (of magnitude %f)\n", NormScale);
03665       fprintf (fout,"#  1st three columns are node's coordinates\n");
03666       fprintf (fout,"#  2nd three columns are the coordinate of a second point along the normal\n");
03667       if (histnote) fprintf (fout,"#History:%s\n", histnote);
03668       
03669       for (i=0; i<SO->N_Node; ++i) {
03670          norm[0] = SO->NodeNormList[3*i]; norm[1] = SO->NodeNormList[3*i+1]; norm[2] = SO->NodeNormList[3*i+2];
03671          /* normal is expected to be normalized...*/
03672          norm[0] *= NormScale; norm[1] *= NormScale; norm[2] *= NormScale;
03673          fprintf (fout,"%f %f %f \t%f %f %f\n", 
03674             SO->NodeList[3*i], SO->NodeList[3*i+1], SO->NodeList[3*i+2], 
03675             SO->NodeList[3*i]+norm[0], SO->NodeList[3*i+1]+norm[1], SO->NodeList[3*i+2]+norm[2]);            
03676       }
03677       
03678       fclose(fout); fout = NULL;
03679       
03680    }
03681    
03682    if (Do_TriNorm) {
03683       float tc[3], norm[3];
03684       int n1, n2, n3;
03685       if (SO->FaceSetDim != 3) {
03686          SUMA_S_Err("Triangular meshes only please.");
03687          exit(1);
03688       }
03689       sprintf(OutName, "%s.TriNormSeg.1D", OutPrefix);
03690       if (SUMA_filexists(OutName)) {
03691          SUMA_S_Err("Triangle normals output file exists.\nWill not overwrite.");
03692          exit(1);
03693       }
03694       fout = fopen(OutName,"w");
03695       if (!fout) {
03696          SUMA_S_Err("Failed to open file for writing.\nCheck your permissions.\n");
03697          exit(1);
03698       }
03699       
03700       fprintf (fout,"#Triangle normals.\n");
03701       fprintf (fout,"#  Segments from centroid of triangle along the direction of the normal (of magnitude %f)\n", NormScale);
03702       fprintf (fout,"#  1st three columns are centroid's coordinates\n");
03703       fprintf (fout,"#  2nd three columns are the coordinate of a second point along the normal\n");
03704       if (histnote) fprintf (fout,"#History:%s\n", histnote);
03705       
03706       for (i=0; i<SO->N_FaceSet; ++i) {
03707          n1 = SO->FaceSetList[3*i]; n2 = SO->FaceSetList[3*i+1]; n3 = SO->FaceSetList[3*i+2];
03708          /* coordinate of centroid */
03709          tc[0] = (SO->NodeList[3*n1]   + SO->NodeList[3*n2]   + SO->NodeList[3*n3]  )/3; /* centroid of triangle */
03710          tc[1] = (SO->NodeList[3*n1+1] + SO->NodeList[3*n2+1] + SO->NodeList[3*n3+1])/3; 
03711          tc[2] = (SO->NodeList[3*n1+2] + SO->NodeList[3*n2+2] + SO->NodeList[3*n3+2])/3;
03712          norm[0] = SO->FaceNormList[3*i]; norm[1] = SO->FaceNormList[3*i+1]; norm[2] = SO->FaceNormList[3*i+2];
03713          /* normal is expected to be normalized...*/
03714          norm[0] *= NormScale; norm[1] *= NormScale; norm[2] *= NormScale;
03715          fprintf (fout,"%f %f %f \t%f %f %f\n", tc[0], tc[1], tc[2], tc[0]+norm[0], tc[1]+norm[1], tc[2]+norm[2]);            
03716       }
03717       
03718       fclose(fout); fout = NULL;
03719    }
03720    
03721    if (Do_cord) {
03722       sprintf(OutName, "%s.coord.1D.dset", OutPrefix);
03723       if (SUMA_filexists(OutName)) {
03724          SUMA_S_Err("Edge output file exists.\nWill not overwrite.");
03725          exit(1);
03726       }
03727       
03728       fout = fopen(OutName,"w");
03729       if (!fout) {
03730          SUMA_S_Err("Failed to open file for writing.\nCheck your permissions.\n");
03731          exit(1);
03732       }
03733       
03734       fprintf (fout,"#Cartesian coords, \n");
03735       fprintf (fout,"#  Center is: [%f %f %f] \n", SO->Center[0], SO->Center[1], SO->Center[2]);
03736       fprintf (fout,"#nI = Node Index\n");
03737       fprintf (fout,"#x  = X \n");
03738       fprintf (fout,"#y  = Y\n");
03739       fprintf (fout,"#z  = Z\n");
03740       fprintf (fout,"#nI\tx\ty\tz\n\n");
03741       if (histnote) fprintf (fout,"#History:%s\n", histnote);
03742       
03743       for (i=0; i < SO->N_Node; ++i) {
03744             fprintf (fout,"%d\t%f\t%f\t%f\t\n",
03745                   i, SO->NodeList[3*i], SO->NodeList[3*i+1],SO->NodeList[3*i+2]);
03746       }
03747       
03748       fclose(fout); fout = NULL;
03749    }  
03750    
03751    if (Do_edges) {
03752       
03753       SUMA_S_Note("Writing edges...");
03754       
03755       if (!SO->EL) {
03756          SUMA_S_Err("Edge list not computed.");
03757          exit(1);
03758       }
03759       
03760       sprintf(OutName, "%s.edges", OutPrefix);
03761       if (SUMA_filexists(OutName)) {
03762          SUMA_S_Err("Edge output file exists.\nWill not overwrite.");
03763          exit(1);
03764       }
03765       
03766       fout = fopen(OutName,"w");
03767       if (!fout) {
03768          SUMA_S_Err("Failed to open file for writing.\nCheck your permissions.\n");
03769          exit(1);
03770       }
03771       
03772       fprintf (fout,"#Edge List\n");
03773       fprintf (fout,"#eI = Edge Index\n");
03774       fprintf (fout,"#n1 = Node 1\n");
03775       fprintf (fout,"#n2 = Node 2\n");
03776       fprintf (fout,"#nt = Number of triangles containing edge\n"); 
03777       fprintf (fout,"#eL = Edge Length\n");
03778       fprintf (fout,"#eI\tn1\tn2\tnt\teL\n\n");
03779       if (histnote) fprintf (fout,"#History:%s\n", histnote);
03780       
03781       for (i=0; i < SO->EL->N_EL; ++i) {
03782          if (SO->EL->ELps[i][2] >= 0) {
03783             n1 = SO->EL->EL[i][0];
03784             n2 = SO->EL->EL[i][1];
03785             nt = SO->EL->ELps[i][2];
03786             n1_3 = 3 * n1;
03787             n2_3 = 3 * n2;
03788             edgeL2 = ( (SO->NodeList[n2_3] - SO->NodeList[n1_3]) * (SO->NodeList[n2_3] - SO->NodeList[n1_3]) ) +
03789                      ( (SO->NodeList[n2_3+1] - SO->NodeList[n1_3+1]) * (SO->NodeList[n2_3+1] - SO->NodeList[n1_3+1]) ) +
03790                      ( (SO->NodeList[n2_3+2] - SO->NodeList[n1_3+2]) * (SO->NodeList[n2_3+2] - SO->NodeList[n1_3+2]) ); 
03791                      
03792             fprintf (fout,"%d\t%d\t%d\t%d\t%f\n",
03793                   i, n1, n2, nt, sqrt(edgeL2));
03794                   
03795          }   
03796       }
03797       fclose(fout); fout = NULL;
03798       
03799    }
03800    
03801    if (Do_area) {
03802       SUMA_S_Note("Writing areas...");
03803       
03804       if (!SO->PolyArea) {
03805          SUMA_S_Err("Areas not computed");
03806          exit(1);
03807       }  
03808       
03809       sprintf(OutName, "%s.area", OutPrefix);
03810       if (SUMA_filexists(OutName)) {
03811          SUMA_S_Err("Area output file exists.\nWill not overwrite.");
03812          exit(1);
03813       }
03814       
03815       fout = fopen(OutName,"w");
03816       if (!fout) {
03817          SUMA_S_Err("Failed to open file for writing.\nCheck your permissions.\n");
03818          exit(1);
03819       }
03820       
03821       fprintf (fout,"#FaceSet Area\n");
03822       fprintf (fout,"#fI = FaceSet Index\n");
03823       fprintf (fout,"#fA = FaceSet Area\n");
03824       fprintf (fout,"#fI\t#fA\n\n");
03825       if (histnote) fprintf (fout,"#History:%s\n", histnote);
03826       for (i=0; i < SO->N_FaceSet; ++i) {
03827          fprintf (fout,"%d\t%f\n", i, SO->PolyArea[i]);
03828       }  
03829       
03830       fclose(fout); fout = NULL;
03831    }
03832    
03833    if (Do_curv) {
03834       SUMA_S_Note("Writing curvatures ...");
03835       
03836       if (!SO->SC) {
03837          SUMA_S_Err("Curvatures not computed");
03838          exit(1);
03839       }
03840       
03841       sprintf(OutName, "%s.curv.1D.dset", OutPrefix);
03842       if (SUMA_filexists(OutName)) {
03843          SUMA_S_Err("Curvature output file exists.\nWill not overwrite.");
03844          exit(1);
03845       }
03846       
03847       fout = fopen(OutName,"w");
03848       if (!fout) {
03849          SUMA_S_Err("Failed to open file for writing.\nCheck your permissions.\n");
03850          exit(1);
03851       }  
03852       
03853       fprintf (fout,"#Curvature\n");
03854       fprintf (fout,"#nI = Node Index\n");
03855       fprintf (fout,"#T1 = 1 x 3 vector of 1st principal direction of surface\n");
03856       fprintf (fout,"#T2 = 1 x 3 vector of 2nd principal direction of surface\n");
03857       fprintf (fout,"#Kp1 = curvature along T1\n");
03858       fprintf (fout,"#Kp2 = curvature along T2\n");
03859       fprintf (fout,"#nI\tT1[0]\tT1[1]\tT1[2]\tT2[0]\tT2[1]\tT2[2]\tKp1\tKp2\n\n");
03860       if (histnote) fprintf (fout,"#History:%s\n", histnote);
03861       
03862       for (i=0; i < SO->N_Node; ++i) {
03863          fprintf (fout,"%d\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\n",
03864             i, SO->SC->T1[i][0], SO->SC->T1[i][1], SO->SC->T1[i][2], 
03865             SO->SC->T2[i][0], SO->SC->T2[i][1], SO->SC->T2[i][2],
03866             SO->SC->Kp1[i], SO->SC->Kp2[i] );
03867       }
03868       
03869       fclose(fout); fout = NULL;
03870    }
03871    
03872    if (Do_conv) {
03873       SUMA_S_Note("Writing convexities ...");
03874       Cx = (float *)SUMA_GetCx(SO->idcode_str, SUMAg_CF->DsetList, 0);
03875       if (!Cx) {
03876          SUMA_S_Err("Convexities not computed");
03877          exit(1);
03878       }
03879       
03880       sprintf(OutName, "%s.conv.1D.dset", OutPrefix);
03881       if (SUMA_filexists(OutName)) {
03882          SUMA_S_Err("Convexities output file exists.\nWill not overwrite.");
03883          exit(1);
03884       }
03885       
03886       fout = fopen(OutName,"w");
03887       if (!fout) {
03888          SUMA_S_Err("Failed to open file for writing.\nCheck your permissions.\n");
03889          exit(1);
03890       }  
03891       
03892       fprintf (fout,"#Convexity\n");
03893       fprintf (fout,"nI = Node Index\n");
03894       fprintf (fout,"C = Convexity\n");
03895       fprintf (fout,"#nI\tC\n\n");
03896       if (histnote) fprintf (fout,"#History:%s\n", histnote);
03897       
03898       for (i=0; i < SO->N_Node; ++i) {
03899          fprintf (fout,"%d\t%f\n", i, Cx[i]);
03900       }
03901       
03902       fclose(fout); fout = NULL;
03903    }   
03904    
03905    if (Do_vol) {
03906       float vol;
03907       fprintf (SUMA_STDOUT,"Calculating surface volume...\n");
03908       vol = SUMA_Mesh_Volume(SO, NULL, -1);
03909       fprintf (SUMA_STDERR,   "Volume of closed surface is %f (units3).\n"
03910                               "Signed volume is  %f (units3).\n", fabs(vol), vol); 
03911    }
03912    
03913    SUMA_LH("Clean up");
03914    /* clean up */
03915    if (MetricList) SUMA_free(MetricList);
03916    if (OutPrefix) SUMA_free(OutPrefix);
03917    if (OutName) SUMA_free(OutName);   
03918    if (SO) SUMA_Free_Surface_Object(SO);
03919    
03920    /* dset and its contents are freed in SUMA_Free_CommonFields */
03921    if (!SUMA_Free_CommonFields(SUMAg_CF)) SUMA_error_message(FuncName,"SUMAg_CF Cleanup Failed!",1);
03922 
03923    if (histnote) SUMA_free(histnote);
03924    
03925    SUMA_RETURN(0);
03926 } /* Main */
03927 #endif
03928 
03929 #ifdef SUMA_Read_SpecFile_STAND_ALONE
03930 
03931 void usage_SUMA_Read_SpecFile ()
03932    
03933   {/*Usage*/
03934           printf ("\nUsage:  SUMA_Read_SpecFile <fname> \n");
03935           printf ("\t <fname> Filename of Surface Specs file\n");
03936           printf ("To compile: \ngcc -DSUMA_Read_SpecFile_STAND_ALONE -Wall -o SUMA_Load_Surface_Object  SUMA_Load_Surface_Object.c ");
03937           printf ("SUMA_lib.a libmri.a -I/usr/X11R6/include -I./ -L/usr/lib -L/usr/X11R6/lib -lm \n");
03938           printf ("\t\t\t Ziad S. Saad SSCC/NIMH/NIH ziad@nih.gov \n");
03939           exit (0);
03940   }/*Usage*/
03941   
03942 int main (int argc,char *argv[])
03943 {/* Main */
03944    char FuncName[]={"Main_SUMA_Read_SpecFile"};
03945    SUMA_SurfSpecFile Spec;   
03946    
03947    if (argc < 2)
03948        {
03949           usage_SUMA_Read_SpecFile ();
03950           exit (1);
03951        }
03952 
03953    /* allocate space for CommonFields structure */
03954    SUMAg_CF = SUMA_Create_CommonFields ();
03955    if (SUMAg_CF == NULL) {
03956       fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_Create_CommonFields\n", FuncName);
03957       exit(1);
03958    }
03959    
03960 
03961    if (!SUMA_Read_SpecFile (argv[1], &Spec)) {
03962       fprintf(SUMA_STDERR,"Error %s: Error in SUMA_Read_SpecFile\n", FuncName);
03963       if (!SUMA_Free_CommonFields(SUMAg_CF)) SUMA_error_message(FuncName,"SUMAg_CF Cleanup Failed!",1);
03964       return (1);
03965    }   else    {      
03966       if (!SUMA_Free_CommonFields(SUMAg_CF)) SUMA_error_message(FuncName,"SUMAg_CF Cleanup Failed!",1);
03967       return (0);
03968    }
03969 } /* Main */
03970 
03971 #endif
03972 
03973 #ifdef SUMA_Load_Surface_Object_STAND_ALONE
03974 
03975 void usage_SUMA_Load_Surface_Object_STAND_ALONE ()
03976    
03977   {/*Usage*/
03978           printf ("\nUsage:  SUMA_Load_Surface_Object <SurfName> [<Type> <format>]\n");
03979           printf ("\t <SurfName> Filename of Surface Object\n");
03980           printf ("\t <Type>: 2 (hard coded at the moment for SUMA_INVENTOR_GENERIC)\n");
03981           printf ("\t <format>: 0 (hard coded at the moment for SUMA_ASCII\n"); 
03982           printf ("To compile: \ngcc -DSUMA_Load_Surface_Object_STAND_ALONE -Wall -o SUMA_Load_Surface_Object SUMA_Load_Surface_Object.c ");
03983           printf ("SUMA_lib.a  -I/usr/X11R6/include -I./ -L/usr/lib -L/usr/X11R6/lib -lm \n");
03984           printf ("-lGL -lGLU -lGLw -lXmu -lXm -lXt -lXext -lX11 -lMesaGLw -lMesaGLw\n");
03985           printf ("\t\t\t Ziad S. Saad SSCC/NIMH/NIH ziad@nih.gov \tWed Jan 23 15:18:12 EST 2002 \n");
03986           exit (0);
03987   }/*Usage*/
03988    
03989 int main (int argc,char *argv[])
03990 {/* Main */
03991    char FuncName[100]; 
03992    SUMA_SurfaceObject *SO;
03993    
03994    /* allocate space for CommonFields structure */
03995    SUMAg_CF = SUMA_Create_CommonFields ();
03996    if (SUMAg_CF == NULL) {
03997       fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_Create_CommonFields\n", FuncName);
03998       exit(1);
03999    }
04000    
04001    /* initialize Main function name for verbose output */
04002    sprintf (FuncName,"SUMA_Load_Surface_Object-Main-");
04003    
04004    
04005    
04006    if (argc < 2)
04007        {
04008           usage_SUMA_Load_Surface_Object_STAND_ALONE ();
04009           exit (1);
04010        }
04011    
04012    SO = SUMA_Load_Surface_Object((void *)argv[1], SUMA_INVENTOR_GENERIC, SUMA_ASCII, NULL);
04013    SUMA_Print_Surface_Object (SO, stdout);
04014    SUMA_Free_Surface_Object (SO);
04015 
04016    if (!SUMA_Free_CommonFields(SUMAg_CF)) SUMA_error_message(FuncName,"SUMAg_CF Cleanup Failed!",1);
04017 
04018    return (0);
04019 }/* Main */
04020 #endif
04021 
04022 /*! function to return a string containing the name of the files 
04023 defining a surface object
04024 
04025    ans = SUMA_SurfaceFileName (SO, MitPath);
04026    \param SO (SUMA_SurfaceObject *) the surface object
04027    \param MitPath (SUMA_Boolean) if YUP then path is included
04028    \ret ans (char *) containing the name of the file from which the surface
04029       was loaded. If the surface is freesurfer format, the filename is 
04030       something like rh.smooth.asc. If it's a SureFit surface then you'll 
04031       get both .coord and .topo xxx.coord__yyy.topo
04032       ans is allocated in the function, of course, and must be freed after use
04033 */
04034 
04035 char * SUMA_SurfaceFileName (SUMA_SurfaceObject * SO, SUMA_Boolean MitPath)
04036 {
04037    static char FuncName[]={"SUMA_SurfaceFileName"};
04038    char *Name=NULL;
04039    int nalloc=0;
04040    
04041    SUMA_ENTRY;
04042 
04043    /* check if recognizable type */
04044    switch (SO->FileType) {
04045       case SUMA_FT_NOT_SPECIFIED:
04046          SUMA_error_message(FuncName, "SO_FileType not specified", 0);
04047          SUMA_RETURN (NULL);
04048          break;
04049       case SUMA_VEC:
04050          if (MitPath) nalloc = strlen(SO->Name_coord.Path) + strlen(SO->Name_coord.FileName) \
04051                            +    strlen(SO->Name_topo.Path) + strlen(SO->Name_topo.FileName) + 5;
04052          else nalloc = strlen(SO->Name_coord.FileName) \
04053                      +   strlen(SO->Name_topo.FileName) + 5;
04054          break;
04055       case SUMA_SUREFIT:
04056          if (MitPath) nalloc = strlen(SO->Name_coord.Path) + strlen(SO->Name_coord.FileName) \
04057                            +    strlen(SO->Name_topo.Path) + strlen(SO->Name_topo.FileName) + 5;
04058          else nalloc = strlen(SO->Name_coord.FileName) \
04059                      +   strlen(SO->Name_topo.FileName) + 5;
04060          break;
04061       case SUMA_INVENTOR_GENERIC:
04062       case SUMA_FREE_SURFER:
04063       case SUMA_FREE_SURFER_PATCH:
04064       case SUMA_BRAIN_VOYAGER:
04065       case SUMA_OPENDX_MESH:
04066       case SUMA_PLY:
04067          if (MitPath) nalloc = strlen(SO->Name.Path) + strlen(SO->Name.FileName) + 5;
04068          else nalloc = strlen(SO->Name.FileName) + 5;
04069          break;
04070       default:
04071          SUMA_error_message(FuncName, "SO_FileType not supported", 0);
04072          SUMA_RETURN (NULL);
04073          break;
04074    } 
04075 
04076    Name = (char *) SUMA_calloc (nalloc, sizeof(char));
04077    if (!Name) {
04078       fprintf (SUMA_STDERR,"Error %s: Could not allocate for Name.\n", FuncName);
04079       SUMA_RETURN (NULL);
04080    }
04081    
04082    switch (SO->FileType) {
04083       case SUMA_INVENTOR_GENERIC:
04084       case SUMA_FREE_SURFER:
04085       case SUMA_FREE_SURFER_PATCH:
04086       case SUMA_PLY:
04087       case SUMA_OPENDX_MESH:
04088       case SUMA_BRAIN_VOYAGER:
04089          if (MitPath) sprintf(Name,"%s%s", SO->Name.Path, SO->Name.FileName);
04090          else sprintf(Name,"%s", SO->Name.FileName);
04091          break;
04092       case SUMA_SUREFIT:
04093          if (MitPath) sprintf(Name,"%s%s__%s%s", SO->Name_coord.Path, SO->Name_coord.FileName, \
04094                               SO->Name_topo.Path, SO->Name_topo.FileName);
04095          else sprintf(Name,"%s__%s", SO->Name_coord.FileName, SO->Name_topo.FileName);
04096          break;
04097       case SUMA_VEC:
04098          if (MitPath) sprintf(Name,"%s%s__%s%s", SO->Name_coord.Path, SO->Name_coord.FileName, \
04099                               SO->Name_topo.Path, SO->Name_topo.FileName);
04100          else sprintf(Name,"%s__%s", SO->Name_coord.FileName, SO->Name_topo.FileName);
04101          break;
04102       case SUMA_FT_NOT_SPECIFIED:
04103       case SUMA_N_SO_FILE_TYPE:
04104       case SUMA_CMAP_SO:
04105       case SUMA_FT_ERROR:
04106          break;
04107    } 
04108    SUMA_RETURN (Name);
04109    
04110 }
04111 
04112 /*!
04113    Guess if a surface is anaomically correct from the name. 
04114 */
04115 char SUMA_GuessAnatCorrect(SUMA_SurfaceObject *SO)
04116 {
04117    static char FuncName[]={"SUMA_GuessAnatCorrect"};
04118    
04119    SUMA_ENTRY;
04120 
04121    switch (SO->FileType) {
04122       case SUMA_INVENTOR_GENERIC:
04123       case SUMA_FREE_SURFER:
04124       case SUMA_FREE_SURFER_PATCH:
04125       case SUMA_OPENDX_MESH:
04126       case SUMA_PLY:
04127       case SUMA_BRAIN_VOYAGER:
04128          if (  SUMA_iswordin (SO->Name.FileName, ".white") || 
04129                SUMA_iswordin (SO->Name.FileName, ".smoothwm") ||
04130                SUMA_iswordin (SO->Name.FileName, ".pial") ||
04131                SUMA_iswordin (SO->Name.FileName, ".orig") ||
04132                SUMA_iswordin (SO->Name.FileName, ".fiducial") ||
04133                SUMA_iswordin (SO->Name.FileName, "_WM") || 
04134                SUMA_iswordin (SO->Name.FileName, "_GM") || 
04135                ( SUMA_iswordin (SO->Name.FileName, "_RECO") && !SUMA_iswordin (SO->Name.FileName, "_inf") )
04136                ) {
04137             SUMA_RETURN('Y');
04138          } else {
04139             SUMA_RETURN('N');
04140          }
04141          break;
04142       case SUMA_SUREFIT:
04143       case SUMA_VEC:
04144          if (  SUMA_iswordin (SO->Name_coord.FileName, ".white") || 
04145                SUMA_iswordin (SO->Name_coord.FileName, ".smoothwm") ||
04146                SUMA_iswordin (SO->Name_coord.FileName, ".pial") ||
04147                SUMA_iswordin (SO->Name_coord.FileName, ".orig") ||
04148                SUMA_iswordin (SO->Name_coord.FileName, ".fiducial") ||
04149                SUMA_iswordin (SO->Name.FileName, "_WM") ||
04150                SUMA_iswordin (SO->Name.FileName, "_GM")
04151                ) {
04152             SUMA_RETURN('Y');
04153          } else {
04154             SUMA_RETURN('N');
04155          }
04156          break;
04157       case SUMA_N_SO_FILE_TYPE:
04158       case SUMA_FT_NOT_SPECIFIED:
04159       case SUMA_CMAP_SO:
04160       case SUMA_FT_ERROR:
04161          break;
04162    } 
04163    
04164    SUMA_RETURN('\0');
04165 }
04166 
04167 SUMA_SO_SIDE SUMA_GuessSide(SUMA_SurfaceObject *SO)
04168 {
04169    static char FuncName[]={"SUMA_GuessSide"};
04170    
04171    SUMA_ENTRY;
04172    
04173    switch (SO->FileType) {
04174       case SUMA_INVENTOR_GENERIC:
04175          break;
04176       case SUMA_FREE_SURFER:
04177       case SUMA_FREE_SURFER_PATCH:
04178          if (SUMA_iswordin (SO->Name.FileName, "lh")) {
04179             SUMA_RETURN(SUMA_LEFT);
04180          } else if (SUMA_iswordin (SO->Name.FileName, "rh")) {
04181                      SUMA_RETURN(SUMA_RIGHT);
04182                   }
04183          break;
04184       case SUMA_BRAIN_VOYAGER:
04185          if (SUMA_iswordin (SO->Name.FileName, "_LH")) {
04186             SUMA_RETURN(SUMA_LEFT);
04187          } else if (SUMA_iswordin (SO->Name.FileName, "_RH")) {
04188                      SUMA_RETURN(SUMA_RIGHT);
04189                   }
04190          break;
04191       case SUMA_SUREFIT:
04192          if (SUMA_iswordin (SO->Name_coord.FileName, "left") ||
04193              SUMA_iswordin (SO->Name_coord.FileName, ".L.")) {
04194             SUMA_RETURN(SUMA_LEFT);
04195          } else if (SUMA_iswordin (SO->Name_coord.FileName, "right") ||
04196              SUMA_iswordin (SO->Name_coord.FileName, ".R.")) {
04197              SUMA_RETURN(SUMA_RIGHT);
04198                 }
04199          break;
04200       case SUMA_VEC:
04201          if (SUMA_iswordin (SO->Name_coord.FileName, "lh") ||
04202              SUMA_iswordin (SO->Name_coord.FileName, "left")) {
04203                SUMA_RETURN(SUMA_LEFT);
04204          } else if (SUMA_iswordin (SO->Name_coord.FileName, "rh") ||
04205                      SUMA_iswordin (SO->Name_coord.FileName, "right")) {
04206                      SUMA_RETURN(SUMA_RIGHT);
04207                }
04208          break;
04209       case SUMA_FT_NOT_SPECIFIED:
04210       case SUMA_CMAP_SO:
04211       case SUMA_N_SO_FILE_TYPE:
04212       case SUMA_FT_ERROR:
04213          break;
04214       case SUMA_OPENDX_MESH:
04215       case SUMA_PLY:
04216          if (SUMA_iswordin (SO->Name.FileName, "lh") ||
04217              SUMA_iswordin (SO->Name.FileName, "left")) {
04218                SUMA_RETURN(SUMA_LEFT);
04219          } else if (SUMA_iswordin (SO->Name.FileName, "rh") ||
04220                   SUMA_iswordin (SO->Name.FileName, "right")) { 
04221                      SUMA_RETURN(SUMA_RIGHT);
04222                }
04223          break;
04224    } 
04225    
04226    SUMA_RETURN (SUMA_NO_SIDE);
04227 }
04228 
04229 /*---------------------------------------------------------------------------
04230  * SUMA_spec_select_surfs         - restrict spec results to given names
04231  *                                                              [rickr]
04232  * for each name in list
04233  *   - verify that it is in the spec file
04234  *   - verify that it is unique in the spec file
04235  * restrict the spec contents to the given name list
04236  *
04237  * return:
04238  *   (-1) on failure
04239  *   new N_Surfs on success
04240  *---------------------------------------------------------------------------
04241 */
04242 int SUMA_spec_select_surfs( SUMA_SurfSpecFile * spec, char ** names, int nnames,
04243                        int debug )
04244 {
04245     char * nfile;
04246     int    name, surf, name_ind;
04247 
04248     if ( ! spec || ! names )
04249     {
04250         fprintf(stderr,"** SUMA_spec_select_surfs: invalid params (%p,%p)\n",
04251                 spec, names);
04252         return -1;
04253     }
04254 
04255     if ( debug > 1 )
04256         fprintf(stderr, "-- select surfs: searching %d names...\n", nnames);
04257 
04258     if ( nnames <= 0 )
04259         return 0;
04260 
04261     /* first, check for existence and uniquenes in list */
04262     for ( name = 0; name < nnames; name++ )
04263     {
04264         if ( ! names[name] )    /* then end the process */
04265         {
04266             nnames = name;
04267             break;
04268         }
04269 
04270         name_ind = SUMA_unique_name_ind(spec, names[name]);
04271 
04272         if ( name_ind < 0 )
04273         {
04274             if ( name_ind == -1 )
04275                 fprintf(stderr,"** surface name '%s' not found\n",names[name]);
04276             return -1;
04277         }
04278 
04279         if ( debug > 1 )
04280             fprintf(stderr, "-- select surfs: found name '%s'\n", names[name]);
04281 
04282         if ( name_ind != name )
04283             SUMA_swap_spec_entries(spec, name, name_ind, debug);
04284     }
04285 
04286     /* now set N_Surfs and N_Groups */
04287     spec->N_Surfs = nnames;
04288 
04289     if ( debug > 1 )
04290         fprintf(stderr, "-- select surfs: returning %d names\n", nnames);
04291 
04292     return nnames;
04293 }
04294 
04295 /*---------------------------------------------------------------------------
04296  * SUMA_spec_set_map_refs         - set *all* mapping refs to SAME
04297  *                                                      [rickr]
04298  *---------------------------------------------------------------------------
04299 */
04300 int SUMA_spec_set_map_refs( SUMA_SurfSpecFile * spec, int debug )
04301 {
04302     int sc;
04303 
04304     for (sc = 0; sc < spec->N_Surfs; sc++ )
04305     {
04306         if ( ! strstr(spec->MappingRef[sc],"SAME") )
04307         {
04308             if ( debug > 0 )
04309                 fprintf(stderr,"-- map ref: replace '%s' with '%s'\n",
04310                         spec->MappingRef[sc], "./SAME");
04311             strcpy(spec->MappingRef[sc], "./SAME");
04312         }
04313         else if ( debug > 2 )
04314             fprintf(stderr,"-- mr: have good map ref '%s'\n",
04315                     spec->MappingRef[sc]);
04316     }
04317 
04318     return 0;
04319 }
04320 
04321 /*---------------------------------------------------------------------------
04322  * SUMA_swap_spec_entries         - swap entries for the 2 given indices
04323  *                                                              [rickr]
04324  * return:
04325  *    0 on success
04326  *   -1 on failure
04327  *---------------------------------------------------------------------------
04328 */
04329 int SUMA_swap_spec_entries( SUMA_SurfSpecFile * spec, int i0, int i1, int debug)
04330 {
04331     char * cpsave;
04332     char   cssave[SUMA_MAX_NAME_LENGTH];
04333     int    isave, c;
04334 
04335     if ( !spec || (i0 < 0) || (i0 >= spec->N_Surfs) ||
04336                   (i1 < 0) || (i1 >= spec->N_Surfs) )
04337     {
04338         fprintf(stderr,"** swap_spec_entries: bad params (%p,%d,%d)\n",
04339                 spec, i0, i1);
04340         return -1;
04341     }
04342 
04343     if ( debug > 2 )
04344         fprintf(stderr,"-- swapping spec entries %d and %d\n", i0, i1);
04345 
04346     cssave[SUMA_MAX_NAME_LENGTH-1] = '\0';              /* to be safe */
04347 
04348     swap_strings(spec->SurfaceType[i0], spec->SurfaceType[i1],
04349             cssave, SUMA_MAX_LABEL_LENGTH);
04350     swap_strings(spec->SurfaceFormat[i0], spec->SurfaceFormat[i1],
04351             cssave, SUMA_MAX_LABEL_LENGTH);
04352     swap_strings(spec->TopoFile[i0], spec->TopoFile[i1],
04353             cssave, SUMA_MAX_NAME_LENGTH);
04354     swap_strings(spec->CoordFile[i0], spec->CoordFile[i1],
04355             cssave, SUMA_MAX_NAME_LENGTH);
04356     swap_strings(spec->MappingRef[i0], spec->MappingRef[i1],
04357             cssave, SUMA_MAX_NAME_LENGTH);
04358     swap_strings(spec->AnatCorrect[i0], spec->AnatCorrect[i1],
04359             cssave, SUMA_MAX_NAME_LENGTH);
04360     swap_strings(spec->Hemisphere[i0], spec->Hemisphere[i1],
04361             cssave, SUMA_MAX_NAME_LENGTH);
04362     swap_strings(spec->DomainGrandParentID[i0], spec->DomainGrandParentID[i1],
04363             cssave, SUMA_MAX_NAME_LENGTH);     
04364     swap_strings(spec->OriginatorID[i0], spec->OriginatorID[i1],
04365             cssave, SUMA_MAX_NAME_LENGTH);
04366     swap_strings(spec->LocalCurvatureParent[i0], spec->LocalCurvatureParent[i1],
04367             cssave, SUMA_MAX_NAME_LENGTH);
04368     swap_strings(spec->LocalDomainParent[i0], spec->LocalDomainParent[i1],
04369             cssave, SUMA_MAX_NAME_LENGTH);
04370     swap_strings(spec->SureFitVolParam[i0], spec->SureFitVolParam[i1],
04371             cssave, SUMA_MAX_NAME_LENGTH);
04372     swap_strings(spec->SurfaceFile[i0], spec->SurfaceFile[i1],
04373             cssave, SUMA_MAX_NAME_LENGTH);
04374     swap_strings(spec->VolParName[i0], spec->VolParName[i1],
04375             cssave, SUMA_MAX_NAME_LENGTH);
04376     
04377     cpsave           = spec->IDcode[i0];        /* (char *)IDcode */
04378     spec->IDcode[i0] = spec->IDcode[i1];
04379     spec->IDcode[i1] = cpsave;
04380 
04381     swap_strings(spec->State[i0], spec->State[i1],
04382             cssave, SUMA_MAX_LABEL_LENGTH);
04383     swap_strings(spec->Group[i0], spec->Group[i1],
04384             cssave, SUMA_MAX_NAME_LENGTH);
04385     swap_strings(spec->SurfaceLabel[i0], spec->SurfaceLabel[i1],
04386             cssave, SUMA_MAX_NAME_LENGTH);
04387 
04388     isave              = spec->EmbedDim[i0];
04389     spec->EmbedDim[i0] = spec->EmbedDim[i1];
04390     spec->EmbedDim[i1] = isave;
04391 
04392     /* leave N_Surfs, N_States, N_Groups, StateList, SpecFilePath */
04393 
04394     return 0;
04395 }
04396 
04397 /*---------------------------------------------------------------------------
04398  * swap_strings                 - swap the two strings using the given space
04399  *                                                              [rickr]
04400  * return:
04401  *   (-1) on failure
04402  *   new N_Surfs on success
04403  *---------------------------------------------------------------------------
04404 */
04405 int swap_strings( char * s0, char * s1, char * space, int len )
04406 {
04407     if ( ! s0 || ! s1 || ! space || len < 1 )
04408     {
04409         fprintf(stderr,"** swap_strings: invalid params (%p,%p,%p,%d)\n",
04410                 s0, s1, space, len);
04411     }
04412 
04413     s0   [len-1] = '\0';                /* now safe using strcpy */
04414     s1   [len-1] = '\0';
04415     space[len-1] = '\0';
04416 
04417     strcpy(space, s0);
04418     strcpy(s0,    s1);
04419     strcpy(s1,    space);
04420 
04421     return 0;
04422 }
04423 
04424 /*---------------------------------------------------------------------------
04425  * SUMA_unique_name_ind           - check that name exists uniquely [rickr]
04426  *
04427  * return:
04428  
04429  *   -1    on "not found"
04430  *   -2    on "multiple matches"
04431  *   -3    on "bad, horrible failure"
04432  *---------------------------------------------------------------------------
04433 */
04434 int SUMA_unique_name_ind( SUMA_SurfSpecFile * spec, char * sname )
04435 {
04436     char * nfile;
04437     int    surf, index = -1;
04438 
04439     if ( ! spec || ! sname )
04440     {
04441         fprintf(stderr,"** unique_name_ind: bad params (%p, %p)\n",spec,sname);
04442         return -3;
04443     }
04444 
04445     for ( surf = 0; surf < spec->N_Surfs; surf++ )
04446     {
04447         nfile = SUMA_coord_file(spec, surf);
04448 
04449         if ( ! nfile )
04450         {
04451             fprintf(stderr,"** surf %d, no coord file\n", surf);
04452             return -3;
04453         }
04454 
04455         /* we have a match */
04456         if ( strstr(nfile, sname) )
04457         {
04458             if ( index >= 0 )
04459             {
04460                 fprintf(stderr,"** surf name %d, '%s': multiple matches\n"
04461                         "   '%s' and '%s'\n",
04462                         surf, sname, nfile, SUMA_coord_file(spec,index));
04463                 return -2;
04464             }
04465 
04466             index = surf;
04467         }
04468     }
04469 
04470     return index;
04471 }
04472 
04473 /*---------------------------------------------------------------------------
04474  * SUMA_coord_file        - based on the surf type, return coord file
04475  *                                                              [rickr]
04476  * return:
04477  *   on success, pointer to coord file
04478  *   on any failure, NULL
04479  *---------------------------------------------------------------------------
04480 */
04481 char * SUMA_coord_file( SUMA_SurfSpecFile * spec, int index )
04482 {
04483     char * rp;
04484 
04485     if ( ! spec || (index < 0) )
04486     {
04487         fprintf(stderr,"** coord_file: bad params (%p,%d)\n", spec, index);
04488         return NULL;
04489     }
04490 
04491     if ( strstr(spec->SurfaceType[index], "SureFit") ||
04492               strstr(spec->SurfaceType[index], "1D") )
04493         return spec->CoordFile[index];
04494     else if ( strstr(spec->SurfaceType[index], "FreeSurfer") ||
04495               strstr(spec->SurfaceType[index], "Ply")        ||
04496               strstr(spec->SurfaceType[index], "GenericInventor" ) ||
04497          strstr(spec->SurfaceType[index], "OpenDX" ) )
04498         return spec->SurfaceFile[index];
04499 
04500     return NULL;
04501 }
04502 
04503 
04504 #define SUMA_CHECK_INPUT_SURF(name, topo, ok) {  \
04505    ok = 0;  \
04506    if (SUMA_filexists(name)) {   \
04507       if  (!(topo)) { ok = 1; }   \
04508       else { if (SUMA_filexists(topo)) {ok = 1;}  } \
04509    } \
04510    if (!ok) {  \
04511       if (topo) { \
04512          fprintf(SUMA_STDERR,"Error %s:\nCould not locate surface %s %s\n", FuncName, name, topo); \
04513       } else { \
04514          fprintf(SUMA_STDERR,"Error %s:\nCould not locate surface %s \n", FuncName, name); \
04515       }  \
04516    }  \
04517 }
04518 
04519 #define SUMA_BLANK_NEW_SPEC_SURF(spec)  {\
04520          spec->IDcode[spec->N_Surfs]= NULL;  \
04521          spec->SurfaceLabel[spec->N_Surfs][0] = '\0'; \
04522          spec->EmbedDim[spec->N_Surfs] = 3;  \
04523          strcpy(spec->AnatCorrect[spec->N_Surfs], "Y");  \
04524          spec->Hemisphere[spec->N_Surfs][0] = '\0';   \
04525          spec->DomainGrandParentID[spec->N_Surfs][0] = '\0';   \
04526          strcpy(spec->LocalDomainParent[spec->N_Surfs],"SAME");  \
04527          spec->LocalCurvatureParent[spec->N_Surfs][0] = '\0';  \
04528          spec->OriginatorID[spec->N_Surfs][0] = '\0'; \
04529 }
04530 
04531 void SUMA_Show_IO_args(SUMA_GENERIC_ARGV_PARSE *ps)
04532 {
04533    static char FuncName[]={"SUMA_Show_IO_args"};
04534    int i;
04535    
04536    SUMA_ENTRY;
04537    
04538    if (!ps) { fprintf(SUMA_STDERR,"NULL ps\n"); SUMA_RETURNe; }
04539    
04540    if (ps->accept_t) fprintf(SUMA_STDERR,"accepting -t* options\n");
04541    if (ps->accept_s) fprintf(SUMA_STDERR,"accepting -surf_* options\n");
04542    if (ps->accept_i) fprintf(SUMA_STDERR,"accepting -i_* options\n");
04543    if (ps->accept_ipar) fprintf(SUMA_STDERR,"accepting -ipar_* options\n");
04544    if (ps->accept_o) fprintf(SUMA_STDERR,"accepting -o_* options\n");
04545    if (ps->accept_spec) fprintf(SUMA_STDERR,"accepting -spec option\n");
04546    if (ps->accept_sv) fprintf(SUMA_STDERR,"accepting -sv option\n");
04547    if (ps->accept_talk_suma) fprintf(SUMA_STDERR,"accepting -talk_suma options\n");
04548    fprintf(SUMA_STDERR,"Check for input surface files: %d\n", ps->check_input_surf);
04549    fprintf(SUMA_STDERR,"%d sv:\n", ps->N_sv);
04550    if (ps->N_sv) {
04551       for (i=0; i<ps->N_sv; ++i) {
04552          fprintf(SUMA_STDERR,"   %d: %s\n", i, ps->sv[i]);
04553       }
04554    }
04555    fprintf(SUMA_STDERR,"%d vp:\n", ps->N_vp);
04556    if (ps->N_vp) {
04557       for (i=0; i<ps->N_vp; ++i) {   
04558          fprintf(SUMA_STDERR,"   %d: %s\n", i, ps->vp[i]);
04559       }
04560    }
04561 
04562    fprintf(SUMA_STDERR,"%d spec names:\n", ps->N_spec_names);
04563    for (i=0; i<ps->N_spec_names; ++i) {
04564       fprintf(SUMA_STDERR,"   %d: %s\n", i, ps->spec_names[i]);
04565    }
04566    fprintf(SUMA_STDERR,"%d s_surfnames from %s\n", ps->s_N_surfnames, ps->spec_names[0]);
04567    for (i=0; i<ps->s_N_surfnames; ++i) {
04568       fprintf(SUMA_STDERR,"   %d: %s\n", i, ps->s_surfnames[i]);
04569    }
04570    fprintf(SUMA_STDERR,"%d i_surfnames\n", ps->i_N_surfnames);
04571    for (i=0; i<ps->i_N_surfnames; ++i) {
04572       if (ps->i_surftopo[i]) fprintf(SUMA_STDERR,"   %d: %s %s %s %s\n", i, ps->i_group[i], ps->i_state[i], ps->i_surfnames[i], ps->i_surftopo[i]);
04573       else fprintf(SUMA_STDERR,"   %d: %s %s %s\n", i, ps->i_group[i], ps->i_state[i],ps->i_surfnames[i]);
04574    }
04575    fprintf(SUMA_STDERR,"%d ipar_surfnames\n", ps->ipar_N_surfnames);
04576    for (i=0; i<ps->ipar_N_surfnames; ++i) {
04577       if (ps->ipar_surftopo[i]) fprintf(SUMA_STDERR,"   %d: %s %s %s %s\n", i, ps->ipar_group[i], ps->ipar_state[i], ps->ipar_surfnames[i], ps->ipar_surftopo[i]);
04578       else fprintf(SUMA_STDERR,"   %d: %s %s %s\n", i, ps->ipar_group[i], ps->ipar_state[i], ps->ipar_surfnames[i]);
04579    }
04580    fprintf(SUMA_STDERR,"%d o_surfnames\n", ps->o_N_surfnames);
04581    for (i=0; i<ps->o_N_surfnames; ++i) {
04582       if (ps->o_surftopo[i]) fprintf(SUMA_STDERR,"   %d: %s %s %s %s\n", i, ps->o_group[i], ps->o_state[i], ps->o_surfnames[i], ps->o_surftopo[i]);
04583       else fprintf(SUMA_STDERR,"   %d: %s %s %s\n", i, ps->o_group[i], ps->o_state[i], ps->o_surfnames[i]);
04584    }
04585    fprintf(SUMA_STDERR,"%d t_surfnames\n", ps->t_N_surfnames);
04586    for (i=0; i<ps->t_N_surfnames; ++i) {
04587       if (ps->t_surftopo[i]) fprintf(SUMA_STDERR,"   %d: %s %s %s %s\n", i, ps->o_group[i], ps->t_state[i], ps->t_surfnames[i], ps->t_surftopo[i]);
04588       else fprintf(SUMA_STDERR,"   %d: %s %s %s\n", i, ps->o_group[i], ps->t_state[i], ps->t_surfnames[i]);
04589    }
04590    
04591    if (ps->accept_talk_suma) {
04592       if (!ps->cs) {
04593          fprintf(SUMA_STDERR,"No Talking to SUMA requested\n");
04594       } else {
04595          fprintf(SUMA_STDERR,"Talking to SUMA requested.\n");
04596       }
04597    } 
04598    fprintf(SUMA_STDERR,"%d arguments on command line:\n", ps->N_args);
04599    for (i=0; i<ps->N_args; ++i) {
04600       if (ps->arg_checked[i]) fprintf(SUMA_STDERR," %d+   ",i);
04601       else fprintf(SUMA_STDERR," %d-   ",i);
04602    }
04603    fprintf(SUMA_STDERR,"\n");
04604       
04605    SUMA_RETURNe;
04606 }
04607 
04608 /*!
04609    Take a vector of independent surfaces and get a Spec file that goes
04610    with them
04611 */
04612 SUMA_SurfSpecFile *SUMA_SOGroup_2_Spec(SUMA_SurfaceObject **SOv, int N_SOv)
04613 {
04614    static char FuncName[]={"SUMA_SOGroup_2_Spec"};
04615    SUMA_SurfSpecFile *spec = NULL;
04616    int i, nspec;
04617    char si[100];
04618    SUMA_GENERIC_ARGV_PARSE *ps=NULL;
04619    SUMA_Boolean LocalHead = NOPE;
04620    
04621    SUMA_ENTRY;
04622    
04623    ps = SUMA_CreateGenericArgParse("-i;");
04624    ps->check_input_surf = 0;
04625    ps->i_N_surfnames = N_SOv;
04626    for (i=0; i<ps->i_N_surfnames; ++i) {
04627       sprintf(si, "s_%d\n", i);
04628       if (SOv[i]->Label) ps->i_surfnames[i] = SUMA_copy_string(SOv[i]->Label); 
04629       else ps->i_surfnames[i] =  SUMA_copy_string(si);
04630       if (SOv[i]->State) ps->i_state[i] = SUMA_copy_string(SOv[i]->State);
04631       if (SOv[i]->Group) ps->i_group[i] = SUMA_copy_string(SOv[i]->Group);
04632       ps->i_FT[i] = SUMA_FT_NOT_SPECIFIED; ps->i_FF[i] = SUMA_FF_NOT_SPECIFIED; 
04633    }
04634    
04635    spec = SUMA_IO_args_2_spec(ps, &nspec);
04636    SUMA_FreeGenericArgParse(ps); ps = NULL;
04637 
04638    SUMA_RETURN(spec);  
04639 }
04640 
04641 SUMA_SurfSpecFile *SUMA_IO_args_2_spec(SUMA_GENERIC_ARGV_PARSE *ps, int *nspec)
04642 {
04643    static char FuncName[]={"SUMA_IO_args_2_spec"};
04644    int i, ispec0;
04645    byte ok;
04646    char sbuf[SUMA_MAX_LABEL_LENGTH+1];
04647    static char defgroup[]={SUMA_DEF_GROUP_NAME};
04648    SUMA_SurfSpecFile *spec = NULL;
04649    SUMA_Boolean LocalHead = NOPE;
04650    
04651    SUMA_ENTRY;
04652    
04653    
04654    /* first look for virtual spec */
04655    *nspec = 1;
04656    spec = (SUMA_SurfSpecFile *)SUMA_malloc(sizeof(SUMA_SurfSpecFile));
04657    spec->N_Surfs = 0;
04658    spec->N_States = 0;
04659    spec->N_Groups = 1;
04660    strcpy(spec->SpecFilePath, "./");
04661    strcpy(spec->SpecFileName, "FromCommandLine.spec");   
04662    if (ps->accept_i) {
04663       SUMA_LH("Processing -i");
04664       if (ps->i_N_surfnames+spec->N_Surfs >= SUMA_MAX_N_SURFACE_SPEC) { SUMA_S_Err("Too many surfaces to work with.\n"); *nspec = 0; SUMA_RETURN(spec); }
04665       for (i=0; i<ps->i_N_surfnames; ++i) {
04666          if (ps->check_input_surf) { 
04667             SUMA_CHECK_INPUT_SURF(ps->i_surfnames[i], ps->i_surftopo[i], ok);
04668             if (!ok) { SUMA_free(spec); spec = NULL; *nspec = 0; SUMA_RETURN(spec); }
04669          }
04670          strcpy(spec->SurfaceType[spec->N_Surfs], SUMA_SurfaceTypeString (ps->i_FT[i]));
04671          if (ps->i_FF[i] == SUMA_BINARY || ps->i_FF[i] == SUMA_BINARY_LE || ps->i_FF[i] == SUMA_BINARY_BE) strcpy(spec->SurfaceFormat[spec->N_Surfs], "BINARY");
04672          else strcpy(spec->SurfaceFormat[spec->N_Surfs], "ASCII");
04673          if (ps->i_FT[i] == SUMA_SUREFIT || ps->i_FT[i] == SUMA_VEC) {
04674             strcpy(spec->TopoFile[spec->N_Surfs], ps->i_surftopo[i]);
04675             strcpy(spec->CoordFile[spec->N_Surfs], ps->i_surfnames[i]);
04676             if (ps->vp[i]) strcpy(spec->SureFitVolParam[spec->N_Surfs], ps->vp[i]);
04677          } else {
04678             strcpy(spec->SurfaceFile[spec->N_Surfs], ps->i_surfnames[i]);
04679          }
04680          if (ps->sv[i]) strcpy(spec->VolParName[spec->N_Surfs], ps->sv[i]); else spec->VolParName[spec->N_Surfs][0] = '\0';
04681          if (ps->i_state[i])  { strcpy(spec->State[spec->N_Surfs], ps->i_state[i]); ++spec->N_States;} 
04682          else { sprintf(spec->State[spec->N_Surfs], "iS_%d", spec->N_States); ++spec->N_States; }
04683          if (ps->i_group[i])  { strcpy(spec->Group[spec->N_Surfs], ps->i_group[i]); } 
04684          else { strcpy(spec->Group[spec->N_Surfs], defgroup);  }
04685          SUMA_BLANK_NEW_SPEC_SURF(spec);
04686          ++spec->N_Surfs;
04687       }
04688    }
04689    if (ps->accept_ipar) {
04690       SUMA_LH("Processing -ipar");
04691       if (ps->ipar_N_surfnames+spec->N_Surfs >= SUMA_MAX_N_SURFACE_SPEC) { SUMA_S_Err("Too many surfaces to work with.\n"); *nspec = 0; SUMA_RETURN(spec); }
04692       for (i=0; i<ps->ipar_N_surfnames; ++i) {
04693          if (ps->check_input_surf) { 
04694             SUMA_CHECK_INPUT_SURF(ps->ipar_surfnames[i], ps->ipar_surftopo[i], ok);
04695             if (!ok) { SUMA_free(spec); spec = NULL; *nspec = 0; SUMA_RETURN(spec); }
04696          }
04697          strcpy(spec->SurfaceType[spec->N_Surfs], SUMA_SurfaceTypeString (ps->ipar_FT[i]));
04698          if (ps->ipar_FF[i] == SUMA_BINARY || ps->ipar_FF[i] == SUMA_BINARY_LE || ps->ipar_FF[i] == SUMA_BINARY_BE) strcpy(spec->SurfaceFormat[spec->N_Surfs], "BINARY");
04699          else strcpy(spec->SurfaceFormat[spec->N_Surfs], "ASCII");
04700          if (ps->ipar_FT[i] == SUMA_SUREFIT || ps->ipar_FT[i] == SUMA_VEC) {
04701             strcpy(spec->TopoFile[spec->N_Surfs], ps->ipar_surftopo[i]);
04702             strcpy(spec->CoordFile[spec->N_Surfs], ps->ipar_surfnames[i]);
04703             if (ps->vp[i]) strcpy(spec->SureFitVolParam[spec->N_Surfs], ps->vp[i]);
04704          } else {
04705             strcpy(spec->SurfaceFile[spec->N_Surfs], ps->ipar_surfnames[i]);
04706          }
04707          if (ps->sv[i]) strcpy(spec->VolParName[spec->N_Surfs], ps->sv[i]); else spec->VolParName[spec->N_Surfs][0] = '\0';
04708          if (ps->ipar_state[i])  { strcpy(spec->State[spec->N_Surfs], ps->ipar_state[i]); ++spec->N_States;} 
04709          else { sprintf(spec->State[spec->N_Surfs], "iS_%d", spec->N_States); ++spec->N_States; }
04710          if (ps->ipar_group[i])  { strcpy(spec->Group[spec->N_Surfs], ps->ipar_group[i]); } 
04711          else { strcpy(spec->Group[spec->N_Surfs], defgroup);  }
04712          SUMA_BLANK_NEW_SPEC_SURF(spec);
04713          ++spec->N_Surfs;
04714       }
04715    }
04716    
04717    if (ps->accept_t) {
04718       SUMA_LH("Processing -t");
04719       if (ps->t_N_surfnames+spec->N_Surfs >= SUMA_MAX_N_SURFACE_SPEC) { SUMA_S_Err("Too many surfaces to work with.\n"); *nspec = 0; SUMA_RETURN(spec); }
04720       for (i=0; i<ps->t_N_surfnames; ++i) {  
04721          if (ps->check_input_surf) { 
04722             SUMA_CHECK_INPUT_SURF(ps->t_surfnames[i], ps->t_surftopo[i], ok);
04723             if (!ok) { SUMA_free(spec); spec = NULL; *nspec = 0; SUMA_RETURN(spec); }
04724          }
04725          strcpy(spec->SurfaceType[spec->N_Surfs], SUMA_SurfaceTypeString (ps->t_FT[i]));
04726          if (ps->t_FF[i] == SUMA_BINARY || ps->t_FF[i] == SUMA_BINARY_LE || ps->t_FF[i] == SUMA_BINARY_BE) strcpy(spec->SurfaceFormat[spec->N_Surfs], "BINARY");
04727          else strcpy(spec->SurfaceFormat[spec->N_Surfs], "ASCII");
04728          if (ps->t_FT[i] == SUMA_SUREFIT || ps->t_FT[i] == SUMA_VEC) {
04729             strcpy(spec->TopoFile[spec->N_Surfs], ps->t_surftopo[i]);
04730             strcpy(spec->CoordFile[spec->N_Surfs], ps->t_surfnames[i]);
04731             if (ps->vp[i]) strcpy(spec->SureFitVolParam[spec->N_Surfs], ps->vp[i]);
04732          } else {
04733             strcpy(spec->SurfaceFile[spec->N_Surfs], ps->t_surfnames[i]);
04734          }
04735          if (ps->sv[i]) strcpy(spec->VolParName[spec->N_Surfs], ps->sv[i]); else spec->VolParName[spec->N_Surfs][0] = '\0';
04736          if (ps->t_state[i])  { strcpy(spec->State[spec->N_Surfs], ps->t_state[i]); ++spec->N_States;} 
04737          else { sprintf(spec->State[spec->N_Surfs], "iS_%d", spec->N_States); ++spec->N_States; }
04738          if (ps->t_group[i])  { strcpy(spec->Group[spec->N_Surfs], ps->t_group[i]); } 
04739          else { strcpy(spec->Group[spec->N_Surfs], defgroup);  }
04740          SUMA_BLANK_NEW_SPEC_SURF(spec);
04741          ++spec->N_Surfs;
04742       }
04743    }
04744    
04745    SUMA_LH("Working States");
04746    
04747    /* now create the states list */
04748    if (spec->N_Surfs) { 
04749       spec->N_States = 1;
04750       sprintf(spec->StateList, "%s|", spec->State[0]);
04751       for (i=1; i<spec->N_Surfs; ++i) {
04752          sprintf(sbuf,"%s|",spec->State[i]); 
04753          if (!SUMA_iswordin(spec->StateList, sbuf)) { sprintf(spec->StateList, "%s|", spec->State[i]); ++spec->N_States; }
04754       }
04755       if (LocalHead) fprintf(SUMA_STDERR,"%s:\n%d distinct states\n%s\n", FuncName, spec->N_States, spec->StateList);
04756       ispec0 = *nspec;
04757    } else {
04758       if (LocalHead) fprintf(SUMA_STDERR,"%s:\n no surfs\n", FuncName);
04759       /* free Spec */
04760       SUMA_free(spec); spec = NULL; *nspec = 0; ispec0 = 0;
04761    }
04762     
04763    /* Now see if you have explicity define specs on command line */
04764    if (ps->accept_spec || ps->accept_s) {
04765       if (ps->N_spec_names) {
04766          *nspec = ispec0 + ps->N_spec_names;
04767          spec = (SUMA_SurfSpecFile *)SUMA_realloc(spec, *nspec * sizeof(SUMA_SurfSpecFile));
04768          SUMA_LH("Here");
04769          for (i=0; i<ps->N_spec_names; ++i) {  
04770             if (!SUMA_Read_SpecFile (ps->spec_names[i], &(spec[i+ispec0]))) {
04771                SUMA_SL_Err("Failed to read SpecFile");
04772                SUMA_free(spec); spec = NULL; *nspec = 0; 
04773                SUMA_RETURN(spec);
04774             }
04775          }
04776          /* do we have a set of surfaces to read here ? only works with one spec  */
04777          if (ps->s_N_surfnames) {
04778             int n_read;
04779             if (ps->N_spec_names > 1) {
04780                SUMA_S_Err("Cannot deal with multiple -spec on command line combined with -surf_ selectors.");
04781                SUMA_free(spec); spec = NULL; *nspec = 0; 
04782                SUMA_RETURN(spec);
04783             }
04784             /* purify the spec */
04785             n_read = SUMA_spec_select_surfs(&(spec[0+ispec0]), ps->s_surfnames, ps->s_N_surfnames, 0);
04786             if (LocalHead) {
04787                fprintf(SUMA_STDERR,"%s (%s:%d): Read in %d surfaces\n", FuncName, __FILE__, __LINE__, n_read);
04788             }
04789          }
04790          
04791       }
04792    }
04793    if (LocalHead) { 
04794       fprintf(SUMA_STDERR,"%s: About to return, have %d spec files.\n", FuncName, *nspec);
04795    }
04796    SUMA_RETURN(spec);
04797 }
04798 
 

Powered by Plone

This site conforms to the following standards: