#include "SUMA_suma.h"

#undef STAND_ALONE

#if defined SUMA_ConvexHull_STANDALONE
#define STAND_ALONE 
#endif

#ifdef STAND_ALONE
/* these global variables must be declared even if they will not be used by this main */
SUMA_SurfaceViewer *SUMAg_cSV = NULL; /*!< Global pointer to current Surface Viewer structure*/
SUMA_SurfaceViewer *SUMAg_SVv = NULL; /*!< Global pointer to the vector containing the various Surface Viewer Structures 
                                    SUMAg_SVv contains SUMA_MAX_SURF_VIEWERS structures */
int SUMAg_N_SVv = 0; /*!< Number of SVs realized by X */
SUMA_DO *SUMAg_DOv = NULL;   /*!< Global pointer to Displayable Object structure vector*/
int SUMAg_N_DOv = 0; /*!< Number of DOs stored in DOv */
SUMA_CommonFields *SUMAg_CF = NULL; /*!< Global pointer to structure containing info common to all viewers */
#else
extern SUMA_CommonFields *SUMAg_CF;
extern SUMA_DO *SUMAg_DOv;
extern SUMA_SurfaceViewer *SUMAg_SVv;
extern int SUMAg_N_SVv; 
extern int SUMAg_N_DOv;  
#endif


/*----------------------------------------------------
  A slightly modified version of Bob's qhull_wrap function
  
  Compute the convex hull of a bunch of 3-vectors
  Inputs:
    npt = number of vectors
    xyz = array of coordinates of 3-vectors;
          the i-th vector is stored in
            xyz[3*i] xyz[3*i+1] xyz[3*i+2]
   fliporient = 0 --> leave triangles as they come out of qhull,
                1 --> flip their orientation
               \sa SUMA_OrientTriangles if you are not sure about flipping.

  Output:
    *ijk = pointer to malloc()-ed array of triangles;
           the j-th triangle is stored in
             ijk[3*j] ijk[3*j+1] ijk[3*j+2]
           where the integer index i refers to the
           i-th 3-vector input

  Return value is the number of triangles.  If this
  is zero, something bad happened.

  Example:
    int ntri , *tri , nvec ;
    float vec[something] ;
    ntri = SUMA_qhull_wrap( nvec , vec , &tri, 0 ) ;

  This function just executes the Geometry Center
  program qhull to compute the result.  This program
  should be in the user's path, or this function
  will fail (return 0).
------------------------------------------------------*/

int SUMA_qhull_wrap( int npt , float * xyz , int ** ijk , int fliporient)
{
   static char FuncName[]={"SUMA_qhull_wrap"};
   int ii,jj , nfac , *fac ;
   int fd ; FILE *fp ;
   char qbuf[128] ;

#ifndef DONT_USE_MKSTEMP
   char fname[] = "/tmp/afniXXXXXX" ;
#else
   char *fname ;
#endif

   if( npt < 3 || xyz == NULL || ijk == NULL ){
      fprintf(stderr,"SUMA_qhull_wrap: bad inputs\n") ;
      return 0 ;
   }

#ifndef DONT_USE_MKSTEMP
   fd = mkstemp( fname ) ;
   if( fd == -1 ){ fprintf(stderr,"SUMA_qhull_wrap: mkstemp fails\n"); return 0; }
   fp = fdopen( fd , "w" ) ;
   if( fp == NULL ){ fprintf(stderr,"SUMA_qhull_wrap: fdopen fails\n"); close(fd); return 0; }
#else
   fname = tmpnam(NULL) ;
   if( fname == NULL ){ fprintf(stderr,"SUMA_qhull_wrap: tmpnam fails\n"); return 0; }
   fp = fopen( fname , "w" ) ;
   if( fp == NULL ){ fprintf(stderr,"SUMA_qhull_wrap: fopen fails\n"); return 0; }
#endif

   fprintf(fp,"3\n%d\n",npt) ;
   for( ii=0 ; ii < npt ; ii++ )
      fprintf(fp,"%g %g %g\n",xyz[3*ii],xyz[3*ii+1],xyz[3*ii+2]) ;

   fclose(fp) ;

   sprintf(qbuf,"qhull QJ i < %s",fname) ;
   fp = popen( qbuf , "r" ) ;
   if( fp == NULL ){ fprintf(stderr,"SUMA_qhull_wrap: popen fails\n"); remove(fname); return 0; }

   jj = fscanf(fp,"%d",&nfac) ;
   if( jj != 1 || nfac < 1 ){ fprintf(stderr,"SUMA_qhull_wrap: 1st fscanf fails\n"); pclose(fp); remove(fname); return 0; }

   fac = (int *) malloc( sizeof(int)*3*nfac ) ;
   if( fac == NULL ){ fprintf(stderr,"SUMA_qhull_wrap: malloc fails\n"); pclose(fp); remove(fname); return 0; }

   if (fliporient) {
      for( ii=0 ; ii < nfac ; ii++ ){
         jj = fscanf(fp,"%d %d %d",fac+(3*ii+2),fac+(3*ii+1),fac+(3*ii)) ;
         if( jj < 3 ){
            fprintf(stderr,"SUMA_qhull_wrap: fscanf fails at ii=%d\n",ii) ;
            pclose(fp); remove(fname); free(fac); return 0;
         }
      }
   } else {
      for( ii=0 ; ii < nfac ; ii++ ){
         jj = fscanf(fp,"%d %d %d",fac+(3*ii),fac+(3*ii+1),fac+(3*ii+2)) ;
         if( jj < 3 ){
            fprintf(stderr,"SUMA_qhull_wrap: fscanf fails at ii=%d\n",ii) ;
            pclose(fp); remove(fname); free(fac); return 0;
         }
      }
   }
   pclose(fp); remove(fname);

   *ijk = fac ; return nfac ;
}

/*!
   A function to call SUMA_qhull_wrap
*/
SUMA_SurfaceObject *SUMA_ConvexHullSurface(SUMA_GENERIC_PROG_OPTIONS_STRUCT * Opt)
{
   static char FuncName[]={"SUMA_ConvexHullSurface"};
   SUMA_SurfaceObject *SO=NULL;
   float *xyz=NULL;
   int npt, *ijk=NULL, nf, cnt, i, j, k, nxx, nyy, nzz;
   FILE *fid=NULL;
   THD_fvec3 fv, iv;

   SUMA_ENTRY;
   
   npt = 0;
   if (Opt->in_vol) {
      cnt = 0; npt = 0;
      nxx = (DSET_NX(Opt->in_vol)); 
      nyy = (DSET_NY(Opt->in_vol));
      nzz = (DSET_NZ(Opt->in_vol));

      if (Opt->debug) fprintf(SUMA_STDERR,"%s:\nRunning qhull...\n", FuncName);
      xyz = (float *)SUMA_malloc(3*nxx*nyy*nzz*sizeof(float));
      if (!xyz) {
         SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NULL);
      }
      for(  k = 0 ; k < nzz ; k++ ) {
         for(  j = 0 ; j < nyy ; j++ ) {
            for(  i = 0 ; i < nxx ; i++ ) {
               if (Opt->mcdatav[cnt] == 1) {
                  fv.xyz[0] = DSET_XORG(Opt->in_vol) + i * DSET_DX(Opt->in_vol);
                  fv.xyz[1] = DSET_YORG(Opt->in_vol) + j * DSET_DY(Opt->in_vol);
                  fv.xyz[2] = DSET_ZORG(Opt->in_vol) + k * DSET_DZ(Opt->in_vol);
                  /* change mm to RAI coords */
		            iv = SUMA_THD_3dmm_to_dicomm( Opt->in_vol->daxes->xxorient, Opt->in_vol->daxes->yyorient, Opt->in_vol->daxes->zzorient, fv );
                  xyz[3*npt] = iv.xyz[0]; xyz[3*npt+1] = iv.xyz[1]; xyz[3*npt+2] = iv.xyz[2]; 
                  npt++;
               }
               ++cnt;
            }
         }
      }
   } else if (Opt->XYZ) {
      xyz = (float *)SUMA_malloc(3*Opt->N_XYZ*sizeof(float));
      if (!xyz) {
         SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NULL);
      }
      for(  k = 0 ; k < 3*Opt->N_XYZ ; k++ ) {  xyz[k] = Opt->XYZ[k]; npt = Opt->N_XYZ; }   
   } else {
      SUMA_S_Err("No input");
      SUMA_RETURN(NULL);
   }
   if (! (nf = SUMA_qhull_wrap(npt, xyz, &ijk, 1)) ) {
      fprintf(SUMA_STDERR,"%s:\nFailed in SUMA_qhull_wrap\n", FuncName);
      SUMA_RETURN(SO);
   }
   
   if (Opt->debug) fprintf(SUMA_STDERR,"%s:\n%d triangles.\n", FuncName, nf);
   
   
   SO = SUMA_Patch2Surf(xyz, npt, ijk, nf, 3);
   free(ijk); ijk=NULL;
   SUMA_free(xyz); xyz = NULL;
      
   SUMA_RETURN(SO);
}


#ifdef SUMA_ConvexHull_STANDALONE
void usage_SUMA_ConvexHull (SUMA_GENERIC_ARGV_PARSE *ps)
   {
      static char FuncName[]={"usage_SUMA_ConvexHull"};
      char * s = NULL, *sio=NULL;
      int i;
      s = SUMA_help_basics();
      sio  = SUMA_help_IO_Args(ps);
      printf ( "\n"
               "Usage: A program to find the convex hull of a set of points.\n"
               "  This program is a wrapper for the Qhull program.\n"
               "  see copyright notice by running suma -sources.\n"
               "\n"
               "  ConvexHull  \n"
               "     usage 1: < -input VOL >\n"
               "              < -isoval V | -isorange V0 V1 | -isocmask MASK_COM >\n"
               "              [<-xform XFORM>]\n"
               "     usage 2: < i_TYPE input surface >\n"
               "              [<-sv SURF_VOL>]\n"
               "     usage 3: < -input_1D XYZ >\n"      
               "     common optional:\n"
               "              [< -o_TYPE PREFIX>]\n"
               "              [< -debug DBG >]\n"  
               "\n"
               "  Mandatory parameters, choose one of three usage modes:\n"
               "  Usage 1:\n"
               "     You must use one of the following two options:\n"
               "     -input VOL: Input AFNI (or AFNI readable) volume.\n"
               "     You must use one of the following iso* options:\n"
               "     -isoval V: Create isosurface where volume = V\n"
               "     -isorange V0 V1: Create isosurface where V0 <= volume < V1\n"
               "     -isocmask MASK_COM: Create isosurface where MASK_COM != 0\n"
               "        For example: -isocmask '-a VOL+orig -expr (1-bool(a-V))' \n"
               "        is equivalent to using -isoval V. \n"
               "     NOTE: -isorange and -isocmask are only allowed with -xform mask\n"
               "            See -xform below for details.\n"
               "\n"
               "  Usage 2:\n"
               "     -i_TYPE SURF:  Use the nodes of a surface model\n"
               "                    for input. See help for i_TYPE usage\n"
               "                    below.\n"
               "\n"
               "  Usage 3:\n"
               "     -input_1D XYZ: Construct the convex hull of the points\n"
               "                    contained in 1D file XYZ. If the file has\n"
               "                    more than 3 columns, use AFNI's [] selectors\n"
               "                    to specify the XYZ columns.\n"
               "\n" 
               "  Optional Parameters:\n"
               "     Usage 1 only:\n"
               "     -xform XFORM:  Transform to apply to volume values\n"
               "                    before searching for sign change\n"
               "                    boundary. XFORM can be one of:\n"
               "            mask: values that meet the iso* conditions\n"
               "                  are set to 1. All other values are set\n"
               "                  to -1. This is the default XFORM.\n"
               "            shift: subtract V from the dataset and then \n"
               "                   search for 0 isosurface. This has the\n"
               "                   effect of constructing the V isosurface\n"
               "                   if your dataset has a continuum of values.\n"
               "                   This option can only be used with -isoval V.\n"
               "            none: apply no transforms. This assumes that\n"
               "                  your volume has a continuum of values \n"
               "                  from negative to positive and that you\n"
               "                  are seeking to 0 isosurface.\n"
               "                  This option can only be used with -isoval 0.\n"
               "     Usage 2 only:\n"
               "     -sv SURF_VOL: Specify a surface volume which contains\n"
               "                   a transform to apply to the surface node\n"
               "                   coordinates prior to constructing the \n"
               "                   convex hull.\n"
               "     All Usage:\n"
               "     -o_TYPE PREFIX: prefix of output surface.\n"
               "        where TYPE specifies the format of the surface\n"
               "        and PREFIX is, well, the prefix.\n"
               "        TYPE is one of: fs, 1d (or vec), sf, ply.\n"
               "        Default is: -o_ply \n"
               "\n"
               "%s\n"
               "\n"
               /*"     -debug DBG: debug levels of 0 (default), 1, 2, 3.\n"
               "        This is no Rick Reynolds debug, which is oft nicer\n"
               "        than the results, but it will do.\n"
               "\n" */
               "%s"
               "\n", sio, s);
       SUMA_free(s); s = NULL;  SUMA_free(sio); sio = NULL;          
       s = SUMA_New_Additions(0, 1); printf("%s\n", s);SUMA_free(s); s = NULL;
       printf("       Ziad S. Saad SSCC/NIMH/NIH saadz@mail.nih.gov     \n");
       exit (0);
   }
/*!
   \brief parse the arguments for SurfSmooth program
   
   \param argv (char *)
   \param argc (int)
   \return Opt (SUMA_GENERIC_PROG_OPTIONS_STRUCT *) options structure.
               To free it, use 
               SUMA_free(Opt->out_name); 
               SUMA_free(Opt);
*/
SUMA_GENERIC_PROG_OPTIONS_STRUCT *SUMA_ConvexHull_ParseInput (char *argv[], int argc, SUMA_GENERIC_ARGV_PARSE *ps)
{
   static char FuncName[]={"SUMA_ConvexHull_ParseInput"}; 
   SUMA_GENERIC_PROG_OPTIONS_STRUCT *Opt=NULL;
   int kar, i, ind;
   char *outname;
   SUMA_Boolean brk = NOPE;
   SUMA_Boolean LocalHead = NOPE;

   SUMA_ENTRY;
   
   Opt = (SUMA_GENERIC_PROG_OPTIONS_STRUCT *)SUMA_malloc(sizeof(SUMA_GENERIC_PROG_OPTIONS_STRUCT));
   
   kar = 1;
   Opt->spec_file = NULL;
   Opt->out_prefix = NULL;
   Opt->sv_name = NULL;
   Opt->N_surf = -1;
   Opt->in_name = NULL;
   Opt->cmask = NULL;
   Opt->MaskMode = SUMA_ISO_UNDEFINED;
   for (i=0; i<SUMA_GENERIC_PROG_MAX_SURF; ++i) { Opt->surf_names[i] = NULL; }
   outname = NULL;
   Opt->in_vol = NULL;
   Opt->nvox = -1;
   Opt->ninmask = -1;
   Opt->mcdatav = NULL;
   Opt->debug = 0;
   Opt->v0 = 0.0;
   Opt->v1 = -1.0;
   Opt->fvec = NULL;
   Opt->SurfFileType = SUMA_PLY;
   Opt->SurfFileFormat = SUMA_ASCII;
   Opt->xform = SUMA_ISO_XFORM_MASK;
   Opt->obj_type = -1;
   Opt->obj_type_res = -1;
   Opt->XYZ = NULL;
   Opt->in_1D = NULL;
   Opt->N_XYZ = 0;
	brk = NOPE;
	while (kar < argc) { /* loop accross command ine options */
		/*fprintf(stdout, "%s verbose: Parsing command line...\n", FuncName);*/
		if (strcmp(argv[kar], "-h") == 0 || strcmp(argv[kar], "-help") == 0) {
			 usage_SUMA_ConvexHull(ps);
          exit (0);
		}
		
		SUMA_SKIP_COMMON_OPTIONS(brk, kar);
      
      if (!brk && (strcmp(argv[kar], "-xform") == 0)) {
         kar ++;
         if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -xform \n");
				exit (1);
			}
         if (!strcmp(argv[kar], "mask")) {
            Opt->xform = SUMA_ISO_XFORM_MASK;
         } else if (!strcmp(argv[kar], "none")) {
            Opt->xform = SUMA_ISO_XFORM_NONE;
         } else if (!strcmp(argv[kar], "shift")) {
            Opt->xform = SUMA_ISO_XFORM_SHIFT;
         }else {
            fprintf (SUMA_STDERR, "%s is a bad parameter for -xform option. \n", argv[kar]);
				exit (1);
         }
         brk = YUP;
      }
      
      if (!brk && (strcmp(argv[kar], "-input_1D") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -input_1D \n");
				exit (1);
			}
			Opt->in_1D = argv[kar];
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-debug") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -debug \n");
				exit (1);
			}
			Opt->debug = atoi(argv[kar]);
         if (Opt->debug > 2) { LocalHead = YUP; }
         brk = YUP;
		}      
      
      if (!brk && (strcmp(argv[kar], "-isocmask") == 0)) {
         if (Opt->MaskMode != SUMA_ISO_UNDEFINED) {
            fprintf (SUMA_STDERR, "only one masking mode (-iso*) allowed.\n");
         }
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -isocmask \n");
				exit (1);
			}
			Opt->cmask = argv[kar];
         Opt->MaskMode = SUMA_ISO_CMASK;
			brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-isoval") == 0)) {
         if (Opt->MaskMode != SUMA_ISO_UNDEFINED) {
            fprintf (SUMA_STDERR, "only one masking mode (-iso*) allowed.\n");
         }
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -isoval \n");
				exit (1);
			}
			Opt->v0 = atof(argv[kar]);
         Opt->MaskMode = SUMA_ISO_VAL;
			brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-isorange") == 0)) {
         if (Opt->MaskMode != SUMA_ISO_UNDEFINED) {
            fprintf (SUMA_STDERR, "only one masking mode (-iso*) allowed.\n");
         }
         kar ++;
			if (kar+1 >= argc)  {
		  		fprintf (SUMA_STDERR, "need 2 arguments after -isorange \n");
				exit (1);
			}
			Opt->v0 = atof(argv[kar]);kar ++;
         Opt->v1 = atof(argv[kar]);
         Opt->MaskMode = SUMA_ISO_RANGE;
         if (Opt->v1 < Opt->v0) {
            fprintf (SUMA_STDERR, "range values wrong. Must have %f <= %f \n", Opt->v0, Opt->v1);
				exit (1);
         }
			brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-input") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -input \n");
				exit (1);
			}
			Opt->in_name = SUMA_copy_string(argv[kar]);
         brk = YUP;
		}
      
      if (!brk && !ps->arg_checked[kar]) {
			fprintf (SUMA_STDERR,"Error %s:\nOption %s not understood. Try -help for usage\n", FuncName, argv[kar]);
			exit (1);
		} else {	
			brk = NOPE;
			kar ++;
		}
   }
   
   /* transfer some options to Opt from ps. Clunky because this is retrofitting */
   if (ps->o_N_surfnames) {
      Opt->out_prefix = SUMA_copy_string(ps->o_surfnames[0]);
      Opt->SurfFileType = ps->o_FT[0];
      Opt->SurfFileFormat = ps->o_FF[0];
   }
   
   if (ps->i_N_surfnames) {
      if (Opt->in_name || Opt->in_1D) {
         fprintf (SUMA_STDERR,"Error %s:\nOptions -i_TYPE, -input and -input_1D are mutually exclusive.\n", FuncName);
         exit(1);
      }
   }
   
   if (Opt->in_name) {
      if (ps->i_N_surfnames !=0 || Opt->in_1D) {
         fprintf (SUMA_STDERR,"Error %s:\nOptions -i_TYPE, -input and -input_1D are mutually exclusive.\n", FuncName);
         exit(1);
      }
   }
   
   if (Opt->in_1D) {
      if (ps->i_N_surfnames !=0 || Opt->in_name) {
         fprintf (SUMA_STDERR,"Error %s:\nOptions -i_TYPE, -input and -input_1D are mutually exclusive.\n", FuncName);
         exit(1);
      }
   }
   
   if (Opt->in_name && Opt->obj_type >= 0) {
      fprintf (SUMA_STDERR,"Error %s:\nOptions -input and -shape are mutually exclusive.\n", FuncName);
      exit(1);
   }
   if ((!Opt->in_name && Opt->obj_type < 0) && (!Opt->in_1D && !ps->i_N_surfnames)) {
      fprintf (SUMA_STDERR,"Error %s:\nEither -input or -input_1D or -i_TYPE options must be used.\n", FuncName);
      exit(1);
   }
   
   if (Opt->in_1D || ps->i_N_surfnames) {
      if (Opt->MaskMode != SUMA_ISO_UNDEFINED) {
         fprintf (SUMA_STDERR,"Error %s:\nCannot use -iso* options with either -input_1D or -i_TYPE options.\n", FuncName);
         exit(1);
      }
      if (Opt->xform != SUMA_ISO_XFORM_MASK) {
         fprintf (SUMA_STDERR,"Error %s:\nCannot use -xform option with either -input_1D or -i_TYPE options.\n", FuncName);
         exit(1);
      }
   }
   
   if (!Opt->out_prefix) Opt->out_prefix = SUMA_copy_string("convexhull_out");
   
   if (Opt->xform == SUMA_ISO_XFORM_NONE) {
      if (Opt->v0 != 0) {
         fprintf (SUMA_STDERR,"Error %s: Bad %f isovalue\nWith -xform none you can only extract the 0 isosurface.\n(i.e. -isoval 0)\n", FuncName, Opt->v0);
         exit(1);
      }
      if (Opt->MaskMode != SUMA_ISO_VAL) {
         fprintf (SUMA_STDERR,"Error %s: \nWith -xform none you can only use -isoval 0\n", FuncName);
         exit(1);
      }
   }
   
   if (Opt->xform == SUMA_ISO_XFORM_SHIFT) {
      if (Opt->MaskMode != SUMA_ISO_VAL) {
         fprintf (SUMA_STDERR,"Error %s: \nWith -xform shift you can only use -isoval val\n", FuncName);
         exit(1);
      }
   }
   
   SUMA_RETURN(Opt);
}

int main (int argc,char *argv[])
{/* Main */    
   static char FuncName[]={"ConvexHull"}; 
	int i, i3, nspec = 0;
   void *SO_name=NULL;
   SUMA_SurfaceObject *SO = NULL;
   SUMA_GENERIC_PROG_OPTIONS_STRUCT *Opt;  
   char  stmp[200];
   SUMA_Boolean exists = NOPE;
   SUMA_Boolean LocalHead = NOPE;
   SUMA_GENERIC_ARGV_PARSE *ps=NULL;

   SUMA_STANDALONE_INIT;
	SUMA_mainENTRY;
   
   
   /* Allocate space for DO structure */
	SUMAg_DOv = SUMA_Alloc_DisplayObject_Struct (SUMA_MAX_DISPLAYABLE_OBJECTS);
   ps = SUMA_Parse_IO_Args(argc, argv, "-o;-i;-sv;");
   
   if (argc < 2) {
      usage_SUMA_ConvexHull(ps);
      exit (1);
   }
   
   Opt = SUMA_ConvexHull_ParseInput (argv, argc, ps);
      
   SO_name = SUMA_Prefix2SurfaceName(Opt->out_prefix, NULL, NULL, Opt->SurfFileType, &exists);
   if (exists) {
      fprintf(SUMA_STDERR,"Error %s:\nOutput file(s) %s* on disk.\nWill not overwrite.\n", FuncName, Opt->out_prefix);
      exit(1);
   }
   
   if (Opt->obj_type < 0) {
      if (Opt->in_name) {
         if (Opt->debug) {
            SUMA_S_Note("Creating mask...");
         }
         if (!SUMA_Get_isosurface_datasets (Opt)) {
            SUMA_SL_Err("Failed to get data.");
            exit(1);
         }

         if (Opt->debug > 1) {
            if (Opt->debug == 2) {
               FILE *fout=fopen("inmaskvec.1D","w");
               SUMA_S_Note("Writing masked values...\n");
               if (!fout) {
                  SUMA_SL_Err("Failed to write maskvec");
                  exit(1);
               }
               fprintf(fout,  "#Col. 0 Voxel Index\n"
                              "#Col. 1 Is a mask (all values here should be 1)\n" );
               for (i=0; i<Opt->nvox; ++i) {
                  if (Opt->mcdatav[i]) {
                     fprintf(fout,"%d %.2f\n", i, Opt->mcdatav[i]);
                  }
               }
               fclose(fout); fout = NULL;
            } else {
               FILE *fout=fopen("maskvec.1D","w");
               SUMA_S_Note("Writing all mask values...\n");
               if (!fout) {
                  SUMA_S_Err("Failed to write maskvec");
                  exit(1);
               }
               fprintf(fout,  "#Col. 0 Voxel Index\n"
                              "#Col. 1 Is in mask ?\n" );
               for (i=0; i<Opt->nvox; ++i) {
                  fprintf(fout,"%d %.2f\n", i, Opt->mcdatav[i]);
               }
               fclose(fout); fout = NULL;
            }
         }
      } else if (Opt->in_1D) {
            MRI_IMAGE *im = NULL;
            float *far=NULL;
            int nx2;
            
            /* load the 1D file */
            im = mri_read_1D (Opt->in_1D);
            if (!im) {
               SUMA_S_Err("Failed to read file");
               exit(1);
            }   

            far = MRI_FLOAT_PTR(im);
            if (im->nx == 0) {
               fprintf(SUMA_STDERR,"Error %s:\n Empty file %s.\n", FuncName, Opt->in_1D);
               exit(1);
            }
            if (im->ny != 3) {
               fprintf(SUMA_STDERR,"Error %s:\n Found %d columns in %s. Expecting 3\n", FuncName, im->ny, Opt->in_1D);
               exit(1);
            }
            
            /* copy the columns */
            Opt->N_XYZ = im->nx;
            Opt->XYZ = (float *)SUMA_malloc(im->nx*im->ny*sizeof(float));
            if (!Opt->XYZ) {
               SUMA_S_Crit("Failed to allocate.");
               exit(1);
            }
            nx2 = 2*im->nx;
            for (i=0;i<Opt->N_XYZ; ++i) {
               i3 = 3*i;
               Opt->XYZ[i3  ] = far[i];
               Opt->XYZ[i3+1] = far[i+im->nx];
               Opt->XYZ[i3+2] = far[i+nx2];
            }
            
            /* done, clean up and out you go */
            if (im) mri_free(im); im = NULL; 
            
            
      } else if (ps->i_N_surfnames) {
         SUMA_SurfSpecFile *Spec=NULL;
         SUMA_SurfaceObject *SO=NULL;
         
         if (ps->i_N_surfnames > 1) {
            SUMA_S_Err("Only 1 input surface allowed!");
            exit(1);
         }
         Spec = SUMA_IO_args_2_spec(ps, &nspec);
         if (!Spec) {
            SUMA_S_Err("Failed to create spec!");
            exit(1);
         }
         if (nspec != 1) {
            SUMA_S_Warn("Expected one spec and nothing else");
         }
         /* load the surface object */
         SO = SUMA_Load_Spec_Surf(Spec, 0, ps->sv[0], 0);
         if (!SO) {
            SUMA_S_Err("Failed to read surface.");
            exit(1);
         }
         /* transfer coords */
         if(SO->NodeDim != 3) {
            SUMA_S_Err("bad node coords.");
            exit(1);
         }
         
         Opt->N_XYZ = SO->N_Node;
         Opt->XYZ = (float *)SUMA_malloc(SO->N_Node * SO->NodeDim * sizeof(float));
         if (!Opt->XYZ) {
            SUMA_S_Crit("Failed to allocate.");
            exit(1);
         }
         for (i=0;i<SO->NodeDim*SO->N_Node; ++i) Opt->XYZ[i] = SO->NodeList[i];
         
         if (nspec) {
            int k=0; 
            for (k=0; k<nspec; ++k) {
               if (!SUMA_FreeSpecFields(&(Spec[k]))) { SUMA_S_Err("Failed to free spec fields"); } 
            }
            SUMA_free(Spec); Spec = NULL; nspec = 0;
         }

         if (SO) SUMA_Free_Surface_Object(SO); SO = NULL;
      } else {
         SUMA_S_Err("No input!");
         exit(1);
      }
   } else {
      SUMA_S_Err("Bad input!");
      exit(1);
   }
   /* Now call Marching Cube functions */
   if (!(SO = SUMA_ConvexHullSurface(Opt))) {
      SUMA_S_Err("Failed to create surface.\n");
      exit(1);
   }

   /* write the surface to disk */
   if (!SUMA_Save_Surface_Object (SO_name, SO, Opt->SurfFileType, Opt->SurfFileFormat, NULL)) {
      fprintf (SUMA_STDERR,"Error %s: Failed to write surface object.\n", FuncName);
      exit (1);
   }
   
   if (ps) SUMA_FreeGenericArgParse(ps); ps = NULL;
   if (Opt->fvec) SUMA_free(Opt->fvec); Opt->fvec = NULL;
   if (Opt->mcdatav) {SUMA_free(Opt->mcdatav); Opt->mcdatav = NULL;} 
   if (Opt->in_vol) { DSET_delete( Opt->in_vol); Opt->in_vol = NULL;} 
   if (Opt->out_prefix) SUMA_free(Opt->out_prefix); Opt->out_prefix = NULL;
   if (Opt->XYZ) SUMA_free(Opt->XYZ); Opt->XYZ = NULL;
   if (Opt) SUMA_free(Opt);
   if (!SUMA_Free_Displayable_Object_Vect (SUMAg_DOv, SUMAg_N_DOv)) {
      SUMA_SL_Err("DO Cleanup Failed!");
   }
   if (SO_name) SUMA_free(SO_name); SO_name = NULL;
   if (!SUMA_Free_CommonFields(SUMAg_CF)) SUMA_error_message(FuncName,"SUMAg_CF Cleanup Failed!",1);
   exit(0);
}   
#endif


syntax highlighted by Code2HTML, v. 0.9.1