00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 static char g_history[] =
00062
00063 "----------------------------------------------------------------------\n"
00064 "history:\n"
00065 "\n"
00066 "1.0 February 10, 2003 [rickr]\n"
00067 " - initial release\n"
00068 "\n"
00069 "1.1 February 11, 2003 [rickr]\n"
00070 " - handle no arguments as with -help\n"
00071 " - minor updates to -help\n"
00072 "\n"
00073 "1.2 February 13, 2003 [rickr]\n"
00074 " - init SUMAg array pointers, check before calling Free_()\n"
00075 "\n"
00076 "1.3 February 14, 2003 [rickr]\n"
00077 " - optionally enable more SUMA debugging\n"
00078 "\n"
00079 "2.0 June 06, 2003 [rickr]\n"
00080 " - re-wrote program according to 3dSurf2Vol (which was written\n"
00081 " according to this :) - using map functions and node lists\n"
00082 " - added midpoint map function\n"
00083 "\n"
00084 "2.1 June 10, 2003 [rickr]\n"
00085 " - added ave map function (see dump_ave_map)\n"
00086 "\n"
00087 "2.2 June 19, 2003 [rickr]\n"
00088 " - added -f_index INDEX_TYPE option (to index across nodes, too)\n"
00089 " - set the default of -f_steps to 2\n"
00090 " - use SMD prefix for macros\n"
00091 "\n"
00092 "2.3 July 21, 2003 [rickr]\n"
00093 " - fixed problem with nodes outside grid_par dataset\n"
00094 " - added min/max distance info\n"
00095 "\n"
00096 "3.0 August 05, 2003 [rickr]\n"
00097 " - renamed SUMA_3dSurfMaskDump.[ch] to SUMA_3dVol2Surf.[ch]\n"
00098 " - all output functions now go through dump_surf_3dt\n"
00099 " - dump_surf_3dt() is a generalized function to get an MRI_IMARR for\n"
00100 " one or a pair of nodes, by converting to a segment of points\n"
00101 " - added v2s_adjust_endpts() to apply segment endpoint modifications\n"
00102 " - added segment_imarr() to get the segment of points and fill the\n"
00103 " MRI_IMARR list (along with other info)\n"
00104 " - filter functions have been taken to v2s_apply_filter()\n"
00105 " - added min, max and seg_vals map functions (filters)\n"
00106 " - added options of the form -f_pX_XX to adjust segment endpoints\n"
00107 " - added -dnode option for specific node debugging\n"
00108 " - changed -output option to -out_1D\n"
00109 " - added new debug info\n"
00110 " - added checking of surface order (process from inner to outer)\n"
00111 "\n"
00112 "3.1 September 17, 2003 [rickr]\n"
00113 " - fixed the help instructions for '-cmask'\n"
00114 "\n"
00115 "3.2 September 20, 2003 [rickr]\n"
00116 " - added max_abs mapping function\n"
00117 " - added options '-oob_index' and '-oob_value'\n"
00118 " - added CHECK_NULL_STR macro\n"
00119 "\n"
00120 "3.3 September 23, 2003 [rickr]\n"
00121 " - added help for -no_headers option\n"
00122 "\n"
00123 "3.4 October 01, 2003 [rickr]\n"
00124 " - added -oom_value option\n"
00125 " - added additional help example (for -oob and -oom options)\n"
00126 "\n"
00127 "3.5 October 20, 2003 [rickr]\n"
00128 " - call the new engine function, SUMA_LoadSpec_eng()\n"
00129 " (this will restrict the debug output from SUMA_LoadSpec())\n"
00130 "\n"
00131 "3.6 October 21, 2003 [rickr]\n"
00132 " - finish upates for -f_keep_surf_order option\n"
00133 " (help and sopt)\n"
00134 "\n"
00135 "3.7 November 04, 2003 [rickr]\n"
00136 " - added ENTRY() stuff\n"
00137 "\n"
00138 "3.8 December 15, 2003 [rickr]\n"
00139 " - added options '-surf_A' and '-surf_B'\n"
00140 " - called SUMA_spec_select_surfs() and SUMA_spec_set_map_refs()\n"
00141 " to pick requested surfaces from spec file\n"
00142 " - removed option '-kso'\n"
00143 " - added '-hist' option\n"
00144 "\n"
00145 "3.9 January 08, 2004 [rickr]\n"
00146 " - added '-use_norms' option (segments come from norms)\n"
00147 " - added '-norm_len' option to alter default normal lengths\n"
00148 " - added '-keep_norm_dir' option to prevent direction check\n"
00149 " - reversed order from '-hist' option (newer at bottom)\n"
00150 " - added example with normals to help, along with option descriptions\n"
00151 "\n"
00152 "4.0 January 23, 2004 [rickr]\n"
00153 " - SUMA_isINHmappable() is depricated, check with AnatCorrect field\n"
00154 " - version -> 4.0 to celebrate normals :)\n"
00155 "\n"
00156 "4.1 February 10, 2004 [rickr]\n"
00157 " - output a little more debug info for !AnatCorrect case\n"
00158 " - small updates to help examples\n"
00159 "\n"
00160 "4.2 February 18, 2004 [rickr]\n"
00161 " - added functionality for mapping functions that require sorting\n"
00162 " - added mapping functions: median and mode\n"
00163 "\n"
00164 "4.3 February 19, 2004 [rickr]\n"
00165 " - track 1dindex sources for new sorting filters (median, mode)\n"
00166 " i.e. idindex is accurate, not just defaulting to first node\n"
00167 "\n"
00168 "4.4 March 26, 2004 [ziad]\n"
00169 " - DsetList added to SUMA_LoadSpec_eng() call\n"
00170 "\n"
00171 "4.5 April 07, 2004 [rickr]\n"
00172 " - fixed inconsistency in check_norm_dirs(), default dirs reversed\n"
00173 "\n"
00174 "5.0 May 18, 2004 [rickr]\n"
00175 " - added '-out_niml' option for niml output\n"
00176 " - added '-first_node' and '-last_node' option for limited output\n"
00177 " - made major additions for memory handling of output data\n"
00178 " (went from 'print as you go' to 'store and output at end')\n"
00179 "\n"
00180 "5.1 May 19, 2004 [rickr]\n"
00181 " - added help for '-first_node' and '-last_node' options (sorry, Ziad)\n"
00182 "\n"
00183 "6.0 September 1, 2004 [rickr]\n"
00184 " - created vol2surf() library files vol2surf.[ch] from core functions\n"
00185 " - this represents a significant re-write of many existing functions,\n"
00186 " modifying locations of action, structure names/contents, etc.\n"
00187 " - add library to libmri (as this will end up in afni proper)\n"
00188 " - separate all vol2surf.[ch] functions from SUMA_3dVol2surf.[ch]\n"
00189 " - keep allocation/free action of results struct within library\n"
00190 " - now using SUMA_surface struct for surface info (replace node_list)\n"
00191 " - added main vol2surf(), afni_vol2surf(), free_v2s_results(),\n"
00192 " and disp...() functions as vol2surf library interface\n"
00193 " - added options to control column output (-skip_col_NAME)\n"
00194 " - added -v2s_hist option for library history access\n"
00195 "\n"
00196 "6.1 September 2, 2004 [rickr]\n"
00197 " - library organizing: moved v2s_map_type() to vol2surf.c\n"
00198 " - moved gv2s_map_names to vol2surf.c, and externs to vol2surf.h\n"
00199 "\n"
00200 "6.2 September 16, 2004 [rickr]\n"
00201 " - added -gp_index option, mostly to use in plugin interface\n"
00202 " - added -reverse_norm_dir option, for reversing the default direction\n"
00203 "\n"
00204 "6.3 October 8, 2004 [rickr]\n"
00205 " - in suma2afni_surf(), dealt with LDP changes to SUMA_surface\n"
00206 " - changed write_outfile functions to v2s_*() and moved them to library\n"
00207 "\n"
00208 "6.3a March 22, 2005 [rickr] - removed tabs\n"
00209 "6.4 June 2, 2005 [rickr] - added -skip_col_non_results option\n"
00210 "---------------------------------------------------------------------\n";
00211
00212 #define VERSION "version 6.4 (June 2, 2005)"
00213
00214
00215
00216
00217
00218
00219 #include "mrilib.h"
00220 #include "SUMA_suma.h"
00221 #include "vol2surf.h"
00222 #include "SUMA_3dVol2Surf.h"
00223
00224
00225
00226
00227 SUMA_SurfaceViewer * SUMAg_SVv = NULL;
00228 int SUMAg_N_SVv = 0;
00229 SUMA_DO * SUMAg_DOv = NULL;
00230 int SUMAg_N_DOv = 0;
00231 SUMA_CommonFields * SUMAg_CF = NULL;
00232
00233
00234
00235 extern void machdep( void );
00236
00237 #define MAIN
00238
00239
00240
00241 int main( int argc , char * argv[] )
00242 {
00243 SUMA_SurfSpecFile spec;
00244 v2s_param_t params;
00245 v2s_opts_t sopt;
00246 opts_t opts;
00247 int ret_val;
00248
00249 mainENTRY("3dVol2Surf main");
00250 machdep();
00251 AFNI_logger("3dVol2Surf",argc,argv);
00252
00253
00254 if ( ( ret_val = init_options(&opts, argc, argv) ) != 0 )
00255 return ret_val;
00256
00257 if ( ( ret_val = validate_options(&opts, ¶ms) ) != 0 )
00258 return ret_val;
00259
00260 if ( (ret_val = set_smap_opts( &opts, ¶ms, &sopt )) != 0 )
00261 return ret_val;
00262
00263
00264 if ( (ret_val = read_surf_files(&opts, &spec)) != 0 )
00265 return ret_val;
00266
00267
00268
00269
00270 if ( (ret_val = get_surf_data( &sopt, ¶ms )) != 0 )
00271 return ret_val;
00272
00273 if ( (ret_val = write_output( &sopt, ¶ms )) != 0 )
00274 return ret_val;
00275
00276
00277 final_clean_up(&opts, ¶ms, &spec);
00278
00279 return ret_val;
00280 }
00281
00282
00283
00284
00285
00286
00287 int write_output ( v2s_opts_t * sopt, v2s_param_t * p )
00288 {
00289 v2s_results * sd;
00290 int rv = 0;
00291 ENTRY("write_output");
00292
00293 if ( sopt == NULL || p == NULL )
00294 {
00295 fprintf( stderr, "** v2s_wo - bad params (%p,%p)\n", sopt, p );
00296 RETURN(-1);
00297 }
00298
00299 if ( sopt->map == E_SMAP_INVALID )
00300 {
00301 fprintf(stderr,"** v2s wo: invalid map %d\n", sopt->map);
00302 RETURN(-1);
00303 }
00304
00305 sd = vol2surf(sopt, p);
00306 if ( !sd )
00307 fprintf(stderr,"** vol2surf failed\n");
00308
00309 if ( sd && sopt->debug > 1 ) disp_v2s_results("-- post vol2surf() : ",sd);
00310
00311 if ( sd && sopt->outfile_1D )
00312 rv = v2s_write_outfile_1D(sopt, sd, p->surf[0].label);
00313
00314 if ( sd && !rv && sopt->outfile_niml )
00315 rv = v2s_write_outfile_niml(sopt, sd, 1);
00316
00317 free_v2s_results( sd );
00318 sd = NULL;
00319
00320 RETURN(rv);
00321 }
00322
00323
00324
00325
00326
00327
00328
00329 int get_surf_data ( v2s_opts_t * sopt, v2s_param_t * p )
00330 {
00331 int nsurf = 2;
00332
00333 ENTRY("get_surf_data");
00334
00335 if ( sopt == NULL || p == NULL )
00336 {
00337 fprintf( stderr, "** cnl - bad params (%p,%p)\n", sopt, p );
00338 RETURN(-1);
00339 }
00340
00341 if ( (sopt->map == E_SMAP_MASK) || sopt->use_norms )
00342 nsurf = 1;
00343
00344 if ( copy_surfaces( sopt, p, nsurf ) )
00345 RETURN(-1);
00346
00347 if ( sopt->use_norms )
00348 {
00349 if ( ! p->surf[0].norm )
00350 {
00351 fprintf(stderr,"** failure: surface '%s' has no normal list\n",
00352 CHECK_NULL_STR(p->surf[0].label));
00353 RETURN(-1);
00354 }
00355
00356 if ((sopt->norm_dir == V2S_NORM_DEFAULT) && check_norm_dirs(sopt, p, 0))
00357 RETURN(-1);
00358 else if ( sopt->norm_dir == V2S_NORM_REVERSE)
00359 {
00360
00361 sopt->norm_len *= -1;
00362 if ( sopt->debug > 0 )
00363 fprintf(stderr,"++ reversing normal direction\n");
00364 }
00365
00366 }
00367
00368 RETURN(0);
00369 }
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387 int check_norm_dirs ( v2s_opts_t * sopt, v2s_param_t * p, int surf )
00388 {
00389 SUMA_ixyz * coords;
00390 THD_fvec3 * norms;
00391 float fmin[3], fmax[3];
00392 int min[3], max[3];
00393 int match[6];
00394 int node, c, ncount;
00395
00396 ENTRY("check_norm_dirs");
00397
00398 norms = p->surf[surf].norm;
00399 coords = p->surf[surf].ixyz;
00400
00401
00402 min[0] = max[0] = min[1] = max[1] = min[2] = max[2] = 0;
00403
00404 fmin[0] = fmax[0] = coords->x;
00405 fmin[1] = fmax[1] = coords->y;
00406 fmin[2] = fmax[2] = coords->z;
00407
00408
00409 for ( node = 1; node < p->surf[surf].num_ixyz; node++, coords++ )
00410 {
00411 if ( fmin[0] > coords[node].x )
00412 {
00413 min [0] = node;
00414 fmin[0] = coords[node].x;
00415 }
00416 if ( fmax[0] < coords[node].x )
00417 {
00418 max [0] = node;
00419 fmax[0] = coords[node].x;
00420 }
00421
00422 if ( fmin[1] > coords[node].y )
00423 {
00424 min [1] = node;
00425 fmin[1] = coords[node].y;
00426 }
00427 if ( fmax[1] < coords[node].y )
00428 {
00429 max [1] = node;
00430 fmax[1] = coords[node].y;
00431 }
00432
00433 if ( fmin[2] > coords[node].z )
00434 {
00435 min [2] = node;
00436 fmin[2] = coords[node].z;
00437 }
00438 if ( fmax[2] < coords[node].z )
00439 {
00440 max [2] = node;
00441 fmax[2] = coords[node].z;
00442 }
00443 }
00444
00445 if ( sopt->debug > 1 )
00446 fprintf(stderr,"++ normals:\n"
00447 " mins : %d, %d, %d\n"
00448 " min coords : %f, %f, %f\n"
00449 " mins0 : %f, %f, %f\n"
00450 " mins1 : %f, %f, %f\n"
00451 " mins2 : %f, %f, %f\n"
00452 "\n"
00453 " maxs : %d, %d, %d\n"
00454 " max coords : %f, %f, %f\n"
00455 " maxs0 : %f, %f, %f\n"
00456 " maxs1 : %f, %f, %f\n"
00457 " maxs2 : %f, %f, %f\n",
00458 min[0], min[1], min[2],
00459 fmin[0], fmin[1], fmin[2],
00460 coords[min[0]].x, coords[min[0]].y, coords[min[0]].z,
00461 coords[min[1]].x, coords[min[1]].y, coords[min[1]].z,
00462 coords[min[2]].x, coords[min[2]].y, coords[min[2]].z,
00463 max[0], max[1], max[2],
00464 fmax[0], fmax[1], fmax[2],
00465 coords[max[0]].x, coords[max[0]].y, coords[max[0]].z,
00466 coords[max[1]].x, coords[max[1]].y, coords[max[1]].z,
00467 coords[max[2]].x, coords[max[2]].y, coords[max[2]].z);
00468
00469
00470
00471 match[0] = norms[min[0]].xyz[0] < 0;
00472 match[1] = norms[min[1]].xyz[1] < 0;
00473 match[2] = norms[min[2]].xyz[2] < 0;
00474
00475 match[3] = norms[max[0]].xyz[0] > 0;
00476 match[4] = norms[max[1]].xyz[1] > 0;
00477 match[5] = norms[max[2]].xyz[2] > 0;
00478
00479 if ( sopt->debug > 1 )
00480 fprintf(stderr,"-- matches[0..5] = (%d, %d, %d, %d, %d, %d)\n",
00481 match[0], match[1], match[2], match[3], match[4], match[5] );
00482
00483 ncount = 0;
00484 for ( c = 0; c < 6; c++ )
00485 if ( match[c] )
00486 ncount++;
00487
00488
00489 if ( (ncount >= 2) && (ncount <= 4) )
00490 {
00491 fprintf(stderr, "** cannot determine directions for normals:\n"
00492 " To proceed, use one of -keep_norm_dir/-reverse_norm_dir.\n"
00493 " \n"
00494 " It is ~%d%% likely that you will want to negate the\n"
00495 " normal length in '-norm_len'\n",
00496 (int)(100*ncount/6.0) );
00497 RETURN(-1);
00498 }
00499
00500
00501 if ( (ncount == 1) || (ncount == 5) )
00502 fprintf(stderr,"** warning: only 83%% sure of direction of normals\n");
00503
00504
00505 if ( ncount < 2 )
00506 {
00507 fprintf(stderr,"-- reversing direction of normals\n");
00508 sopt->norm_len *= -1.0;
00509 }
00510
00511 RETURN(0);
00512 }
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524 int copy_surfaces ( v2s_opts_t * sopt, v2s_param_t * p, int nsurf )
00525 {
00526 SUMA_SurfaceObject ** so;
00527 float radius[V2S_MAX_SURFS];
00528 int rv, sindex;
00529
00530 ENTRY("copy_surfaces");
00531
00532 if ( sopt == NULL || p == NULL || nsurf < 0 )
00533 {
00534 fprintf( stderr, "** anl: bad params (%p,%p,%d)\n", sopt, p, nsurf );
00535 RETURN(-1);
00536 }
00537
00538
00539 so = (SUMA_SurfaceObject **)calloc(nsurf, sizeof(SUMA_SurfaceObject *));
00540 if ( so == NULL )
00541 {
00542 fprintf( stderr, "** anl: failed to alloc %d surf pointers\n", nsurf );
00543 RETURN(-1);
00544 }
00545
00546 if ( (rv = get_mappable_surfs( so, nsurf, sopt->debug )) != nsurf )
00547 {
00548 fprintf( stderr, "** found %d mappable surfaces (but expected %d)\n",
00549 rv, nsurf );
00550 free(so);
00551 RETURN(-1);
00552 }
00553
00554
00555
00556 p->nsurf = nsurf;
00557 for ( sindex = 0; sindex < nsurf; sindex++ )
00558 {
00559 if ( suma2afni_surf( sopt, p, so[sindex], sindex ) )
00560 RETURN(-1);
00561 surf_ave_radius(radius+sindex, so[sindex], sopt->debug);
00562 }
00563
00564 if ( sopt->debug ) fprintf(stderr,"-- surfaces converted: suma to afni\n");
00565
00566 free(so);
00567
00568 RETURN(0);
00569 }
00570
00571
00572
00573
00574
00575
00576 int suma2afni_surf(v2s_opts_t * sopt, v2s_param_t * p, SUMA_SurfaceObject * so,
00577 int sindex)
00578 {
00579 SUMA_surface * sp;
00580 float * fp;
00581 int node;
00582
00583 ENTRY("suma2afni_surf");
00584
00585 if ( !sopt || !p || !so || sindex < 0 || sindex >= V2S_MAX_SURFS )
00586 {
00587 fprintf(stderr,"** s2as: bad params (%p,%p,%p,%d)\n",sopt,p,so,sindex);
00588 RETURN(-1);
00589 }
00590
00591 sp = p->surf + sindex;
00592
00593 sp->type = SUMA_SURFACE_TYPE;
00594 sp->num_ixyz = so->N_Node;
00595 sp->nall_ixyz = so->N_Node;
00596 sp->num_ijk = 0;
00597 sp->nall_ijk = 0;
00598
00599 sp->seq = 1;
00600 sp->seqbase = 0;
00601 sp->sorted = 1;
00602
00603 sp->ixyz = NULL;
00604 sp->norm = NULL;
00605
00606 if ( !so->NodeList )
00607 {
00608 fprintf(stderr,"** s2as: missing surface NodeList for '%s'\n",
00609 so->Label ? so->Label: "<no label>");
00610 RETURN(1);
00611 }
00612
00613 if ( sopt->use_norms )
00614 {
00615 if ( so->NodeNormList )
00616 {
00617 sp->norm = (THD_fvec3 *)malloc(sp->num_ixyz * sizeof(THD_fvec3));
00618 if ( !sp->norm )
00619 {
00620 fprintf(stderr,"** s2as: cannot allocate %d THD_fvec3's\n",
00621 sp->num_ixyz);
00622 RETURN(1);
00623 }
00624
00625 if ( sopt->debug > 1 )
00626 fprintf(stderr,"++ filling in norms for surf # %d (%d bytes)\n",
00627 sindex, (int)(sp->num_ixyz * sizeof(THD_fvec3)));
00628
00629 fp = so->NodeNormList;
00630 for ( node = 0; node < sp->num_ixyz; node++ )
00631 {
00632 sp->norm[node].xyz[0] = *fp++;
00633 sp->norm[node].xyz[1] = *fp++;
00634 sp->norm[node].xyz[2] = *fp++;
00635 }
00636 }
00637 else
00638 {
00639 fprintf(stderr,"** missing normals for surface # %d, '%s'\n",
00640 sindex, so->Label ? so->Label: "<no label>");
00641 }
00642 }
00643
00644 sp->ixyz = (SUMA_ixyz *)malloc(sp->num_ixyz * sizeof(SUMA_ixyz));
00645
00646 if ( !sp->ixyz )
00647 {
00648 fprintf(stderr,"** failed to allocate %d SUMA_ixyz\n",sp->num_ixyz);
00649 if (sp->norm) free(sp->norm);
00650 RETURN(1);
00651 }
00652 else if ( sopt->debug > 1 )
00653 fprintf(stderr,"++ s2as: allocated %d SUMA_ixyz nodes (%d bytes)\n",
00654 sp->num_ixyz, (int)(sp->num_ixyz*sizeof(SUMA_ixyz)));
00655
00656 fp = so->NodeList;
00657 for ( node = 0; node < sp->num_ixyz; node++ )
00658 {
00659 sp->ixyz[node].id = node;
00660 sp->ixyz[node].x = *fp++;
00661 sp->ixyz[node].y = *fp++;
00662 sp->ixyz[node].z = *fp++;
00663 }
00664
00665 sp->xbot = so->MinDims[0];
00666 sp->ybot = so->MinDims[1];
00667 sp->zbot = so->MinDims[2];
00668
00669 sp->xtop = so->MaxDims[0];
00670 sp->ytop = so->MaxDims[1];
00671 sp->ztop = so->MaxDims[2];
00672
00673 sp->xcen = so->Center[0];
00674 sp->ycen = so->Center[1];
00675 sp->zcen = so->Center[2];
00676
00677 if (so->idcode_str)
00678 {
00679 strncpy(sp->idcode, so->idcode_str, 31);
00680 sp->idcode[31] = '\0';
00681 }
00682 else
00683 UNIQ_idcode_fill(sp->idcode);
00684
00685 sp->idcode_ldp[0] = '\0';
00686 sp->idcode_dset[0] = '\0';
00687
00688 strncpy(sp->label, so->Label, 63); sp->label[63] = '\0';
00689 if (so->LocalDomainParent && *so->LocalDomainParent)
00690 {
00691 strncpy(sp->label_ldp, so->LocalDomainParent, 63);
00692 sp->label[63] = '\0';
00693 }
00694 else
00695 strcpy(sp->label_ldp, "no_LDP_label");
00696
00697 sp->vv = NULL;
00698 sp->vn = NULL;
00699
00700 RETURN(0);
00701 }
00702
00703
00704
00705
00706
00707
00708
00709
00710 int get_mappable_surfs( SUMA_SurfaceObject ** slist, int how_many, int debug )
00711 {
00712 SUMA_SurfaceObject * so;
00713 int count, socount = 0;
00714
00715 ENTRY("get_mappable_surfs");
00716
00717 if ( slist == NULL )
00718 {
00719 fprintf( stderr, "** gms: missing slist!\n" );
00720 RETURN(-1);
00721 }
00722
00723 for ( count = 0; count < SUMAg_N_DOv; count++ )
00724 {
00725 if ( ! SUMA_isSO(SUMAg_DOv[count]) )
00726 continue;
00727
00728 so = (SUMA_SurfaceObject *)SUMAg_DOv[count].OP;
00729
00730 if ( ! so->AnatCorrect )
00731 {
00732 if ( debug )
00733 fprintf(stderr,"-- surf #%d '%s', anat not correct, skipping\n",
00734 socount, CHECK_NULL_STR(so->Label));
00735 if ( debug > 1 )
00736 fprintf(stderr,"** consider adding the following to the "
00737 "surface definition in the spec file:\n"
00738 " Anatomical = Y\n");
00739 continue;
00740 }
00741
00742 if ( debug > 1 )
00743 fprintf( stderr, "\n---------- surface #%d '%s' -----------\n",
00744 socount, CHECK_NULL_STR(so->Label) );
00745 if ( debug > 2 ) SUMA_Print_Surface_Object( so, stderr );
00746
00747 if ( socount < how_many )
00748 slist[socount] = so;
00749
00750 socount++;
00751 }
00752
00753 if ( debug > 1 )
00754 fprintf( stderr, "++ found %d mappable surfaces\n", socount );
00755
00756 RETURN(socount);
00757 }
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767 int set_smap_opts( opts_t * opts, v2s_param_t * p, v2s_opts_t * sopt )
00768 {
00769 int nsurf = 1;
00770
00771 ENTRY("set_smap_opts");
00772
00773 memset( sopt, 0, sizeof(*sopt) );
00774
00775 if ( (sopt->map = check_map_func( opts->map_str )) == E_SMAP_INVALID )
00776 RETURN(-1);
00777
00778
00779
00780 sopt->gp_index = opts->gp_index;
00781 sopt->debug = opts->debug;
00782 sopt->dnode = opts->dnode;
00783 sopt->no_head = opts->no_head;
00784 sopt->skip_cols = opts->skip_cols;
00785
00786 sopt->first_node = opts->first_node > 0 ? opts->first_node : 0;
00787 sopt->last_node = opts->last_node > 0 ? opts->last_node : 0;
00788 if ( sopt->first_node > sopt->last_node )
00789 {
00790 fprintf(stderr, "** error: -first_node (%d) > -last_node (%d)\n",
00791 sopt->first_node, sopt->last_node);
00792 RETURN(1);
00793 }
00794
00795 sopt->use_norms = opts->use_norms;
00796 sopt->norm_len = opts->norm_len;
00797 sopt->norm_dir = opts->norm_dir;
00798 sopt->f_index = V2S_INDEX_VOXEL;
00799
00800 if ( (opts->f_index_str != NULL) &&
00801 (!strncmp(opts->f_index_str, "node", 4)) )
00802 sopt->f_index = V2S_INDEX_NODE;
00803
00804 if ( opts->f_steps <= V2S_M2_STEPS_DEFAULT )
00805 sopt->f_steps = V2S_M2_STEPS_DEFAULT;
00806 else
00807 sopt->f_steps = opts->f_steps;
00808
00809 sopt->f_p1_fr = opts->f_p1_fr;
00810 sopt->f_pn_fr = opts->f_pn_fr;
00811 sopt->f_p1_mm = opts->f_p1_mm;
00812 sopt->f_pn_mm = opts->f_pn_mm;
00813 sopt->outfile_1D = opts->outfile_1D;
00814 sopt->outfile_niml = opts->outfile_niml;
00815 sopt->oob = opts->oob;
00816 sopt->oom = opts->oom;
00817
00818 if ( sopt->oom.show && !p->cmask )
00819 {
00820 fprintf(stderr,"** '-cmask' option is required with '-oom_value'\n");
00821 RETURN(1);
00822 }
00823
00824
00825 switch (sopt->map)
00826 {
00827 default:
00828 break;
00829
00830 case E_SMAP_AVE:
00831 case E_SMAP_COUNT:
00832 case E_SMAP_MAX:
00833 case E_SMAP_MAX_ABS:
00834 case E_SMAP_MIN:
00835 case E_SMAP_MASK2:
00836 case E_SMAP_SEG_VALS:
00837 case E_SMAP_MEDIAN:
00838 case E_SMAP_MODE:
00839 nsurf = 2;
00840 break;
00841
00842 case E_SMAP_MIDPT:
00843 nsurf = 2;
00844
00845 case E_SMAP_MASK:
00846 if (sopt->f_steps != V2S_M2_STEPS_DEFAULT)
00847 {
00848 fprintf(stderr,"** -f_steps option not valid\n");
00849 RETURN(-1);
00850 }
00851
00852
00853 sopt->f_steps = 1;
00854 break;
00855 }
00856
00857 if ( (nsurf == 2) && !opts->snames[1] && !opts->use_norms )
00858 {
00859 fprintf(stderr, "** function '%s' requires 2 surfaces\n",
00860 gv2s_map_names[sopt->map]);
00861 RETURN(-1);
00862 }
00863
00864 p->over_steps = v2s_vals_over_steps(sopt->map);
00865
00866 if ( opts->debug > 0 )
00867 disp_v2s_opts_t( "++ smap opts set :", sopt );
00868
00869 RETURN(0);
00870 }
00871
00872
00873
00874
00875
00876
00877 int final_clean_up ( opts_t * opts, v2s_param_t * p, SUMA_SurfSpecFile * spec )
00878 {
00879 int surf;
00880 ENTRY("final_clean_up");
00881
00882 for ( surf = 0; surf < p->nsurf; surf++ )
00883 {
00884 if ( opts->debug > 2 ) fprintf(stderr,"-- freeing nodes[%d]\n",surf);
00885 if ( p->surf[surf].ixyz ) free(p->surf[surf].ixyz);
00886 if ( opts->debug > 2 ) fprintf(stderr,"-- freeing norms[%d]\n",surf);
00887 if ( p->surf[surf].norm ) free(p->surf[surf].norm);
00888 }
00889
00890 if ( p->cmask ) free(p->cmask);
00891
00892 if ( opts->debug > 2 ) fprintf(stderr,"-- freeing DOV\n");
00893 if ( ( SUMAg_DOv != NULL ) &&
00894 ( SUMA_Free_Displayable_Object_Vect(SUMAg_DOv, SUMAg_N_DOv) == 0 ) )
00895 fprintf(stderr, "** failed SUMA_Free_Displayable_Object_Vect()\n" );
00896
00897 if ( opts->debug > 2 ) fprintf(stderr,"-- freeing SVSV\n");
00898 if ( ( SUMAg_SVv != NULL ) &&
00899 ( SUMA_Free_SurfaceViewer_Struct_Vect(SUMAg_SVv, SUMAg_N_SVv) == 0 ) )
00900 fprintf( stderr, "** failed SUMA_Free_SurfaceViewer_Struct_Vect()\n" );
00901
00902 if ( opts->debug > 2 ) fprintf(stderr,"-- freeing CF\n");
00903 if ( ( SUMAg_CF != NULL ) && ( SUMA_Free_CommonFields(SUMAg_CF) == 0 ) )
00904 fprintf( stderr, "** failed SUMA_Free_CommonFields()\n" );
00905
00906 if ( opts->debug > 1 ) fprintf(stderr,"-- freeing complete\n");
00907
00908 RETURN(0);
00909 }
00910
00911
00912
00913
00914
00915
00916 int read_surf_files ( opts_t * opts, SUMA_SurfSpecFile * spec )
00917 {
00918 int debug, rv;
00919
00920 ENTRY("read_surf_files");
00921
00922 debug = (opts->debug > 2);
00923
00924 if ( debug )
00925 fputs( "-- SUMA_Create_CommonFields()...\n", stderr );
00926
00927
00928 SUMAg_CF = SUMA_Create_CommonFields();
00929
00930 if ( SUMAg_CF == NULL )
00931 {
00932 fprintf( stderr, "** failed SUMA_Create_CommonFields(), exiting...\n" );
00933 RETURN(-1);
00934 }
00935
00936
00937 if ( opts->debug > 3 )
00938 {
00939 SUMAg_CF->MemTrace = 1;
00940
00941 if ( opts->debug > 4 )
00942 SUMAg_CF->InOut_Notify = 1;
00943 }
00944
00945 if ( debug )
00946 fputs( "-- SUMA_Alloc_DisplayObject_Struct()...\n", stderr );
00947
00948 SUMAg_DOv = SUMA_Alloc_DisplayObject_Struct(SUMA_MAX_DISPLAYABLE_OBJECTS);
00949
00950 if ( debug )
00951 fputs( "-- SUMA_Read_SpecFile()...\n", stderr );
00952
00953 if ( SUMA_Read_SpecFile( opts->spec_file, spec) == 0 )
00954 {
00955 fprintf( stderr, "** failed SUMA_Read_SpecFile(), exiting...\n" );
00956 RETURN(-1);
00957 }
00958
00959 rv = SUMA_spec_select_surfs(spec, opts->snames, V2S_MAX_SURFS, opts->debug);
00960 if ( rv < 1 )
00961 {
00962 if ( rv == 0 )
00963 fprintf(stderr,"** no named surfaces found in spec file\n");
00964 RETURN(-1);
00965 }
00966
00967 if ( debug )
00968 SUMA_ShowSpecStruct(spec, stderr, opts->debug > 2 ? 3 : 1);
00969
00970 if ( SUMA_spec_set_map_refs(spec, opts->debug) != 0 )
00971 RETURN(-1);
00972
00973
00974 if ( spec->N_Groups != 1 )
00975 {
00976 fprintf( stderr,"** error: N_Groups <%d> must be 1 in spec file <%s>\n",
00977 spec->N_Groups, opts->spec_file );
00978 RETURN(-1);
00979 }
00980
00981 if ( debug )
00982 fputs( "-- SUMA_LoadSpec_eng()...\n", stderr );
00983
00984
00985 if (SUMA_LoadSpec_eng(spec,SUMAg_DOv,&SUMAg_N_DOv,opts->sv_file,debug,
00986 SUMAg_CF->DsetList) == 0)
00987 {
00988 fprintf( stderr, "** error: failed SUMA_LoadSpec_eng(), exiting...\n" );
00989 RETURN(-1);
00990 }
00991
00992 if ( opts->debug > 1 )
00993 fprintf(stderr, "++ %d surfaces loaded.\n", spec->N_Surfs );
00994
00995 RETURN(0);
00996 }
00997
00998
00999
01000
01001
01002
01003 int init_options ( opts_t * opts, int argc, char * argv [] )
01004 {
01005 int ac, ind;
01006
01007 ENTRY("init_options");
01008
01009 if ( argc < 2 )
01010 {
01011 usage( PROG_NAME, V2S_USE_LONG );
01012 RETURN(-1);
01013 }
01014
01015
01016 memset( opts, 0, sizeof( opts_t) );
01017 opts->gpar_file = NULL;
01018 opts->outfile_1D = NULL;
01019 opts->outfile_niml = NULL;
01020 opts->spec_file = NULL;
01021 opts->sv_file = NULL;
01022 opts->cmask_cmd = NULL;
01023 opts->map_str = NULL;
01024 opts->snames[0] = NULL;
01025 opts->snames[1] = NULL;
01026 opts->f_index_str = NULL;
01027
01028 opts->gp_index = -1;
01029 opts->norm_len = 1.0;
01030 opts->dnode = -1;
01031
01032 for ( ac = 1; ac < argc; ac++ )
01033 {
01034
01035 if ( ! strncmp(argv[ac], "-cmask", 6) )
01036 {
01037 if ( (ac+1) >= argc )
01038 {
01039 fputs( "option usage: -cmask COMMAND\n\n", stderr );
01040 usage( PROG_NAME, V2S_USE_SHORT );
01041 RETURN(-1);
01042 }
01043
01044 opts->cmask_cmd = argv[++ac];
01045 }
01046 else if ( ! strncmp(argv[ac], "-debug", 6) )
01047 {
01048 if ( (ac+1) >= argc )
01049 {
01050 fputs( "option usage: -debug LEVEL\n\n", stderr );
01051 usage( PROG_NAME, V2S_USE_SHORT );
01052 RETURN(-1);
01053 }
01054
01055 opts->debug = atoi(argv[++ac]);
01056 if ( opts->debug < 0 || opts->debug > V2S_DEBUG_MAX_LEV )
01057 {
01058 fprintf( stderr, "bad debug level <%d>, should be in [0,%d]\n",
01059 opts->debug, V2S_DEBUG_MAX_LEV );
01060 usage( PROG_NAME, V2S_USE_SHORT );
01061 RETURN(-1);
01062 }
01063 }
01064 else if ( ! strncmp(argv[ac], "-dnode", 6) )
01065 {
01066 if ( (ac+1) >= argc )
01067 {
01068 fputs( "option usage: -dnode NODE_NUM\n\n", stderr );
01069 usage( PROG_NAME, V2S_USE_SHORT );
01070 RETURN(-1);
01071 }
01072
01073 opts->dnode = atoi(argv[++ac]);
01074 }
01075 else if ( ! strncmp(argv[ac], "-f_index", 7) )
01076 {
01077 if ( (ac+1) >= argc )
01078 {
01079 fputs( "option usage: -f_index INDEX_TYPE\n\n", stderr );
01080 usage( PROG_NAME, V2S_USE_SHORT );
01081 RETURN(-1);
01082 }
01083
01084 opts->f_index_str = argv[++ac];
01085 }
01086 else if ( ! strncmp(argv[ac], "-f_keep_surf_order", 9) )
01087 {
01088
01089
01090 fprintf(stderr,"** the -f_keep_surf_order option is depreciated\n"
01091 " in favor of -surf_A and -surf_B (version 3.8)\n");
01092 RETURN(-1);
01093 }
01094 else if ( ! strncmp(argv[ac], "-f_p1_fr", 9) )
01095 {
01096 if ( (ac+1) >= argc )
01097 {
01098 fputs( "option usage: -f_p1_fr FRACTION\n\n", stderr );
01099 usage( PROG_NAME, V2S_USE_SHORT );
01100 RETURN(-1);
01101 }
01102
01103 opts->f_p1_fr = atof(argv[++ac]);
01104 }
01105 else if ( ! strncmp(argv[ac], "-f_pn_fr", 9) )
01106 {
01107 if ( (ac+1) >= argc )
01108 {
01109 fputs( "option usage: -f_pn_fr FRACTION\n\n", stderr );
01110 usage( PROG_NAME, V2S_USE_SHORT );
01111 RETURN(-1);
01112 }
01113
01114 opts->f_pn_fr = atof(argv[++ac]);
01115 }
01116 else if ( ! strncmp(argv[ac], "-f_p1_mm", 9) )
01117 {
01118 if ( (ac+1) >= argc )
01119 {
01120 fputs( "option usage: -f_p1_mm DISTANCE\n\n", stderr );
01121 usage( PROG_NAME, V2S_USE_SHORT );
01122 RETURN(-1);
01123 }
01124
01125 opts->f_p1_mm = atof(argv[++ac]);
01126 }
01127 else if ( ! strncmp(argv[ac], "-f_pn_mm", 9) )
01128 {
01129 if ( (ac+1) >= argc )
01130 {
01131 fputs( "option usage: -f_pn_mm DISTANCE\n\n", stderr );
01132 usage( PROG_NAME, V2S_USE_SHORT );
01133 RETURN(-1);
01134 }
01135
01136 opts->f_pn_mm = atof(argv[++ac]);
01137 }
01138 else if ( ! strncmp(argv[ac], "-f_steps", 7) )
01139 {
01140 if ( (ac+1) >= argc )
01141 {
01142 fputs( "option usage: -f_steps NUM_STEPS\n\n", stderr );
01143 usage( PROG_NAME, V2S_USE_SHORT );
01144 RETURN(-1);
01145 }
01146
01147 opts->f_steps = atoi(argv[++ac]);
01148 }
01149 else if ( ! strncmp(argv[ac], "-first_node", 11) )
01150 {
01151 if ( (ac+1) >= argc )
01152 {
01153 fputs( "option usage: -first_node NODE_INDEX\n\n", stderr );
01154 usage( PROG_NAME, V2S_USE_SHORT );
01155 RETURN(-1);
01156 }
01157
01158 opts->first_node = atoi(argv[++ac]);
01159 }
01160 else if ( ! strncmp(argv[ac], "-gp_index", 7) )
01161 {
01162 if ( (ac+1) >= argc )
01163 {
01164 fputs( "option usage: -gp_index BRICK_INDEX\n\n", stderr );
01165 usage( PROG_NAME, V2S_USE_SHORT );
01166 RETURN(-1);
01167 }
01168
01169 opts->gp_index = atoi(argv[++ac]);
01170 }
01171 else if ( ! strncmp(argv[ac], "-help", 5) )
01172 {
01173 usage( PROG_NAME, V2S_USE_LONG );
01174 RETURN(-1);
01175 }
01176 else if ( ! strncmp(argv[ac], "-hist", 5) )
01177 {
01178 usage( PROG_NAME, V2S_USE_HIST );
01179 RETURN(-1);
01180 }
01181 else if ( ! strncmp(argv[ac], "-v2s_hist", 9) )
01182 {
01183 usage( PROG_NAME, V2S_USE_LIB_HIST );
01184 RETURN(-1);
01185 }
01186 else if ( ! strncmp(argv[ac], "-grid_parent", 5) ||
01187 ! strncmp(argv[ac], "-inset", 6) ||
01188 ! strncmp(argv[ac], "-input", 6) )
01189 {
01190 if ( (ac+1) >= argc )
01191 {
01192 fputs( "option usage: -grid_parent INPUT_DSET\n\n", stderr );
01193 usage( PROG_NAME, V2S_USE_SHORT );
01194 RETURN(-1);
01195 }
01196
01197 opts->gpar_file = argv[++ac];
01198 }
01199 else if ( ! strncmp(argv[ac], "-keep_norm_dir", 14) )
01200 {
01201 opts->norm_dir = V2S_NORM_KEEP;
01202 }
01203 else if ( ! strncmp(argv[ac], "-last_node", 11) )
01204 {
01205 if ( (ac+1) >= argc )
01206 {
01207 fputs( "option usage: -last_node NODE_INDEX\n\n", stderr );
01208 usage( PROG_NAME, V2S_USE_SHORT );
01209 RETURN(-1);
01210 }
01211
01212 opts->last_node = atoi(argv[++ac]);
01213 }
01214 else if ( ! strncmp(argv[ac], "-map_func", 4) )
01215 {
01216 if ( (ac+1) >= argc )
01217 {
01218 fputs( "option usage: -map_func FUNCTION\n\n", stderr );
01219 RETURN(-1);
01220 }
01221
01222 opts->map_str = argv[++ac];
01223 }
01224 else if ( ! strncmp(argv[ac], "-no_headers", 5) )
01225 {
01226 opts->no_head = 1;
01227 }
01228 else if ( ! strncmp(argv[ac], "-norm_len", 9) )
01229 {
01230 if ( (ac+1) >= argc )
01231 {
01232 fputs( "option usage: -norm_len LENGTH\n\n", stderr );
01233 usage( PROG_NAME, V2S_USE_SHORT );
01234 RETURN(-1);
01235 }
01236
01237 opts->norm_len = atof(argv[++ac]);
01238 }
01239 else if ( ! strncmp(argv[ac], "-oob_index", 8) )
01240 {
01241 if ( (ac+1) >= argc )
01242 {
01243 fputs( "option usage: -oob_index INDEX_VALUE\n\n", stderr );
01244 usage( PROG_NAME, V2S_USE_SHORT );
01245 RETURN(-1);
01246 }
01247
01248 opts->oob.show = 1;
01249 opts->oob.index = atoi(argv[++ac]);
01250 }
01251 else if ( ! strncmp(argv[ac], "-oob_value", 8) )
01252 {
01253 if ( (ac+1) >= argc )
01254 {
01255 fputs( "option usage: -oob_value VALUE\n\n", stderr );
01256 usage( PROG_NAME, V2S_USE_SHORT );
01257 RETURN(-1);
01258 }
01259
01260 opts->oob.show = 1;
01261 opts->oob.value = atof(argv[++ac]);
01262 }
01263 else if ( ! strncmp(argv[ac], "-oom_value", 8) )
01264 {
01265 if ( (ac+1) >= argc )
01266 {
01267 fputs( "option usage: -oob_value VALUE\n\n", stderr );
01268 usage( PROG_NAME, V2S_USE_SHORT );
01269 RETURN(-1);
01270 }
01271
01272 opts->oom.show = 1;
01273 opts->oom.value = atof(argv[++ac]);
01274 }
01275 else if ( ! strncmp(argv[ac], "-out_1D", 7) )
01276 {
01277 if ( (ac+1) >= argc )
01278 {
01279 fputs( "option usage: -out_1D OUTPUT_FILE\n\n", stderr );
01280 usage( PROG_NAME, V2S_USE_SHORT );
01281 RETURN(-1);
01282 }
01283
01284 opts->outfile_1D = argv[++ac];
01285 }
01286 else if ( ! strncmp(argv[ac], "-out_niml", 7) )
01287 {
01288 if ( (ac+1) >= argc )
01289 {
01290 fputs( "option usage: -out_niml OUTPUT_FILE\n\n", stderr );
01291 usage( PROG_NAME, V2S_USE_SHORT );
01292 RETURN(-1);
01293 }
01294
01295 opts->outfile_niml = argv[++ac];
01296 }
01297 else if ( ! strncmp(argv[ac], "-reverse_norm_dir", 8) )
01298 {
01299 opts->norm_dir = V2S_NORM_REVERSE;
01300 }
01301 else if ( ! strncmp(argv[ac], "-skip_col_non_results", 15) )
01302 opts->skip_cols |= (V2S_SKIP_ALL & ~V2S_SKIP_VALS);
01303 else if ( ! strncmp(argv[ac], "-skip_col_nodes", 13) )
01304 opts->skip_cols |= V2S_SKIP_NODES;
01305 else if ( ! strncmp(argv[ac], "-skip_col_1dindex", 12) )
01306 opts->skip_cols |= V2S_SKIP_VOLIND;
01307 else if ( ! strncmp(argv[ac], "-skip_col_i", 11) )
01308 opts->skip_cols |= V2S_SKIP_I;
01309 else if ( ! strncmp(argv[ac], "-skip_col_j", 11) )
01310 opts->skip_cols |= V2S_SKIP_J;
01311 else if ( ! strncmp(argv[ac], "-skip_col_k", 11) )
01312 opts->skip_cols |= V2S_SKIP_K;
01313 else if ( ! strncmp(argv[ac], "-skip_col_vals", 13) )
01314 opts->skip_cols |= V2S_SKIP_NVALS;
01315 else if ( ! strncmp(argv[ac], "-skip_col_results", 13) )
01316 opts->skip_cols |= V2S_SKIP_VALS;
01317 else if ( ! strncmp(argv[ac], "-spec", 3) )
01318 {
01319 if ( (ac+1) >= argc )
01320 {
01321 fputs( "option usage: -spec SPEC_FILE\n\n", stderr );
01322 usage( PROG_NAME, V2S_USE_SHORT );
01323 RETURN(-1);
01324 }
01325
01326 opts->spec_file = argv[++ac];
01327 }
01328 else if ( ! strncmp(argv[ac], "-surf_", 6) )
01329 {
01330 if ( (ac+1) >= argc )
01331 {
01332 fputs( "option usage: -surf_X SURF_NAME\n\n", stderr );
01333 usage( PROG_NAME, V2S_USE_SHORT );
01334 RETURN(-1);
01335 }
01336 ind = argv[ac][6] - 'A';
01337 if ( (ind < 0) || (ind >= V2S_MAX_SURFS) )
01338 {
01339 fprintf(stderr,"** -surf_X option: '%s' out of range,\n"
01340 " use one of '-surf_A' through '-surf_%c'\n",
01341 argv[ac], 'A'+V2S_MAX_SURFS-1);
01342 RETURN(-1);
01343 }
01344
01345 opts->snames[ind] = argv[++ac];
01346 }
01347 else if ( ! strncmp(argv[ac], "-sv", 3) )
01348 {
01349 if ( (ac+1) >= argc )
01350 {
01351 fputs( "option usage: -sv SURFACE_VOLUME\n\n", stderr );
01352 usage( PROG_NAME, V2S_USE_SHORT );
01353 RETURN(-1);
01354 }
01355
01356 opts->sv_file = argv[++ac];
01357 }
01358 else if ( ! strncmp(argv[ac], "-use_norms", 5) )
01359 {
01360 opts->use_norms = 1;
01361 }
01362 else if ( ! strncmp(argv[ac], "-version", 2) )
01363 {
01364 usage( PROG_NAME, V2S_USE_VERSION );
01365 RETURN(-1);
01366 }
01367 else
01368 {
01369 fprintf( stderr, "invalid option <%s>\n", argv[ac] );
01370 usage( PROG_NAME, V2S_USE_SHORT );
01371 RETURN(-1);
01372 }
01373 }
01374
01375 RETURN(0);
01376 }
01377
01378
01379
01380
01381
01382
01383
01384
01385 int validate_options ( opts_t * opts, v2s_param_t * p )
01386 {
01387 ENTRY("validate_options");
01388
01389 memset( p, 0, sizeof(*p) );
01390 p->gpar = NULL;
01391 p->cmask = NULL;
01392
01393 if ( opts->debug > 0 )
01394 {
01395 usage( PROG_NAME, V2S_USE_VERSION );
01396 disp_opts_t ( "++ opts read: ", opts );
01397 }
01398
01399 if ( check_map_func( opts->map_str ) == E_SMAP_INVALID )
01400 RETURN(-1);
01401
01402 if ( !opts->outfile_1D && !opts->outfile_niml )
01403 {
01404 fprintf( stderr, "** missing '-out_1D OUTPUT_FILE' option\n" );
01405 RETURN(-1);
01406 }
01407
01408 if ( opts->spec_file == NULL )
01409 {
01410 fprintf( stderr, "** missing '-spec_file SPEC_FILE' option\n" );
01411 RETURN(-1);
01412 }
01413
01414 if ( opts->sv_file == NULL )
01415 {
01416 fprintf( stderr, "** missing '-sv SURF_VOL' option\n" );
01417 RETURN(-1);
01418 }
01419
01420 if ( opts->snames[0] == NULL )
01421 {
01422 fprintf(stderr,"** missing '-surf_A SURF_NAME' option\n");
01423 RETURN(-1);
01424 }
01425
01426 if ( opts->use_norms )
01427 {
01428 if ( opts->snames[1] )
01429 {
01430 fprintf(stderr,"** no '-use_norms' option with 2 surfaces\n");
01431 RETURN(-1);
01432 }
01433 }
01434 else if ( opts->norm_len != 1.0 || opts->norm_dir )
01435 {
01436 fprintf(stderr,"** options for normals requires '-use_norms'\n");
01437 RETURN(-1);
01438 }
01439
01440 if ( check_outfile( opts, p ) != 0 )
01441 RETURN(-1);
01442
01443 if ( validate_datasets( opts, p ) != 0 )
01444 RETURN(-1);
01445
01446 if ( opts->debug > 1 )
01447 disp_v2s_param_t( "++ opts validated: ", p );
01448
01449 RETURN(0);
01450 }
01451
01452
01453
01454
01455
01456
01457 int check_outfile( opts_t * opts, v2s_param_t * p )
01458 {
01459 ENTRY("check_outfile");
01460
01461 if ( opts == NULL || p == NULL )
01462 RETURN(-1);
01463
01464 if ( THD_is_file(opts->outfile_1D) )
01465 {
01466 fprintf(stderr, "** output file '%s' already exists\n",
01467 opts->outfile_1D);
01468 RETURN(-1);
01469 }
01470
01471 if ( THD_is_file(opts->outfile_niml) )
01472 {
01473 fprintf(stderr, "** output file '%s' already exists\n",
01474 opts->outfile_niml);
01475 RETURN(-1);
01476 }
01477
01478 RETURN(0);
01479 }
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489 int check_map_func ( char * map_str )
01490 {
01491 int map;
01492
01493 ENTRY("check_map_func");
01494
01495 if ( map_str == NULL )
01496 {
01497 fprintf( stderr, "** missing option: '-map_func FUNCTION'\n" );
01498 RETURN(E_SMAP_INVALID);
01499 }
01500
01501 map = v2s_map_type( map_str );
01502
01503 switch ( map )
01504 {
01505 default:
01506 map = E_SMAP_INVALID;
01507 break;
01508
01509 case E_SMAP_COUNT:
01510 case E_SMAP_MASK2:
01511 fprintf( stderr, "** function '%s' coming soon ...\n",
01512 gv2s_map_names[map] );
01513 RETURN(E_SMAP_INVALID);
01514 break;
01515
01516 case E_SMAP_AVE:
01517 case E_SMAP_MASK:
01518 case E_SMAP_MAX:
01519 case E_SMAP_MAX_ABS:
01520 case E_SMAP_MIN:
01521 case E_SMAP_MIDPT:
01522 case E_SMAP_SEG_VALS:
01523 case E_SMAP_MEDIAN:
01524 case E_SMAP_MODE:
01525 break;
01526 }
01527
01528 if ( map == E_SMAP_INVALID )
01529 fprintf( stderr, "** invalid map string '%s'\n", map_str );
01530
01531 RETURN(map);
01532 }
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546 int validate_datasets( opts_t * opts, v2s_param_t * p )
01547 {
01548 int ccount = 0;
01549 ENTRY("validate_datasets");
01550
01551 p->gpar = THD_open_dataset( opts->gpar_file );
01552
01553 if ( !ISVALID_DSET(p->gpar) )
01554 {
01555 if ( opts->gpar_file == NULL )
01556 fprintf( stderr, "** error: missing '-grid_parent DSET' option\n" );
01557 else
01558 fprintf( stderr, "** error: invalid input dataset '%s'\n",
01559 opts->gpar_file);
01560 RETURN(-1);
01561 }
01562 else if ( DSET_BRICK_TYPE(p->gpar, 0) == MRI_complex )
01563 {
01564 fprintf(stderr,
01565 "** failure: cannot deal with complex-valued dataset, '%s'\n",
01566 opts->gpar_file);
01567 RETURN(-1);
01568 }
01569 else if ( opts->gp_index >= DSET_NVALS(p->gpar) )
01570 {
01571 fprintf(stderr,"** error: gp_index (%d) > max grid parent index (%d)\n",
01572 opts->gp_index, DSET_NVALS(p->gpar)-1);
01573 RETURN(-1);
01574 }
01575
01576 p->nvox = DSET_NVOX( p->gpar );
01577
01578
01579
01580
01581 if ( opts->cmask_cmd != NULL )
01582 {
01583 int ncmask, clen = strlen( opts->cmask_cmd );
01584 char * cmd;
01585
01586
01587 cmd = (char *)malloc((clen + 1) * sizeof(char));
01588 strcpy( cmd, opts->cmask_cmd );
01589
01590 p->cmask = EDT_calcmask( cmd, &ncmask );
01591
01592 free( cmd );
01593
01594 if ( p->cmask == NULL )
01595 {
01596 fprintf( stderr, "** failure: cannot compute mask from option:\n"
01597 " -cmask '%s'\n", opts->cmask_cmd );
01598 RETURN(-1);
01599 }
01600 if ( ncmask != p->nvox )
01601 {
01602 fprintf( stderr, "** error: input and cmask datasets do not have "
01603 "the same dimensions\n" );
01604 RETURN(-1);
01605 }
01606 if ( ( ccount = THD_countmask( ncmask, p->cmask ) ) <= 0 )
01607 {
01608 fprintf( stderr, "** Warning! No voxels in computed cmask!\n" );
01609
01610 }
01611 }
01612
01613 if ( opts->debug > 0 )
01614 {
01615 fprintf( stderr, "++ input dset has nvox = %d, nvals = %d",
01616 p->nvox, DSET_NVALS(p->gpar) );
01617 if ( p->cmask == NULL )
01618 fputc( '\n', stderr );
01619 else
01620 fprintf( stderr, " (%d voxels in mask)\n", ccount );
01621 }
01622
01623 RETURN(0);
01624 }
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634 int usage ( char * prog, int level )
01635 {
01636 ENTRY("usage");
01637
01638 if ( level == V2S_USE_SHORT )
01639 {
01640 fprintf( stderr,
01641 "usage: %s [options] -spec SPEC_FILE -sv SURF_VOL "
01642 " -grid_parent AFNI_DSET\n"
01643 "usage: %s -help\n",
01644 prog, prog );
01645 }
01646 else if ( level == V2S_USE_LONG )
01647 {
01648 printf(
01649 "\n"
01650 "%s - map data from a volume domain to a surface domain\n"
01651 "\n"
01652 " usage: %s [options] -spec SPEC_FILE -sv SURF_VOL \\\n"
01653 " -grid_parent AFNI_DSET -map_func MAP_FUNC\n"
01654 "\n"
01655 "This program is used to map data values from an AFNI volume\n"
01656 "dataset to a surface dataset. A filter may be applied to the\n"
01657 "volume data to produce the value(s) for each surface node.\n"
01658 "\n"
01659 "The surface and volume domains are spacially matched via the\n"
01660 "'surface volume' AFNI dataset. This gives each surface node xyz\n"
01661 "coordinates, which are then matched to the input 'grid parent'\n"
01662 "dataset. This grid parent is an AFNI dataset containing the\n"
01663 "data values destined for output.\n"
01664 "\n"
01665 "Typically, two corresponding surfaces will be input (via the\n"
01666 "spec file and the '-surf_A' and '-surf_B' options), along with\n"
01667 "a mapping function and relevant options. The mapping function\n"
01668 "will act as a filter over the values in the AFNI volume.\n"
01669 "\n"
01670 "Note that an alternative to using a second surface with the\n"
01671 "'-surf_B' option is to define the second surface by using the\n"
01672 "normals from the first surface. By default, the second surface\n"
01673 "would be defined at a distance of 1mm along the normals, but the\n"
01674 "user may modify the applied distance (and direction). See the\n"
01675 "'-use_norms' and '-norm_len' options for more details.\n"
01676 "\n"
01677 "For each pair of corresponding surface nodes, let NA be the node\n"
01678 "on surface A (such as a white/grey boundary) and NB be the\n"
01679 "corresponding node on surface B (such as a pial surface). The\n"
01680 "filter is applied to the volume data values along the segment\n"
01681 "from NA to NB (consider the average or maximum as examples of\n"
01682 "filters).\n"
01683 "\n"
01684 "Note: if either endpoint of a segment is outside the grid parent\n"
01685 " volume, that node (pair) will be skipped.\n"
01686 "\n"
01687 "Note: surface A corresponds to the required '-surf_A' argument,\n"
01688 " while surface B corresponds to '-surf_B'.\n"
01689 "\n",
01690 prog, prog);
01691
01692 printf(
01693 "By default, this segment only consists of the endpoints, NA and\n"
01694 "NB (the actual nodes on the two surfaces). However the number\n"
01695 "of evenly spaced points along the segment may be specified with\n"
01696 "the -f_steps option, and the actual locations of NA and NB may\n"
01697 "be altered with any of the -f_pX_XX options, covered below.\n"
01698 "\n"
01699 "As an example, for each node pair, one could output the average\n"
01700 "value from some functional dataset along a segment of 10 evenly\n"
01701 "spaced points, where the segment endpoints are defined by the\n"
01702 "xyz coordinates of the nodes. This is example 3, below.\n"
01703 "\n"
01704 "The mapping function (i.e. filter) is a required parameter to\n"
01705 "the program.\n"
01706 "\n"
01707 "Brief descriptions of the current mapping functions are as\n"
01708 "follows. These functions are defined over a segment of points.\n"
01709 "\n"
01710 " ave : output the average of all voxel values along the\n"
01711 " segment\n"
01712 " mask : output the voxel value for the trivial case of a\n"
01713 " segment - defined by a single surface point\n"
01714 " median : output the median value from the segment\n"
01715 " midpoint : output the dataset value at the segment midpoint\n"
01716 " mode : output the mode of the values along the segment\n"
01717 " max : output the maximum volume value over the segment\n"
01718 " max_abs : output the dataset value with max abs over seg\n"
01719 " min : output the minimum volume value over the segment\n"
01720 " seg_vals : output _all_ volume values over the segment (one\n"
01721 " sub-brick only)\n"
01722 "\n"
01723 );
01724
01725 printf(
01726 " --------------------------------------------------\n"
01727 "\n"
01728 " examples:\n"
01729 "\n"
01730 " 1. Apply a single surface mask to output volume values over\n"
01731 " each surface node. Output is one value per sub-brick\n"
01732 " (per surface node).\n"
01733 "\n"
01734 " %s \\\n"
01735 " -spec fred.spec \\\n"
01736 " -surf_A smoothwm \\\n"
01737 " -sv fred_anat+orig \\\n"
01738 " -grid_parent fred_anat+orig \\\n"
01739 " -map_func mask \\\n"
01740 " -out_1D fred_anat_vals.1D\n"
01741 "\n"
01742 " 2. Apply a single surface mask to output volume values over\n"
01743 " each surface node. In this case restrict input to the\n"
01744 " mask implied by the -cmask option. Supply additional\n"
01745 " debug output, and more for surface node 1874\n"
01746 "\n"
01747 " %s \\\n"
01748 " -spec fred.spec \\\n"
01749 " -surf_A smoothwm \\\n"
01750 " -sv fred_anat+orig \\\n"
01751 " -grid_parent 'fred_epi+orig[0]' \\\n"
01752 " -cmask '-a fred_func+orig[2] -expr step(a-0.6)' \\\n"
01753 " -map_func mask \\\n"
01754 " -debug 2 \\\n"
01755 " -dnode 1874 \\\n"
01756 " -out_niml fred_epi_vals.niml\n"
01757 "\n"
01758 " 3. Given a pair of related surfaces, for each node pair,\n"
01759 " break the connected line segment into 10 points, and\n"
01760 " compute the average dataset value over those points.\n"
01761 " Since the index is nodes, each of the 10 points will be\n"
01762 " part of the average. This could be changed so that only\n"
01763 " values from distinct volume nodes are considered (by\n"
01764 " changing the -f_index from nodes to voxels). Restrict\n"
01765 " input voxels to those implied by the -cmask option\n"
01766 " Output is one average value per sub-brick (per surface\n"
01767 " node).\n"
01768 "\n"
01769 " %s \\\n"
01770 " -spec fred.spec \\\n"
01771 " -surf_A smoothwm \\\n"
01772 " -surf_B pial \\\n"
01773 " -sv fred_anat+orig \\\n"
01774 " -grid_parent fred_func+orig \\\n"
01775 " -cmask '-a fred_func+orig[2] -expr step(a-0.6)' \\\n"
01776 " -map_func ave \\\n"
01777 " -f_steps 10 \\\n"
01778 " -f_index nodes \\\n"
01779 " -out_1D fred_func_ave.1D\n"
01780 "\n"
01781 " 4. Similar to example 3, but restrict the output columns to\n"
01782 " only node indices and values (i.e. skip 1dindex, i, j, k\n"
01783 " and vals).\n"
01784 "\n"
01785 " %s \\\n"
01786 " -spec fred.spec \\\n"
01787 " -surf_A smoothwm \\\n"
01788 " -surf_B pial \\\n"
01789 " -sv fred_anat+orig \\\n"
01790 " -grid_parent fred_func+orig \\\n"
01791 " -cmask '-a fred_func+orig[2] -expr step(a-0.6)' \\\n"
01792 " -map_func ave \\\n"
01793 " -f_steps 10 \\\n"
01794 " -f_index nodes \\\n"
01795 " -skip_col_1dindex \\\n"
01796 " -skip_col_i \\\n"
01797 " -skip_col_j \\\n"
01798 " -skip_col_k \\\n"
01799 " -skip_col_vals \\\n"
01800 " -out_1D fred_func_ave_short.1D\n"
01801 "\n"
01802 " 5. Similar to example 3, but each of the node pair segments\n"
01803 " has grown by 10%% on the inside of the first surface,\n"
01804 " and 20%% on the outside of the second. This is a 30%%\n"
01805 " increase in the length of each segment. To shorten the\n"
01806 " node pair segment, use a '+' sign for p1 and a '-' sign\n"
01807 " for pn.\n"
01808 " As an interesting side note, '-f_p1_fr 0.5 -f_pn_fr -0.5'\n"
01809 " would give a zero length vector identical to that of the\n"
01810 " 'midpoint' filter.\n"
01811 "\n"
01812 " %s \\\n"
01813 " -spec fred.spec \\\n"
01814 " -surf_A smoothwm \\\n"
01815 " -surf_B pial \\\n"
01816 " -sv fred_anat+orig \\\n"
01817 " -grid_parent fred_func+orig \\\n"
01818 " -cmask '-a fred_func+orig[2] -expr step(a-0.6)' \\\n"
01819 " -map_func ave \\\n"
01820 " -f_steps 10 \\\n"
01821 " -f_index voxels \\\n"
01822 " -f_p1_fr -0.1 \\\n"
01823 " -f_pn_fr 0.2 \\\n"
01824 " -out_1D fred_func_ave2.1D\n"
01825 "\n"
01826 " 6. Similar to example 3, instead of computing the average\n"
01827 " across each segment (one average per sub-brick), output\n"
01828 " the volume value at _every_ point across the segment.\n"
01829 " The output here would be 'f_steps' values per node pair,\n"
01830 " though the output could again be restricted to unique\n"
01831 " voxels along each segment with '-f_index voxels'.\n"
01832 " Note that only sub-brick 0 will be considered here.\n"
01833 "\n"
01834 " %s \\\n"
01835 " -spec fred.spec \\\n"
01836 " -surf_A smoothwm \\\n"
01837 " -surf_B pial \\\n"
01838 " -sv fred_anat+orig \\\n"
01839 " -grid_parent fred_func+orig \\\n"
01840 " -cmask '-a fred_func+orig[2] -expr step(a-0.6)' \\\n"
01841 " -map_func seg_vals \\\n"
01842 " -f_steps 10 \\\n"
01843 " -f_index nodes \\\n"
01844 " -out_1D fred_func_segvals_10.1D\n"
01845 "\n"
01846 " 7. Similar to example 6, but make sure there is output for\n"
01847 " every node pair in the surfaces. Since it is expected\n"
01848 " that some nodes are out of bounds (meaning that they lie\n"
01849 " outside the domain defined by the grid parent dataset),\n"
01850 " the '-oob_value' option is added to include a default\n"
01851 " value of 0.0 in such cases. And since it is expected\n"
01852 " that some node pairs are \"out of mask\" (meaning that\n"
01853 " their resulting segment lies entirely outside the cmask),\n"
01854 " the '-oom_value' was added to output the same default\n"
01855 " value of 0.0.\n"
01856 "\n"
01857 " %s \\\n"
01858 " -spec fred.spec \\\n"
01859 " -surf_A smoothwm \\\n"
01860 " -surf_B pial \\\n"
01861 " -sv fred_anat+orig \\\n"
01862 " -grid_parent fred_func+orig \\\n"
01863 " -cmask '-a fred_func+orig[2] -expr step(a-0.6)' \\\n"
01864 " -map_func seg_vals \\\n"
01865 " -f_steps 10 \\\n"
01866 " -f_index nodes \\\n"
01867 " -oob_value 0.0 \\\n"
01868 " -oom_value 0.0 \\\n"
01869 " -out_1D fred_func_segvals_10_all.1D\n"
01870 "\n"
01871 " 8. This is a basic example of calculating the average along\n"
01872 " each segment, but where the segment is produced by only\n"
01873 " one surface, along with its set of surface normals. The\n"
01874 " segments will be 2.5 mm in length.\n"
01875 "\n"
01876 " %s \\\n"
01877 " -spec fred.spec \\\n"
01878 " -surf_A smoothwm \\\n"
01879 " -sv fred_anat+orig \\\n"
01880 " -grid_parent fred_anat+orig \\\n"
01881 " -use_norms \\\n"
01882 " -norm_len 2.5 \\\n"
01883 " -map_func ave \\\n"
01884 " -f_steps 10 \\\n"
01885 " -f_index nodes \\\n"
01886 " -out_1D fred_anat_norm_ave.2.5.1D\n"
01887 "\n"
01888 " 9. This is the same as example 8, but where the surface\n"
01889 " nodes are restricted to the range 1000..1999 via the\n"
01890 " options '-first_node' and '-last_node'.\n"
01891 "\n"
01892 " %s \\\n"
01893 " -spec fred.spec \\\n"
01894 " -surf_A smoothwm \\\n"
01895 " -sv fred_anat+orig \\\n"
01896 " -grid_parent fred_anat+orig \\\n"
01897 " -first_node 1000 \\\n"
01898 " -last_node 1999 \\\n"
01899 " -use_norms \\\n"
01900 " -norm_len 2.5 \\\n"
01901 " -map_func ave \\\n"
01902 " -f_steps 10 \\\n"
01903 " -f_index nodes \\\n"
01904 " -out_1D fred_anat_norm_ave.2.5.1D\n"
01905 "\n"
01906 " --------------------------------------------------\n",
01907 prog, prog, prog, prog, prog, prog, prog, prog, prog );
01908
01909 printf(
01910 "\n"
01911 " REQUIRED COMMAND ARGUMENTS:\n"
01912 "\n"
01913 " -spec SPEC_FILE : SUMA spec file\n"
01914 "\n"
01915 " e.g. -spec fred.spec\n"
01916 "\n"
01917 " The surface specification file contains the list of\n"
01918 " mappable surfaces that are used.\n"
01919 "\n"
01920 " See @SUMA_Make_Spec_FS and @SUMA_Make_Spec_SF.\n"
01921 "\n"
01922 " -surf_A SURF_NAME : name of surface A (from spec file)\n"
01923 " -surf_B SURF_NAME : name of surface B (from spec file)\n"
01924 "\n"
01925 " e.g. -surf_A smoothwm\n"
01926 " e.g. -surf_A lh.smoothwm\n"
01927 " e.g. -surf_B lh.pial\n"
01928 "\n"
01929 " This is used to specify which surface(s) will be used by\n"
01930 " the program. The '-surf_A' parameter is required, as it\n"
01931 " specifies the first surface, whereas since '-surf_B' is\n"
01932 " used to specify an optional second surface, it is not\n"
01933 " required.\n"
01934 "\n"
01935 " Note that any need for '-surf_B' may be fulfilled using\n"
01936 " the '-use_norms' option.\n"
01937 "\n"
01938 " Note that any name provided must be in the spec file,\n"
01939 " uniquely matching the name of a surface node file (such\n"
01940 " as lh.smoothwm.asc, for example). Note that if both\n"
01941 " hemispheres are represented in the spec file, then there\n"
01942 " may be both lh.pial.asc and rh.pial.asc, for instance.\n"
01943 " In such a case, 'pial' would not uniquely determine a\n"
01944 " a surface, but the name 'lh.pial' would.\n"
01945 "\n"
01946 " -sv SURFACE_VOLUME : AFNI volume dataset\n"
01947 "\n"
01948 " e.g. -sv fred_anat+orig\n"
01949 "\n"
01950 " This is the AFNI dataset that the surface is mapped to.\n"
01951 " This dataset is used for the initial surface node to xyz\n"
01952 " coordinate mapping, in the Dicom orientation.\n"
01953 "\n"
01954 " -grid_parent AFNI_DSET : AFNI volume dataset\n"
01955 "\n"
01956 " e.g. -grid_parent fred_function+orig\n"
01957 "\n"
01958 " This dataset is used as a grid and orientation master\n"
01959 " for the output (i.e. it defines the volume domain).\n"
01960 " It is also the source of the output data values.\n"
01961 "\n"
01962 " -map_func MAP_FUNC : filter for values along the segment\n"
01963 "\n"
01964 " e.g. -map_func ave\n"
01965 " e.g. -map_func ave -f_steps 10\n"
01966 " e.g. -map_func ave -f_steps 10 -f_index nodes\n"
01967 "\n"
01968 " The current mapping function for 1 surface is:\n"
01969 "\n"
01970 " mask : For each surface xyz location, output the\n"
01971 " dataset values of each sub-brick.\n"
01972 "\n"
01973 " Most mapping functions are defined for 2 related input\n"
01974 " surfaces (such as white/grey boundary and pial). For\n"
01975 " each node pair, the function will be performed on the\n"
01976 " values from the 'grid parent dataset', and along the\n"
01977 " segment connecting the nodes.\n"
01978 "\n"
01979 " ave : Output the average of the dataset values\n"
01980 " along the segment.\n"
01981 "\n"
01982 " max : Output the maximum dataset value along the\n"
01983 " connecting segment.\n"
01984 "\n"
01985 " max_abs : Output the dataset value with the maximum\n"
01986 " absolute value along the segment.\n"
01987 "\n"
01988 " median : Output the median of the dataset values\n"
01989 " along the connecting segment.\n"
01990 "\n"
01991 " midpoint : Output the dataset value with xyz\n"
01992 " coordinates at the midpoint of the nodes.\n"
01993 "\n"
01994 " min : Output the minimum dataset value along the\n"
01995 " connecting segment.\n"
01996 "\n"
01997 " mode : Output the mode of the dataset values along\n"
01998 " the connecting segment.\n"
01999 "\n"
02000 " seg_vals : Output all of the dataset values along the\n"
02001 " connecting segment. Here, only sub-brick\n"
02002 " number 0 will be considered.\n"
02003 "\n"
02004 " ------------------------------\n"
02005 "\n"
02006 " options specific to functions on 2 surfaces:\n"
02007 "\n"
02008 " -f_steps NUM_STEPS :\n"
02009 "\n"
02010 " Use this option to specify the number of\n"
02011 " evenly spaced points along each segment.\n"
02012 " The default is 2 (i.e. just use the two\n"
02013 " surface nodes as endpoints).\n"
02014 "\n"
02015 " e.g. -f_steps 10\n"
02016 " default: -f_steps 2\n"
02017 "\n"
02018 " -f_index TYPE :\n"
02019 "\n"
02020 " This option specifies whether to use all\n"
02021 " segment point values in the filter (using\n"
02022 " the 'nodes' TYPE), or to use only those\n"
02023 " corresponding to unique volume voxels (by\n"
02024 " using the 'voxel' TYPE).\n"
02025 "\n"
02026 " For instance, when taking the average along\n"
02027 " one node pair segment using 10 node steps,\n"
02028 " perhaps 3 of those nodes may occupy one\n"
02029 " particular voxel. In this case, does the\n"
02030 " user want the voxel counted only once, or 3\n" " times? Each way makes sense.\n"
02031 " \n"
02032 " Note that this will only make sense when\n"
02033 " used along with the '-f_steps' option.\n"
02034 " \n"
02035 " Possible values are \"nodes\", \"voxels\".\n"
02036 " The default value is voxels. So each voxel\n"
02037 " along a segment will be counted only once.\n"
02038 " \n"
02039 " e.g. -f_index nodes\n"
02040 " e.g. -f_index voxels\n"
02041 " default: -f_index voxels\n"
02042 "\n"
02043 " -f_keep_surf_order :\n"
02044 "\n"
02045 " Depreciated.\n"
02046 "\n"
02047 " See required arguments -surf_A and -surf_B,\n"
02048 " above.\n"
02049 "\n"
02050 " Note: The following -f_pX_XX options are used to alter\n"
02051 " the lengths and locations of the computational\n"
02052 " segments. Recall that by default, segments are\n"
02053 " defined using the node pair coordinates as\n"
02054 " endpoints. And the direction from p1 to pn is\n"
02055 " from the inner surface to the outer surface.\n"
02056 "\n"
02057 " -f_p1_mm DISTANCE :\n"
02058 "\n"
02059 " This option is used to specify a distance\n"
02060 " in millimeters to add to the first point of\n"
02061 " each line segment (in the direction of the\n"
02062 " second point). DISTANCE can be negative\n"
02063 " (which would set p1 to be farther from pn\n"
02064 " than before).\n"
02065 "\n"
02066 " For example, if a computation is over the\n"
02067 " grey matter (from the white matter surface\n"
02068 " to the pial), and it is wished to increase\n"
02069 " the range by 1mm, set this DISTANCE to -1.0\n"
02070 " and the DISTANCE in -f_pn_mm to 1.0.\n"
02071 "\n"
02072 " e.g. -f_p1_mm -1.0\n"
02073 " e.g. -f_p1_mm -1.0 -f_pn_mm 1.0\n"
02074 "\n"
02075 " -f_pn_mm DISTANCE :\n"
02076 "\n"
02077 " Similar to -f_p1_mm, this option is used\n"
02078 " to specify a distance in millimeters to add\n"
02079 " to the second point of each line segment.\n"
02080 " Note that this is in the same direction as\n"
02081 " above, from point p1 to point pn.\n"
02082 " \n"
02083 " So a positive DISTANCE, for this option,\n"
02084 " would set pn to be farther from p1 than\n"
02085 " before, and a negative DISTANCE would set\n"
02086 " it to be closer.\n"
02087 "\n"
02088 " e.g. -f_pn_mm 1.0\n"
02089 " e.g. -f_p1_mm -1.0 -f_pn_mm 1.0\n"
02090 "\n"
02091 " -f_p1_fr FRACTION :\n"
02092 "\n"
02093 " Like the -f_pX_mm options above, this\n"
02094 " is used to specify a change to point p1, in\n"
02095 " the direction of point pn, but the change\n"
02096 " is a fraction of the original distance,\n"
02097 " not a pure change in millimeters.\n"
02098 " \n"
02099 " For example, suppose one wishes to do a\n"
02100 " computation based on the segments spanning\n"
02101 " the grey matter, but to add 20%% to either\n"
02102 " side. Then use -0.2 and 0.2:\n"
02103 "\n"
02104 " e.g. -f_p1_fr -0.2\n"
02105 " e.g. -f_p1_fr -0.2 -f_pn_fr 0.2\n"
02106 "\n"
02107 " -f_pn_fr FRACTION :\n"
02108 "\n"
02109 " See -f_p1_fr above. Note again that the\n"
02110 " FRACTION is in the direction from p1 to pn.\n"
02111 " So to extend the segment past pn, this\n"
02112 " FRACTION will be positive (and to reduce\n"
02113 " the segment back toward p1, this -f_pn_fr\n"
02114 " FRACTION will be negative).\n"
02115 "\n"
02116 " e.g. -f_pn_fr 0.2\n"
02117 " e.g. -f_p1_fr -0.2 -f_pn_fr 0.2\n"
02118 "\n"
02119 " Just for entertainment, one could reverse\n"
02120 " the order that the segment points are\n"
02121 " considered by adjusting p1 to be pn, and\n"
02122 " pn to be p1. This could be done by adding\n"
02123 " a fraction of 1.0 to p1 and by subtracting\n"
02124 " a fraction of 1.0 from pn.\n"
02125 "\n"
02126 " e.g. -f_p1_fr 1.0 -f_pn_fr -1.0\n"
02127 "\n"
02128 " ------------------------------\n"
02129 );
02130
02131 printf(
02132 "\n"
02133 " options specific to use of normals:\n"
02134 "\n"
02135 " Notes:\n"
02136 "\n"
02137 " o Using a single surface with its normals for segment\n"
02138 " creation can be done in lieu of using two surfaces.\n"
02139 "\n"
02140 " o Normals at surface nodes are defined by the average of\n"
02141 " the normals of the triangles including the given node.\n"
02142 "\n"
02143 " o The default normals have a consistent direction, but it\n"
02144 " may be opposite of what is should be. For this reason,\n"
02145 " the direction is verified by default, and may be negated\n"
02146 " internally. See the '-keep_norm_dir' option for more\n"
02147 " information.\n"
02148 "\n"
02149 " -use_norms : use normals for second surface\n"
02150 "\n"
02151 " Segments are usually defined by connecting corresponding\n"
02152 " node pairs from two surfaces. With this options the\n"
02153 " user can use one surface, along with its normals, to\n"
02154 " define the segments.\n"
02155 "\n"
02156 " By default, each segment will be 1.0 millimeter long, in\n"
02157 " the direction of the normal. The '-norm_len' option\n"
02158 " can be used to alter this default action.\n"
02159 "\n"
02160 " -keep_norm_dir : keep the direction of the normals\n"
02161 "\n"
02162 " Normal directions are verified by checking that the\n"
02163 " normals of the outermost 6 points point away from the\n"
02164 " center of mass. If they point inward instead, then\n"
02165 " they are negated.\n"
02166 "\n"
02167 " This option will override the directional check, and\n"
02168 " use the normals as they come.\n"
02169 "\n"
02170 " See also -reverse_norm_dir, below.\n"
02171 "\n"
02172 " -norm_len LENGTH : use LENGTH for node normals\n"
02173 "\n"
02174 " e.g. -norm_len 3.0\n"
02175 " e.g. -norm_len -3.0\n"
02176 " default: -norm_len 1.0\n"
02177 "\n"
02178 " For use with the '-use_norms' option, this allows the\n"
02179 " user to specify a directed distance to use for segments\n"
02180 " based on the normals. So for each node on a surface,\n"
02181 " the computation segment will be from the node, in the\n"
02182 " direction of the normal, a signed distance of LENGTH.\n"
02183 "\n"
02184 " A negative LENGTH means to use the opposite direction\n"
02185 " from the normal.\n"
02186 "\n"
02187 " The '-surf_B' option is not allowed with the use of\n"
02188 " normals.\n"
02189 "\n"
02190 " -reverse_norm_dir : reverse the normal directions\n"
02191 "\n"
02192 " Normal directions are verified by checking that the\n"
02193 " normals of the outermost 6 points point away from the\n"
02194 " center of mass. If they point inward instead, then\n"
02195 " they are negated.\n"
02196 "\n"
02197 " This option will override the directional check, and\n"
02198 " reverse the direction of the normals as they come.\n"
02199 "\n"
02200 " See also -keep_norm_dir, above.\n"
02201 "\n"
02202 " ------------------------------\n"
02203 "\n"
02204 " general options:\n"
02205 "\n"
02206 " -cmask MASK_COMMAND : (optional) command for dataset mask\n"
02207 "\n"
02208 " e.g. -cmask '-a fred_func+orig[2] -expr step(a-0.8)'\n"
02209 "\n"
02210 " This option will produce a mask to be applied to the\n"
02211 " input AFNI dataset. Note that this mask should form a\n"
02212 " single sub-brick.\n"
02213 "\n"
02214 " This option follows the style of 3dmaskdump (since the\n"
02215 " code for it was, uh, borrowed from there (thanks Bob!)).\n"
02216 "\n"
02217 " See '3dmaskdump -help' for more information.\n"
02218 "\n"
02219 " -debug LEVEL : (optional) verbose output\n"
02220 "\n"
02221 " e.g. -debug 2\n"
02222 "\n"
02223 " This option is used to print out status information \n"
02224 " during the execution of the program. Current levels are\n"
02225 " from 0 to 5.\n"
02226 "\n"
02227 " -first_node NODE_NUM : skip all previous nodes\n"
02228 "\n"
02229 " e.g. -first_node 1000\n"
02230 " e.g. -first_node 1000 -last_node 1999\n"
02231 "\n"
02232 " Restrict surface node output to those with indices as\n"
02233 " large as NODE_NUM. In the first example, the first 1000\n"
02234 " nodes are ignored (those with indices from 0 through\n"
02235 " 999).\n"
02236 "\n"
02237 " See also, '-last_node'.\n"
02238 "\n"
02239 " -dnode NODE_NUM : (optional) node for debug\n"
02240 "\n"
02241 " e.g. -dnode 1874\n"
02242 "\n"
02243 " This option is used to print out status information \n"
02244 " for node NODE_NUM.\n"
02245 "\n"
02246 " -gp_index SUB_BRICK : choose grid_parent sub-brick\n"
02247 "\n"
02248 " e.g. -gp_index 3\n"
02249 "\n"
02250 " This option allows the user to choose only a single\n"
02251 " sub-brick from the grid_parent dataset for computation.\n"
02252 " Note that this option is virtually useless when using\n"
02253 " the command-line, as the user can more directly do this\n"
02254 " via brick selectors, e.g. func+orig'[3]'.\n"
02255 " \n"
02256 " This option was written for the afni interface.\n"
02257 "\n"
02258 " -help : show this help\n"
02259 "\n"
02260 " If you can't get help here, please get help somewhere.\n"
02261 "\n"
02262 " -hist : show revision history\n"
02263 "\n"
02264 " Display module history over time.\n"
02265 "\n"
02266 " See also, -v2s_hist\n"
02267 "\n"
02268 " -last_node NODE_NUM : skip all following nodes\n"
02269 "\n"
02270 " e.g. -last_node 1999\n"
02271 " e.g. -first_node 1000 -last_node 1999\n"
02272 "\n"
02273 " Restrict surface node output to those with indices no\n"
02274 " larger than NODE_NUM. In the first example, nodes above\n"
02275 " 1999 are ignored (those with indices from 2000 on up).\n"
02276 "\n"
02277 " See also, '-first_node'.\n"
02278 "\n"
02279 " -no_headers : do not output column headers\n"
02280 "\n"
02281 " Column header lines all begin with the '#' character.\n"
02282 " With the '-no_headers' option, these lines will not be\n"
02283 " output.\n"
02284 "\n"
02285 " -oob_index INDEX_NUM : specify default index for oob nodes\n"
02286 "\n"
02287 " e.g. -oob_index -1\n"
02288 " default: -oob_index 0\n"
02289 "\n"
02290 " By default, nodes which lie outside the box defined by\n"
02291 " the -grid_parent dataset are considered out of bounds,\n"
02292 " and are skipped. If an out of bounds index is provided,\n"
02293 " or an out of bounds value is provided, such nodes will\n"
02294 " not be skipped, and will have indices and values output,\n"
02295 " according to the -oob_index and -oob_value options.\n"
02296 " \n"
02297 " This INDEX_NUM will be used for the 1dindex field, along\n"
02298 " with the i, j and k indices.\n"
02299 " \n"
02300 "\n"
02301 " -oob_value VALUE : specify default value for oob nodes\n"
02302 "\n"
02303 " e.g. -oob_value -999.0\n"
02304 " default: -oob_value 0.0\n"
02305 "\n"
02306 " See -oob_index, above.\n"
02307 " \n"
02308 " VALUE will be output for nodes which are out of bounds.\n"
02309 "\n"
02310 " -oom_value VALUE : specify default value for oom nodes\n"
02311 "\n"
02312 " e.g. -oom_value -999.0\n"
02313 " e.g. -oom_value 0.0\n"
02314 "\n"
02315 " By default, node pairs defining a segment which gets\n"
02316 " completely obscured by a command-line mask (see -cmask)\n"
02317 " are considered \"out of mask\", and are skipped.\n"
02318 "\n"
02319 " If an out of mask value is provided, such nodes will not\n"
02320 " be skipped. The output indices will come from the first\n"
02321 " segment point, mapped to the AFNI volume. All output vN\n"
02322 " values will be the VALUE provided with this option.\n"
02323 "\n"
02324 " This option is meaningless without a '-cmask' option.\n"
02325 "\n"
02326 " -out_1D OUTPUT_FILE : specify a 1D file for the output\n"
02327 "\n"
02328 " e.g. -out_1D mask_values_over_dataset.1D\n"
02329 "\n"
02330 " This is where the user will specify which file they want\n"
02331 " the output to be written to. In this case, the output\n"
02332 " will be in readable, column-formatted ASCII text.\n"
02333 "\n"
02334 " Note : the output file should not yet exist.\n"
02335 " : -out_1D or -out_niml must be used\n"
02336 "\n"
02337 " -out_niml OUTPUT_FILE : specify a niml file for the output\n"
02338 "\n"
02339 " e.g. -out_niml mask_values_over_dataset.niml\n"
02340 "\n"
02341 " The user may use this option to get output in the form\n"
02342 " of a niml element, with binary data. The output will\n"
02343 " contain (binary) columns of the form:\n"
02344 "\n"
02345 " node_index value_0 value_1 value_2 ...\n"
02346 "\n"
02347 " A major difference between 1D output and niml output is\n"
02348 " that the value_0 column number will be 6 in the 1D case,\n"
02349 " but will be 2 in the niml case. The index columns will\n"
02350 " not be used for niml output.\n"
02351 "\n"
02352 " Note : the output file should not yet exist.\n"
02353 " : -out_1D or -out_niml must be used\n"
02354 "\n"
02355 " -skip_col_nodes : do not output node column\n"
02356 " -skip_col_1dindex : do not output 1dindex column\n"
02357 " -skip_col_i : do not output i column\n"
02358 " -skip_col_j : do not output j column\n"
02359 " -skip_col_k : do not output k column\n"
02360 " -skip_col_vals : do not output vals column\n"
02361 " -skip_col_results : only output ONE result column\n"
02362 " (seems to make the most sense)\n"
02363 " -skip_col_non_results : skip everything but the results\n"
02364 " (i.e. only output result columns)\n"
02365 "\n"
02366 " These options are used to restrict output. Each option\n"
02367 " will prevent the program from writing that column of\n"
02368 " output to the 1D file.\n"
02369 "\n"
02370 " For now, the only effect that these options can have on\n"
02371 " the niml output is by skipping nodes or results (all\n"
02372 " other columns are skipped by default).\n"
02373 "\n"
02374 " -v2s_hist : show revision history for library\n"
02375 "\n"
02376 " Display vol2surf library history over time.\n"
02377 "\n"
02378 " See also, -hist\n"
02379 "\n"
02380 " -version : show version information\n"
02381 "\n"
02382 " Show version and compile date.\n"
02383 "\n"
02384 " --------------------------------------------------\n"
02385 "\n"
02386 "Output from the program defaults to 1D format, in ascii text.\n"
02387 "For each node (pair) that results in output, there will be one\n"
02388 "line, consisting of:\n"
02389 "\n"
02390 " node : the index of the current node (or node pair)\n"
02391 "\n"
02392 " 1dindex : the global index of the AFNI voxel used for output\n"
02393 "\n"
02394 " Note that for some filters (min, max, midpoint,\n"
02395 " median and mode) there is a specific location (and\n"
02396 " therefore voxel) that the result comes from. It\n"
02397 " will be accurate (though median may come from one\n"
02398 " of two voxels that are averaged).\n"
02399 "\n"
02400 " For filters without a well-defined source (such as\n"
02401 " average or seg_vals), the 1dindex will come from\n"
02402 " the first point on the corresponding segment.\n"
02403 "\n"
02404 " Note: this will _not_ be output in the niml case.\n"
02405 "\n"
02406 " i j k : the i j k indices matching 1dindex\n"
02407 "\n"
02408 " These indices are based on the orientation of the\n"
02409 " grid parent dataset.\n"
02410 "\n"
02411 " Note: these will _not_ be output in the niml case.\n"
02412 "\n"
02413 " vals : the number of segment values applied to the filter\n"
02414 "\n"
02415 " Note that when -f_index is 'nodes', this will\n"
02416 " always be the same as -f_steps, except when using\n"
02417 " the -cmask option. In that case, along a single \n"
02418 " segment, some points may be in the mask, and some\n"
02419 " may not.\n"
02420 "\n"
02421 " When -f_index is 'voxels' and -f_steps is used,\n"
02422 " vals will often be much smaller than -f_steps.\n"
02423 " This is because many segment points may in a\n"
02424 " single voxel.\n"
02425 "\n"
02426 " Note: this will _not_ be output in the niml case.\n"
02427 "\n"
02428 " v0, ... : the requested output values\n"
02429 "\n"
02430 " These are the filtered values, usually one per\n"
02431 " AFNI sub-brick. For example, if the -map_func\n"
02432 " is 'ave', then there will be one segment-based\n"
02433 " average output per sub-brick of the grid parent.\n"
02434 "\n"
02435 " In the case of the 'seg_vals' filter, however,\n"
02436 " there will be one output value per segment point\n"
02437 " (possibly further restricted to voxels). Since\n"
02438 " output is not designed for a matrix of values,\n"
02439 " 'seg_vals' is restricted to a single sub-brick.\n"
02440 "\n"
02441 "\n"
02442 " Author: R. Reynolds - %s\n"
02443 "\n"
02444 " (many thanks to Z. Saad and R.W. Cox)\n"
02445 "\n",
02446 VERSION );
02447 }
02448 else if ( level == V2S_USE_HIST )
02449 fputs(g_history, stdout);
02450 else if ( level == V2S_USE_LIB_HIST )
02451 fputs(gv2s_history, stdout);
02452 else if ( level == V2S_USE_VERSION )
02453 fprintf(stderr,"%s : %s, compile date: %s\n", prog, VERSION, __DATE__);
02454 else
02455 fprintf( stderr, "usage called with illegal level <%d>\n", level );
02456
02457 RETURN(-1);
02458 }
02459
02460
02461
02462
02463
02464
02465 int surf_ave_radius( float * radius, SUMA_SurfaceObject * so, int disp )
02466 {
02467 double ss, sum = 0.0;
02468 float * fp;
02469 float c0, c1, c2;
02470 int node;
02471
02472 ENTRY("surf_ave_radius");
02473
02474 if ( !so || !radius || so->N_Node <= 0 )
02475 {
02476 fprintf(stderr, "** disp_sar, so, radius == %p,%p\n", so, radius );
02477 RETURN(-1);
02478 }
02479
02480 c0 = so->Center[0];
02481 c1 = so->Center[1];
02482 c2 = so->Center[2];
02483
02484 fp = so->NodeList;
02485 for ( node = 0; node < so->N_Node; node++ )
02486 {
02487 ss = (*fp - c0) * (*fp - c0); fp++;
02488 ss += (*fp - c1) * (*fp - c1); fp++;
02489 ss += (*fp - c2) * (*fp - c2); fp++;
02490
02491 sum += sqrt(ss);
02492 }
02493
02494 *radius = sum/so->N_Node;
02495
02496 if ( disp )
02497 fprintf(stderr,"-- surf %s has average dist %f\n"
02498 " to center (%f, %f, %f)\n",
02499 so->Label, *radius, c0, c1, c2 );
02500
02501 RETURN(0);
02502 }
02503
02504
02505
02506
02507
02508
02509 int disp_opts_t ( char * info, opts_t * opts )
02510 {
02511 ENTRY("disp_opts_t");
02512
02513 if ( info )
02514 fputs( info, stderr );
02515
02516 if ( opts == NULL )
02517 {
02518 fprintf( stderr, "disp_opts_t: opts == NULL\n" );
02519 RETURN(-1);
02520 }
02521
02522 fprintf(stderr,
02523 "options struct at %p :\n"
02524 " gpar_file = %s\n"
02525 " outfile_1D = %s\n"
02526 " outfile_niml = %s\n"
02527 " spec_file = %s\n"
02528 " sv_file = %s\n"
02529 " cmask_cmd = %s\n"
02530 " map_str = %s\n"
02531 " snames[0,1] = %s, %s\n"
02532 " gp_index, no_head = %d, %d\n"
02533 " first_node, last_node = %d, %d\n"
02534 " use_norms, norm_len = %d, %f\n"
02535 " norm_dir, debug, dnode = %d, %d, %d\n"
02536 " f_index_str = %s\n"
02537 " f_steps = %d\n"
02538 " f_p1_fr, f_pn_fr = %f, %f\n"
02539 " f_p1_mm, f_pn_mm = %f, %f\n"
02540 , opts,
02541 CHECK_NULL_STR(opts->gpar_file), CHECK_NULL_STR(opts->outfile_1D),
02542 CHECK_NULL_STR(opts->outfile_niml),
02543 CHECK_NULL_STR(opts->spec_file), CHECK_NULL_STR(opts->sv_file),
02544 CHECK_NULL_STR(opts->cmask_cmd), CHECK_NULL_STR(opts->map_str),
02545 CHECK_NULL_STR(opts->snames[0]), CHECK_NULL_STR(opts->snames[1]),
02546 opts->gp_index, opts->no_head, opts->first_node, opts->last_node,
02547 opts->use_norms, opts->norm_len, opts->norm_dir, opts->debug,
02548 opts->dnode, CHECK_NULL_STR(opts->f_index_str), opts->f_steps,
02549 opts->f_p1_fr, opts->f_pn_fr, opts->f_p1_mm, opts->f_pn_mm
02550 );
02551
02552 RETURN(0);
02553 }
02554