예제 #1
0
int main (int argc,char *argv[])
{/* Main */    
   static char FuncName[]={"SurfToSurf"}; 
   SUMA_GENERIC_PROG_OPTIONS_STRUCT *Opt;  
   SUMA_GENERIC_ARGV_PARSE *ps=NULL;
   SUMA_SurfaceObject *SO1=NULL, *SO2 = NULL;
   SUMA_SurfSpecFile *Spec = NULL;
   SUMA_M2M_STRUCT *M2M = NULL;
   int N_Spec=0, *nodeind = NULL, N_nodeind, icol, i, j;
   MRI_IMAGE *im = NULL, *im_data=NULL;
	int nvec=0, ncol=0, nvec_data=0, ncol_data=0, Nchar=0;
   float *far = NULL, *far_data=NULL, *dt = NULL, *projdir=NULL;
   char *outname = NULL, *s=NULL, sbuf[100];
   void *SO_name = NULL;   
   FILE *outptr=NULL;
   SUMA_Boolean exists = NOPE;
   SUMA_INDEXING_ORDER d_order = SUMA_NO_ORDER;
   SUMA_STRING *SS=NULL;
   SUMA_Boolean LocalHead = NOPE;

   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, "-i;-t;-spec;-s;-sv;-o;");
   
   Opt = SUMA_SurfToSurf_ParseInput (argv, argc, ps);
   if (argc < 2) {
      SUMA_S_Err("Too few options");
      usage_SurfToSurf(ps, 0);
      exit (1);
   }
   

   /* if output surface requested, check on pre-existing file */
   if (ps->o_N_surfnames) {
      SO_name = SUMA_Prefix2SurfaceName(ps->o_surfnames[0], 
                                        NULL, NULL, ps->o_FT[0], &exists);
      if (exists) {
         fprintf(SUMA_STDERR,
                  "Error %s:\nOutput file(s) %s* on disk.\n"
                  "Will not overwrite.\n", FuncName, ps->o_surfnames[0]);
         exit(1);
      }
   } 
   
   if (Opt->debug > 2) LocalHead = YUP;
   outname = SUMA_append_extension(Opt->out_prefix,".1D");
   if (SUMA_filexists(outname) && !THD_ok_overwrite()) {
      fprintf(SUMA_STDERR,"Output file %s exists.\n", outname);
      exit(1);
   }
   
   /* Load the surfaces from command line*/
   Spec = SUMA_IO_args_2_spec(ps, &N_Spec);
   if (N_Spec != 1) {
      SUMA_S_Err( "Multiple spec at input.\n"
                  "Do not mix surface input types together\n");
      exit(1);
   }

      if (Spec->N_Surfs != 2) {
      SUMA_S_Err("2 surfaces expected.");
      exit(1);
   }
   
   SO1 = SUMA_Load_Spec_Surf(Spec, 0, ps->sv[0], 0);
   if (!SO1) {
         fprintf (SUMA_STDERR,"Error %s:\n"
                              "Failed to find surface\n"
                              "in spec file. \n",
                              FuncName );
         exit(1);
   }
   if (!SUMA_SurfaceMetrics(SO1, "EdgeList|MemberFace", NULL)) { 
      SUMA_SL_Err("Failed to create edge list for SO1"); 
      exit(1);  
   }
   if (Opt->fix_winding) {
      int orient, trouble;
      if (LocalHead) 
         fprintf(SUMA_STDERR,
                  "%s: Making sure S1 is consistently orientated\n", FuncName);
      if (!SUMA_MakeConsistent (SO1->FaceSetList, SO1->N_FaceSet, 
                                SO1->EL, Opt->debug, &trouble)) {
         SUMA_SL_Err("Failed in SUMA_MakeConsistent");
      }
      if (trouble && LocalHead) {
         fprintf(SUMA_STDERR,
                     "%s: trouble value of %d from SUMA_MakeConsistent.\n"
                     "Inconsistencies were found and corrected unless \n"
                     "stderr output messages from SUMA_MakeConsistent\n"
                     "indicate otherwise.\n", FuncName, trouble);
      }
      if (LocalHead) 
         fprintf(SUMA_STDERR,"%s: Checking orientation.\n", FuncName);
      orient = SUMA_OrientTriangles (SO1->NodeList, SO1->N_Node, 
                                     SO1->FaceSetList, SO1->N_FaceSet, 
                                     1, 0, NULL, NULL);
      if (orient < 0) { 
         /* flipping was done, dump the edge list since it is not 
            automatically updated (should do that in function, 
            just like in SUMA_MakeConsistent,  shame on you) 
            
            If you revisit this section, use the newer:
            SUMA_OrientSOTriangles
         */ 
         if (SO1->EL) SUMA_free_Edge_List(SO1->EL); SO1->EL = NULL; 
         if (!SUMA_SurfaceMetrics(SO1, "EdgeList", NULL)) { 
            SUMA_SL_Err("Failed to create edge list for SO1"); exit(1);  
         }
         /* free normals, new ones needed (Normals should be flipped inside  of 
            SUMA_OrientTriangles! (just like in SUMA_MakeConsistent) ) */
         if (SO1->NodeNormList) SUMA_free(SO1->NodeNormList); 
            SO1->NodeNormList = NULL;
         if (SO1->FaceNormList) SUMA_free(SO1->FaceNormList); 
            SO1->FaceNormList = NULL;
      }
      if (!orient) { 
         fprintf(SUMA_STDERR,
                  "Error %s:\nFailed in SUMA_OrientTriangles\n", FuncName); 
      }
      if (LocalHead) {
         if (orient < 0) { SUMA_SL_Note("S1 was reoriented"); }
         else { SUMA_SL_Note("S1 was properly oriented"); }
      }
   }
  
   
   if (!SO1->NodeNormList || !SO1->FaceNormList) { 
      SUMA_LH("Node Normals"); SUMA_RECOMPUTE_NORMALS(SO1); 
   }
   if (Opt->NodeDbg >= SO1->N_Node) {
      SUMA_SL_Warn(  "node_debug index is larger than number "
                     "of nodes in surface, ignoring -node_debug.");
      Opt->NodeDbg = -1;
   }
      
   SO2 = SUMA_Load_Spec_Surf(Spec, 1, ps->sv[1], 0);
   if (!SO2) {
      fprintf (SUMA_STDERR,"Error %s:\n"
                           "Failed to find surface\n"
                           "in spec file. \n",
                           FuncName );
      exit(1);
   }  
   if (!SUMA_SurfaceMetrics(SO2, "EdgeList|MemberFace", NULL)) { 
      SUMA_SL_Err("Failed to create edge list for SO2"); exit(1);  
   }
   if (!SO2->NodeNormList || !SO2->FaceNormList) { 
      SUMA_LH("Node Normals"); SUMA_RECOMPUTE_NORMALS(SO2); 
   }
   
   if (LocalHead) { 
      SUMA_LH("Surf1");
      SUMA_Print_Surface_Object(SO1, NULL);
      SUMA_LH("Surf2");
      SUMA_Print_Surface_Object(SO2, NULL);
   }
   
   /* a select list of nodes? */
   nodeind = NULL; N_nodeind = 0;
   if (Opt->in_nodeindices) {
      im = mri_read_1D(Opt->in_nodeindices);
      if (!im) { SUMA_SL_Err("Failed to read 1D file of node indices"); exit(1);}
      far = MRI_FLOAT_PTR(im);
      N_nodeind = nvec = im->nx;
      ncol = im->ny;
      if (ncol != 1) { 
         SUMA_SL_Err("More than one column in node index input file."); exit(1);
      }
      nodeind = (int *)SUMA_calloc(nvec, sizeof(int));
      if (!nodeind) { SUMA_SL_Crit("Failed to allocate"); exit(1); }
      for (i=0;i<nvec;++i) { 
         nodeind[i] = (int)far[i]; 
         if (nodeind[i] < 0 || nodeind[i] >= SO1->N_Node) {
            fprintf(SUMA_STDERR, 
                    "Error %s:\n"
                    "A node index of %d was found in input file %s, entry %d.\n"
                    "Acceptable indices are positive and less than %d\n", 
                    FuncName, nodeind[i], Opt->in_nodeindices, i, SO1->N_Node);
            exit(1);
         }
      } 
      mri_free(im); im = NULL;   /* done with that baby */
   }
   
   /* a preset directions vector ?*/
   projdir = NULL; 
   if (Opt->in_1D) {
      im = mri_read_1D(Opt->in_1D);
      if (!im) { 
         SUMA_SL_Err("Failed to read 1D file of projection directions"); exit(1);
      }
      far = MRI_FLOAT_PTR(im);
      if (im->ny != 3) { 
         SUMA_SL_Err("Need three columns in projection directions file."); 
         exit(1); 
      }
      if (im->nx != SO1->N_Node) {
         fprintf(SUMA_STDERR, 
                  "Error %s: You must have a direction for each node in SO1.\n"
                  "%d directions found but SO1 has %d nodes.\n", 
                  FuncName, im->nx, SO1->N_Node);
         exit(1);
      }

      /* change to row major major and make it match nodeind */
      projdir = (float *)SUMA_calloc(SO1->N_Node*3, sizeof(float));
      if (!projdir) { SUMA_SL_Crit("Failed to allocate"); exit(1); }
      for (i=0; i<SO1->N_Node; ++i) {
         projdir[3*i  ] = far[i              ];
         projdir[3*i+1] = far[i+  SO1->N_Node];
         projdir[3*i+2] = far[i+2*SO1->N_Node];
      }
      mri_free(im); im = NULL;   /* done with that baby */

   }
   
   if (SO_name) {
      /* user is interpolating surface coords, check on other input insanity */
      if (nodeind) {
         fprintf( SUMA_STDERR, 
                  "Error %s: You cannot combine "
                  "option -o_TYPE with -node_indices", FuncName);
         exit(1);
      }
      if (Opt->in_name) {
         fprintf(SUMA_STDERR, 
                  "Error %s: You cannot combine option -o_TYPE with -data", 
                  FuncName);
         exit(1);
      }
   } 
   /* a 1D file containing data, or Data parameter (for XYZ)? */
   if (Opt->Data > 0) {
      if (Opt->in_name) {
         /* When you are ready to work with dsets, you should 
         checkout the function morphDsetToStd. It uses M2M */
         im_data = mri_read_1D(Opt->in_name);
         if (!im_data) { 
            SUMA_SL_Err("Failed to read 1D file of data"); exit(1);}
         far_data = MRI_FLOAT_PTR(im_data);
         nvec_data = im_data->nx;
         ncol_data = im_data->ny;
         if (nvec_data != SO2->N_Node) {
            SUMA_SL_Err("Your data file must have one row "
                        "for each node in surface 2.\n"); exit(1);
         }
         d_order = SUMA_COLUMN_MAJOR;
      } else { 
         im_data = NULL;
         far_data = SO2->NodeList;
         nvec_data = SO2->N_Node;
         ncol_data = 3;
         d_order = SUMA_ROW_MAJOR;
      }
   } else {
      /* just -dset */
   }
   
     

   
   if (!Opt->s) {
      SUMA_LH("Going for the mapping of SO1 --> SO2");
      M2M = SUMA_GetM2M_NN( SO1, SO2, nodeind, N_nodeind, 
                            projdir, 0, Opt->NodeDbg, Opt->iopt);
      SUMA_S_Notev("Saving M2M into %s\n\n",
               Opt->out_prefix);
      if (!(SUMA_Save_M2M(Opt->out_prefix, M2M))) {
         SUMA_S_Err("Failed to save M2M");
         exit(1);
      }
   } else {
      SUMA_S_Notev("Reusing mapping of SO1 --> SO2 from %s\n\n", 
               Opt->s);   
      if (!(M2M = SUMA_Load_M2M(Opt->s))) {
         SUMA_S_Errv("Failed to load %s\n", Opt->s);
         exit(1);
      }
   }

   /* Now show the mapping results for a debug node ? */
   if (Opt->NodeDbg >= 0) {
      char *s = NULL;
      s = SUMA_M2M_node_Info(M2M, Opt->NodeDbg);
      fprintf(SUMA_STDERR,"%s: Debug for node %d ([%f, %f, %f])of SO1:\n%s\n\n", 
                           FuncName, Opt->NodeDbg, 
                           SO1->NodeList[3*Opt->NodeDbg], 
                           SO1->NodeList[3*Opt->NodeDbg+1], 
                           SO1->NodeList[3*Opt->NodeDbg+2],
                           s); 
      SUMA_free(s); s = NULL;
   }
   
   /* Now please do the interpolation */
   if (Opt->Data > 0) {
      if (Opt->NearestNode > 1) 
         dt = SUMA_M2M_interpolate( M2M, far_data, ncol_data, 
                                    nvec_data, d_order, 0 );
      else if (Opt->NearestNode == 1) 
         dt = SUMA_M2M_interpolate( M2M, far_data, ncol_data, 
                                    nvec_data, d_order, 1 );
      if (!dt) {
         SUMA_SL_Err("Failed to interpolate");
         exit(1);
      }
   } else if (Opt->Data < 0) {
         SUMA_DSET *dset=NULL, *dseto=NULL;
         char *oname=NULL, *uname=NULL, *s1=NULL, *s2=NULL;
         int iform=SUMA_NO_DSET_FORMAT;
         if (Opt->NodeDbg>= 0) {
            SUMA_S_Notev("Processing dset %s\n", Opt->in_name);
         }
         iform = SUMA_NO_DSET_FORMAT;
         if (!(dset = SUMA_LoadDset_s (Opt->in_name, &iform, 0))) {
            SUMA_S_Errv("Failed to load %s\n", Opt->in_name);
            exit(1);
         }
         if (!(dseto = SUMA_morphDsetToStd ( dset, M2M, 
                                             Opt->NearestNode == 1 ? 1:0))) {
            SUMA_S_Errv("Failed to map %s\n", Opt->in_name);
            exit(1);
         }
         s1 = SUMA_append_string(
                  SUMA_FnameGet(Opt->in_name,"pa", SUMAg_CF->cwd),
                  Opt->out_prefix); 
         s2 = SUMA_RemoveDsetExtension_s(
               SUMA_FnameGet(Opt->in_name,"l",SUMAg_CF->cwd), 
               SUMA_NO_DSET_FORMAT);
         uname = SUMA_append_extension(s1,s2);      
         SUMA_free(s1); SUMA_free(s2);
         oname = SUMA_WriteDset_s (uname, dseto, Opt->oform, 1, 1);
         if (Opt->NodeDbg>= 0) SUMA_S_Notev("Wrote %s\n", oname);
         if (oname) SUMA_free(oname); oname=NULL;
         if (uname) SUMA_free(uname); oname=NULL;
         if (dseto) SUMA_FreeDset(dseto); dseto = NULL;
         if (dset) SUMA_FreeDset(dset); dset = NULL;      
   }
   
   SUMA_LH("Forming the remaining output");
   outptr = fopen(outname,"w");
   if (!outptr) {
      SUMA_SL_Err("Failed to open file for output.\n");
      exit(1);
   }
   
   /* first create the header of the output */
   SS = SUMA_StringAppend(NULL, NULL);
   SS = SUMA_StringAppend_va(SS, 
      "#Mapping from nodes on surf 1 (S1) to nodes on surf 2 (S2)\n"
      "#  Surf 1 is labeled %s, idcode:%s\n"
      "#  Surf 2 is labeled %s, idcode:%s\n",
      SO1->Label, SO1->idcode_str, SO2->Label, SO2->idcode_str);
   icol = 0;
   SS = SUMA_StringAppend_va(SS, "#Col. %d:\n"
                                 "#     S1n (or nj): Index of node on S1\n"
                                 , icol); 
   ++icol;
   if (Opt->NearestNode > 1) {
      SS = SUMA_StringAppend_va(SS, 
         "#Col. %d..%d:\n"
         "#     S2ne_S1n: Indices of %d nodes on S2 \n"
         "#     that are closest neighbors of nj.\n"
         "#     The first index is that of the node on S2 that is closest \n"
         "#     to nj. If -1 then these values should be ignored because\n"
         "#     in such cases, nj's projection failed.\n" 
         , icol, icol+Opt->NearestNode-1, Opt->NearestNode); 
      icol += Opt->NearestNode;
      SS = SUMA_StringAppend_va(SS, 
         "#Col. %d..%d:\n"
         "#     S2we_S1n: Weights assigned to nodes on surf 2 (S2) \n"
         "#     that are closest neighbors of nj.\n"
         , icol, icol+Opt->NearestNode-1, Opt->NearestNode); 
      icol += Opt->NearestNode;
   } else if (Opt->NearestNode == 1) {
      SS = SUMA_StringAppend_va(SS, 
         "#Col. %d:\n"
         "#     S2ne_S1n: Index of the node on S2 (label:%s idcode:%s)\n"
         "#     that is the closest neighbor of nj.\n"
         "#     If -1 then this value should be ignored because\n"
         "#     nj's projection failed.\n" 
         , icol, SO2->Label, SO2->idcode_str); 
      ++icol;
   }
   if (Opt->NearestTriangle) { 
      SS = SUMA_StringAppend_va(SS, 
         "#Col. %d:\n"
         "#     S2t_S1n: Index of the S2 triangle that hosts node nj on S1.\n"
         "#     In other words, nj's closest projection onto S2 falls on \n"
         "#     triangle S2t_S1n\n"
         "#     If -1 then this value should be ignored because \n"
         "#     nj's projection failed.\n" 
         , icol); 
      ++icol; 
   }
   if (Opt->ProjectionOnMesh) { 
      SS = SUMA_StringAppend_va(SS, 
         "#Col. %d..%d:\n"
         "#     S2p_S1n: Coordinates of projection of nj onto S2\n"
         , icol, icol+2); 
      icol += 3; 
   }
   if (Opt->DistanceToMesh) {
      SS = SUMA_StringAppend_va(SS, 
         "#Col. %d:\n"
         "#     Closest distance from nj to S2\n"
         , icol); 
         ++icol;
   }
   if (Opt->NearestNodeCoords) {
      SS = SUMA_StringAppend_va(SS, 
         "#Col. %d .. %d:\n"
         "#     X Y Z coords of nearest node\n"
         , icol,  icol+2); 
      icol += 3; 
   }
   if (Opt->Data > 0) {
      if (!Opt->in_name) {
         SS = SUMA_StringAppend_va(SS, 
      "#Col. %d..%d:\n"
      "#     Interpolation using XYZ coordinates of S2 nodes that neighbor nj\n"
      "#     (same as coordinates of node's projection onto triangle in S2, \n"
      "#     if using barycentric interpolation)\n"
         , icol, icol+2); 
      icol += 3; 
} else {
SS = SUMA_StringAppend_va(SS, 
         "#Col. %d..%d:\n"
         "#     Interpolation of data at nodes on S2 that neighbor nj\n"
         "#     Data obtained from %s\n"
         , icol, icol+ncol_data-1, Opt->in_name);  icol += ncol_data;
      }
   } 
   s = SUMA_HistString("SurfToSurf", argc, argv, NULL);
   SS = SUMA_StringAppend_va(SS, 
                                "#History:\n"
                                "#%s\n", s); SUMA_free(s); s = NULL;
   SUMA_SS2S(SS,s);
   fprintf(outptr,"%s\n",s); SUMA_free(s); s = NULL;
   
   /* put headers atop columns */
   Nchar = 6; /* if you change this number you'll need to fix  formats below */
   for (i=0; i<icol; ++i) { 
      sprintf(sbuf,"#%s", MV_format_fval2(i, Nchar -1)); 
      fprintf(outptr,"%6s   ", sbuf); 
   }
   fprintf(outptr,"\n");
   
   /* Now put in the values, make sure you parallel columns above! */
   for (i=0; i<M2M->M1Nn; ++i) {
      fprintf(outptr,"%6s   ", MV_format_fval2(M2M->M1n[i], Nchar));
      if (Opt->NearestNode > 0) {
         for (j=0; j<Opt->NearestNode; ++j) { 
            if (j < M2M->M2Nne_M1n[i]) 
               fprintf(outptr,"%6s   ", 
                  MV_format_fval2(M2M->M2ne_M1n[i][j], Nchar)); 
            else fprintf(outptr,"%6s   ", "-1"); 
         } /* Neighboring nodes */
      } 
      if (Opt->NearestNode > 1) { /* add the weights */
         for (j=0; j<Opt->NearestNode; ++j) { 
            if (j < M2M->M2Nne_M1n[i]) 
               fprintf(outptr,"%6s   ", 
                  MV_format_fval2(M2M->M2we_M1n[i][j], Nchar)); 
            else fprintf(outptr,"%6s   ", "0.0"); 
         } 
      }
      if (Opt->NearestTriangle) {
         fprintf(outptr,"%6s   ", MV_format_fval2(M2M->M2t_M1n[i], Nchar)); 
      }
      if (Opt->ProjectionOnMesh) {
         fprintf(outptr,"%6s   ", MV_format_fval2(M2M->M2p_M1n[3*i], Nchar));
         fprintf(outptr,"%6s   ", MV_format_fval2(M2M->M2p_M1n[3*i+1], Nchar));
         fprintf(outptr,"%6s   ", MV_format_fval2(M2M->M2p_M1n[3*i+2], Nchar)); 
      }
      if (Opt->DistanceToMesh) { 
         fprintf(outptr,"%6s   ", MV_format_fval2(M2M->PD[i], Nchar)); 
      }
      if (Opt->NearestNodeCoords) {
         float x=0.0,y=0.0,z=0.0;
         int n = M2M->M2ne_M1n[i][0];
         if (n>0) {
            n = n * SO2->NodeDim;
            x = SO2->NodeList[n];
            y = SO2->NodeList[n+1];
            z = SO2->NodeList[n+2];
         }
         fprintf(outptr,"%6s   ", MV_format_fval2(x, Nchar)); 
         fprintf(outptr,"%6s   ", MV_format_fval2(y, Nchar)); 
         fprintf(outptr,"%6s   ", MV_format_fval2(z, Nchar)); 
      }
      if (dt && Opt->Data > 0) {
         if (!Opt->in_name) {
            fprintf(outptr,"%6s   ", MV_format_fval2(dt[3*i], Nchar));
            fprintf(outptr,"%6s   ", MV_format_fval2(dt[3*i+1], Nchar));
            fprintf(outptr,"%6s   ", MV_format_fval2(dt[3*i+2], Nchar));
         } else { /* Column major business */
            for (j=0; j<ncol_data; ++j) { 
               fprintf(outptr,"%6s   ", 
                     MV_format_fval2(dt[i+j*M2M->M1Nn], Nchar)); }
         }
      }
      fprintf(outptr,"\n");
   }
   
   /* do they want an output surface ? */
   if (SO_name) {
      float *tmpfv = NULL;
      SUMA_LH("Writing surface");
      tmpfv = SO1->NodeList;
      SO1->NodeList = dt;
      if (!SUMA_Save_Surface_Object (SO_name, SO1, 
                                     ps->o_FT[0], ps->o_FF[0], NULL)) {
         SUMA_S_Err("Failed to write surface object.\n");
         exit (1);
      }
      SO1->NodeList = tmpfv; tmpfv = NULL;
   }
   
   if (N_Spec) {
      int k=0; 
      for (k=0; k<N_Spec; ++k) {
         if (!SUMA_FreeSpecFields(&(Spec[k]))) {
            SUMA_S_Err("Failed to free spec fields");
         } 
      }
      SUMA_free(Spec); Spec = NULL; N_Spec = 0;
   }

   if (projdir) SUMA_free(projdir); projdir = NULL;
   if (SO_name) SUMA_free(SO_name); SO_name = NULL;   
   if (outptr) fclose(outptr); outptr = NULL;
   if (dt) SUMA_free(dt); dt = NULL;
   if (s) SUMA_free(s); s = NULL;
   if (im_data) mri_free(im_data); im_data = NULL;   /* done with the data */
   if (nodeind) SUMA_free(nodeind); nodeind = NULL;
   if (M2M) M2M = SUMA_FreeM2M(M2M);
   if (SO1) SUMA_Free_Surface_Object(SO1); SO1 = NULL;
   if (SO2) SUMA_Free_Surface_Object(SO2); SO2 = NULL;
   if (Spec) SUMA_free(Spec); Spec = NULL;
   if (ps) SUMA_FreeGenericArgParse(ps); ps = NULL;
   if (Opt) Opt = SUMA_Free_Generic_Prog_Options_Struct(Opt);
   if (!SUMA_Free_CommonFields(SUMAg_CF)) SUMA_error_message(FuncName,"SUMAg_CF Cleanup Failed!",1);
   exit(0);
   
} 
예제 #2
0
int main (int argc,char *argv[])
{/* Main */    
   static char FuncName[]={"SurfPatch"};
   SUMA_GETPATCH_OPTIONS *Opt; 
   char *ppref=NULL, ext[5]; 
   float *far=NULL;
   MRI_IMAGE *im = NULL;
   int SO_read = -1;
   int   *NodePatch=NULL, N_NodePatch=-1, *FaceSetList=NULL , 
         N_FaceSet = -1, N_Node = -1, N_Spec=0;          
   int i, inodeoff=-1, ilabeloff=-1, nvec, ncol, cnt;
   SUMA_SurfaceObject *SO = NULL;
   SUMA_PATCH *ptch = NULL; 
   SUMA_SurfSpecFile *Spec;
   SUMA_INDEXING_ORDER d_order;
   void *SO_name = NULL;
   SUMA_Boolean exists = NOPE;
   SUMA_SO_File_Type typetmp;
   SUMA_SurfaceObject *SOnew = NULL;
   float *NodeList = NULL;
   SUMA_GENERIC_ARGV_PARSE *ps=NULL;
   SUMA_Boolean LocalHead = NOPE;
	
   SUMA_STANDALONE_INIT;
   SUMA_mainENTRY;
   
   
   ps = SUMA_Parse_IO_Args(argc, argv, "-i;-t;-spec;-s;-sv;");
   
	/* Allocate space for DO structure */
	SUMAg_DOv = SUMA_Alloc_DisplayObject_Struct (SUMA_MAX_DISPLAYABLE_OBJECTS);
   
   Opt = SUMA_GetPatch_ParseInput (argv, argc, ps);
   if (argc < 2)
    {
       SUMA_S_Err("Too few options");
       usage_SUMA_getPatch(ps, 0);
       exit (1);
    }


   /* read all surfaces */
   Spec = SUMA_IO_args_2_spec(ps, &N_Spec);
   if (N_Spec == 0) {
      SUMA_S_Err("No surfaces found.");
      exit(1);
   }

   if (N_Spec > 1 ) {
      SUMA_S_Err( "Mike, you cannot mix -spec with -i or -t options "
                  "for specifying surfaces.");
      exit(1);
   }
   
   if (Spec->N_Surfs < 1) {
      SUMA_S_Err("No surfaces");
      exit(1);
   }
     
   if (Opt->DoVol && Spec->N_Surfs != 2) {
      SUMA_S_Errv("Must specify 2 and only 2 surfaces with -vol options\n"
                  "Have %d from the command line\n",Spec->N_Surfs);
      exit(1);
   }
   
   if (Opt->oType != SUMA_FT_NOT_SPECIFIED && !Opt->VolOnly) { 
      for (i=0; i < Spec->N_Surfs; ++i) {
         if (Spec->N_Surfs > 1) {
            sprintf(ext, "_%c", 65+i);
            ppref = SUMA_append_string(Opt->out_prefix, ext);
         } else {
            ppref = SUMA_copy_string(Opt->out_prefix);
         }
         
         SO_name = SUMA_Prefix2SurfaceName(ppref, NULL, NULL, 
                                           Opt->oType, &exists);
         if (exists && !THD_ok_overwrite()) {
            fprintf(SUMA_STDERR, "Error %s:\nOutput file(s) %s* on disk.\n"
                                 "Will not overwrite.\n", FuncName, ppref);
            exit(1);
         }
         if (ppref) SUMA_free(ppref); ppref = NULL; 
         if (SO_name) SUMA_free(SO_name); SO_name = NULL;
      } 
   }
   
   /* read in the file containing the node information */
   im = mri_read_1D (Opt->in_name);

   if (!im) {
      SUMA_S_Errv("Failed to read 1D file '%s'\n", Opt->in_name);
      exit(1);
   }

   far = MRI_FLOAT_PTR(im);
   nvec = im->nx;
   ncol = im->ny;
   if (Opt->nodecol >= ncol || Opt->labelcol >= ncol) {
      fprintf(SUMA_STDERR, "\n"
                           "Error %s: Input file has a total of %d columns.\n"
                           "One or both user-specified node (%d) and \n"
                           "label (%d) columns are too high. Maximum usable\n"
                           "column index is %d.\n"
                           , FuncName, ncol, Opt->nodecol, 
                           Opt->labelcol, ncol -1 );
      exit(1);
   }
   
   d_order = SUMA_COLUMN_MAJOR;

   if (!nvec) {
      SUMA_SL_Err("Empty file");
      exit(1);
   }
   /* form the node vector */
   NodePatch = (int *)SUMA_malloc(sizeof(int)*nvec);
   if (!NodePatch) {
      SUMA_SL_Crit("Failed to allocate.");
      exit(1);
   }
   inodeoff = Opt->nodecol*nvec;
   if (Opt->labelcol < 0) { /* all listed nodes */ 
      for (i=0; i<nvec; ++i) {
         NodePatch[i] = far[i+inodeoff];
      }
      N_NodePatch = nvec;
   } else {
      ilabeloff =  Opt->labelcol*nvec;
      if (Opt->thislabel < 0) { /* all nodes with non zero labels */
         cnt = 0;
         for (i=0; i<nvec; ++i) {
            if (far[i+ilabeloff]) {
               NodePatch[cnt] = far[i+inodeoff];
               ++cnt;
            }
         }
         N_NodePatch = cnt;     
      } else { /* select labels */
         cnt = 0;
         for (i=0; i<nvec; ++i) {
            if (far[i+ilabeloff] == Opt->thislabel) {
               NodePatch[cnt] = far[i+inodeoff];
               ++cnt;
            }
         }
         N_NodePatch = cnt;    
      }
      NodePatch = (int *) SUMA_realloc(NodePatch , sizeof(int)*N_NodePatch);
   }
   
   /* done with im, free it */
   mri_free(im); im = NULL;   
   
   if (Opt->DoVol) {
      SUMA_SurfaceObject *SO1 = 
         SUMA_Load_Spec_Surf_with_Metrics(Spec, 0, ps->sv[0], 0);
      SUMA_SurfaceObject *SO2 = 
         SUMA_Load_Spec_Surf_with_Metrics(Spec, 1, ps->sv[0], 0);
      double Vol = 0.0;
      SUMA_SurfaceObject *SOp = SUMA_Alloc_SurfObject_Struct(1);
      byte *adj_N=NULL;
      
      if (Opt->adjust_contour) 
         adj_N = SUMA_calloc(SO1->N_Node, sizeof(byte));
      
      if (!SO1 || !SO2) {
         SUMA_SL_Err("Failed to load surfaces.");
         exit(1);
      }
      /* a chunk used to test SUMA_Pattie_Volume */
      Vol = SUMA_Pattie_Volume(SO1, SO2, NodePatch, N_NodePatch, 
                               SOp, Opt->minhits, 
                               Opt->FixBowTie, Opt->adjust_contour, 
                               adj_N, Opt->verb);
      fprintf (SUMA_STDOUT,"Volume = %f\n", fabs(Vol));
      if (Opt->out_volprefix) {
         if (Opt->oType != SUMA_FT_NOT_SPECIFIED) SOp->FileType = Opt->oType;
         if (Opt->flip) {
            if (Opt->verb > 1) 
               SUMA_S_Note("Flipping stitched surf's triangles\n");
            SUMA_FlipSOTriangles (SOp);
         }

         if (!(SUMA_Save_Surface_Object_Wrap ( Opt->out_volprefix, NULL,
                                               SOp, SUMA_PLY, SUMA_ASCII, 
                                               NULL))) {
            fprintf (SUMA_STDERR,
                     "Error %s: Failed to write surface object.\n", FuncName);
         }
         if (Opt->adjust_contour && adj_N) {
            Opt->out_volprefix = 
                     SUMA_append_replace_string(Opt->out_volprefix, 
                                                   ".adjneighb","",1);
            ppref = SUMA_Extension(Opt->out_volprefix, ".1D.dset", NOPE);
            SUMA_WRITE_IND_ARRAY_1D(adj_N, NULL, SO1->N_Node, 1, ppref);
            SUMA_free(ppref); ppref=NULL;
         }
      }
      if (SOp) SUMA_Free_Surface_Object(SOp); SOp = NULL;
   }
   
   
   if (!Opt->VolOnly) {
      FaceSetList = NULL;
      N_FaceSet = -1;
      for (i=0; i < Spec->N_Surfs; ++i) {/* loop to read in surfaces */
         /* now identify surface needed */
         if (!(SO = SUMA_Load_Spec_Surf_with_Metrics(Spec, i, ps->sv[0], 0))) {
            SUMA_S_Err("Failed to load surface .\n");
            exit(1);
         }
         if (SO->aSO) {
            /* otherwise, when you reset the number of FaceSets for example,
               and you still write in GIFTI, the old contents of aSO will
               prevail */
            SO->aSO = SUMA_FreeAfniSurfaceObject(SO->aSO); 
         }
         /* extract the patch */
         ptch = SUMA_getPatch (NodePatch, N_NodePatch, SO->N_Node,
                               SO->FaceSetList,  SO->N_FaceSet, 
                               SO->MF, Opt->minhits, 
                               Opt->FixBowTie, (!i && !Opt->DoVol)); 
                                    /* verbose only for first patch, and 
                                    if no volume computation was required  
                                    This is to keep the warnings to a minimum*/
         if (!ptch) {
            SUMA_SL_Err("Failed to form patch.");
            exit(1);
         }
         if (LocalHead) SUMA_ShowPatch(ptch, NULL);
      
         /* Now create a surface with that patch */
         if (Spec->N_Surfs > 1) {
            sprintf(ext, "_%c", 65+i);
            ppref = SUMA_append_string(Opt->out_prefix, ext);
         } else {
            ppref = SUMA_copy_string(Opt->out_prefix);
         }
         /* save the original type */
         typetmp = SO->FileType;
         if (Opt->oType != SUMA_FT_NOT_SPECIFIED) SO->FileType = Opt->oType;
         SO_name = SUMA_Prefix2SurfaceName(ppref, NULL, NULL, 
                                           SO->FileType, &exists);
         if (ppref) SUMA_free(ppref); ppref = NULL;
         /* save the original pointers to the facesets and their number */
         FaceSetList = SO->FaceSetList;
         N_FaceSet = SO->N_FaceSet;
         NodeList = SO->NodeList;
         N_Node = SO->N_Node;
         
         /* replace with Patch */
         SO->FaceSetList = ptch->FaceSetList;
         SO->N_FaceSet = ptch->N_FaceSet; 
         
         if (Opt->Do_p2s) {
            if (LocalHead) 
               fprintf (SUMA_STDERR,
                        "%s: Changing patch to surface...\n", FuncName);
            SOnew = SUMA_Patch2Surf(SO->NodeList, SO->N_Node, 
                                    SO->FaceSetList, SO->N_FaceSet, 3);
            if (!SOnew) {
               SUMA_S_Err("Failed to change patch to surface.");
               exit(1);
            }
            SO->FaceSetList = SOnew->FaceSetList;
            SO->N_FaceSet = SOnew->N_FaceSet;
            SO->N_Node = SOnew->N_Node;
            SO->NodeList = SOnew->NodeList;
         }
          
         if (SO->N_FaceSet <= 0) {
            SUMA_S_Warn("The patch is empty.\n"
                        " Non existing surface not written to disk.\n");
         } else {
            /* Is the gain wanted? */
            if (Opt->coordgain) {
               SUMA_SL_Note("Applying coord gain to surface nodes!");
               for (cnt=0; cnt < SO->NodeDim*SO->N_Node; ++cnt) 
                  SO->NodeList[cnt] *= Opt->coordgain;
            }
            if (Opt->flip) {
               if (Opt->verb > 1) SUMA_S_Note("Flipping triangles\n");
               SUMA_FlipTriangles (SO->FaceSetList, SO->N_FaceSet);
               SUMA_RECOMPUTE_NORMALS(SO);
            }

            if (!SUMA_Save_Surface_Object (SO_name, SO, SO->FileType, 
                                           SUMA_ASCII, NULL)) {
                  fprintf (SUMA_STDERR,
                           "Error %s: Failed to write surface object.\n", 
                           FuncName);
                  exit (1);
            }
         }
         
         /* bring SO back to shape */
         SO->FileType = typetmp;
         SO->FaceSetList = FaceSetList; FaceSetList = NULL;
         SO->N_FaceSet = N_FaceSet; N_FaceSet = -1;
         SO->NodeList = NodeList; NodeList = NULL;
         SO->N_Node = N_Node; N_Node = -1;
         
         if (SO_name) SUMA_free(SO_name); SO_name = NULL;
         if (ptch) SUMA_freePatch(ptch); ptch = NULL;
         if (SOnew) SUMA_Free_Surface_Object(SOnew); SOnew = NULL; 
               /* get rid of old surface object */
            

      }
   } 
   
   SUMA_LH("clean up");
   if (!SUMA_FreeSpecFields(Spec)) { SUMA_S_Err("Failed to free spec fields"); }
   SUMA_free(Spec); Spec = NULL;
   if (Opt->out_prefix) SUMA_free(Opt->out_prefix); Opt->out_prefix = NULL;
   if (Opt->out_volprefix) SUMA_free(Opt->out_volprefix); 
                                                Opt->out_volprefix = NULL;
   if (Opt) SUMA_free(Opt);   
   if (!SUMA_Free_Displayable_Object_Vect (SUMAg_DOv, SUMAg_N_DOv)) {
      SUMA_SL_Err("DO Cleanup Failed!");
   }
   
   if (!SUMA_Free_CommonFields(SUMAg_CF)) {
      SUMA_SL_Err("SUMAg_CF Cleanup Failed!");
   }
   
   SUMA_RETURN(0);
}